SlideShare a Scribd company logo
1 of 189
Download to read offline
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


...

More Related Content

What's hot

Understanding DPDK algorithmics
Understanding DPDK algorithmicsUnderstanding DPDK algorithmics
Understanding DPDK algorithmicsDenys Haryachyy
 
Intel DPDK Step by Step instructions
Intel DPDK Step by Step instructionsIntel DPDK Step by Step instructions
Intel DPDK Step by Step instructionsHisaki Ohara
 
Profiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf ToolsProfiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf ToolsemBO_Conference
 
CETH for XDP [Linux Meetup Santa Clara | July 2016]
CETH for XDP [Linux Meetup Santa Clara | July 2016] CETH for XDP [Linux Meetup Santa Clara | July 2016]
CETH for XDP [Linux Meetup Santa Clara | July 2016] IO Visor Project
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend PortingShiva Chen
 
How shit works: the CPU
How shit works: the CPUHow shit works: the CPU
How shit works: the CPUTomer Gabel
 
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling ToolsTIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling ToolsXiaozhe Wang
 
Kernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven Rostedt
Kernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven RostedtKernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven Rostedt
Kernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven RostedtAnne Nicolas
 
Reverse Mapping (rmap) in Linux Kernel
Reverse Mapping (rmap) in Linux KernelReverse Mapping (rmap) in Linux Kernel
Reverse Mapping (rmap) in Linux KernelAdrian Huang
 
Linux kernel debugging
Linux kernel debuggingLinux kernel debugging
Linux kernel debuggingHao-Ran Liu
 
from Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu Worksfrom Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu WorksZhen Wei
 
Kernel_Crash_Dump_Analysis
Kernel_Crash_Dump_AnalysisKernel_Crash_Dump_Analysis
Kernel_Crash_Dump_AnalysisBuland Singh
 
DPDK & Layer 4 Packet Processing
DPDK & Layer 4 Packet ProcessingDPDK & Layer 4 Packet Processing
DPDK & Layer 4 Packet ProcessingMichelle Holley
 

What's hot (20)

Dpdk applications
Dpdk applicationsDpdk applications
Dpdk applications
 
Understanding DPDK algorithmics
Understanding DPDK algorithmicsUnderstanding DPDK algorithmics
Understanding DPDK algorithmics
 
Intel DPDK Step by Step instructions
Intel DPDK Step by Step instructionsIntel DPDK Step by Step instructions
Intel DPDK Step by Step instructions
 
Profiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf ToolsProfiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf Tools
 
CETH for XDP [Linux Meetup Santa Clara | July 2016]
CETH for XDP [Linux Meetup Santa Clara | July 2016] CETH for XDP [Linux Meetup Santa Clara | July 2016]
CETH for XDP [Linux Meetup Santa Clara | July 2016]
 
Qemu JIT Code Generator and System Emulation
Qemu JIT Code Generator and System EmulationQemu JIT Code Generator and System Emulation
Qemu JIT Code Generator and System Emulation
 
Making Linux do Hard Real-time
Making Linux do Hard Real-timeMaking Linux do Hard Real-time
Making Linux do Hard Real-time
 
How A Compiler Works: GNU Toolchain
How A Compiler Works: GNU ToolchainHow A Compiler Works: GNU Toolchain
How A Compiler Works: GNU Toolchain
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend Porting
 
How shit works: the CPU
How shit works: the CPUHow shit works: the CPU
How shit works: the CPU
 
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling ToolsTIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
 
Kernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven Rostedt
Kernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven RostedtKernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven Rostedt
Kernel Recipes 2017 - Understanding the Linux kernel via ftrace - Steven Rostedt
 
Memory model
Memory modelMemory model
Memory model
 
Ixgbe internals
Ixgbe internalsIxgbe internals
Ixgbe internals
 
Reverse Mapping (rmap) in Linux Kernel
Reverse Mapping (rmap) in Linux KernelReverse Mapping (rmap) in Linux Kernel
Reverse Mapping (rmap) in Linux Kernel
 
Linux kernel debugging
Linux kernel debuggingLinux kernel debugging
Linux kernel debugging
 
Build Programming Language Runtime with LLVM
Build Programming Language Runtime with LLVMBuild Programming Language Runtime with LLVM
Build Programming Language Runtime with LLVM
 
from Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu Worksfrom Binary to Binary: How Qemu Works
from Binary to Binary: How Qemu Works
 
Kernel_Crash_Dump_Analysis
Kernel_Crash_Dump_AnalysisKernel_Crash_Dump_Analysis
Kernel_Crash_Dump_Analysis
 
DPDK & Layer 4 Packet Processing
DPDK & Layer 4 Packet ProcessingDPDK & Layer 4 Packet Processing
DPDK & Layer 4 Packet Processing
 

Similar to Debug Information And Where They Come From

lldb – Debugger auf Abwegen
lldb – Debugger auf Abwegenlldb – Debugger auf Abwegen
lldb – Debugger auf Abwegeninovex 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' MistakesAndrey Karpov
 
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019corehard_by
 
Anomalies in X-Ray Engine
Anomalies in X-Ray EngineAnomalies in X-Ray Engine
Anomalies in X-Ray EnginePVS-Studio
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...DevGAMM Conference
 
JVM code reading -- C2
JVM code reading -- C2JVM code reading -- C2
JVM code reading -- C2ytoshima
 
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 2PVS-Studio
 
Score (smart contract for icon)
Score (smart contract for icon) Score (smart contract for icon)
Score (smart contract for icon) Doyun Hwang
 
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 MicrocosmAndrey 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-upMark Price
 
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 systemsAndrey Karpov
 
Introduction to AspectJ
Introduction to AspectJIntroduction to AspectJ
Introduction to AspectJmukhtarhudaya
 
Analysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsAnalysis of Microsoft Code Contracts
Analysis of Microsoft Code ContractsPVS-Studio
 
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 JobyGrejoJoby1
 

Similar to 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
 

More from 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 BlocksMin-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 LLVMMin-Yih Hsu
 
How to write a TableGen backend
How to write a TableGen backendHow to write a TableGen backend
How to write a TableGen backendMin-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 UglyMin-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 FlowMin-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 alMin-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 InfoMin-Yih Hsu
 
From V8 to Modern Compilers
From V8 to Modern CompilersFrom V8 to Modern Compilers
From V8 to Modern CompilersMin-Yih Hsu
 
Introduction to Khronos SYCL
Introduction to Khronos SYCLIntroduction to Khronos SYCL
Introduction to Khronos SYCLMin-Yih Hsu
 
Trace Scheduling
Trace SchedulingTrace Scheduling
Trace SchedulingMin-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 AOSPMin-Yih Hsu
 

More from 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
 

Recently uploaded

WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
WSO2CON 2024 - Software Engineering for Digital Businesses
WSO2CON 2024 - Software Engineering for Digital BusinessesWSO2CON 2024 - Software Engineering for Digital Businesses
WSO2CON 2024 - Software Engineering for Digital BusinessesWSO2
 
WSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid EnvironmentsWSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid EnvironmentsWSO2
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2
 
Evolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI EraEvolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI Eraconfluent
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2
 
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...WSO2
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2
 
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfAzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfryanfarris8
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2
 
WSO2Con2024 - Low-Code Integration Tooling
WSO2Con2024 - Low-Code Integration ToolingWSO2Con2024 - Low-Code Integration Tooling
WSO2Con2024 - Low-Code Integration ToolingWSO2
 
WSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - KanchanaWSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - KanchanaWSO2
 
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...WSO2
 
Novo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMsNovo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMsNeo4j
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2
 

Recently uploaded (20)

WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
WSO2CON 2024 - Software Engineering for Digital Businesses
WSO2CON 2024 - Software Engineering for Digital BusinessesWSO2CON 2024 - Software Engineering for Digital Businesses
WSO2CON 2024 - Software Engineering for Digital Businesses
 
WSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid EnvironmentsWSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid Environments
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
Evolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI EraEvolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI Era
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfAzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
WSO2Con2024 - Low-Code Integration Tooling
WSO2Con2024 - Low-Code Integration ToolingWSO2Con2024 - Low-Code Integration Tooling
WSO2Con2024 - Low-Code Integration Tooling
 
WSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - KanchanaWSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - Kanchana
 
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
Novo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMsNovo Nordisk: When Knowledge Graphs meet LLMs
Novo Nordisk: When Knowledge Graphs meet LLMs
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 

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 ...