Skip to content

Commit 8d0c3db

Browse files
committed
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
1 parent 5adac8b commit 8d0c3db

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+761
-17
lines changed

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
2525
#include "llvm/CodeGen/MachineFunctionPass.h"
2626
#include "llvm/CodeGen/StackMaps.h"
27+
#include "llvm/DebugInfo/CodeView/CodeView.h"
2728
#include "llvm/IR/InlineAsm.h"
2829
#include "llvm/Support/ErrorHandling.h"
2930
#include <cstdint>
@@ -766,6 +767,18 @@ class AsmPrinter : public MachineFunctionPass {
766767
/// Recursively emit Dwarf DIE tree.
767768
void emitDwarfDIE(const DIE &Die) const;
768769

770+
//===------------------------------------------------------------------===//
771+
// CodeView Helper Routines
772+
//===------------------------------------------------------------------===//
773+
774+
/// Gets information required to create a CodeView debug symbol for a jump
775+
/// table.
776+
/// Return value is <Base Address, Base Offset, Branch Address, Entry Size>
777+
virtual std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
778+
codeview::JumpTableEntrySize>
779+
getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
780+
const MCSymbol *BranchLabel) const;
781+
769782
//===------------------------------------------------------------------===//
770783
// Inline Asm Support
771784
//===------------------------------------------------------------------===//

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,10 @@ enum NodeType {
10481048
/// is the jumptable index, the last one is the jumptable entry index.
10491049
BR_JT,
10501050

1051+
/// JUMP_TABLE_DEBUG_INFO - Jumptable debug info. The first operand is the
1052+
/// chain, the second is the jumptable index.
1053+
JUMP_TABLE_DEBUG_INFO,
1054+
10511055
/// BRCOND - Conditional branch. The first operand is the chain, the
10521056
/// second is the condition, the third is the block to branch to if the
10531057
/// condition is true. If the type of the condition is not i1, then the

llvm/include/llvm/CodeGen/MachineInstr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,10 @@ class MachineInstr
13501350
return false;
13511351
}
13521352

1353+
bool isJumpTableDebugInfo() const {
1354+
return getOpcode() == TargetOpcode::JUMP_TABLE_DEBUG_INFO;
1355+
}
1356+
13531357
bool isPHI() const {
13541358
return getOpcode() == TargetOpcode::PHI ||
13551359
getOpcode() == TargetOpcode::G_PHI;

llvm/include/llvm/CodeGen/SelectionDAG.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ class SelectionDAG {
731731
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags = 0) {
732732
return getJumpTable(JTI, VT, true, TargetFlags);
733733
}
734+
SDValue getJumpTableDebugInfo(int JTI, SDValue Chain, const SDLoc &DL);
734735
SDValue getConstantPool(const Constant *C, EVT VT,
735736
MaybeAlign Align = std::nullopt, int Offs = 0,
736737
bool isT = false, unsigned TargetFlags = 0);

llvm/include/llvm/CodeGen/SelectionDAGISel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ class SelectionDAGISel : public MachineFunctionPass {
328328
void Select_STACKMAP(SDNode *N);
329329
void Select_PATCHPOINT(SDNode *N);
330330

331+
void Select_JUMP_TABLE_DEBUG_INFO(SDNode *N);
332+
331333
private:
332334
void DoInstructionSelection();
333335
SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList,

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5303,11 +5303,10 @@ class TargetLowering : public TargetLoweringBase {
53035303
SelectionDAG &DAG) const;
53045304

53055305
/// Expands target specific indirect branch for the case of JumpTable
5306-
/// expanasion.
5307-
virtual SDValue expandIndirectJTBranch(const SDLoc& dl, SDValue Value, SDValue Addr,
5308-
SelectionDAG &DAG) const {
5309-
return DAG.getNode(ISD::BRIND, dl, MVT::Other, Value, Addr);
5310-
}
5306+
/// expansion.
5307+
virtual SDValue expandIndirectJTBranch(const SDLoc &dl, SDValue Value,
5308+
SDValue Addr, int JTI,
5309+
SelectionDAG &DAG) const;
53115310

53125311
// seteq(x, 0) -> truncate(srl(ctlz(zext(x)), log2(#bits)))
53135312
// If we're comparing for equality to zero and isCtlzFast is true, expose the

llvm/include/llvm/DebugInfo/CodeView/CodeView.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,29 @@ inline uint32_t alignOf(CodeViewContainer Container) {
615615
return 1;
616616
return 4;
617617
}
618+
619+
// Corresponds to CV_armswitchtype enum.
620+
// This enum represents the different ways that jump tables entries can be
621+
// encoded to represent the target address to jump to.
622+
// * Pointer: The absolute address to jump to.
623+
// * [U]Int[8|16|32]: A value that is added to some "base" address to get the
624+
// address to jump to.
625+
// * [U]Int[8|16]ShiftLeft: A value that is shifted left by an implementation
626+
// specified amount, then added to some "base" address to get the address to
627+
// jump to.
628+
enum class JumpTableEntrySize : uint16_t {
629+
Int8 = 0,
630+
UInt8 = 1,
631+
Int16 = 2,
632+
UInt16 = 3,
633+
Int32 = 4,
634+
UInt32 = 5,
635+
Pointer = 6,
636+
UInt8ShiftLeft = 7,
637+
UInt16ShiftLeft = 8,
638+
Int8ShiftLeft = 9,
639+
Int16ShiftLeft = 10,
640+
};
618641
}
619642
}
620643

llvm/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ CV_SYMBOL(S_LDATA_HLSL , 0x1152)
170170
CV_SYMBOL(S_LOCAL_DPC_GROUPSHARED, 0x1154)
171171
CV_SYMBOL(S_DEFRANGE_DPC_PTR_TAG, 0x1157)
172172
CV_SYMBOL(S_DPC_SYM_TAG_MAP, 0x1158)
173-
CV_SYMBOL(S_ARMSWITCHTABLE , 0x1159)
174173
CV_SYMBOL(S_POGODATA , 0x115c)
175174
CV_SYMBOL(S_INLINESITE2 , 0x115d)
176175
CV_SYMBOL(S_MOD_TYPEREF , 0x115f)
@@ -231,6 +230,8 @@ SYMBOL_RECORD(S_FILESTATIC , 0x1153, FileStaticSym)
231230
SYMBOL_RECORD(S_HEAPALLOCSITE , 0x115e, HeapAllocationSiteSym)
232231
SYMBOL_RECORD(S_FRAMECOOKIE , 0x113a, FrameCookieSym)
233232

233+
SYMBOL_RECORD(S_ARMSWITCHTABLE, 0x1159, JumpTableSym)
234+
234235
SYMBOL_RECORD(S_CALLEES , 0x115a, CallerSym)
235236
SYMBOL_RECORD_ALIAS(S_CALLERS, 0x115b, CalleeSym, CallerSym)
236237

llvm/include/llvm/DebugInfo/CodeView/EnumTables.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ ArrayRef<EnumEntry<uint16_t>> getTypeModifierNames();
4848
ArrayRef<EnumEntry<uint8_t>> getCallingConventions();
4949
ArrayRef<EnumEntry<uint8_t>> getFunctionOptionEnum();
5050
ArrayRef<EnumEntry<uint16_t>> getLabelTypeEnum();
51+
ArrayRef<EnumEntry<uint16_t>> getJumpTableEntrySizeNames();
5152

5253
} // end namespace codeview
5354
} // end namespace llvm

llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,27 @@ class ScopeEndSym : public SymbolRecord {
144144
uint32_t RecordOffset = 0;
145145
};
146146

147+
class JumpTableSym : public SymbolRecord {
148+
public:
149+
explicit JumpTableSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
150+
JumpTableSym(uint32_t RecordOffset)
151+
: SymbolRecord(SymbolRecordKind::JumpTableSym),
152+
RecordOffset(RecordOffset) {}
153+
154+
uint32_t BaseOffset = 0;
155+
uint16_t BaseSegment = 0;
156+
157+
JumpTableEntrySize SwitchType;
158+
uint32_t BranchOffset = 0;
159+
uint32_t TableOffset = 0;
160+
uint16_t BranchSegment = 0;
161+
uint16_t TableSegment = 0;
162+
163+
uint32_t EntriesCount = 0;
164+
165+
uint32_t RecordOffset = 0;
166+
};
167+
147168
class CallerSym : public SymbolRecord {
148169
public:
149170
explicit CallerSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}

llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ class LVSymbolVisitor final : public SymbolVisitorCallbacks {
225225
Error visitKnownRecord(CVSymbol &Record, Thunk32Sym &Thunk) override;
226226
Error visitKnownRecord(CVSymbol &Record, UDTSym &UDT) override;
227227
Error visitKnownRecord(CVSymbol &Record, UsingNamespaceSym &UN) override;
228+
Error visitKnownRecord(CVSymbol &Record, JumpTableSym &JumpTable) override;
228229
};
229230

230231
// Visitor for CodeView types and symbols to populate elements.

llvm/include/llvm/Support/TargetOpcodes.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ HANDLE_TARGET_OPCODE(ICALL_BRANCH_FUNNEL)
226226
// barrier, but does not correspond to any generated instruction.
227227
HANDLE_TARGET_OPCODE(MEMBARRIER)
228228

229+
// Provides information about what jump table the following indirect branch is
230+
// using.
231+
HANDLE_TARGET_OPCODE(JUMP_TABLE_DEBUG_INFO)
232+
229233
/// The following generic opcodes are not supposed to appear after ISel.
230234
/// This is something we might want to relax, but for now, this is convenient
231235
/// to produce diagnostics.

llvm/include/llvm/Target/Target.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,14 @@ def MEMBARRIER : StandardPseudoInstruction {
14101410
let Size = 0;
14111411
let isMeta = true;
14121412
}
1413+
def JUMP_TABLE_DEBUG_INFO : StandardPseudoInstruction {
1414+
let OutOperandList = (outs);
1415+
let InOperandList = (ins i64imm:$jti);
1416+
let AsmString = "";
1417+
let hasSideEffects = false;
1418+
let Size = 0;
1419+
let isMeta = true;
1420+
}
14131421

14141422
// Generic opcodes used in GlobalISel.
14151423
include "llvm/Target/GenericOpcodes.td"

llvm/include/llvm/Target/TargetSelectionDAG.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,9 @@ def readcyclecounter : SDNode<"ISD::READCYCLECOUNTER", SDTIntLeaf,
650650
def membarrier : SDNode<"ISD::MEMBARRIER", SDTNone,
651651
[SDNPHasChain, SDNPSideEffect]>;
652652

653+
def jump_table_debug_info : SDNode<"ISD::JUMP_TABLE_DEBUG_INFO", SDTNone,
654+
[SDNPHasChain]>;
655+
653656
def atomic_fence : SDNode<"ISD::ATOMIC_FENCE" , SDTAtomicFence,
654657
[SDNPHasChain, SDNPSideEffect]>;
655658

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,10 @@ void AsmPrinter::emitFunctionBody() {
17261726
case TargetOpcode::MEMBARRIER:
17271727
OutStreamer->emitRawComment("MEMBARRIER");
17281728
break;
1729+
case TargetOpcode::JUMP_TABLE_DEBUG_INFO:
1730+
// This instruction is only used to note jump table debug info, it's
1731+
// purely meta information.
1732+
break;
17291733
default:
17301734
emitInstruction(&MI);
17311735
if (CanDoExtraAnalysis) {
@@ -4166,3 +4170,18 @@ unsigned int AsmPrinter::getUnitLengthFieldByteSize() const {
41664170
return dwarf::getUnitLengthFieldByteSize(
41674171
OutStreamer->getContext().getDwarfFormat());
41684172
}
4173+
4174+
std::tuple<const MCSymbol *, uint64_t, const MCSymbol *,
4175+
codeview::JumpTableEntrySize>
4176+
AsmPrinter::getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr,
4177+
const MCSymbol *BranchLabel) const {
4178+
const auto TLI = MF->getSubtarget().getTargetLowering();
4179+
const auto BaseExpr =
4180+
TLI->getPICJumpTableRelocBaseExpr(MF, JTI, MMI->getContext());
4181+
const auto Base = &cast<MCSymbolRefExpr>(BaseExpr)->getSymbol();
4182+
4183+
// By default, for the architectures that support CodeView,
4184+
// EK_LabelDifference32 is implemented as an Int32 from the base address.
4185+
return std::make_tuple(Base, 0, BranchLabel,
4186+
codeview::JumpTableEntrySize::Int32);
4187+
}

0 commit comments

Comments
 (0)