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

Skip to content

Commit dd13552

Browse files
authored
Reland: [LowerTypeTests] Add debug info to jump table entries (llvm#193670)
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 ``` This is reland of llvm#192736, reverted with llvm#193663. This version don't update debug info for "Cross-DSO CFI" mode.
1 parent c1ff819 commit dd13552

3 files changed

Lines changed: 116 additions & 16 deletions

File tree

llvm/lib/Transforms/IPO/LowerTypeTests.cpp

Lines changed: 68 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,88 @@ 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+
// FIXME: Support Cross-DSO CFI.
1590+
if (M.getDwarfVersion() != 0 && !M.getModuleFlag("Cross-DSO CFI"))
1591+
Locations = createJumpTableDebugInfo(F, Functions);
1592+
15321593
InlineAsm *JumpTableAsm = createJumpTableEntryAsm(JumpTableArch);
15331594

15341595
// Check if all entries have the NoUnwind attribute.
15351596
// If all entries have it, we can safely mark the
15361597
// cfi.jumptable as NoUnwind, otherwise, direct calls
15371598
// to the jump table will not handle exceptions properly
15381599
bool areAllEntriesNounwind = true;
1539-
for (GlobalTypeMember *GTM : Functions) {
1540-
if (!llvm::cast<llvm::Function>(GTM->getGlobal())
1541-
->hasFnAttribute(llvm::Attribute::NoUnwind)) {
1600+
assert(Locations.empty() || Functions.size() == Locations.size());
1601+
for (auto [GTM, Loc] : zip_longest(Functions, Locations)) {
1602+
if (Loc.has_value())
1603+
IRB.SetCurrentDebugLocation(*Loc);
1604+
if (!cast<Function>((*GTM)->getGlobal())
1605+
->hasFnAttribute(Attribute::NoUnwind)) {
15421606
areAllEntriesNounwind = false;
15431607
}
1544-
IRB.CreateCall(JumpTableAsm, GTM->getGlobal());
1608+
IRB.CreateCall(JumpTableAsm, (*GTM)->getGlobal());
15451609
}
15461610
IRB.CreateUnreachable();
15471611

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)