How to select different frame in lldb? - lldb

How can I make frame select actually make the frame stay selected, instead of popping back to frame 0?
Here's the output explaining the problem:
(lldb) frame select 6
frame #6: 0x06b35dc9 Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 40
Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 40:
-> 0x6b35dc9: addl $24, %esp
0x6b35dcc: popl %ebp
0x6b35dcd: ret
0x6b35dce: nop
(lldb) frame info
frame #0: 0x00c64123 Facebook`-[APHCurrentSession updateMessage:] + 1347 at APHCurrentSession.m:102

This is a known bug with Xcode and lldb. Changing the selected thread and selected frame in the Debugger console window is lost immediately. Or more accurately, lldb does not broadcast this state change to Xcode and Xcode, between commands, resets the debugger state to a known setup. Unfortunately, until this is fixed you will need to do frame/thread changes using the GUI so Xcode can update the selected thread/frame.

Related

Macbook M1 assembly lldb displays only 3 source lines then switches to object code display

First attempt at ARM64 (apple M1) assembly coding. Have basic 'hello world' code which assembles and runs correctly but when I run it in lldb, only the first three lines are displayed in full source code format like this:
Abenaki:hello jiml$ ~/llvm/clang+llvm-15.0.2-arm64-apple-darwin21.0/bin/lldb hello
(lldb) target create "hello"
Current executable set to '/Users/jiml/Projects/GitRepos/ARM/hello/hello/hello/hello' (arm64).
(lldb) b main
Breakpoint 1: where = hello`main + 4, address = 0x0000000100003f7c
(lldb) r
Process 5017 launched: '/Users/jiml/Projects/GitRepos/ARM/hello/hello/hello/hello' (arm64)
Process 5017 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100003f7c hello`main at hello.s:19
16
17 _main:
18 mov x0, #0x0 // stdout
-> 19 adrp x1, msg#PAGE // pointer to string
20 add x1, x1, msg#PAGEOFF
21 ldr x2, =msg_len // bytes to output
22 mov x16, #0x04 // sys_write
warning: This version of LLDB has no plugin for the language "assembler". Inspection of frame variables will be limited.
(lldb)
After three steps, the display reverts to bare object code like this:
(lldb) s
Process 5017 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100003f88 hello`main + 16
hello`main:
-> 0x100003f88 <+16>: mov x16, #0x4
0x100003f8c <+20>: svc #0x80
0x100003f90 <+24>: adrp x1, 1
0x100003f94 <+28>: mov x2, #0x0
dwarfdump -a shows that all source lines are present in the .o; same behavior for .dSYM assembly. Using the 'list' command in lldb however displays all source lines correctly.
Is this a known issue for LLVM (clang, lldb) development? Any help appreciated...
I have tried LLVM version 14 and 15, same behavior, searched for similar issues but no help.
I did find this https://stackoverflow.com/questions/73778648/why-is-it-that-assembling-linking-in-one-step-loses-debug-info-for-my-assembly-s but it did not solve my issue.
So I think I have this resolved but not sure if it is actual compiler bug.
I wrote hello world in C, compiled and confirmed complete source display in lldb. I then reran clang with -S to generate the assembler source.
I then assembled that source...
clang -g -c -o hello.o hello.s
clang -o hello hello.o -lSystem -arch arm64
and confirmed it also runs in lldb with complete source display. Then I moved my hand written code line-by-line in order to figure out where the problem occurs. Seems my string data and length calculation is problematic. In the data section I originally had:
msg: ascii "Hello ARM64\n"
msg_len = . - msg
Coming from Intel world this seems perfectly natural ;-) Adding that length calculation caused some sort of corruption of the debug data. However, the executable has a proper OSO statement pointing at hello.o (nm -ap hello) and further the object file has references for all source statements in the source file (dwarfdump --debug-line hello.o) but still doesn't display source code after the third step. Curious that 'source info -f hello.s' within lldb only listed four lines.
I found three work-arounds. First adding a label between the two statements seems to allow correct behavior:
msg: ascii "Hello ARM64\n"
nothing:
msg_len = . - msg
Second, using equate:
msg: ascii "Hello ARM64\n"
.equ msg_len, . - msg
Third, using two labels:
msg: ascii "Hello ARM64\n"
msg_end:
msg_len = msg_end - msg
Will file report with llvm and see what they say.

Linux Kernel function memblock_alloc_range_nid is not presented in the address space

I'm trying to debug physical memory allocation to understand what part of the Linux Kernel use memblock_alloc_range_nid on x86-64 and how.
I'm running the latest Linux Kernel 5.19-rc2 built from upstream with Ubuntu 20.04 inside QEMU. The problem is it's not possible to access memory address the function memblock_alloc_range_nid is located at. While other Kernel functions can be easily disassembled.
Here is what I have in my gdb connected to the QEMU VM:
(gdb) disas memblock_alloc_range_nid
Cannot access memory at address 0xffffffff831a05d1
(gdb) disas native_safe_halt
Dump of assembler code for function native_safe_halt:
#...
End of assembler dump.
What's wrong with the function memblock_alloc_range_nid? Why is it not possible to access its address? It seems all the function from memblock.c cannot be accessed.
As Margaret and Roi have noted in the above comments, memblock_alloc_range_nid() is annotated with __init. Functions annotated with __init, __head and similar macros are only needed during kernel initialization right after boot. After the kernel has finished initializing things, the special memory section containing all those functions is unmapped from memory since they are not needed anymore.
If you want to debug any such function, you will have to break very early, for example at start_kernel(), then you can inspect the function or set a breakpoint and continue execution to hit it.
Important: add -S (uppercase) to your QEMU command line options to make it stop and wait for the debugger before starting the kernel, and start the kernel with KASLR disabled using -append "nokaslr" (or adding nokaslr if you are already specifying -append).
The following GDB script should be what you need:
$ cat script.gdb
directory /path/to/kernel-source-dir
file /path/to/kernel-source-dir/vmlinux
target remote localhost:1234
break start_kernel
continue
Launch gdb -x script.gdb (after starting QEMU), and when you hit the start_kernel breakpoint, you can add another one for memblock_alloc_range_nid, then continue:
0x000000000000fff0 in exception_stacks ()
Breakpoint 1 at 0xffffffff82fbab4c
Breakpoint 1, 0xffffffff82fbab4c in start_kernel ()
(gdb) b memblock_alloc_range_nid
Breakpoint 2 at 0xffffffff82fe2879
(gdb) c
Continuing.
Breakpoint 2, 0xffffffff82fe2879 in memblock_alloc_range_nid ()
(gdb) disassemble
Dump of assembler code for function memblock_alloc_range_nid:
=> 0xffffffff82fe2879 <+0>: push r15
0xffffffff82fe287b <+2>: mov r15,rcx
0xffffffff82fe287e <+5>: push r14
0xffffffff82fe2880 <+7>: mov r14,rdx
0xffffffff82fe2883 <+10>: push r13
0xffffffff82fe2885 <+12>: mov r13d,r9
...

printing stack with variable names with gdb?

I was just reading this article.
In the article, the author uses gdb to look around in a c executable.
At one point, when a breakpoint is hit, the author says to have a look at the stack, and shows this output:
STACK:
0x00007fffffffdf40│+0x0000: 0x00007fffffffe058 → 0x00007fffffffe380
0x00007fffffffdf48│+0x0008: 0x0000000100401050
0x00007fffffffdf50│+0x0010: 0x00007fffffffe050 → 0x0000000000000001
0x00007fffffffdf58│+0x0018: 0x0000000000402004 → “p#ssw0rD”
0x00007fffffffdf60│+0x0020: 0x0000000000000000 ← $rbp
0x00007fffffffdf68│+0x0028: 0x00007ffff7ded0b3 → <__libc_start_main+243> mov edi, eax
0x00007fffffffdf70│+0x0030: 0x00007ffff7ffc620 → 0x0005043700000000
0x00007fffffffdf78│+0x0038: 0x00007fffffffe058 → 0x00007fffffffe380 →
This is nice, but how do I generate this output in gdb?
I've been googling for a while with no luck
Also, in this output there is two different columns of hex adresses, I'm guessing one points to the stack, what is the other one? and which is which?
The author doesn't state it explicitly, but in their gdb output you can see the prompt gef>. This indicates they are likely making use of the gef addon for gdb.
I have never used this addon myself, but you can see in some of the example output on the gef site that the addon has a stack view identical to the output you gave above.
The gef addon makes use of gdb's Python API to provide additional features for gdb, one of which appears to be the alternative stack view.

Is there an equivalent of dds on lldb

I am trying to debug an issue on OSX and lldb is getting in my way. I think my program has a corrupted stack, and I would like to be able to manually walk the stack.
In WinDBG, there is a command called dds that I can use to dump all the pointers on the stack (basically, walking from rsp, walking towards higher addresses) and resolve all pointers to symbols (and print nothing if it does not correspond to code), I am looking for a similar command on lldb. I know I could memory read --format x manually one by one and then look them up using image lookup, but that would be too time consuming.
There isn't a built-in command to do the walk itself, so you will have to page through the memory up from rsp by hand.
But you might find the "A" format helpful for this task. That will print the memory as a list of address-sized words, and for any values that point into TEXT or DATA it will print the symbol's name. Like:
(lldb) mem read -fA `$rsp - 16 * 8` `$rsp` -fA
0x7ffeefbff660: 0x0000000000000000
0x7ffeefbff668: 0x00007ffeefbff660
0x7ffeefbff670: 0x0000003002000000
0x7ffeefbff678: 0x00007fff6e2ee568 libsystem_platform.dylib`__platform_sigaction + 103
0x7ffeefbff680: 0x0000000000000000
0x7ffeefbff688: 0x0000000000000000
0x7ffeefbff690: 0x0000000000013dc9
0x7ffeefbff698: 0x0000000000000000
0x7ffeefbff6a0: 0x00007fff6e238fe2 libsystem_kernel.dylib`__sigaction + 10
0x7ffeefbff6a8: 0x0000000000000000
0x7ffeefbff6b0: 0x000000000000001e
0x7ffeefbff6b8: 0x0000000000013dc9
0x7ffeefbff6c0: 0x00007ffeefbff700
0x7ffeefbff6c8: 0x0000000100002020 _dyld_private
0x7ffeefbff6d0: 0x000000000000000e
0x7ffeefbff6d8: 0x0000000100000f45 signals`main + 53 at signals.c:13:3

Debug Break on Win32 Api functions

I would like to have a break on the SetTimer function in order to see which components register what timers with what values. Is this possible?
Yes, you can do this. First make sure you have public symbols setup for your debugger.
SetTimer lives in user32 but that is just what it is exported as. The easiest way to do this is with the command line debugger, NTSD. We need its real name, so look for symbols in user32 that match:
0:000> x user32!*timer*
759992b9 USER32!NtUserValidateTimerCallback = <no type information>
759977d5 USER32!NtUserSetTimer = <no type information>
759e4f13 USER32!NtUserSetSystemTimer = <no type information>
759993bf USER32!NtUserKillTimer = <no type information>
Ah-ha! Its debug symbol is NtUserSetTimer:
0:000> bp user32!NtUserSetTimer
In Visual Studio, you can figure out where SetTimer lives by writting a simple scratch program and then setting a breakpoint and right clicking and selecting "Go to Disassembly":
int _tmain(int argc, _TCHAR* argv[]) {
SetTimer(NULL, 0, 0, NULL);
004113BE mov esi,esp
004113C0 push 0
004113C2 push 0
004113C4 push 0
004113C6 push 0
004113C8 call dword ptr [__imp__SetTimer#16 (418338h)]
If we step into that call, then we land here:
_NtUserSetTimer#16:
759977D5 mov eax,123Dh
759977DA mov edx,7FFE0300h
759977DF call dword ptr [edx]
759977E1 ret 10h
So the to set a breakpoint there in Visual Studio, you have to use the context operator in the breakpoint. Select from the menus: Debug -> New Breakpoint -> Break at Function, then enter:
{,,user32.dll}_NtUserSetTimer#16
Here's a walkthrough, with screenshots, for VS2005. Note that for VS2008+ you don't need to input decorated function names (perhaps that's the reason the previous description didn't work out directly? What's your platform/IDE ?).
[Edit:] You definitely need public MS symbols to be able to locate Win32 API in binaries. The shortest route there is go to Tools/Options/Debugging/Symbols, then paste 'http://msdl.microsoft.com/download/symbols' into 'pdb locations'. It is highly recommended - but not necessary - to set a local cache for downloaded pdb's (first pdb loads can be a few minutes), and for your needs you should probably uncheck 'Search the above locations only when symbols are loaded manually'. There'd be some startup delay as all symbols are loaded, but you won't have to chase down user32.dll (or whatever dll holds the function you wish to break at) and load its pdb manually.

Resources