Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit abb4ff5

Browse files
authored
[LowerTypeTests] Add debug info to jump table entries (llvm#192736)
When Control Flow Integrity (CFI) is enabled, jump tables are used to redirect indirect calls. Previously, these jump table entries lacked debug information, making it difficult for profilers and debuggers to attribute execution time correctly. Now stack trace, when stopped on jump table entry will looks like this: ``` #0: __ubsan_check_cfi_icall_jt at sanitizer/ubsan_interface.h:0 #1: c::c() (.cfi_jt) at sanitizer/ubsan_interface.h:0:0 #2: .cfi.jumptable.81 at sanitizer/ubsan_interface.h:0:0 ```
1 parent c74951c commit abb4ff5

3 files changed

Lines changed: 115 additions & 16 deletions

File tree

llvm/lib/Transforms/IPO/LowerTypeTests.cpp

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "llvm/IR/BasicBlock.h"
3636
#include "llvm/IR/Constant.h"
3737
#include "llvm/IR/Constants.h"
38+
#include "llvm/IR/DIBuilder.h"
3839
#include "llvm/IR/DataLayout.h"
3940
#include "llvm/IR/DerivedTypes.h"
4041
#include "llvm/IR/Function.h"
@@ -1523,25 +1524,87 @@ Triple::ArchType LowerTypeTestsModule::selectJumpTableArmEncoding(
15231524
return ArmCount > ThumbCount ? Triple::arm : Triple::thumb;
15241525
}
15251526

1527+
// Create location for each function entry which should look like this:
1528+
// frame #0: __ubsan_check_cfi_icall_jt at sanitizer/ubsan_interface.h:0
1529+
// frame #1: c::c() (.cfi_jt) at sanitizer/ubsan_interface.h:0:0
1530+
// frame #2: .cfi.jumptable.81 at sanitizer/ubsan_interface.h:0:0
1531+
static SmallVector<DILocation *>
1532+
createJumpTableDebugInfo(Function *F, ArrayRef<GlobalTypeMember *> Functions) {
1533+
Module &M = *F->getParent();
1534+
DICompileUnit *CU = nullptr;
1535+
auto CUs = M.debug_compile_units();
1536+
if (!CUs.empty())
1537+
CU = *CUs.begin();
1538+
1539+
DIBuilder DIB(M, /*AllowUnresolved=*/true, CU);
1540+
DIFile *File = DIB.createFile("ubsan_interface.h", "sanitizer");
1541+
if (!CU) {
1542+
// Even with debug info enabled it can be missing if not info yet.
1543+
CU = DIB.createCompileUnit(
1544+
DISourceLanguageName(dwarf::DW_LANG_C), File, "llvm", true, "", 0, "",
1545+
DICompileUnit::DebugEmissionKind::LineTablesOnly);
1546+
}
1547+
1548+
DISubroutineType *DIFnTy = DIB.createSubroutineType(nullptr);
1549+
1550+
DISubprogram *JTSP = DIB.createFunction(File, F->getName(), StringRef(), File,
1551+
0, DIFnTy, 0, DINode::FlagArtificial,
1552+
DISubprogram::SPFlagDefinition);
1553+
F->setSubprogram(JTSP);
1554+
1555+
DILocation *JTLoc = DILocation::get(M.getContext(), 0, 0, JTSP);
1556+
1557+
DISubprogram *UbsanSP = DIB.createFunction(
1558+
File, "__ubsan_check_cfi_icall_jt", StringRef(), File, 0, DIFnTy, 0,
1559+
DINode::FlagArtificial, DISubprogram::SPFlagDefinition);
1560+
1561+
SmallVector<DILocation *> Locations;
1562+
Locations.reserve(Functions.size());
1563+
1564+
for (auto *Func : Functions) {
1565+
StringRef FuncName = Func->getGlobal()->getName();
1566+
FuncName.consume_back(".cfi");
1567+
DISubprogram *JumpSP = DIB.createFunction(
1568+
File, (FuncName + ".cfi_jt").str(), StringRef(), File, 0, DIFnTy, 0,
1569+
DINode::FlagArtificial, DISubprogram::SPFlagDefinition);
1570+
1571+
DILocation *EntryLoc = JTLoc;
1572+
EntryLoc = DILocation::get(M.getContext(), 0, 0, JumpSP, EntryLoc);
1573+
EntryLoc = DILocation::get(M.getContext(), 0, 0, UbsanSP, EntryLoc);
1574+
Locations.push_back(EntryLoc);
1575+
}
1576+
1577+
DIB.finalize();
1578+
1579+
return Locations;
1580+
}
1581+
15261582
void LowerTypeTestsModule::createJumpTable(
15271583
Function *F, ArrayRef<GlobalTypeMember *> Functions,
15281584
Triple::ArchType JumpTableArch) {
15291585
BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", F);
15301586
IRBuilder<> IRB(BB);
15311587

1588+
SmallVector<DILocation *> Locations;
1589+
if (M.getDwarfVersion() != 0)
1590+
Locations = createJumpTableDebugInfo(F, Functions);
1591+
15321592
InlineAsm *JumpTableAsm = createJumpTableEntryAsm(JumpTableArch);
15331593

15341594
// Check if all entries have the NoUnwind attribute.
15351595
// If all entries have it, we can safely mark the
15361596
// cfi.jumptable as NoUnwind, otherwise, direct calls
15371597
// to the jump table will not handle exceptions properly
15381598
bool areAllEntriesNounwind = true;
1539-
for (GlobalTypeMember *GTM : Functions) {
1540-
if (!llvm::cast<llvm::Function>(GTM->getGlobal())
1541-
->hasFnAttribute(llvm::Attribute::NoUnwind)) {
1599+
assert(Locations.empty() || Functions.size() == Locations.size());
1600+
for (auto [GTM, Loc] : zip_longest(Functions, Locations)) {
1601+
if (Loc.has_value())
1602+
IRB.SetCurrentDebugLocation(*Loc);
1603+
if (!cast<Function>((*GTM)->getGlobal())
1604+
->hasFnAttribute(Attribute::NoUnwind)) {
15421605
areAllEntriesNounwind = false;
15431606
}
1544-
IRB.CreateCall(JumpTableAsm, GTM->getGlobal());
1607+
IRB.CreateCall(JumpTableAsm, (*GTM)->getGlobal());
15451608
}
15461609
IRB.CreateUnreachable();
15471610

llvm/test/Transforms/LowerTypeTests/aarch64-jumptable-dbg.ll

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ define i1 @foo(ptr %p) {
5656
; AARCH64: Function Attrs: naked noinline
5757
; AARCH64-LABEL: @.cfi.jumptable(
5858
; AARCH64-NEXT: entry:
59-
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0A", "s"(ptr @f.cfi)
60-
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0A", "s"(ptr @g.cfi)
61-
; AARCH64-NEXT: unreachable
59+
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0A", "s"(ptr @f.cfi), !dbg [[DBG8:![0-9]+]]
60+
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0A", "s"(ptr @g.cfi), !dbg [[DBG13:![0-9]+]]
61+
; AARCH64-NEXT: unreachable, !dbg [[DBG13]]
6262
;
6363
;.
6464
; AARCH64: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
@@ -68,5 +68,17 @@ define i1 @foo(ptr %p) {
6868
; AARCH64: [[META0:![0-9]+]] = !{i32 4, !"branch-target-enforcement", i32 1}
6969
; AARCH64: [[META1:![0-9]+]] = !{i32 7, !"Dwarf Version", i32 5}
7070
; AARCH64: [[META2:![0-9]+]] = !{i32 2, !"Debug Info Version", i32 3}
71-
; AARCH64: [[META3:![0-9]+]] = !{i32 0, !"typeid1"}
71+
; AARCH64: [[META3:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C, file: [[META4:![0-9]+]], producer: "llvm", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly)
72+
; AARCH64: [[META4]] = !DIFile(filename: "{{.*}}ubsan_interface.h", directory: {{.*}})
73+
; AARCH64: [[META5:![0-9]+]] = !{i32 0, !"typeid1"}
74+
; AARCH64: [[META6:![0-9]+]] = distinct !DISubprogram(name: ".cfi.jumptable", scope: [[META4]], file: [[META4]], type: [[META7:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
75+
; AARCH64: [[META7]] = !DISubroutineType(types: null)
76+
; AARCH64: [[DBG8]] = !DILocation(line: 0, scope: [[META9:![0-9]+]], inlinedAt: [[META10:![0-9]+]])
77+
; AARCH64: [[META9]] = distinct !DISubprogram(name: "__ubsan_check_cfi_icall_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
78+
; AARCH64: [[META10]] = !DILocation(line: 0, scope: [[META11:![0-9]+]], inlinedAt: [[META12:![0-9]+]])
79+
; AARCH64: [[META11]] = distinct !DISubprogram(name: "f.cfi_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
80+
; AARCH64: [[META12]] = !DILocation(line: 0, scope: [[META6]])
81+
; AARCH64: [[DBG13]] = !DILocation(line: 0, scope: [[META9]], inlinedAt: [[META14:![0-9]+]])
82+
; AARCH64: [[META14]] = !DILocation(line: 0, scope: [[META15:![0-9]+]], inlinedAt: [[META12]])
83+
; AARCH64: [[META15]] = distinct !DISubprogram(name: "g.cfi_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
7284
;.

llvm/test/Transforms/LowerTypeTests/x86-jumptable-dbg.ll

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ define i1 @foo(ptr %p) {
5656
;
5757
; X86_32-LABEL: @.cfi.jumptable(
5858
; X86_32-NEXT: entry:
59-
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @f.cfi)
60-
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @g.cfi)
61-
; X86_32-NEXT: unreachable
59+
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @f.cfi), !dbg [[DBG8:![0-9]+]]
60+
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @g.cfi), !dbg [[DBG13:![0-9]+]]
61+
; X86_32-NEXT: unreachable, !dbg [[DBG13]]
6262
;
6363
;
6464
; X86_64-LABEL: @f.cfi(
@@ -79,9 +79,9 @@ define i1 @foo(ptr %p) {
7979
;
8080
; X86_64-LABEL: @.cfi.jumptable(
8181
; X86_64-NEXT: entry:
82-
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @f.cfi)
83-
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @g.cfi)
84-
; X86_64-NEXT: unreachable
82+
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @f.cfi), !dbg [[DBG8:![0-9]+]]
83+
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @g.cfi), !dbg [[DBG13:![0-9]+]]
84+
; X86_64-NEXT: unreachable, !dbg [[DBG13]]
8585
;
8686
;.
8787
; X86_32: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
@@ -95,10 +95,34 @@ define i1 @foo(ptr %p) {
9595
; X86_32: [[META0:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 1}
9696
; X86_32: [[META1:![0-9]+]] = !{i32 7, !"Dwarf Version", i32 5}
9797
; X86_32: [[META2:![0-9]+]] = !{i32 2, !"Debug Info Version", i32 3}
98-
; X86_32: [[META3:![0-9]+]] = !{i32 0, !"typeid1"}
98+
; X86_32: [[META3:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C, file: [[META4:![0-9]+]], producer: "llvm", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly)
99+
; X86_32: [[META4]] = !DIFile(filename: "{{.*}}ubsan_interface.h", directory: {{.*}})
100+
; X86_32: [[META5:![0-9]+]] = !{i32 0, !"typeid1"}
101+
; X86_32: [[META6:![0-9]+]] = distinct !DISubprogram(name: ".cfi.jumptable", scope: [[META4]], file: [[META4]], type: [[META7:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
102+
; X86_32: [[META7]] = !DISubroutineType(types: null)
103+
; X86_32: [[DBG8]] = !DILocation(line: 0, scope: [[META9:![0-9]+]], inlinedAt: [[META10:![0-9]+]])
104+
; X86_32: [[META9]] = distinct !DISubprogram(name: "__ubsan_check_cfi_icall_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
105+
; X86_32: [[META10]] = !DILocation(line: 0, scope: [[META11:![0-9]+]], inlinedAt: [[META12:![0-9]+]])
106+
; X86_32: [[META11]] = distinct !DISubprogram(name: "f.cfi_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
107+
; X86_32: [[META12]] = !DILocation(line: 0, scope: [[META6]])
108+
; X86_32: [[DBG13]] = !DILocation(line: 0, scope: [[META9]], inlinedAt: [[META14:![0-9]+]])
109+
; X86_32: [[META14]] = !DILocation(line: 0, scope: [[META15:![0-9]+]], inlinedAt: [[META12]])
110+
; X86_32: [[META15]] = distinct !DISubprogram(name: "g.cfi_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
99111
;.
100112
; X86_64: [[META0:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 1}
101113
; X86_64: [[META1:![0-9]+]] = !{i32 7, !"Dwarf Version", i32 5}
102114
; X86_64: [[META2:![0-9]+]] = !{i32 2, !"Debug Info Version", i32 3}
103-
; X86_64: [[META3:![0-9]+]] = !{i32 0, !"typeid1"}
115+
; X86_64: [[META3:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C, file: [[META4:![0-9]+]], producer: "llvm", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly)
116+
; X86_64: [[META4]] = !DIFile(filename: "{{.*}}ubsan_interface.h", directory: {{.*}})
117+
; X86_64: [[META5:![0-9]+]] = !{i32 0, !"typeid1"}
118+
; X86_64: [[META6:![0-9]+]] = distinct !DISubprogram(name: ".cfi.jumptable", scope: [[META4]], file: [[META4]], type: [[META7:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
119+
; X86_64: [[META7]] = !DISubroutineType(types: null)
120+
; X86_64: [[DBG8]] = !DILocation(line: 0, scope: [[META9:![0-9]+]], inlinedAt: [[META10:![0-9]+]])
121+
; X86_64: [[META9]] = distinct !DISubprogram(name: "__ubsan_check_cfi_icall_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
122+
; X86_64: [[META10]] = !DILocation(line: 0, scope: [[META11:![0-9]+]], inlinedAt: [[META12:![0-9]+]])
123+
; X86_64: [[META11]] = distinct !DISubprogram(name: "f.cfi_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
124+
; X86_64: [[META12]] = !DILocation(line: 0, scope: [[META6]])
125+
; X86_64: [[DBG13]] = !DILocation(line: 0, scope: [[META9]], inlinedAt: [[META14:![0-9]+]])
126+
; X86_64: [[META14]] = !DILocation(line: 0, scope: [[META15:![0-9]+]], inlinedAt: [[META12]])
127+
; X86_64: [[META15]] = distinct !DISubprogram(name: "g.cfi_jt", scope: [[META4]], file: [[META4]], type: [[META7]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META3]])
104128
;.

0 commit comments

Comments
 (0)