Short example of degugging with LLDB.
As an example, I will use a small program that I wrote for Rosetta Code:
const std = @import("std");
const stdout = @import("std").io.getStdOut().writer();
pub fn rot(txt: []u8, key: u8) void {
for (txt, 0..txt.len) |c, i| {
if (std.ascii.isLower(c)) {
txt[i] = (c - 'a' + key) % 26 + 'a';
} else if (std.ascii.isUpper(c)) {
txt[i] = (c - 'A' + key) % 26 + 'A';
}
}
}
pub fn main() !void {
const key = 3;
var txt = "The five boxing wizards jump quickly".*;
try stdout.print("Original: {s}\n", .{txt});
rot(&txt, key);
try stdout.print("Encrypted: {s}\n", .{txt});
rot(&txt, 26 - key);
try stdout.print("Decrypted: {s}\n", .{txt});
}
Now let’s compile:
zig build-exe caesar.zig
Start debugging:
lldb caesar
(lldb) target create "caesar"
Current executable set to '/home/chris/workspace/zig/rosetta/caesar' (x86_64).
(lldb) █
Now we set a breakpoint at main function:
(lldb) b main
Breakpoint 1: where = caesar`caesar.main + 18 at caesar.zig:16:5, address = 0x0000000001033c22
(lldb) █
And then run the program:
(lldb) r
Process 24175 launched: '/home/chris/workspace/zig/chris/usb/caesar' (x86_64)
Process 24175 stopped
* thread #1, name = 'caesar', stop reason = breakpoint 1.1
frame #0: 0x0000000001033c22 caesar`caesar.main at caesar.zig:16:5
13
14 pub fn main() !void {
15 const key = 3;
-> 16 var txt = "The five boxing wizards jump quickly".*;
17
18 try stdout.print("Original: {s}\n", .{txt});
19 rot(&txt, key);
(lldb) █
We can step forward with next:
(lldb) n
Process 24175 stopped
* thread #1, name = 'caesar', stop reason = step over
frame #0: 0x0000000001033c43 caesar`caesar.main at caesar.zig:18:21
15 const key = 3;
16 var txt = "The five boxing wizards jump quickly".*;
17
-> 18 try stdout.print("Original: {s}\n", .{txt});
19 rot(&txt, key);
20 try stdout.print("Encrypted: {s}\n", .{txt});
21 rot(&txt, 26 - key);
(lldb) █
And so on. A very nice feature is switching to GUI mode:
(lldb) gui
| LLDB (F1) | Target (F2) | Process (F3) | Thread (F4) | View (F5) | Help (F6) |
┌──<Sources>──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐┌──<Threads>───────────────────────────────────────────────────┐
│ caesar`caesar.main ││ ◆─process 24175 │
│ 1 │ const std = @import("std"); ││ └─◆─thread #1: tid = 0x5e6f, stop reason = step over │
│ 2 │ const stdout = @import("std").io.getStdOut().writer(); ││ ├─#0: caesar.main + 51 │
│ 3 │ ││ ├─#1: start.posixCallMainAndExit [inlined] start.callMain +│
│ 4 │ pub fn rot(txt: []u8, key: u8) void { ││ ├─#2: start.posixCallMainAndExit + 93 │
│ 5 │ for (txt, 0..txt.len) |c, i| { ││ ├─#3: start.posixCallMainAndExit + 1133 │
│ 6 │ if (std.ascii.isLower(c)) { ││ └─#4: start._start + 18 │
│ 7 │ txt[i] = (c - 'a' + key) % 26 + 'a'; ││ │
│ 8 │ } else if (std.ascii.isUpper(c)) { ││ │
│ 9 │ txt[i] = (c - 'A' + key) % 26 + 'A'; ││ │
│ 10 │ } ││ │
│ 11 │ } ││ │
│ 12 │ } ││ │
│ 13 │ ││ │
│ 14 │ pub fn main() !void { ││ │
│ 15 │ const key = 3; ││ │
│ 16 │ var txt = "The five boxing wizards jump quickly".*; ││ │
│ 17 │ ││ │
│ 18 │◆ try stdout.print("Original: {s}\n", .{txt}); <<< Thread 1: step over││ │
│ 19 │ rot(&txt, key); ││ │
│ 20 │ try stdout.print("Encrypted: {s}\n", .{txt}); ││ │
│ 21 │ rot(&txt, 26 - key); ││ │
│ 22 │ try stdout.print("Decrypted: {s}\n", .{txt}); ││ │
│ 23 │ } ││ │
│ 24 │ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘│ │
┌──<Variables>────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│ │
│ ◆─(unsigned char[36]) txt "The five boxing wizards jump quickly" ││ │
│ ◆─(elf.Elf64_Dyn) _DYNAMIC ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────────┘
Process: 24175 stopped Thread: 24175 Frame: 0 PC = 0x0000000001033c43
You can set breakpoints there by navigating to a line and pressing ‘b’. To exit the GUI, press Esc.
The other commands can be found in the help.