SlideShare une entreprise Scribd logo
Debug INFormation

And Where They Come From
Min-Yih “Min” Hsu, COSCUP 2022
Debugging
2
Execution
Program
Debugging
2
Execution
Program
Pause
Debugging
2
Execution
Program
Pause
Debugger
Developers
Debugging
2
Execution
Program
Pause
Debugger
Developers
Source Code
• Source location (e.g. line number)
Debugging
2
Execution
Program
Pause
Debugger
Developers
Source Code
• Source location (e.g. line number)
• Variable values
Debugging
2
Execution
Program
Pause
Debugger
Developers
Source Code
• Source location (e.g. line number)
• Variable values
• Function call hierarchy
Languages & Debugging
3
Languages & Debugging
3
Languages & Debugging
4
Run & Debug on
Native Binaries
Debug Symbols / Info
5
Program
Binary
Debug Symbols / Info
5
Program
Binary
Debug Info
Debug Symbols / Info
5
Program
Binary
Debug Info
Source Code
Mapping
Debug Symbols / Info
5
Program
Binary
Debug Info
Debugger
Consume
Source Code
Mapping
Debug Symbols / Info
5
Program
Binary
Debug Info
Debugger
Consume
Source Code
Mapping
Pro
fi
ler
Today’s Topic
6
Program
Binary
Debug Info
Source Code
Compiler
Today’s Topic
6
Program
Binary
Debug Info
Source Code
Compiler
Debug Info…
Today’s Topic
6
Program
Binary
Debug Info
Source Code
Compiler
Debug Info…
… And Where They Come From
Learning Debug Info
Example Input
8
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
*Host Architecture: x86_64
Example Input
8
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
$ cc -g -c demo.c -o demo.o
*Host Architecture: x86_64
Example Input
8
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
$ cc -g -c demo.c -o demo.o
$ llvm-dva demo.o …
*Host Architecture: x86_64
llvm-dva: Visualizing Debug Info
9
{CompileUnit} ‘demo.c'


....


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


....


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24


3 {Line}


{Code} 'endbr64'


{Code} 'pushq %rbp'


....


4 {Line}


{Code} 'movl $0x0, -0x8(%rbp)'


{Code} 'movl $0x0, -0x4(%rbp)'


5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
llvm-dva: Visualizing Debug Info
10
{CompileUnit} ‘demo.c'


....


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


....


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24


3 {Line}


{Code} 'endbr64'


{Code} 'pushq %rbp'


....


4 {Line}


{Code} 'movl $0x0, -0x8(%rbp)'


{Code} 'movl $0x0, -0x4(%rbp)'


5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
llvm-dva: Visualizing Debug Info
10
{CompileUnit} ‘demo.c'


....


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


....


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24


3 {Line}


{Code} 'endbr64'


{Code} 'pushq %rbp'


....


4 {Line}


{Code} 'movl $0x0, -0x8(%rbp)'


{Code} 'movl $0x0, -0x4(%rbp)'


5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
llvm-dva: Visualizing Debug Info
11
{CompileUnit} ‘demo.c'


....


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


....


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24


3 {Line}


{Code} 'endbr64'


{Code} 'pushq %rbp'


....


4 {Line}


{Code} 'movl $0x0, -0x8(%rbp)'


{Code} 'movl $0x0, -0x4(%rbp)'


5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
llvm-dva: Visualizing Debug Info
11
{CompileUnit} ‘demo.c'


....


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


....


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24


3 {Line}


{Code} 'endbr64'


{Code} 'pushq %rbp'


....


4 {Line}


{Code} 'movl $0x0, -0x8(%rbp)'


{Code} 'movl $0x0, -0x4(%rbp)'


5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
llvm-dva: Visualizing Debug Info
12
5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Line numbers & instructions
llvm-dva: Visualizing Debug Info
12
5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Line numbers & instructions
llvm-dva: Visualizing Debug Info
12
5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Where ‘c’ is stored
Line numbers & instructions
llvm-dva: Visualizing Debug Info
12
5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Where ‘c’ is stored
PC Address Line Number
Assembly 

(NOT stored in debug info)
0x1C 5 cmpl $0x0,-0x18(%rbp)
0x20 5 je 0xc
Line numbers & instructions
llvm-dva: Visualizing Debug Info
13
{CompileUnit} ‘demo.c'


....


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


....


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24


3 {Line}


{Code} 'endbr64'


{Code} 'pushq %rbp'


....


4 {Line}


{Code} 'movl $0x0, -0x8(%rbp)'


{Code} 'movl $0x0, -0x4(%rbp)'


5 {Line}


{Code} 'cmpl $0x0, -0x18(%rbp)'


{Code} 'je 0xc’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
llvm-dva: Visualizing Debug Info
14
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Variable locations
llvm-dva: Visualizing Debug Info
14
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Variable locations
llvm-dva: Visualizing Debug Info
15
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Variable locations
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
Current Stack Frame
Lo Address
Hi Address
llvm-dva: Visualizing Debug Info
15
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Variable locations
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
Current Stack Frame
Lo Address
Hi Address
fbreg
llvm-dva: Visualizing Debug Info
15
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Variable locations
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
-24
Current Stack Frame
Lo Address
Hi Address
fbreg
llvm-dva: Visualizing Debug Info
15
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Variable locations
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
-24
-36
Current Stack Frame
Lo Address
Hi Address
fbreg
llvm-dva: Visualizing Debug Info
15
3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Variable locations
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
-24
-36
-40
Current Stack Frame
Lo Address
Hi Address
fbreg
llvm-dva: Visualizing Debug Info
16
{CompileUnit} ‘demo.c'


1 {Struct} 'Point'


1 {Member} public 'x' -> 'int'


{Location}


{Entry} offset 0


1 {Member} public 'y' -> 'int'


{Location}


{Entry} offset 4


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Type Layout
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
Current Stack Frame
Lo Address
Hi Address
llvm-dva: Visualizing Debug Info
16
{CompileUnit} ‘demo.c'


1 {Struct} 'Point'


1 {Member} public 'x' -> 'int'


{Location}


{Entry} offset 0


1 {Member} public 'y' -> 'int'


{Location}


{Entry} offset 4


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Type Layout
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
Current Stack Frame
Lo Address
Hi Address
llvm-dva: Visualizing Debug Info
16
{CompileUnit} ‘demo.c'


1 {Struct} 'Point'


1 {Member} public 'x' -> 'int'


{Location}


{Entry} offset 0


1 {Member} public 'y' -> 'int'


{Location}


{Entry} offset 4


3 {Function} extern not_inlined 'foo' -> 'int'


3 {Parameter} 'k' -> 'int'


{Location}


{Entry} fbreg -36


3 {Parameter} 'c' -> 'int'


{Location}


{Entry} fbreg -40


4 {Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
Type Layout
Variable ‘point’
Variable ‘k’
Variable ‘c’
Previous Frame Ptr
Return Address
Current Stack Frame
Lo Address
Hi Address
Field ‘x’
Field ‘y’
+0
+4
Other Common Debug Info Properties
17
Other Common Debug Info Properties
• Scopes
17
Other Common Debug Info Properties
• Scopes
• Advanced type information

• Type aliases

• Type hierarchy
17
Debug Info Standards
18
Debug Info Standards
18
DWARF CodeView
Debug Info Standards
18
DWARF CodeView
• Default format in Linux, Apple platforms,

most of the Unix
Debug Info Standards
18
DWARF CodeView
• Default format in Linux, Apple platforms,

most of the Unix
• Supported by GNU & LLVM toolchain
Debug Info Standards
18
DWARF CodeView
• Default format in Linux, Apple platforms,

most of the Unix
• Supported by GNU & LLVM toolchain
• Container formats: DWO, DWP, dSYM
Debug Info Standards
18
DWARF CodeView
• Default format in Linux, Apple platforms,

most of the Unix
• Supported by GNU & LLVM toolchain
• Container formats: DWO, DWP, dSYM
• Default format in Windows (MSVC)
Debug Info Standards
18
DWARF CodeView
• Default format in Linux, Apple platforms,

most of the Unix
• Supported by GNU & LLVM toolchain
• Container formats: DWO, DWP, dSYM
• Default format in Windows (MSVC)
• Supported by MSVC & LLVM toolchain
Debug Info Standards
18
DWARF CodeView
• Default format in Linux, Apple platforms,

most of the Unix
• Supported by GNU & LLVM toolchain
• Container formats: DWO, DWP, dSYM
• Default format in Windows (MSVC)
• Supported by MSVC & LLVM toolchain
• Container format: PDB
19
DWARF CodeView
Abstraction
llvm-dva
Logical View
Generating Debug Info
Compilation Pipeline: A Crash Course
21
Source Code
Native Code


(e.g. *.o
fi
les)
Compilation Pipeline: A Crash Course
21
Source Code
AST
Parse
Native Code


(e.g. *.o
fi
les)
Compilation Pipeline: A Crash Course
21
Source Code
AST
Parse
Intermediate
Representation
(IR)
Native Code


(e.g. *.o
fi
les)
Compilation Pipeline: A Crash Course
21
Source Code
AST
Parse
Intermediate
Representation
(IR)
Another
Intermediate
Representation
Native Code


(e.g. *.o
fi
les)
Debug Info in a Compilation Pipeline: Highlights
22
Source Code
AST
Parse
Intermediate
Representation
(IR)
Another
Intermediate
Representation
Native Code


(e.g. *.o
fi
les)
Debug Info in a Compilation Pipeline: Highlights
22
Source Code
AST
Parse
Intermediate
Representation
(IR)
Another
Intermediate
Representation
Native Code


(e.g. *.o
fi
les)
• How to “carry” debug info in IR ?
Debug Info in a Compilation Pipeline: Highlights
22
Source Code
AST
Parse
Intermediate
Representation
(IR)
Another
Intermediate
Representation
Native Code


(e.g. *.o
fi
les)
• How to “carry” debug info in IR ?
• Correctly translate from source to debug info in IR
Debug Info in a Compilation Pipeline: Highlights
22
Source Code
AST
Parse
Intermediate
Representation
(IR)
Another
Intermediate
Representation
Native Code


(e.g. *.o
fi
les)
• How to “carry” debug info in IR ?
• Correctly translate from source to debug info in IR
• Preserve debug info across transformations (e.g. optimizations)
Case Study: LLVM / Clang
23
void foo() {


int x = 9;


int y = 4;


}
C Source (foo.c)
Case Study: LLVM / Clang
23
define void @foo() {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1


store i32 4, i32* %2


ret void


}
void foo() {


int x = 9;


int y = 4;


}
C Source (foo.c)
LLVM IR (foo.ll)
$ clang -emit-llvm -S foo.c -o foo.ll
Case Study: LLVM / Clang
23
define void @foo() {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1


store i32 4, i32* %2


ret void


}
void foo() {


int x = 9;


int y = 4;


}
C Source (foo.c)
LLVM IR (foo.ll)
$ clang -emit-llvm -S foo.c -o foo.ll
Allocating stack space
Case Study: LLVM / Clang
23
define void @foo() {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1


store i32 4, i32* %2


ret void


}
void foo() {


int x = 9;


int y = 4;


}
C Source (foo.c)
LLVM IR (foo.ll)
$ clang -emit-llvm -S foo.c -o foo.ll
24
$ clang -g -emit-llvm -S foo.c -o foo.ll
Debug Info in LLVM IR
24
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR (foo.ll)
$ clang -g -emit-llvm -S foo.c -o foo.ll
Debug Info in LLVM IR
25
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1, !dbg !13


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
void foo() {


int x = 9;


int y = 4;


}
C Source
1


2


3


4
LLVM IR
Debug Info in LLVM IR
25
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1, !dbg !13


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
void foo() {


int x = 9;


int y = 4;


}
C Source
1


2


3


4
LLVM IR
Debug Info in LLVM IR
25
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1, !dbg !13


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
void foo() {


int x = 9;


int y = 4;


}
C Source
1


2


3


4
LLVM IR
!13 = !DILocation(line: 2, column: 7, ...) At the bottom of IR
fi
le
Debug Info in LLVM IR
25
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


store i32 9, i32* %1, !dbg !13


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
void foo() {


int x = 9;


int y = 4;


}
C Source
1


2


3


4
LLVM IR
!13 = !DILocation(line: 2, column: 7, ...)
!15 = !DILocation(line: 3, column: 7, ...)
At the bottom of IR
fi
le
Debug Info in LLVM IR
26
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
Debug Info in LLVM IR
27
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
Debug Info in LLVM IR
27
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
Debug Info in LLVM IR
27
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
Debug Info in LLVM IR
27
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
Associated
Debug Info in LLVM IR
27
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
Associated
representing variable’s location during runtime
Debug Info in LLVM IR
27
define void @foo() !dbg !7 {


%1 = alloca i32


%2 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13


store i32 9, i32* %1, !dbg !13


call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15


store i32 4, i32* %2, !dbg !15


ret void, !dbg !16


}
LLVM IR
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
!14 = !DILocalVariable(name: "y", ..., line: 3, ...)
Visualizing Debug Info
28
$ cc -g -c foo.c -o foo.o
$ llvm-dva foo.o …
Visualizing Debug Info
29
{CompileUnit} ‘foo.c’


1 {Function} extern not_inlined ‘foo’…


2 {Variable} 'x' -> 'int'


{Location}


{Entry} fbreg -4


3 {Variable} 'y' -> 'int'


{Location}


{Entry} fbreg -8


1 {Line}


{Code} 'pushq %rbp'


{Code} 'movq %rsp, %rbp'


2 {Line}


{Code} 'movl $0x9, -0x4(%rbp)'


3 {Line}


{Code} 'movl $0x4, -0x8(%rbp)'


4 {Line}


{Code} 'popq %rbp'


{Code} 'retq'


4 {Line}
Visualizing Debug Info
29
{CompileUnit} ‘foo.c’


1 {Function} extern not_inlined ‘foo’…


2 {Variable} 'x' -> 'int'


{Location}


{Entry} fbreg -4


3 {Variable} 'y' -> 'int'


{Location}


{Entry} fbreg -8


1 {Line}


{Code} 'pushq %rbp'


{Code} 'movq %rsp, %rbp'


2 {Line}


{Code} 'movl $0x9, -0x4(%rbp)'


3 {Line}


{Code} 'movl $0x4, -0x8(%rbp)'


4 {Line}


{Code} 'popq %rbp'


{Code} 'retq'


4 {Line}
store i32 9, i32* %1, !dbg !13
!13 = !DILocation(line: 2, column: 7, ...)
Visualizing Debug Info
29
{CompileUnit} ‘foo.c’


1 {Function} extern not_inlined ‘foo’…


2 {Variable} 'x' -> 'int'


{Location}


{Entry} fbreg -4


3 {Variable} 'y' -> 'int'


{Location}


{Entry} fbreg -8


1 {Line}


{Code} 'pushq %rbp'


{Code} 'movq %rsp, %rbp'


2 {Line}


{Code} 'movl $0x9, -0x4(%rbp)'


3 {Line}


{Code} 'movl $0x4, -0x8(%rbp)'


4 {Line}


{Code} 'popq %rbp'


{Code} 'retq'


4 {Line}
store i32 9, i32* %1, !dbg !13
!13 = !DILocation(line: 2, column: 7, ...)
Visualizing Debug Info
29
{CompileUnit} ‘foo.c’


1 {Function} extern not_inlined ‘foo’…


2 {Variable} 'x' -> 'int'


{Location}


{Entry} fbreg -4


3 {Variable} 'y' -> 'int'


{Location}


{Entry} fbreg -8


1 {Line}


{Code} 'pushq %rbp'


{Code} 'movq %rsp, %rbp'


2 {Line}


{Code} 'movl $0x9, -0x4(%rbp)'


3 {Line}


{Code} 'movl $0x4, -0x8(%rbp)'


4 {Line}


{Code} 'popq %rbp'


{Code} 'retq'


4 {Line}
%1 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …)
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
store i32 9, i32* %1, !dbg !13
!13 = !DILocation(line: 2, column: 7, ...)
Visualizing Debug Info
29
{CompileUnit} ‘foo.c’


1 {Function} extern not_inlined ‘foo’…


2 {Variable} 'x' -> 'int'


{Location}


{Entry} fbreg -4


3 {Variable} 'y' -> 'int'


{Location}


{Entry} fbreg -8


1 {Line}


{Code} 'pushq %rbp'


{Code} 'movq %rsp, %rbp'


2 {Line}


{Code} 'movl $0x9, -0x4(%rbp)'


3 {Line}


{Code} 'movl $0x4, -0x8(%rbp)'


4 {Line}


{Code} 'popq %rbp'


{Code} 'retq'


4 {Line}
%1 = alloca i32


call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …)
!11 = !DILocalVariable(name: "x", ..., line: 2, ...)
store i32 9, i32* %1, !dbg !13
!13 = !DILocation(line: 2, column: 7, ...)
30
30
…And Developers Lives a Happy Debu
gg
ing Life Ever Since
30
…And Developers Lives a Happy Debu
gg
ing Life Ever Since
Debug Info in Optimized Binaries
Debug Info in Optimized Binaries
32
$ cc -g -O2 -c foo.c
Debug Info in Optimized Binaries
32
$ cc -g -O2 -c foo.c
Debug Info in Optimized Binaries
32
$ cc -g -O2 -c foo.c
Why?
Debugging Optimized Programs
33
Debugging Optimized Programs
• Games

• Di
ffi
cult (if not nearly impossible) to debug low-FPS games
33
Debugging Optimized Programs
• Games

• Di
ffi
cult (if not nearly impossible) to debug low-FPS games
• Embedded systems

• Size optimization is usually a hard requirement
33
Debugging Optimized Programs
• Games

• Di
ffi
cult (if not nearly impossible) to debug low-FPS games
• Embedded systems

• Size optimization is usually a hard requirement
• Easier debugging on release binaries

• E.g. Using core
fi
les directly from customers
33
Recall: Early Example Code
34
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
$ clang -g foo.c -emit-llvm -S
35
define i32 @foo(i32 %0, i32 %1) !dbg !7 {


%3 = alloca i32


%4 = alloca i32


%5 = alloca %struct.Point


store i32 %0, i32* %3


call void @llvm.dbg.declare(metadata i32* %3, metadata !12, ...), !dbg !13


store i32 %1, i32* %4


call void @llvm.dbg.declare(metadata i32* %4, metadata !14, ...), !dbg !15


call void @llvm.dbg.declare(metadata %struct.Point* %5, metadata !16, ...), !dbg !21


...


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
36
define i32 @foo(i32 %0, i32 %1) !dbg !7 {


%3 = alloca i32


%4 = alloca i32


%5 = alloca %struct.Point


store i32 %0, i32* %3


call void @llvm.dbg.declare(metadata i32* %3, metadata !12, ...), !dbg !13


store i32 %1, i32* %4


call void @llvm.dbg.declare(metadata i32* %4, metadata !14, ...), !dbg !15


call void @llvm.dbg.declare(metadata %struct.Point* %5, metadata !16, ...), !dbg !21


...


}
Allocating stack space for ‘k’, ‘c’, and ‘point’
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
37
define i32 @foo(i32 %0, i32 %1) !dbg !7 {


%3 = alloca i32


%4 = alloca i32


%5 = alloca %struct.Point


store i32 %0, i32* %3


call void @llvm.dbg.declare(metadata i32* %3, metadata !12, ...), !dbg !13


store i32 %1, i32* %4


call void @llvm.dbg.declare(metadata i32* %4, metadata !14, ...), !dbg !15


call void @llvm.dbg.declare(metadata %struct.Point* %5, metadata !16, ...), !dbg !21


...


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Associating stack spaces with the source variables
Optimized Example Code
38
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
$ clang -O2 foo.c -emit-llvm -S
39
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
39
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Values are not put on stack anymore!
40
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Prompt: 

What is the runtime location/value of source
variable ‘point’ ?
40
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Prompt: 

What is the runtime location/value of source
variable ‘point’ ?
(gdb) print point


<your answer>


(gdb)
40
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Prompt: 

What is the runtime location/value of source
variable ‘point’ ?
(gdb) print point


<your answer>


(gdb)
?
41
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Which instructions should I annotate
with source line 4, 6, and 7 ?
41
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Which instructions should I annotate
with source line 4, 6, and 7 ?
?
Other Common Challenges
42
Updating Scopes
Function Inlining
Preserving Debug Info in Optimized Code
• Most modern compilers preserve debug information as part of the code
transformations (e.g. optimizations)
43
Preserving Debug Info in Optimized Code
• Most modern compilers preserve debug information as part of the code
transformations (e.g. optimizations)
• Challenges
43
Preserving Debug Info in Optimized Code
• Most modern compilers preserve debug information as part of the code
transformations (e.g. optimizations)
• Challenges
• It’s easy for compiler developers to forget to handle debug info
43
Preserving Debug Info in Optimized Code
• Most modern compilers preserve debug information as part of the code
transformations (e.g. optimizations)
• Challenges
• It’s easy for compiler developers to forget to handle debug info
• It’s not possible to (faithfully) map optimized code back to source
locations in every cases
43
Preserving Debug Info in Optimized Code
• Most modern compilers preserve debug information as part of the code
transformations (e.g. optimizations)
• Challenges
• It’s easy for compiler developers to forget to handle debug info
• It’s not possible to (faithfully) map optimized code back to source
locations in every cases
• Debug info in optimized binaries is preserved on a best-e
ff
ort basis
43
Case Study:


How LLVM Mitigates These Issues
Recall: Optimized Code Example
45
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Prompt: 

What is the runtime location/value of source
variable ‘point’ ?
(gdb) print point


<your answer>


(gdb)
?
Optimized Example Code w/ Debug Info
46
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
$ clang -O2 -g foo.c -emit-llvm -S
Preserving Variable Locations / Values in LLVM
47
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32))


call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32))


%5 = add nsw i32 %4, %1


ret i32 %5


}
Preserving Variable Locations / Values in LLVM
48
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


…


}
Preserving Variable Locations / Values in LLVM
48
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


…


} !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11)


!14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
Preserving Variable Locations / Values in LLVM
49
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


…


} !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11)


!14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
LLVM Intrinsic Name Description
llvm.dbg.declare
Specify the (memory) location for a source variable. 

Only a single occurrence per source variable is allowed
llvm.dbg.value
Designate a (runtime) value to a source variable

Can have multiple occurrences for a source variable

(akin to updating di
ff
erent values on a source variable)
Preserving Variable Locations / Values in LLVM
49
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


…


} !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11)


!14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
LLVM Intrinsic Name Description
llvm.dbg.declare
Specify the (memory) location for a source variable. 

Only a single occurrence per source variable is allowed
llvm.dbg.value
Designate a (runtime) value to a source variable

Can have multiple occurrences for a source variable

(akin to updating di
ff
erent values on a source variable)
Preserving Variable Locations / Values in LLVM
49
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


…


} !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11)


!14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
LLVM Intrinsic Name Description
llvm.dbg.declare
Specify the (memory) location for a source variable. 

Only a single occurrence per source variable is allowed
llvm.dbg.value
Designate a (runtime) value to a source variable

Can have multiple occurrences for a source variable

(akin to updating di
ff
erent values on a source variable)
Preserving Variable Locations / Values in LLVM
49
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …)


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


…


} !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11)


!14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
Preserving Variable Locations / Values in LLVM
50
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Preserving Variable Locations / Values in LLVM
50
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
Preserving Variable Locations / Values in LLVM
50
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
Why this is not “point.x” or “point.y” ?
Preserving Variable Locations / Values in LLVM
50
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
Why this is not “point.x” or “point.y” ?
Preserving Variable Locations / Values in LLVM
51
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
A fragment of source variable “point” has value 0.
Preserving Variable Locations / Values in LLVM
51
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
A fragment of source variable “point” has value 0.
Preserving Variable Locations / Values in LLVM
51
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
A fragment of source variable “point” has value 0.
Preserving Variable Locations / Values in LLVM
51
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
A fragment of source variable “point” has value 0.
Preserving Variable Locations / Values in LLVM
52
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
A 32-bit, o
ff
set 0 fragment of source variable “point” has value 0.
Preserving Variable Locations / Values in LLVM
52
define i32 @foo(i32 %0, i32 %1) {


...


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


...


}
!15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
A 32-bit, o
ff
set 0 fragment of source variable “point” has value 0.
(i.e. the “point.x”
fi
eld)
Preserving Variable Locations / Values in LLVM
53
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32))


call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32))


%5 = add nsw i32 %4, %1


ret i32 %5


}
First, “point.x” & “point.y” were initialized to zeros…
Preserving Variable Locations / Values in LLVM
54
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32))


call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32))


%5 = add nsw i32 %4, %1


ret i32 %5


}
After these two instructions…
Preserving Variable Locations / Values in LLVM
55
define i32 @foo(i32 %0, i32 %1) {


call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression())


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32))


call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32))


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32))


call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32))


%5 = add nsw i32 %4, %1


ret i32 %5


}
“point.x” & “point.y” now have values %4 and %1, respectively
Recall: Optimized Code Example
56
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Which instructions should I annotate
with source line 4, 6, and 7 ?
Preserving Debug Locations in LLVM
57
Principles
Actions
Preserving Debug Locations in LLVM
57
Principles
Actions
Keep
Preserving Debug Locations in LLVM
57
Principles
Actions
Keep Merge
Preserving Debug Locations in LLVM
57
Principles
Actions
Keep Merge Delete
Preserving Debug Locations in LLVM
57
Principles
• Don’t create misleading debug locations that are only correct in some cases
Actions
Keep Merge Delete
Preserving Debug Locations in LLVM
57
Principles
• Don’t create misleading debug locations that are only correct in some cases
• If you’re not sure, just drop the debug locations
Actions
Keep Merge Delete
Preserving Debug Locations in LLVM
57
Principles
• Don’t create misleading debug locations that are only correct in some cases
• If you’re not sure, just drop the debug locations
• Otherwise, preserve as much debug locations as possible
Actions
Keep Merge Delete
Debug Locations in our Example Code
58
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Debug Locations in our Example Code
59
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
Debug Locations in our Example Code
59
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
line 6 will only hit conditionally
Debug Locations in our Example Code
59
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
line 6 will only hit conditionally
“Don’t create misleading debug locations 

that are only correct in some cases”
Debug Locations in our Example Code
59
define i32 @foo(i32 %0, i32 %1) {


%3 = icmp eq i32 %1, 0


%4 = select i1 %3, i32 0, i32 %0


%5 = add nsw i32 %4, %1


ret i32 %5


}
struct Point { int x, y; };


int foo(int k, int c) {


struct Point point = {x: 0, y: 0};


if (c) {


point.x = k;


point.y = c;


}


return point.x + point.y;


}
1


2


3


4


5


6


7


8


9


10
line 6 will only hit conditionally
“Don’t create misleading debug locations 

that are only correct in some cases”
Delete
Preserving Debug Locations in LLVM
60
Prantl and Kumar, US LLVM Dev Meeting 2020
Guidelines for updating debug locations in code transformations
https://tinyurl.com/llvmdebuginfo
Full write-up:
Preserving Debug Info in LLVM: Automatically
61
Preserving Debug Info in LLVM: Automatically
61
• Common transformation APIs will help you to keep / merge debug
location underlying
Preserving Debug Info in LLVM: Automatically
61
• Common transformation APIs will help you to keep / merge debug
location underlying
• e.g. Replace All Uses With (RAUW)
Preserving Debug Info in LLVM: Automatically
61
• Common transformation APIs will help you to keep / merge debug
location underlying
• e.g. Replace All Uses With (RAUW)
• Handy debug info utilities to make debug info manipulations easier
Preserving Debug Info in LLVM: Automatically
61
• Common transformation APIs will help you to keep / merge debug
location underlying
• e.g. Replace All Uses With (RAUW)
• Handy debug info utilities to make debug info manipulations easier
• salvageDebugInfo helps you to generate llvm.dbg.value intrinsics
Preserving Debug Info in LLVM: Automatically
61
• Common transformation APIs will help you to keep / merge debug
location underlying
• e.g. Replace All Uses With (RAUW)
• Handy debug info utilities to make debug info manipulations easier
• salvageDebugInfo helps you to generate llvm.dbg.value intrinsics
• Instruction::applyMergedLocation helps you to merge debug
locations
Summary
62
Summary
• We learned how line source locations (e.g. line number) and variable
locations are represented in debug info
62
Summary
• We learned how line source locations (e.g. line number) and variable
locations are represented in debug info
• We learned how debug info is stored in LLVM IR
62
Summary
• We learned how line source locations (e.g. line number) and variable
locations are represented in debug info
• We learned how debug info is stored in LLVM IR
• The challenges of debug info in optimized binaries, and how LLVM
mitigates those issues
62
Contact
63
Email: minyihh@uci.edu 

GitHub: mshockwave

LinkedIn: https://www.linkedin.com/in/bekketmcclane/
Thank You!
Q&A
Appendix
llvm-dva
• LLVM DVA is still in the process of upstreaming to LLVM

• RFC: https://discourse.llvm.org/t/llvm-dev-rfc-llvm-dva-debug-
information-visual-analyzer/62570 

• You can, however, build it with this patch: https://reviews.llvm.org/D88661 

• The llvm-dva command I used in this slides:

• llvm-dva --attribute=location,format --output-sort=offset —
print=symbols,lines,instructions,scopes <object file>
66
Debug Info & Object Files
67
#include <greet.h>


void hello() {…}
#include <greet.h>


void bye() {…}
foo.c bar.c
Debug Info & Object Files
67
foo.o
Debug info for:


foo.c + greet.h
#include <greet.h>


void hello() {…}
#include <greet.h>


void bye() {…}
foo.c bar.c
Debug Info & Object Files
67
foo.o
Debug info for:


foo.c + greet.h
#include <greet.h>


void hello() {…}
#include <greet.h>


void bye() {…}
foo.c bar.c
bar.o
Debug info for:


bar.c + greet.h
Splitting (DWARF) Debug Info
68
#include <greet.h>


void hello() {…}
#include <greet.h>


void bye() {…}
foo.c bar.c
foo.o
foo.c.dwo
bar.o
bar.c.dwo
greet.h.dwo
Splitting (DWARF) Debug Info
68
#include <greet.h>


void hello() {…}
#include <greet.h>


void bye() {…}
foo.c bar.c
foo.o
foo.c.dwo
bar.o
bar.c.dwo
greet.h.dwo
Debug info
container
Splitting Debug Info
69
Splitting Debug Info
• Saving disk spaces

• E.g. Able to de-duplicate type information
69
Splitting Debug Info
• Saving disk spaces

• E.g. Able to de-duplicate type information
• Attaching debug info
fi
les (e.g. *.dwo) on release binaries

• E.g. When debugging crashes reported by users
69
Splitting Debug Info
• Saving disk spaces

• E.g. Able to de-duplicate type information
• Attaching debug info
fi
les (e.g. *.dwo) on release binaries

• E.g. When debugging crashes reported by users
• Apple platforms are doing this by default (i.e. *.dSYM folders)
69
70
{Struct} 'Point'


{Member} public 'x' -> 'int'


{Location}


{Entry} offset 0


{Member} public 'y' -> 'int'


{Location}


{Entry} offset 4


{Function} extern not_inlined 'foo' -> 'int'


{Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
llvm-dva output DWARF dump
70
0x0000002d: DW_TAG_structure_type


DW_AT_name
	
("Point")


…


0x0000003a: DW_TAG_member


DW_AT_name
	
("x")


DW_AT_data_member_location (0x00)


…


0x00000045: DW_TAG_member


DW_AT_name
	
("y")


DW_AT_data_member_location (0x04)


…


0x00000058: DW_TAG_subprogram


DW_AT_name
	
("foo")


DW_AT_decl_line
	
(3)


DW_AT_decl_column
	
(0x05)


…


0x00000090: DW_TAG_variable


DW_AT_name
	
("point")


DW_AT_decl_line
	
(4)


…


DW_AT_location
	
(DW_OP_fbreg -24)
{Struct} 'Point'


{Member} public 'x' -> 'int'


{Location}


{Entry} offset 0


{Member} public 'y' -> 'int'


{Location}


{Entry} offset 4


{Function} extern not_inlined 'foo' -> 'int'


{Variable} 'point' -> 'Point'


{Location}


{Entry} fbreg -24
llvm-dva output DWARF dump
Validating Debug Info in
Optimized Code
LLVM Debugify
72
define i32 @add(i32 %0, i32 %1) {


%x = add i32 %0, %1


ret i32 %x


}
LLVM Debugify
72
define i32 @add(i32 %0, i32 %1) {


%x = add i32 %0, %1


ret i32 %x


}
define i32 @add(i32 %0, i32 %1) !dbg !7 {


%x = add i32 %0, %1, !dbg, !8


ret i32 %x, !dbg, !9


}
!7 = !DISubprogram(name: "add", line: 1,...)


!8 = !DILocation(line: 2, ...)


!9 = !DILocation(line: 3, ...)
LLVM Debugify
• Adding arti
fi
cially-created (fake) debug info metadata to every instructions
72
define i32 @add(i32 %0, i32 %1) {


%x = add i32 %0, %1


ret i32 %x


}
define i32 @add(i32 %0, i32 %1) !dbg !7 {


%x = add i32 %0, %1, !dbg, !8


ret i32 %x, !dbg, !9


}
!7 = !DISubprogram(name: "add", line: 1,...)


!8 = !DILocation(line: 2, ...)


!9 = !DILocation(line: 3, ...)
LLVM Debugify
• Adding arti
fi
cially-created (fake) debug info metadata to every instructions
• Useful to test if a compiler transformation preserves debug info as expected
72
define i32 @add(i32 %0, i32 %1) {


%x = add i32 %0, %1


ret i32 %x


}
define i32 @add(i32 %0, i32 %1) !dbg !7 {


%x = add i32 %0, %1, !dbg, !8


ret i32 %x, !dbg, !9


}
!7 = !DISubprogram(name: "add", line: 1,...)


!8 = !DILocation(line: 2, ...)


!9 = !DILocation(line: 3, ...)
LLVM Debugify
• Adding arti
fi
cially-created (fake) debug info metadata to every instructions
• Useful to test if a compiler transformation preserves debug info as expected
• Don’t need a compiler frontend to generate debug info
72
define i32 @add(i32 %0, i32 %1) {


%x = add i32 %0, %1


ret i32 %x


}
define i32 @add(i32 %0, i32 %1) !dbg !7 {


%x = add i32 %0, %1, !dbg, !8


ret i32 %x, !dbg, !9


}
!7 = !DISubprogram(name: "add", line: 1,...)


!8 = !DILocation(line: 2, ...)


!9 = !DILocation(line: 3, ...)
DExTer: End-to-End Debug Info Tests
73
void bar(int *test) {}


int main() {


int test;


test = 23;


bar(&test); // DexLabel('before_bar')


return test; // DexLabel('after_bar')


}


// DexExpectWatchValue('test', '23', on_line=ref('before_bar'))


// DexExpectWatchValue('test', '23', on_line=ref('after_bar'))
foo.c
DExTer: End-to-End Debug Info Tests
73
void bar(int *test) {}


int main() {


int test;


test = 23;


bar(&test); // DexLabel('before_bar')


return test; // DexLabel('after_bar')


}


// DexExpectWatchValue('test', '23', on_line=ref('before_bar'))


// DexExpectWatchValue('test', '23', on_line=ref('after_bar'))
Expectations / Assertions
foo.c
DExTer: End-to-End Debug Info Tests
73
void bar(int *test) {}


int main() {


int test;


test = 23;


bar(&test); // DexLabel('before_bar')


return test; // DexLabel('after_bar')


}


// DexExpectWatchValue('test', '23', on_line=ref('before_bar'))


// DexExpectWatchValue('test', '23', on_line=ref('after_bar'))
Expectations / Assertions
foo.o
foo.c
Debugger
DExTer: End-to-End Debug Info Tests
73
void bar(int *test) {}


int main() {


int test;


test = 23;


bar(&test); // DexLabel('before_bar')


return test; // DexLabel('after_bar')


}


// DexExpectWatchValue('test', '23', on_line=ref('before_bar'))


// DexExpectWatchValue('test', '23', on_line=ref('after_bar'))
Expectations / Assertions
foo.o
foo.c
Debugger
DExTer
DExTer: End-to-End Debug Info Tests
73
void bar(int *test) {}


int main() {


int test;


test = 23;


bar(&test); // DexLabel('before_bar')


return test; // DexLabel('after_bar')


}


// DexExpectWatchValue('test', '23', on_line=ref('before_bar'))


// DexExpectWatchValue('test', '23', on_line=ref('after_bar'))
Expectations / Assertions
foo.o
foo.c
Debugger
DExTer
Validation
Example: Merging Debug Locations
74
store i32 9, i32* %1


...
store i32 9, i32* %1


...
store i32 9, i32* %1


...

Contenu connexe

Tendances

Qemu device prototyping
Qemu device prototypingQemu device prototyping
Qemu device prototyping
Yan Vugenfirer
 
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
Mr. Vengineer
 
LLVM
LLVMLLVM
Tcache Exploitation
Tcache ExploitationTcache Exploitation
Tcache Exploitation
Angel Boy
 
BPF: Tracing and more
BPF: Tracing and moreBPF: Tracing and more
BPF: Tracing and more
Brendan Gregg
 
密かに話題のBufferbloat
密かに話題のBufferbloat密かに話題のBufferbloat
密かに話題のBufferbloat
Kazuhito Ohkawa
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
MITSUNARI Shigeo
 
From IA-32 to avx-512
From IA-32 to avx-512From IA-32 to avx-512
From IA-32 to avx-512
MITSUNARI Shigeo
 
Play with FILE Structure - Yet Another Binary Exploit Technique
Play with FILE Structure - Yet Another Binary Exploit TechniquePlay with FILE Structure - Yet Another Binary Exploit Technique
Play with FILE Structure - Yet Another Binary Exploit Technique
Angel Boy
 
BPF - in-kernel virtual machine
BPF - in-kernel virtual machineBPF - in-kernel virtual machine
BPF - in-kernel virtual machine
Alexei Starovoitov
 
twlkh-linux-vsyscall-and-vdso
twlkh-linux-vsyscall-and-vdsotwlkh-linux-vsyscall-and-vdso
twlkh-linux-vsyscall-and-vdso
Viller Hsiao
 
Understand more about C
Understand more about CUnderstand more about C
Understand more about C
Yi-Hsiu Hsu
 
10分で分かるLinuxブロックレイヤ
10分で分かるLinuxブロックレイヤ10分で分かるLinuxブロックレイヤ
10分で分かるLinuxブロックレイヤTakashi Hoshino
 
COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺
宗凡 楊
 
Vivado hls勉強会5(axi4 stream)
Vivado hls勉強会5(axi4 stream)Vivado hls勉強会5(axi4 stream)
Vivado hls勉強会5(axi4 stream)
marsee101
 
Linux I2C
Linux I2CLinux I2C
Linux I2C
KaidenYu
 
Introduction to the LLVM Compiler System
Introduction to the LLVM  Compiler SystemIntroduction to the LLVM  Compiler System
Introduction to the LLVM Compiler System
zionsaint
 
Understanding a kernel oops and a kernel panic
Understanding a kernel oops and a kernel panicUnderstanding a kernel oops and a kernel panic
Understanding a kernel oops and a kernel panic
Joseph Lu
 
The Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast StorageThe Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast Storage
Kernel TLV
 
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgenIntel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
MITSUNARI Shigeo
 

Tendances (20)

Qemu device prototyping
Qemu device prototypingQemu device prototyping
Qemu device prototyping
 
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
 
LLVM
LLVMLLVM
LLVM
 
Tcache Exploitation
Tcache ExploitationTcache Exploitation
Tcache Exploitation
 
BPF: Tracing and more
BPF: Tracing and moreBPF: Tracing and more
BPF: Tracing and more
 
密かに話題のBufferbloat
密かに話題のBufferbloat密かに話題のBufferbloat
密かに話題のBufferbloat
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
 
From IA-32 to avx-512
From IA-32 to avx-512From IA-32 to avx-512
From IA-32 to avx-512
 
Play with FILE Structure - Yet Another Binary Exploit Technique
Play with FILE Structure - Yet Another Binary Exploit TechniquePlay with FILE Structure - Yet Another Binary Exploit Technique
Play with FILE Structure - Yet Another Binary Exploit Technique
 
BPF - in-kernel virtual machine
BPF - in-kernel virtual machineBPF - in-kernel virtual machine
BPF - in-kernel virtual machine
 
twlkh-linux-vsyscall-and-vdso
twlkh-linux-vsyscall-and-vdsotwlkh-linux-vsyscall-and-vdso
twlkh-linux-vsyscall-and-vdso
 
Understand more about C
Understand more about CUnderstand more about C
Understand more about C
 
10分で分かるLinuxブロックレイヤ
10分で分かるLinuxブロックレイヤ10分で分かるLinuxブロックレイヤ
10分で分かるLinuxブロックレイヤ
 
COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺
 
Vivado hls勉強会5(axi4 stream)
Vivado hls勉強会5(axi4 stream)Vivado hls勉強会5(axi4 stream)
Vivado hls勉強会5(axi4 stream)
 
Linux I2C
Linux I2CLinux I2C
Linux I2C
 
Introduction to the LLVM Compiler System
Introduction to the LLVM  Compiler SystemIntroduction to the LLVM  Compiler System
Introduction to the LLVM Compiler System
 
Understanding a kernel oops and a kernel panic
Understanding a kernel oops and a kernel panicUnderstanding a kernel oops and a kernel panic
Understanding a kernel oops and a kernel panic
 
The Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast StorageThe Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast Storage
 
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgenIntel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
 

Similaire à Debug Information And Where They Come From

lldb – Debugger auf Abwegen
lldb – Debugger auf Abwegenlldb – Debugger auf Abwegen
lldb – Debugger auf Abwegen
inovex GmbH
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
Andrey Karpov
 
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
corehard_by
 
Anomalies in X-Ray Engine
Anomalies in X-Ray EngineAnomalies in X-Ray Engine
Anomalies in X-Ray Engine
PVS-Studio
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
DevGAMM Conference
 
JVM code reading -- C2
JVM code reading -- C2JVM code reading -- C2
JVM code reading -- C2
ytoshima
 
Chapter 5
Chapter 5Chapter 5
Chapter 5
EasyStudy3
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
PVS-Studio
 
Score (smart contract for icon)
Score (smart contract for icon) Score (smart contract for icon)
Score (smart contract for icon)
Doyun Hwang
 
oop Lecture 4
oop Lecture 4oop Lecture 4
oop Lecture 4
Anwar Ul Haq
 
The Unicorn's Travel to the Microcosm
The Unicorn's Travel to the MicrocosmThe Unicorn's Travel to the Microcosm
The Unicorn's Travel to the Microcosm
Andrey Karpov
 
Hot Code is Faster Code - Addressing JVM Warm-up
Hot Code is Faster Code - Addressing JVM Warm-upHot Code is Faster Code - Addressing JVM Warm-up
Hot Code is Faster Code - Addressing JVM Warm-up
Mark Price
 
C # (2)
C # (2)C # (2)
Static analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systemsStatic analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systems
Andrey Karpov
 
Introduction to AspectJ
Introduction to AspectJIntroduction to AspectJ
Introduction to AspectJ
mukhtarhudaya
 
Analysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsAnalysis of Microsoft Code Contracts
Analysis of Microsoft Code Contracts
PVS-Studio
 
C++ file
C++ fileC++ file
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyC++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
GrejoJoby1
 
Monadic parsers in C++
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++
Alexander Granin
 
C lab-programs
C lab-programsC lab-programs
C lab-programs
Tony Kurishingal
 

Similaire à Debug Information And Where They Come From (20)

lldb – Debugger auf Abwegen
lldb – Debugger auf Abwegenlldb – Debugger auf Abwegen
lldb – Debugger auf Abwegen
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
 
Anomalies in X-Ray Engine
Anomalies in X-Ray EngineAnomalies in X-Ray Engine
Anomalies in X-Ray Engine
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
 
JVM code reading -- C2
JVM code reading -- C2JVM code reading -- C2
JVM code reading -- C2
 
Chapter 5
Chapter 5Chapter 5
Chapter 5
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
 
Score (smart contract for icon)
Score (smart contract for icon) Score (smart contract for icon)
Score (smart contract for icon)
 
oop Lecture 4
oop Lecture 4oop Lecture 4
oop Lecture 4
 
The Unicorn's Travel to the Microcosm
The Unicorn's Travel to the MicrocosmThe Unicorn's Travel to the Microcosm
The Unicorn's Travel to the Microcosm
 
Hot Code is Faster Code - Addressing JVM Warm-up
Hot Code is Faster Code - Addressing JVM Warm-upHot Code is Faster Code - Addressing JVM Warm-up
Hot Code is Faster Code - Addressing JVM Warm-up
 
C # (2)
C # (2)C # (2)
C # (2)
 
Static analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systemsStatic analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systems
 
Introduction to AspectJ
Introduction to AspectJIntroduction to AspectJ
Introduction to AspectJ
 
Analysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsAnalysis of Microsoft Code Contracts
Analysis of Microsoft Code Contracts
 
C++ file
C++ fileC++ file
C++ file
 
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo JobyC++ and OOPS Crash Course by ACM DBIT | Grejo Joby
C++ and OOPS Crash Course by ACM DBIT | Grejo Joby
 
Monadic parsers in C++
Monadic parsers in C++Monadic parsers in C++
Monadic parsers in C++
 
C lab-programs
C lab-programsC lab-programs
C lab-programs
 

Plus de Min-Yih Hsu

MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
MCA Daemon: Hybrid Throughput Analysis Beyond Basic BlocksMCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
Min-Yih Hsu
 
Handling inline assembly in Clang and LLVM
Handling inline assembly in Clang and LLVMHandling inline assembly in Clang and LLVM
Handling inline assembly in Clang and LLVM
Min-Yih Hsu
 
How to write a TableGen backend
How to write a TableGen backendHow to write a TableGen backend
How to write a TableGen backend
Min-Yih Hsu
 
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
Min-Yih Hsu
 
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
Min-Yih Hsu
 
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Paper Study - Demand-Driven Computation of Interprocedural Data FlowPaper Study - Demand-Driven Computation of Interprocedural Data Flow
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Min-Yih Hsu
 
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et alPaper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Min-Yih Hsu
 
Souper-Charging Peepholes with Target Machine Info
Souper-Charging Peepholes with Target Machine InfoSouper-Charging Peepholes with Target Machine Info
Souper-Charging Peepholes with Target Machine Info
Min-Yih Hsu
 
From V8 to Modern Compilers
From V8 to Modern CompilersFrom V8 to Modern Compilers
From V8 to Modern Compilers
Min-Yih Hsu
 
Introduction to Khronos SYCL
Introduction to Khronos SYCLIntroduction to Khronos SYCL
Introduction to Khronos SYCL
Min-Yih Hsu
 
Trace Scheduling
Trace SchedulingTrace Scheduling
Trace Scheduling
Min-Yih Hsu
 
Polymer Start-Up (SITCON 2016)
Polymer Start-Up (SITCON 2016)Polymer Start-Up (SITCON 2016)
Polymer Start-Up (SITCON 2016)
Min-Yih Hsu
 
War of Native Speed on Web (SITCON2016)
War of Native Speed on Web (SITCON2016)War of Native Speed on Web (SITCON2016)
War of Native Speed on Web (SITCON2016)
Min-Yih Hsu
 
From Android NDK To AOSP
From Android NDK To AOSPFrom Android NDK To AOSP
From Android NDK To AOSP
Min-Yih Hsu
 

Plus de Min-Yih Hsu (14)

MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
MCA Daemon: Hybrid Throughput Analysis Beyond Basic BlocksMCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
 
Handling inline assembly in Clang and LLVM
Handling inline assembly in Clang and LLVMHandling inline assembly in Clang and LLVM
Handling inline assembly in Clang and LLVM
 
How to write a TableGen backend
How to write a TableGen backendHow to write a TableGen backend
How to write a TableGen backend
 
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
 
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
 
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Paper Study - Demand-Driven Computation of Interprocedural Data FlowPaper Study - Demand-Driven Computation of Interprocedural Data Flow
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
 
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et alPaper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
 
Souper-Charging Peepholes with Target Machine Info
Souper-Charging Peepholes with Target Machine InfoSouper-Charging Peepholes with Target Machine Info
Souper-Charging Peepholes with Target Machine Info
 
From V8 to Modern Compilers
From V8 to Modern CompilersFrom V8 to Modern Compilers
From V8 to Modern Compilers
 
Introduction to Khronos SYCL
Introduction to Khronos SYCLIntroduction to Khronos SYCL
Introduction to Khronos SYCL
 
Trace Scheduling
Trace SchedulingTrace Scheduling
Trace Scheduling
 
Polymer Start-Up (SITCON 2016)
Polymer Start-Up (SITCON 2016)Polymer Start-Up (SITCON 2016)
Polymer Start-Up (SITCON 2016)
 
War of Native Speed on Web (SITCON2016)
War of Native Speed on Web (SITCON2016)War of Native Speed on Web (SITCON2016)
War of Native Speed on Web (SITCON2016)
 
From Android NDK To AOSP
From Android NDK To AOSPFrom Android NDK To AOSP
From Android NDK To AOSP
 

Dernier

Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
mz5nrf0n
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
Rakesh Kumar R
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
Alberto Brandolini
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
Yara Milbes
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
dakas1
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
Patrick Weigel
 
316895207-SAP-Oil-and-Gas-Downstream-Training.pptx
316895207-SAP-Oil-and-Gas-Downstream-Training.pptx316895207-SAP-Oil-and-Gas-Downstream-Training.pptx
316895207-SAP-Oil-and-Gas-Downstream-Training.pptx
ssuserad3af4
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
Alina Yurenko
 
Top 9 Trends in Cybersecurity for 2024.pptx
Top 9 Trends in Cybersecurity for 2024.pptxTop 9 Trends in Cybersecurity for 2024.pptx
Top 9 Trends in Cybersecurity for 2024.pptx
devvsandy
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
Hornet Dynamics
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
XfilesPro
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
Quickdice ERP
 

Dernier (20)

Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
 
316895207-SAP-Oil-and-Gas-Downstream-Training.pptx
316895207-SAP-Oil-and-Gas-Downstream-Training.pptx316895207-SAP-Oil-and-Gas-Downstream-Training.pptx
316895207-SAP-Oil-and-Gas-Downstream-Training.pptx
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
 
Top 9 Trends in Cybersecurity for 2024.pptx
Top 9 Trends in Cybersecurity for 2024.pptxTop 9 Trends in Cybersecurity for 2024.pptx
Top 9 Trends in Cybersecurity for 2024.pptx
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
 

Debug Information And Where They Come From

  • 1. Debug INFormation And Where They Come From Min-Yih “Min” Hsu, COSCUP 2022
  • 7. Debugging 2 Execution Program Pause Debugger Developers Source Code • Source location (e.g. line number) • Variable values • Function call hierarchy
  • 10. Languages & Debugging 4 Run & Debug on Native Binaries
  • 11. Debug Symbols / Info 5 Program Binary
  • 12. Debug Symbols / Info 5 Program Binary Debug Info
  • 13. Debug Symbols / Info 5 Program Binary Debug Info Source Code Mapping
  • 14. Debug Symbols / Info 5 Program Binary Debug Info Debugger Consume Source Code Mapping
  • 15. Debug Symbols / Info 5 Program Binary Debug Info Debugger Consume Source Code Mapping Pro fi ler
  • 18. Today’s Topic 6 Program Binary Debug Info Source Code Compiler Debug Info… … And Where They Come From
  • 20. Example Input 8 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } *Host Architecture: x86_64
  • 21. Example Input 8 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } $ cc -g -c demo.c -o demo.o *Host Architecture: x86_64
  • 22. Example Input 8 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } $ cc -g -c demo.c -o demo.o $ llvm-dva demo.o … *Host Architecture: x86_64
  • 23. llvm-dva: Visualizing Debug Info 9 {CompileUnit} ‘demo.c' .... 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 .... 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 3 {Line} {Code} 'endbr64' {Code} 'pushq %rbp' .... 4 {Line} {Code} 'movl $0x0, -0x8(%rbp)' {Code} 'movl $0x0, -0x4(%rbp)' 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 24. llvm-dva: Visualizing Debug Info 10 {CompileUnit} ‘demo.c' .... 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 .... 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 3 {Line} {Code} 'endbr64' {Code} 'pushq %rbp' .... 4 {Line} {Code} 'movl $0x0, -0x8(%rbp)' {Code} 'movl $0x0, -0x4(%rbp)' 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 25. llvm-dva: Visualizing Debug Info 10 {CompileUnit} ‘demo.c' .... 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 .... 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 3 {Line} {Code} 'endbr64' {Code} 'pushq %rbp' .... 4 {Line} {Code} 'movl $0x0, -0x8(%rbp)' {Code} 'movl $0x0, -0x4(%rbp)' 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 26. llvm-dva: Visualizing Debug Info 11 {CompileUnit} ‘demo.c' .... 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 .... 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 3 {Line} {Code} 'endbr64' {Code} 'pushq %rbp' .... 4 {Line} {Code} 'movl $0x0, -0x8(%rbp)' {Code} 'movl $0x0, -0x4(%rbp)' 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 27. llvm-dva: Visualizing Debug Info 11 {CompileUnit} ‘demo.c' .... 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 .... 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 3 {Line} {Code} 'endbr64' {Code} 'pushq %rbp' .... 4 {Line} {Code} 'movl $0x0, -0x8(%rbp)' {Code} 'movl $0x0, -0x4(%rbp)' 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 28. llvm-dva: Visualizing Debug Info 12 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Line numbers & instructions
  • 29. llvm-dva: Visualizing Debug Info 12 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Line numbers & instructions
  • 30. llvm-dva: Visualizing Debug Info 12 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Where ‘c’ is stored Line numbers & instructions
  • 31. llvm-dva: Visualizing Debug Info 12 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Where ‘c’ is stored PC Address Line Number Assembly 
 (NOT stored in debug info) 0x1C 5 cmpl $0x0,-0x18(%rbp) 0x20 5 je 0xc Line numbers & instructions
  • 32. llvm-dva: Visualizing Debug Info 13 {CompileUnit} ‘demo.c' .... 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 .... 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 3 {Line} {Code} 'endbr64' {Code} 'pushq %rbp' .... 4 {Line} {Code} 'movl $0x0, -0x8(%rbp)' {Code} 'movl $0x0, -0x4(%rbp)' 5 {Line} {Code} 'cmpl $0x0, -0x18(%rbp)' {Code} 'je 0xc’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 33. llvm-dva: Visualizing Debug Info 14 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Variable locations
  • 34. llvm-dva: Visualizing Debug Info 14 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Variable locations
  • 35. llvm-dva: Visualizing Debug Info 15 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Variable locations Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address Current Stack Frame Lo Address Hi Address
  • 36. llvm-dva: Visualizing Debug Info 15 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Variable locations Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address Current Stack Frame Lo Address Hi Address fbreg
  • 37. llvm-dva: Visualizing Debug Info 15 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Variable locations Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address -24 Current Stack Frame Lo Address Hi Address fbreg
  • 38. llvm-dva: Visualizing Debug Info 15 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Variable locations Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address -24 -36 Current Stack Frame Lo Address Hi Address fbreg
  • 39. llvm-dva: Visualizing Debug Info 15 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Variable locations Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address -24 -36 -40 Current Stack Frame Lo Address Hi Address fbreg
  • 40. llvm-dva: Visualizing Debug Info 16 {CompileUnit} ‘demo.c' 1 {Struct} 'Point' 1 {Member} public 'x' -> 'int' {Location} {Entry} offset 0 1 {Member} public 'y' -> 'int' {Location} {Entry} offset 4 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Type Layout Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address Current Stack Frame Lo Address Hi Address
  • 41. llvm-dva: Visualizing Debug Info 16 {CompileUnit} ‘demo.c' 1 {Struct} 'Point' 1 {Member} public 'x' -> 'int' {Location} {Entry} offset 0 1 {Member} public 'y' -> 'int' {Location} {Entry} offset 4 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Type Layout Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address Current Stack Frame Lo Address Hi Address
  • 42. llvm-dva: Visualizing Debug Info 16 {CompileUnit} ‘demo.c' 1 {Struct} 'Point' 1 {Member} public 'x' -> 'int' {Location} {Entry} offset 0 1 {Member} public 'y' -> 'int' {Location} {Entry} offset 4 3 {Function} extern not_inlined 'foo' -> 'int' 3 {Parameter} 'k' -> 'int' {Location} {Entry} fbreg -36 3 {Parameter} 'c' -> 'int' {Location} {Entry} fbreg -40 4 {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 Type Layout Variable ‘point’ Variable ‘k’ Variable ‘c’ Previous Frame Ptr Return Address Current Stack Frame Lo Address Hi Address Field ‘x’ Field ‘y’ +0 +4
  • 43. Other Common Debug Info Properties 17
  • 44. Other Common Debug Info Properties • Scopes 17
  • 45. Other Common Debug Info Properties • Scopes • Advanced type information • Type aliases • Type hierarchy 17
  • 48. Debug Info Standards 18 DWARF CodeView • Default format in Linux, Apple platforms,
 most of the Unix
  • 49. Debug Info Standards 18 DWARF CodeView • Default format in Linux, Apple platforms,
 most of the Unix • Supported by GNU & LLVM toolchain
  • 50. Debug Info Standards 18 DWARF CodeView • Default format in Linux, Apple platforms,
 most of the Unix • Supported by GNU & LLVM toolchain • Container formats: DWO, DWP, dSYM
  • 51. Debug Info Standards 18 DWARF CodeView • Default format in Linux, Apple platforms,
 most of the Unix • Supported by GNU & LLVM toolchain • Container formats: DWO, DWP, dSYM • Default format in Windows (MSVC)
  • 52. Debug Info Standards 18 DWARF CodeView • Default format in Linux, Apple platforms,
 most of the Unix • Supported by GNU & LLVM toolchain • Container formats: DWO, DWP, dSYM • Default format in Windows (MSVC) • Supported by MSVC & LLVM toolchain
  • 53. Debug Info Standards 18 DWARF CodeView • Default format in Linux, Apple platforms,
 most of the Unix • Supported by GNU & LLVM toolchain • Container formats: DWO, DWP, dSYM • Default format in Windows (MSVC) • Supported by MSVC & LLVM toolchain • Container format: PDB
  • 56. Compilation Pipeline: A Crash Course 21 Source Code Native Code (e.g. *.o fi les)
  • 57. Compilation Pipeline: A Crash Course 21 Source Code AST Parse Native Code (e.g. *.o fi les)
  • 58. Compilation Pipeline: A Crash Course 21 Source Code AST Parse Intermediate Representation (IR) Native Code (e.g. *.o fi les)
  • 59. Compilation Pipeline: A Crash Course 21 Source Code AST Parse Intermediate Representation (IR) Another Intermediate Representation Native Code (e.g. *.o fi les)
  • 60. Debug Info in a Compilation Pipeline: Highlights 22 Source Code AST Parse Intermediate Representation (IR) Another Intermediate Representation Native Code (e.g. *.o fi les)
  • 61. Debug Info in a Compilation Pipeline: Highlights 22 Source Code AST Parse Intermediate Representation (IR) Another Intermediate Representation Native Code (e.g. *.o fi les) • How to “carry” debug info in IR ?
  • 62. Debug Info in a Compilation Pipeline: Highlights 22 Source Code AST Parse Intermediate Representation (IR) Another Intermediate Representation Native Code (e.g. *.o fi les) • How to “carry” debug info in IR ? • Correctly translate from source to debug info in IR
  • 63. Debug Info in a Compilation Pipeline: Highlights 22 Source Code AST Parse Intermediate Representation (IR) Another Intermediate Representation Native Code (e.g. *.o fi les) • How to “carry” debug info in IR ? • Correctly translate from source to debug info in IR • Preserve debug info across transformations (e.g. optimizations)
  • 64. Case Study: LLVM / Clang 23 void foo() { int x = 9; int y = 4; } C Source (foo.c)
  • 65. Case Study: LLVM / Clang 23 define void @foo() { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1 store i32 4, i32* %2 ret void } void foo() { int x = 9; int y = 4; } C Source (foo.c) LLVM IR (foo.ll) $ clang -emit-llvm -S foo.c -o foo.ll
  • 66. Case Study: LLVM / Clang 23 define void @foo() { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1 store i32 4, i32* %2 ret void } void foo() { int x = 9; int y = 4; } C Source (foo.c) LLVM IR (foo.ll) $ clang -emit-llvm -S foo.c -o foo.ll Allocating stack space
  • 67. Case Study: LLVM / Clang 23 define void @foo() { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1 store i32 4, i32* %2 ret void } void foo() { int x = 9; int y = 4; } C Source (foo.c) LLVM IR (foo.ll) $ clang -emit-llvm -S foo.c -o foo.ll
  • 68. 24 $ clang -g -emit-llvm -S foo.c -o foo.ll
  • 69. Debug Info in LLVM IR 24 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR (foo.ll) $ clang -g -emit-llvm -S foo.c -o foo.ll
  • 70. Debug Info in LLVM IR 25 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1, !dbg !13 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } void foo() { int x = 9; int y = 4; } C Source 1 2 3 4 LLVM IR
  • 71. Debug Info in LLVM IR 25 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1, !dbg !13 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } void foo() { int x = 9; int y = 4; } C Source 1 2 3 4 LLVM IR
  • 72. Debug Info in LLVM IR 25 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1, !dbg !13 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } void foo() { int x = 9; int y = 4; } C Source 1 2 3 4 LLVM IR !13 = !DILocation(line: 2, column: 7, ...) At the bottom of IR fi le
  • 73. Debug Info in LLVM IR 25 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 store i32 9, i32* %1, !dbg !13 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } void foo() { int x = 9; int y = 4; } C Source 1 2 3 4 LLVM IR !13 = !DILocation(line: 2, column: 7, ...) !15 = !DILocation(line: 3, column: 7, ...) At the bottom of IR fi le
  • 74. Debug Info in LLVM IR 26 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR
  • 75. Debug Info in LLVM IR 27 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR
  • 76. Debug Info in LLVM IR 27 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR !11 = !DILocalVariable(name: "x", ..., line: 2, ...)
  • 77. Debug Info in LLVM IR 27 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR !11 = !DILocalVariable(name: "x", ..., line: 2, ...)
  • 78. Debug Info in LLVM IR 27 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR !11 = !DILocalVariable(name: "x", ..., line: 2, ...) Associated
  • 79. Debug Info in LLVM IR 27 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR !11 = !DILocalVariable(name: "x", ..., line: 2, ...) Associated representing variable’s location during runtime
  • 80. Debug Info in LLVM IR 27 define void @foo() !dbg !7 { %1 = alloca i32 %2 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …), !dbg !13 store i32 9, i32* %1, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, …), !dbg !15 store i32 4, i32* %2, !dbg !15 ret void, !dbg !16 } LLVM IR !11 = !DILocalVariable(name: "x", ..., line: 2, ...) !14 = !DILocalVariable(name: "y", ..., line: 3, ...)
  • 81. Visualizing Debug Info 28 $ cc -g -c foo.c -o foo.o $ llvm-dva foo.o …
  • 82. Visualizing Debug Info 29 {CompileUnit} ‘foo.c’ 1 {Function} extern not_inlined ‘foo’… 2 {Variable} 'x' -> 'int' {Location} {Entry} fbreg -4 3 {Variable} 'y' -> 'int' {Location} {Entry} fbreg -8 1 {Line} {Code} 'pushq %rbp' {Code} 'movq %rsp, %rbp' 2 {Line} {Code} 'movl $0x9, -0x4(%rbp)' 3 {Line} {Code} 'movl $0x4, -0x8(%rbp)' 4 {Line} {Code} 'popq %rbp' {Code} 'retq' 4 {Line}
  • 83. Visualizing Debug Info 29 {CompileUnit} ‘foo.c’ 1 {Function} extern not_inlined ‘foo’… 2 {Variable} 'x' -> 'int' {Location} {Entry} fbreg -4 3 {Variable} 'y' -> 'int' {Location} {Entry} fbreg -8 1 {Line} {Code} 'pushq %rbp' {Code} 'movq %rsp, %rbp' 2 {Line} {Code} 'movl $0x9, -0x4(%rbp)' 3 {Line} {Code} 'movl $0x4, -0x8(%rbp)' 4 {Line} {Code} 'popq %rbp' {Code} 'retq' 4 {Line} store i32 9, i32* %1, !dbg !13 !13 = !DILocation(line: 2, column: 7, ...)
  • 84. Visualizing Debug Info 29 {CompileUnit} ‘foo.c’ 1 {Function} extern not_inlined ‘foo’… 2 {Variable} 'x' -> 'int' {Location} {Entry} fbreg -4 3 {Variable} 'y' -> 'int' {Location} {Entry} fbreg -8 1 {Line} {Code} 'pushq %rbp' {Code} 'movq %rsp, %rbp' 2 {Line} {Code} 'movl $0x9, -0x4(%rbp)' 3 {Line} {Code} 'movl $0x4, -0x8(%rbp)' 4 {Line} {Code} 'popq %rbp' {Code} 'retq' 4 {Line} store i32 9, i32* %1, !dbg !13 !13 = !DILocation(line: 2, column: 7, ...)
  • 85. Visualizing Debug Info 29 {CompileUnit} ‘foo.c’ 1 {Function} extern not_inlined ‘foo’… 2 {Variable} 'x' -> 'int' {Location} {Entry} fbreg -4 3 {Variable} 'y' -> 'int' {Location} {Entry} fbreg -8 1 {Line} {Code} 'pushq %rbp' {Code} 'movq %rsp, %rbp' 2 {Line} {Code} 'movl $0x9, -0x4(%rbp)' 3 {Line} {Code} 'movl $0x4, -0x8(%rbp)' 4 {Line} {Code} 'popq %rbp' {Code} 'retq' 4 {Line} %1 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …) !11 = !DILocalVariable(name: "x", ..., line: 2, ...) store i32 9, i32* %1, !dbg !13 !13 = !DILocation(line: 2, column: 7, ...)
  • 86. Visualizing Debug Info 29 {CompileUnit} ‘foo.c’ 1 {Function} extern not_inlined ‘foo’… 2 {Variable} 'x' -> 'int' {Location} {Entry} fbreg -4 3 {Variable} 'y' -> 'int' {Location} {Entry} fbreg -8 1 {Line} {Code} 'pushq %rbp' {Code} 'movq %rsp, %rbp' 2 {Line} {Code} 'movl $0x9, -0x4(%rbp)' 3 {Line} {Code} 'movl $0x4, -0x8(%rbp)' 4 {Line} {Code} 'popq %rbp' {Code} 'retq' 4 {Line} %1 = alloca i32 call void @llvm.dbg.declare(metadata i32* %1, metadata !11, …) !11 = !DILocalVariable(name: "x", ..., line: 2, ...) store i32 9, i32* %1, !dbg !13 !13 = !DILocation(line: 2, column: 7, ...)
  • 87. 30
  • 88. 30 …And Developers Lives a Happy Debu gg ing Life Ever Since
  • 89. 30 …And Developers Lives a Happy Debu gg ing Life Ever Since
  • 90. Debug Info in Optimized Binaries
  • 91. Debug Info in Optimized Binaries 32 $ cc -g -O2 -c foo.c
  • 92. Debug Info in Optimized Binaries 32 $ cc -g -O2 -c foo.c
  • 93. Debug Info in Optimized Binaries 32 $ cc -g -O2 -c foo.c Why?
  • 95. Debugging Optimized Programs • Games • Di ffi cult (if not nearly impossible) to debug low-FPS games 33
  • 96. Debugging Optimized Programs • Games • Di ffi cult (if not nearly impossible) to debug low-FPS games • Embedded systems • Size optimization is usually a hard requirement 33
  • 97. Debugging Optimized Programs • Games • Di ffi cult (if not nearly impossible) to debug low-FPS games • Embedded systems • Size optimization is usually a hard requirement • Easier debugging on release binaries • E.g. Using core fi les directly from customers 33
  • 98. Recall: Early Example Code 34 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } $ clang -g foo.c -emit-llvm -S
  • 99. 35 define i32 @foo(i32 %0, i32 %1) !dbg !7 { %3 = alloca i32 %4 = alloca i32 %5 = alloca %struct.Point store i32 %0, i32* %3 call void @llvm.dbg.declare(metadata i32* %3, metadata !12, ...), !dbg !13 store i32 %1, i32* %4 call void @llvm.dbg.declare(metadata i32* %4, metadata !14, ...), !dbg !15 call void @llvm.dbg.declare(metadata %struct.Point* %5, metadata !16, ...), !dbg !21 ... } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 100. 36 define i32 @foo(i32 %0, i32 %1) !dbg !7 { %3 = alloca i32 %4 = alloca i32 %5 = alloca %struct.Point store i32 %0, i32* %3 call void @llvm.dbg.declare(metadata i32* %3, metadata !12, ...), !dbg !13 store i32 %1, i32* %4 call void @llvm.dbg.declare(metadata i32* %4, metadata !14, ...), !dbg !15 call void @llvm.dbg.declare(metadata %struct.Point* %5, metadata !16, ...), !dbg !21 ... } Allocating stack space for ‘k’, ‘c’, and ‘point’ struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 101. 37 define i32 @foo(i32 %0, i32 %1) !dbg !7 { %3 = alloca i32 %4 = alloca i32 %5 = alloca %struct.Point store i32 %0, i32* %3 call void @llvm.dbg.declare(metadata i32* %3, metadata !12, ...), !dbg !13 store i32 %1, i32* %4 call void @llvm.dbg.declare(metadata i32* %4, metadata !14, ...), !dbg !15 call void @llvm.dbg.declare(metadata %struct.Point* %5, metadata !16, ...), !dbg !21 ... } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Associating stack spaces with the source variables
  • 102. Optimized Example Code 38 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } $ clang -O2 foo.c -emit-llvm -S
  • 103. 39 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 104. 39 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Values are not put on stack anymore!
  • 105. 40 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Prompt: 
 What is the runtime location/value of source variable ‘point’ ?
  • 106. 40 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Prompt: 
 What is the runtime location/value of source variable ‘point’ ? (gdb) print point <your answer> (gdb)
  • 107. 40 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Prompt: 
 What is the runtime location/value of source variable ‘point’ ? (gdb) print point <your answer> (gdb) ?
  • 108. 41 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Which instructions should I annotate with source line 4, 6, and 7 ?
  • 109. 41 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Which instructions should I annotate with source line 4, 6, and 7 ? ?
  • 110. Other Common Challenges 42 Updating Scopes Function Inlining
  • 111. Preserving Debug Info in Optimized Code • Most modern compilers preserve debug information as part of the code transformations (e.g. optimizations) 43
  • 112. Preserving Debug Info in Optimized Code • Most modern compilers preserve debug information as part of the code transformations (e.g. optimizations) • Challenges 43
  • 113. Preserving Debug Info in Optimized Code • Most modern compilers preserve debug information as part of the code transformations (e.g. optimizations) • Challenges • It’s easy for compiler developers to forget to handle debug info 43
  • 114. Preserving Debug Info in Optimized Code • Most modern compilers preserve debug information as part of the code transformations (e.g. optimizations) • Challenges • It’s easy for compiler developers to forget to handle debug info • It’s not possible to (faithfully) map optimized code back to source locations in every cases 43
  • 115. Preserving Debug Info in Optimized Code • Most modern compilers preserve debug information as part of the code transformations (e.g. optimizations) • Challenges • It’s easy for compiler developers to forget to handle debug info • It’s not possible to (faithfully) map optimized code back to source locations in every cases • Debug info in optimized binaries is preserved on a best-e ff ort basis 43
  • 116. Case Study: How LLVM Mitigates These Issues
  • 117. Recall: Optimized Code Example 45 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Prompt: 
 What is the runtime location/value of source variable ‘point’ ? (gdb) print point <your answer> (gdb) ?
  • 118. Optimized Example Code w/ Debug Info 46 struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } $ clang -O2 -g foo.c -emit-llvm -S
  • 119. Preserving Variable Locations / Values in LLVM 47 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32)) call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32)) %5 = add nsw i32 %4, %1 ret i32 %5 }
  • 120. Preserving Variable Locations / Values in LLVM 48 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 … }
  • 121. Preserving Variable Locations / Values in LLVM 48 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 … } !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11) !14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
  • 122. Preserving Variable Locations / Values in LLVM 49 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 … } !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11) !14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11) LLVM Intrinsic Name Description llvm.dbg.declare Specify the (memory) location for a source variable. 
 Only a single occurrence per source variable is allowed llvm.dbg.value Designate a (runtime) value to a source variable Can have multiple occurrences for a source variable
 (akin to updating di ff erent values on a source variable)
  • 123. Preserving Variable Locations / Values in LLVM 49 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 … } !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11) !14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11) LLVM Intrinsic Name Description llvm.dbg.declare Specify the (memory) location for a source variable. 
 Only a single occurrence per source variable is allowed llvm.dbg.value Designate a (runtime) value to a source variable Can have multiple occurrences for a source variable
 (akin to updating di ff erent values on a source variable)
  • 124. Preserving Variable Locations / Values in LLVM 49 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 … } !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11) !14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11) LLVM Intrinsic Name Description llvm.dbg.declare Specify the (memory) location for a source variable. 
 Only a single occurrence per source variable is allowed llvm.dbg.value Designate a (runtime) value to a source variable Can have multiple occurrences for a source variable
 (akin to updating di ff erent values on a source variable)
  • 125. Preserving Variable Locations / Values in LLVM 49 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata …) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 … } !13 = !DILocalVariable(name: "k", arg: 1, ..., line: 3, type: !11) !14 = !DILocalVariable(name: "c", arg: 2, ..., line: 3, type: !11)
  • 126. Preserving Variable Locations / Values in LLVM 50 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 127. Preserving Variable Locations / Values in LLVM 50 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16)
  • 128. Preserving Variable Locations / Values in LLVM 50 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) Why this is not “point.x” or “point.y” ?
  • 129. Preserving Variable Locations / Values in LLVM 50 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) Why this is not “point.x” or “point.y” ?
  • 130. Preserving Variable Locations / Values in LLVM 51 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) A fragment of source variable “point” has value 0.
  • 131. Preserving Variable Locations / Values in LLVM 51 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) A fragment of source variable “point” has value 0.
  • 132. Preserving Variable Locations / Values in LLVM 51 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) A fragment of source variable “point” has value 0.
  • 133. Preserving Variable Locations / Values in LLVM 51 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) A fragment of source variable “point” has value 0.
  • 134. Preserving Variable Locations / Values in LLVM 52 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) A 32-bit, o ff set 0 fragment of source variable “point” has value 0.
  • 135. Preserving Variable Locations / Values in LLVM 52 define i32 @foo(i32 %0, i32 %1) { ... call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 ... } !15 = !DILocalVariable(name: "point", ..., line: 4, type: !16) A 32-bit, o ff set 0 fragment of source variable “point” has value 0. (i.e. the “point.x” fi eld)
  • 136. Preserving Variable Locations / Values in LLVM 53 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32)) call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32)) %5 = add nsw i32 %4, %1 ret i32 %5 } First, “point.x” & “point.y” were initialized to zeros…
  • 137. Preserving Variable Locations / Values in LLVM 54 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32)) call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32)) %5 = add nsw i32 %4, %1 ret i32 %5 } After these two instructions…
  • 138. Preserving Variable Locations / Values in LLVM 55 define i32 @foo(i32 %0, i32 %1) { call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)) call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)) %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 call void @llvm.dbg.value(metadata i32 %1, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 32,32)) call void @llvm.dbg.value(metadata i32 %4, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 0,32)) %5 = add nsw i32 %4, %1 ret i32 %5 } “point.x” & “point.y” now have values %4 and %1, respectively
  • 139. Recall: Optimized Code Example 56 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 Which instructions should I annotate with source line 4, 6, and 7 ?
  • 140. Preserving Debug Locations in LLVM 57 Principles Actions
  • 141. Preserving Debug Locations in LLVM 57 Principles Actions Keep
  • 142. Preserving Debug Locations in LLVM 57 Principles Actions Keep Merge
  • 143. Preserving Debug Locations in LLVM 57 Principles Actions Keep Merge Delete
  • 144. Preserving Debug Locations in LLVM 57 Principles • Don’t create misleading debug locations that are only correct in some cases Actions Keep Merge Delete
  • 145. Preserving Debug Locations in LLVM 57 Principles • Don’t create misleading debug locations that are only correct in some cases • If you’re not sure, just drop the debug locations Actions Keep Merge Delete
  • 146. Preserving Debug Locations in LLVM 57 Principles • Don’t create misleading debug locations that are only correct in some cases • If you’re not sure, just drop the debug locations • Otherwise, preserve as much debug locations as possible Actions Keep Merge Delete
  • 147. Debug Locations in our Example Code 58 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 148. Debug Locations in our Example Code 59 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10
  • 149. Debug Locations in our Example Code 59 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 line 6 will only hit conditionally
  • 150. Debug Locations in our Example Code 59 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 line 6 will only hit conditionally “Don’t create misleading debug locations 
 that are only correct in some cases”
  • 151. Debug Locations in our Example Code 59 define i32 @foo(i32 %0, i32 %1) { %3 = icmp eq i32 %1, 0 %4 = select i1 %3, i32 0, i32 %0 %5 = add nsw i32 %4, %1 ret i32 %5 } struct Point { int x, y; }; int foo(int k, int c) { struct Point point = {x: 0, y: 0}; if (c) { point.x = k; point.y = c; } return point.x + point.y; } 1 2 3 4 5 6 7 8 9 10 line 6 will only hit conditionally “Don’t create misleading debug locations 
 that are only correct in some cases” Delete
  • 152. Preserving Debug Locations in LLVM 60 Prantl and Kumar, US LLVM Dev Meeting 2020 Guidelines for updating debug locations in code transformations https://tinyurl.com/llvmdebuginfo Full write-up:
  • 153. Preserving Debug Info in LLVM: Automatically 61
  • 154. Preserving Debug Info in LLVM: Automatically 61 • Common transformation APIs will help you to keep / merge debug location underlying
  • 155. Preserving Debug Info in LLVM: Automatically 61 • Common transformation APIs will help you to keep / merge debug location underlying • e.g. Replace All Uses With (RAUW)
  • 156. Preserving Debug Info in LLVM: Automatically 61 • Common transformation APIs will help you to keep / merge debug location underlying • e.g. Replace All Uses With (RAUW) • Handy debug info utilities to make debug info manipulations easier
  • 157. Preserving Debug Info in LLVM: Automatically 61 • Common transformation APIs will help you to keep / merge debug location underlying • e.g. Replace All Uses With (RAUW) • Handy debug info utilities to make debug info manipulations easier • salvageDebugInfo helps you to generate llvm.dbg.value intrinsics
  • 158. Preserving Debug Info in LLVM: Automatically 61 • Common transformation APIs will help you to keep / merge debug location underlying • e.g. Replace All Uses With (RAUW) • Handy debug info utilities to make debug info manipulations easier • salvageDebugInfo helps you to generate llvm.dbg.value intrinsics • Instruction::applyMergedLocation helps you to merge debug locations
  • 160. Summary • We learned how line source locations (e.g. line number) and variable locations are represented in debug info 62
  • 161. Summary • We learned how line source locations (e.g. line number) and variable locations are represented in debug info • We learned how debug info is stored in LLVM IR 62
  • 162. Summary • We learned how line source locations (e.g. line number) and variable locations are represented in debug info • We learned how debug info is stored in LLVM IR • The challenges of debug info in optimized binaries, and how LLVM mitigates those issues 62
  • 163. Contact 63 Email: minyihh@uci.edu GitHub: mshockwave LinkedIn: https://www.linkedin.com/in/bekketmcclane/
  • 166. llvm-dva • LLVM DVA is still in the process of upstreaming to LLVM • RFC: https://discourse.llvm.org/t/llvm-dev-rfc-llvm-dva-debug- information-visual-analyzer/62570 • You can, however, build it with this patch: https://reviews.llvm.org/D88661 • The llvm-dva command I used in this slides: • llvm-dva --attribute=location,format --output-sort=offset — print=symbols,lines,instructions,scopes <object file> 66
  • 167. Debug Info & Object Files 67 #include <greet.h> void hello() {…} #include <greet.h> void bye() {…} foo.c bar.c
  • 168. Debug Info & Object Files 67 foo.o Debug info for: foo.c + greet.h #include <greet.h> void hello() {…} #include <greet.h> void bye() {…} foo.c bar.c
  • 169. Debug Info & Object Files 67 foo.o Debug info for: foo.c + greet.h #include <greet.h> void hello() {…} #include <greet.h> void bye() {…} foo.c bar.c bar.o Debug info for: bar.c + greet.h
  • 170. Splitting (DWARF) Debug Info 68 #include <greet.h> void hello() {…} #include <greet.h> void bye() {…} foo.c bar.c foo.o foo.c.dwo bar.o bar.c.dwo greet.h.dwo
  • 171. Splitting (DWARF) Debug Info 68 #include <greet.h> void hello() {…} #include <greet.h> void bye() {…} foo.c bar.c foo.o foo.c.dwo bar.o bar.c.dwo greet.h.dwo Debug info container
  • 173. Splitting Debug Info • Saving disk spaces • E.g. Able to de-duplicate type information 69
  • 174. Splitting Debug Info • Saving disk spaces • E.g. Able to de-duplicate type information • Attaching debug info fi les (e.g. *.dwo) on release binaries • E.g. When debugging crashes reported by users 69
  • 175. Splitting Debug Info • Saving disk spaces • E.g. Able to de-duplicate type information • Attaching debug info fi les (e.g. *.dwo) on release binaries • E.g. When debugging crashes reported by users • Apple platforms are doing this by default (i.e. *.dSYM folders) 69
  • 176. 70 {Struct} 'Point' {Member} public 'x' -> 'int' {Location} {Entry} offset 0 {Member} public 'y' -> 'int' {Location} {Entry} offset 4 {Function} extern not_inlined 'foo' -> 'int' {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 llvm-dva output DWARF dump
  • 177. 70 0x0000002d: DW_TAG_structure_type DW_AT_name ("Point") … 0x0000003a: DW_TAG_member DW_AT_name ("x") DW_AT_data_member_location (0x00) … 0x00000045: DW_TAG_member DW_AT_name ("y") DW_AT_data_member_location (0x04) … 0x00000058: DW_TAG_subprogram DW_AT_name ("foo") DW_AT_decl_line (3) DW_AT_decl_column (0x05) … 0x00000090: DW_TAG_variable DW_AT_name ("point") DW_AT_decl_line (4) … DW_AT_location (DW_OP_fbreg -24) {Struct} 'Point' {Member} public 'x' -> 'int' {Location} {Entry} offset 0 {Member} public 'y' -> 'int' {Location} {Entry} offset 4 {Function} extern not_inlined 'foo' -> 'int' {Variable} 'point' -> 'Point' {Location} {Entry} fbreg -24 llvm-dva output DWARF dump
  • 178. Validating Debug Info in Optimized Code
  • 179. LLVM Debugify 72 define i32 @add(i32 %0, i32 %1) { %x = add i32 %0, %1 ret i32 %x }
  • 180. LLVM Debugify 72 define i32 @add(i32 %0, i32 %1) { %x = add i32 %0, %1 ret i32 %x } define i32 @add(i32 %0, i32 %1) !dbg !7 { %x = add i32 %0, %1, !dbg, !8 ret i32 %x, !dbg, !9 } !7 = !DISubprogram(name: "add", line: 1,...) !8 = !DILocation(line: 2, ...) !9 = !DILocation(line: 3, ...)
  • 181. LLVM Debugify • Adding arti fi cially-created (fake) debug info metadata to every instructions 72 define i32 @add(i32 %0, i32 %1) { %x = add i32 %0, %1 ret i32 %x } define i32 @add(i32 %0, i32 %1) !dbg !7 { %x = add i32 %0, %1, !dbg, !8 ret i32 %x, !dbg, !9 } !7 = !DISubprogram(name: "add", line: 1,...) !8 = !DILocation(line: 2, ...) !9 = !DILocation(line: 3, ...)
  • 182. LLVM Debugify • Adding arti fi cially-created (fake) debug info metadata to every instructions • Useful to test if a compiler transformation preserves debug info as expected 72 define i32 @add(i32 %0, i32 %1) { %x = add i32 %0, %1 ret i32 %x } define i32 @add(i32 %0, i32 %1) !dbg !7 { %x = add i32 %0, %1, !dbg, !8 ret i32 %x, !dbg, !9 } !7 = !DISubprogram(name: "add", line: 1,...) !8 = !DILocation(line: 2, ...) !9 = !DILocation(line: 3, ...)
  • 183. LLVM Debugify • Adding arti fi cially-created (fake) debug info metadata to every instructions • Useful to test if a compiler transformation preserves debug info as expected • Don’t need a compiler frontend to generate debug info 72 define i32 @add(i32 %0, i32 %1) { %x = add i32 %0, %1 ret i32 %x } define i32 @add(i32 %0, i32 %1) !dbg !7 { %x = add i32 %0, %1, !dbg, !8 ret i32 %x, !dbg, !9 } !7 = !DISubprogram(name: "add", line: 1,...) !8 = !DILocation(line: 2, ...) !9 = !DILocation(line: 3, ...)
  • 184. DExTer: End-to-End Debug Info Tests 73 void bar(int *test) {} int main() { int test; test = 23; bar(&test); // DexLabel('before_bar') return test; // DexLabel('after_bar') } // DexExpectWatchValue('test', '23', on_line=ref('before_bar')) // DexExpectWatchValue('test', '23', on_line=ref('after_bar')) foo.c
  • 185. DExTer: End-to-End Debug Info Tests 73 void bar(int *test) {} int main() { int test; test = 23; bar(&test); // DexLabel('before_bar') return test; // DexLabel('after_bar') } // DexExpectWatchValue('test', '23', on_line=ref('before_bar')) // DexExpectWatchValue('test', '23', on_line=ref('after_bar')) Expectations / Assertions foo.c
  • 186. DExTer: End-to-End Debug Info Tests 73 void bar(int *test) {} int main() { int test; test = 23; bar(&test); // DexLabel('before_bar') return test; // DexLabel('after_bar') } // DexExpectWatchValue('test', '23', on_line=ref('before_bar')) // DexExpectWatchValue('test', '23', on_line=ref('after_bar')) Expectations / Assertions foo.o foo.c Debugger
  • 187. DExTer: End-to-End Debug Info Tests 73 void bar(int *test) {} int main() { int test; test = 23; bar(&test); // DexLabel('before_bar') return test; // DexLabel('after_bar') } // DexExpectWatchValue('test', '23', on_line=ref('before_bar')) // DexExpectWatchValue('test', '23', on_line=ref('after_bar')) Expectations / Assertions foo.o foo.c Debugger DExTer
  • 188. DExTer: End-to-End Debug Info Tests 73 void bar(int *test) {} int main() { int test; test = 23; bar(&test); // DexLabel('before_bar') return test; // DexLabel('after_bar') } // DexExpectWatchValue('test', '23', on_line=ref('before_bar')) // DexExpectWatchValue('test', '23', on_line=ref('after_bar')) Expectations / Assertions foo.o foo.c Debugger DExTer Validation
  • 189. Example: Merging Debug Locations 74 store i32 9, i32* %1 ... store i32 9, i32* %1 ... store i32 9, i32* %1 ...