diff options
author | Daniel Paoliello <danpao@microsoft.com> | 2023-08-31 12:06:50 -0700 |
---|---|---|
committer | Daniel Paoliello <danpao@microsoft.com> | 2023-08-31 12:06:50 -0700 |
commit | 0c5c7b52f0f395a6beb7956ba210b8ca727c0471 (patch) | |
tree | 1276e579895de3151c7a1de5131443c5b8f05bc1 /llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | |
parent | cf552493a417c838783568887337c99671b088fd (diff) | |
download | llvm-0c5c7b52f0f395a6beb7956ba210b8ca727c0471.zip llvm-0c5c7b52f0f395a6beb7956ba210b8ca727c0471.tar.gz llvm-0c5c7b52f0f395a6beb7956ba210b8ca727c0471.tar.bz2 |
Emit the CodeView `S_ARMSWITCHTABLE` debug symbol for jump tables
The CodeView `S_ARMSWITCHTABLE` debug symbol is used to describe the layout of a jump table, it contains the following information:
* The address of the branch instruction that uses the jump table.
* The address of the jump table.
* The "base" address that the values in the jump table are relative to.
* The type of each entry (absolute pointer, a relative integer, a relative integer that is shifted).
Together this information can be used by debuggers and binary analysis tools to understand what an jump table indirect branch is doing and where it might jump to.
Documentation for the symbol can be found in the Microsoft PDB library dumper: https://github.com/microsoft/microsoft-pdb/blob/0fe89a942f9a0f8e061213313e438884f4c9b876/cvdump/dumpsym7.cpp#L5518
This change adds support to LLVM to emit the `S_ARMSWITCHTABLE` debug symbol as well as to dump it out (for testing purposes).
Reviewed By: efriedma
Differential Revision: https://reviews.llvm.org/D149367
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 8161de5..47a18ec 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -13,6 +13,7 @@ #include "CodeViewDebug.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/TinyPtrVector.h" @@ -26,6 +27,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" @@ -1243,6 +1245,8 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, if (SP != nullptr) emitDebugInfoForUDTs(LocalUDTs); + emitDebugInfoForJumpTables(FI); + // We're done with this function. emitEndSymbolRecord(SymbolKind::S_PROC_ID_END); } @@ -1578,6 +1582,11 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { } } } + + // Mark branches that may potentially be using jump tables with labels. + bool isThumb = Triple(MMI->getModule()->getTargetTriple()).getArch() == + llvm::Triple::ArchType::thumb; + discoverJumpTableBranches(MF, isThumb); } static bool shouldEmitUdt(const DIType *T) { @@ -3083,6 +3092,10 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { } } + bool isThumb = Triple(MMI->getModule()->getTargetTriple()).getArch() == + llvm::Triple::ArchType::thumb; + collectDebugInfoForJumpTables(MF, isThumb); + CurFn->Annotations = MF->getCodeViewAnnotations(); CurFn->End = Asm->getFunctionEnd(); @@ -3442,3 +3455,135 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) { emitConstantSymbolRecord(DIGV->getType(), Value, QualifiedName); } } + +void forEachJumpTableBranch( + const MachineFunction *MF, bool isThumb, + const std::function<void(const MachineJumpTableInfo &, const MachineInstr &, + int64_t)> &Callback) { + auto JTI = MF->getJumpTableInfo(); + if (JTI && !JTI->isEmpty()) { +#ifndef NDEBUG + auto UsedJTs = llvm::SmallBitVector(JTI->getJumpTables().size()); +#endif + for (const auto &MBB : *MF) { + // Search for indirect branches... + const auto LastMI = MBB.getFirstTerminator(); + if (LastMI != MBB.end() && LastMI->isIndirectBranch()) { + if (isThumb) { + // ... that directly use jump table operands. + // NOTE: ARM uses pattern matching to lower its BR_JT SDNode to + // machine instructions, hence inserting a JUMP_TABLE_DEBUG_INFO node + // interferes with this process *but* the resulting pseudo-instruction + // uses a Jump Table operand, so extract the jump table index directly + // from that. + for (const auto &MO : LastMI->operands()) { + if (MO.isJTI()) { + unsigned Index = MO.getIndex(); +#ifndef NDEBUG + UsedJTs.set(Index); +#endif + Callback(*JTI, *LastMI, Index); + break; + } + } + } else { + // ... that have jump table debug info. + // NOTE: The debug info is inserted as a JUMP_TABLE_DEBUG_INFO node + // when lowering the BR_JT SDNode to an indirect branch. + for (auto I = MBB.instr_rbegin(), E = MBB.instr_rend(); I != E; ++I) { + if (I->isJumpTableDebugInfo()) { + unsigned Index = I->getOperand(0).getImm(); +#ifndef NDEBUG + UsedJTs.set(Index); +#endif + Callback(*JTI, *LastMI, Index); + break; + } + } + } + } + } +#ifndef NDEBUG + assert(UsedJTs.all() && + "Some of jump tables were not used in a debug info instruction"); +#endif + } +} + +void CodeViewDebug::discoverJumpTableBranches(const MachineFunction *MF, + bool isThumb) { + forEachJumpTableBranch( + MF, isThumb, + [this](const MachineJumpTableInfo &, const MachineInstr &BranchMI, + int64_t) { requestLabelBeforeInsn(&BranchMI); }); +} + +void CodeViewDebug::collectDebugInfoForJumpTables(const MachineFunction *MF, + bool isThumb) { + forEachJumpTableBranch( + MF, isThumb, + [this, MF](const MachineJumpTableInfo &JTI, const MachineInstr &BranchMI, + int64_t JumpTableIndex) { + // For label-difference jump tables, find the base expression. + // Otherwise the jump table uses an absolute address (so no base + // is required). + const MCSymbol *Base; + uint64_t BaseOffset = 0; + const MCSymbol *Branch = getLabelBeforeInsn(&BranchMI); + JumpTableEntrySize EntrySize; + switch (JTI.getEntryKind()) { + case MachineJumpTableInfo::EK_Custom32: + case MachineJumpTableInfo::EK_GPRel32BlockAddress: + case MachineJumpTableInfo::EK_GPRel64BlockAddress: + llvm_unreachable( + "EK_Custom32, EK_GPRel32BlockAddress, and " + "EK_GPRel64BlockAddress should never be emitted for COFF"); + case MachineJumpTableInfo::EK_BlockAddress: + // Each entry is an absolute address. + EntrySize = JumpTableEntrySize::Pointer; + Base = nullptr; + break; + case MachineJumpTableInfo::EK_Inline: + case MachineJumpTableInfo::EK_LabelDifference32: + // Ask the AsmPrinter. + std::tie(Base, BaseOffset, Branch, EntrySize) = + Asm->getCodeViewJumpTableInfo(JumpTableIndex, &BranchMI, Branch); + break; + } + + CurFn->JumpTables.push_back( + {EntrySize, Base, BaseOffset, Branch, + MF->getJTISymbol(JumpTableIndex, MMI->getContext()), + JTI.getJumpTables()[JumpTableIndex].MBBs.size()}); + }); +} + +void CodeViewDebug::emitDebugInfoForJumpTables(const FunctionInfo &FI) { + for (auto JumpTable : FI.JumpTables) { + MCSymbol *JumpTableEnd = beginSymbolRecord(SymbolKind::S_ARMSWITCHTABLE); + if (JumpTable.Base) { + OS.AddComment("Base offset"); + OS.emitCOFFSecRel32(JumpTable.Base, JumpTable.BaseOffset); + OS.AddComment("Base section index"); + OS.emitCOFFSectionIndex(JumpTable.Base); + } else { + OS.AddComment("Base offset"); + OS.emitInt32(0); + OS.AddComment("Base section index"); + OS.emitInt16(0); + } + OS.AddComment("Switch type"); + OS.emitInt16(static_cast<uint16_t>(JumpTable.EntrySize)); + OS.AddComment("Branch offset"); + OS.emitCOFFSecRel32(JumpTable.Branch, /*Offset=*/0); + OS.AddComment("Table offset"); + OS.emitCOFFSecRel32(JumpTable.Table, /*Offset=*/0); + OS.AddComment("Branch section index"); + OS.emitCOFFSectionIndex(JumpTable.Branch); + OS.AddComment("Table section index"); + OS.emitCOFFSectionIndex(JumpTable.Table); + OS.AddComment("Entries count"); + OS.emitInt32(JumpTable.TableSize); + endSymbolRecord(JumpTableEnd); + } +} |