262 lines
7.7 KiB
Markdown
262 lines
7.7 KiB
Markdown
## Debugging
|
|
|
|
Currently the Kotlin/Native compiler produces debug info compatible with the DWARF 2 specification, so modern debugger tools can
|
|
perform the following operations:
|
|
- breakpoints
|
|
- stepping
|
|
- inspection of type information
|
|
- variable inspection
|
|
|
|
### Producing binaries with debug info with Kotlin/Native compiler
|
|
|
|
To produce binaries with the Kotlin/Native compiler it's sufficient to use the ``-g`` option on the command line.<br/>
|
|
_Example:_
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
0:b-debugger-fixes:minamoto@unit-703(0)# cat - > hello.kt
|
|
fun main(args: Array<String>) {
|
|
println("Hello world")
|
|
println("I need your clothes, your boots and your motocycle")
|
|
}
|
|
0:b-debugger-fixes:minamoto@unit-703(0)# dist/bin/konanc -g hello.kt -o terminator
|
|
KtFile: hello.kt
|
|
0:b-debugger-fixes:minamoto@unit-703(0)# lldb terminator.kexe
|
|
(lldb) target create "terminator.kexe"
|
|
Current executable set to 'terminator.kexe' (x86_64).
|
|
(lldb) b kfun:main(kotlin.Array<kotlin.String>)
|
|
Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = 0x00000001000012e4
|
|
(lldb) r
|
|
Process 28473 launched: '/Users/minamoto/ws/.git-trees/debugger-fixes/terminator.kexe' (x86_64)
|
|
Process 28473 stopped
|
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|
frame #0: 0x00000001000012e4 terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) at hello.kt:2
|
|
1 fun main(args: Array<String>) {
|
|
-> 2 println("Hello world")
|
|
3 println("I need your clothes, your boots and your motocycle")
|
|
4 }
|
|
(lldb) n
|
|
Hello world
|
|
Process 28473 stopped
|
|
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
|
|
frame #0: 0x00000001000012f0 terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) at hello.kt:3
|
|
1 fun main(args: Array<String>) {
|
|
2 println("Hello world")
|
|
-> 3 println("I need your clothes, your boots and your motocycle")
|
|
4 }
|
|
(lldb)
|
|
```
|
|
|
|
</div>
|
|
|
|
### Breakpoints
|
|
Modern debuggers provide several ways to set a breakpoint, see below for a tool-by-tool breakdown:
|
|
|
|
#### lldb
|
|
- by name
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(lldb) b -n kfun:main(kotlin.Array<kotlin.String>)
|
|
Breakpoint 4: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = 0x00000001000012e4
|
|
```
|
|
|
|
</div>
|
|
|
|
_``-n`` is optional, this flag is applied by default_
|
|
- by location (filename, line number)
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(lldb) b -f hello.kt -l 1
|
|
Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = 0x00000001000012e4
|
|
```
|
|
|
|
</div>
|
|
|
|
- by address
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(lldb) b -a 0x00000001000012e4
|
|
Breakpoint 2: address = 0x00000001000012e4
|
|
```
|
|
|
|
</div>
|
|
|
|
- by regex, you might find it useful for debugging generated artifacts, like lambda etc. (where used ``#`` symbol in name).
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
3: regex = 'main\(', locations = 1
|
|
3.1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at hello.kt:2, address = terminator.kexe[0x00000001000012e4], unresolved, hit count = 0
|
|
```
|
|
|
|
</div>
|
|
|
|
#### gdb
|
|
- by regex
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(gdb) rbreak main(
|
|
Breakpoint 1 at 0x1000109b4
|
|
struct ktype:kotlin.Unit &kfun:main(kotlin.Array<kotlin.String>);
|
|
```
|
|
|
|
</div>
|
|
|
|
- by name __unusable__, because ``:`` is a separator for the breakpoint by location
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(gdb) b kfun:main(kotlin.Array<kotlin.String>)
|
|
No source file named kfun.
|
|
Make breakpoint pending on future shared library load? (y or [n]) y
|
|
Breakpoint 1 (kfun:main(kotlin.Array<kotlin.String>)) pending
|
|
```
|
|
|
|
</div>
|
|
|
|
- by location
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(gdb) b hello.kt:1
|
|
Breakpoint 2 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 1.
|
|
```
|
|
|
|
</div>
|
|
|
|
- by address
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
(gdb) b *0x100001704
|
|
Note: breakpoint 2 also set at pc 0x100001704.
|
|
Breakpoint 3 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 2.
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
### Stepping
|
|
Stepping functions works mostly the same way as for C/C++ programs
|
|
|
|
### Variable inspection
|
|
|
|
Variable inspections for var variables works out of the box for primitive types.
|
|
For non-primitive types there are custom pretty printers for lldb in
|
|
`konan_lldb.py`:
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
λ cat main.kt | nl
|
|
1 fun main(args: Array<String>) {
|
|
2 var x = 1
|
|
3 var y = 2
|
|
4 var p = Point(x, y)
|
|
5 println("p = $p")
|
|
6 }
|
|
|
|
7 data class Point(val x: Int, val y: Int)
|
|
|
|
λ lldb ./program.kexe -o 'b main.kt:5' -o
|
|
(lldb) target create "./program.kexe"
|
|
Current executable set to './program.kexe' (x86_64).
|
|
(lldb) b main.kt:5
|
|
Breakpoint 1: where = program.kexe`kfun:main(kotlin.Array<kotlin.String>) + 289 at main.kt:5, address = 0x000000000040af11
|
|
(lldb) r
|
|
Process 4985 stopped
|
|
* thread #1, name = 'program.kexe', stop reason = breakpoint 1.1
|
|
frame #0: program.kexe`kfun:main(kotlin.Array<kotlin.String>) at main.kt:5
|
|
2 var x = 1
|
|
3 var y = 2
|
|
4 var p = Point(x, y)
|
|
-> 5 println("p = $p")
|
|
6 }
|
|
7
|
|
8 data class Point(val x: Int, val y: Int)
|
|
|
|
Process 4985 launched: './program.kexe' (x86_64)
|
|
(lldb) fr var
|
|
(int) x = 1
|
|
(int) y = 2
|
|
(ObjHeader *) p = 0x00000000007643d8
|
|
(lldb) command script import dist/tools/konan_lldb.py
|
|
(lldb) fr var
|
|
(int) x = 1
|
|
(int) y = 2
|
|
(ObjHeader *) p = Point(x=1, y=2)
|
|
(lldb) p p
|
|
(ObjHeader *) $2 = Point(x=1, y=2)
|
|
(lldb)
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
Getting representation of the object variable (var) could also be done using the
|
|
built-in runtime function `Konan_DebugPrint` (this approach also works for gdb,
|
|
using a module of command syntax):
|
|
|
|
<div class="sample" markdown="1" theme="idea" mode="shell">
|
|
|
|
```bash
|
|
0:b-debugger-fixes:minamoto@unit-703(0)# cat ../debugger-plugin/1.kt | nl -p
|
|
1 fun foo(a:String, b:Int) = a + b
|
|
2 fun one() = 1
|
|
3 fun main(arg:Array<String>) {
|
|
4 var a_variable = foo("(a_variable) one is ", 1)
|
|
5 var b_variable = foo("(b_variable) two is ", 2)
|
|
6 var c_variable = foo("(c_variable) two is ", 3)
|
|
7 var d_variable = foo("(d_variable) two is ", 4)
|
|
8 println(a_variable)
|
|
9 println(b_variable)
|
|
10 println(c_variable)
|
|
11 println(d_variable)
|
|
12 }
|
|
0:b-debugger-fixes:minamoto@unit-703(0)# lldb ./program.kexe -o 'b -f 1.kt -l 9' -o r
|
|
(lldb) target create "./program.kexe"
|
|
Current executable set to './program.kexe' (x86_64).
|
|
(lldb) b -f 1.kt -l 9
|
|
Breakpoint 1: where = program.kexe`kfun:main(kotlin.Array<kotlin.String>) + 463 at 1.kt:9, address = 0x0000000100000dbf
|
|
(lldb) r
|
|
(a_variable) one is 1
|
|
Process 80496 stopped
|
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
|
frame #0: 0x0000000100000dbf program.kexe`kfun:main(kotlin.Array<kotlin.String>) at 1.kt:9
|
|
6 var c_variable = foo("(c_variable) two is ", 3)
|
|
7 var d_variable = foo("(d_variable) two is ", 4)
|
|
8 println(a_variable)
|
|
-> 9 println(b_variable)
|
|
10 println(c_variable)
|
|
11 println(d_variable)
|
|
12 }
|
|
|
|
Process 80496 launched: './program.kexe' (x86_64)
|
|
(lldb) expression -- Konan_DebugPrint(a_variable)
|
|
(a_variable) one is 1(KInt) $0 = 0
|
|
(lldb)
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
### Known issues
|
|
- performance of Python bindings.
|
|
|
|
_Note:_ Supporting the DWARF 2 specification means that the debugger tool recognizes Kotlin as C89, because before the DWARF 5 specification, there is no identifier for the Kotlin language type in specification.
|
|
|