LLDB is a high-performance CLI debugger, commonly used as an alternative to GDB. LLDB is maintained by Apple and it's an awesome debugger full of functionalities. And today we will go on through some of them.
The first thing we need to do after installing lldb is to
run it (yeah, you definitely need to run it in order to use it).
So, you can simply run lldb by typing lldb
on you terminal prompt.
It should appear a prompt like
(lldb) #
But it's normally better to initialize the debugger with
the binary you want to debug it. In order to do so, you need to
simply type lldb a.out
, or lldb -- a.out x
if you
want to run the binary with the argument x
. It should return someting
like
(lldb) target create "a.out"
Current executable set to '/Users/lups/tests/a.out' (arm64).
(lldb)
Now that we have our binary loaded, we can now run it.
(lldb) r
In order to show the next examples, I'll be using an exemplary C code, i.e
#include <stdio.h>
int addNums(int x, int y);
int main(){
int a;
int b = 15;
scanf("%d", &a);
printf("scanned: %d\n", a);
printf("sum of a + b: %d\n", addNums(a, b));
return 0;
}
int addNums(int x, int y) {
return x + y;
}
In order to add the debugger information to the binary, we must compile it with
clang -g inp.c
So, let's first start lldb and run the binary.
➜ tests lldb a.out
(lldb) target create "a.out"
Current executable set to '/Users/lups/tests/a.out' (arm64).
(lldb) r
Process 1364 launched: '/Users/lups/tests/a.out' (arm64)
5
scanned: 5
sum of a + b: 20
Process 1364 exited with status = 0 (0x00000000)
So, I've ran the binary and he asked for an input, I inputted it and it ran normally. Let's talk about setting breakpoints.
let's set a break point on line 7, in order to do so, we must run:
b 5
or
b inp.c:7
(lldb) b 5
Breakpoint 2: where = a.out`main + 28 at inp.c:7:6, address = 0x0000000100003ee4
(lldb) b inp.c:7 # yea, you must insert name of src file.
Breakpoint 1: where = a.out`main + 28 at inp.c:7:6, address = 0x0000000100003ee4
We can also set a breakpoint under a function, for example, let's set for main
.
(lldb) b main
Breakpoint 2: where = a.out`main + 28 at inp.c:7:6, address = 0x0000000100003ee4
We can manage the breakpoints we created. Let's first see them (lldb) b # notice you can also use "br list" Current breakpoints:
1: file = 'inp.c', line = 7, exact_match = 0, locations = 1
1.1: where = a.out`main + 28 at inp.c:7:6, address = a.out[0x0000000100003ee4], unresolved, hit count = 0
2: name = 'main', locations = 1
2.1: where = a.out`main + 28 at inp.c:7:6, address = a.out[0x0000000100003ee4], unresolved, hit count = 0
if we want to delete breakpoint number 1, we can do
(lldb) br del 1
1 breakpoints deleted; 0 breakpoint locations disabled.
if we want to delete all breakpoints, we can run
(lldb) br del
About to delete all breakpoints, do you want to do that?: [Y/n] y
All breakpoints removed. (1 breakpoint)
So, let's set a breakpoint and stop on it.
(lldb) b 8
Breakpoint 4: where = a.out`main + 40 at inp.c:8:2, address = 0x0000000100003ef0
(lldb) run
Process 1960 launched: '/Users/lups/tests/a.out' (arm64)
Process 1960 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
frame #0: 0x0000000100003ef0 a.out`main at inp.c:8:2
5 int main(){
6 int a;
7 int b = 15;
-> 8 scanf("%d", &a);
9 printf("scanned: %d\n", a);
10 printf("sum of a + b: %d\n", addNums(a, b));
11 return 0;
Target 0: (a.out) stopped.
So, we stopped right into the scanf
function. Let's manage variables a
and b
.
we can print their values by running
(lldb) p a
(int) $0 = 753760
(lldb) p b
(int) $1 = 15
We can see a
has no initial value setted by us, and b
has the value of 15. If we want to see everything we need to know about all the variables, we can run
(lldb) frame variable
(int) a = 753760
(int) b = 15
Let's change b
value to 20.
(lldb) expr b = 20
(int) $2 = 20
(lldb) p b
(int) $3 = 20
Now, let's run the next line of the binary using n
(lldb) n
5
Process 2010 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100003f00 a.out`main at inp.c:9:26
6 int a;
7 int b = 15;
8 scanf("%d", &a);
-> 9 printf("scanned: %d\n", a);
10 printf("sum of a + b: %d\n", addNums(a, b));
11 return 0;
12 }
Target 0: (a.out) stopped.
We can check which line we are by typing
(lldb) f
frame #0: 0x0000000100003f00 a.out`main at inp.c:9:26
6 int a;
7 int b = 15;
8 scanf("%d", &a);
-> 9 printf("scanned: %d\n", a);
10 printf("sum of a + b: %d\n", addNums(a, b));
11 return 0;
12 }
So, I moved onto the next line and it asked for me to insert a value for a
, so I inserted 5. Let's now print a
, and them conclude the binary.
(lldb) p a
(int) $4 = 5
We can continue the binary using c
(lldb) c
Process 2010 resuming
scanned: 5
sum of a + b: 25
Process 2010 exited with status = 0 (0x00000000)
As you could see, a
is now equal to 5 and b
equal to 20.
If you think your program died into some internal function, you can check it by running bt
(backtrace).
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
* frame #0: 0x0000000100003f00 a.out`main at inp.c:9:26
frame #1: 0x00000001000110f4 dyld`start + 520
I hope you liked the paper and could learn about debugging with LLDB. If you found any error here on this paper or you have any doubt/comment to make, feel free to contact me at: [email protected]