Skip to content

Commit 74d908b

Browse files
committed
lldb fu
1 parent 942995b commit 74d908b

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

docs/lldb-fun.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Adding symbols to LLDB
22

3+
## Overview
4+
35
See relevant issues:
46
+ https://github.com/pwndbg/pwndbg/issues/3595
57
+ https://github.com/llvm/llvm-project/issues/179839
@@ -15,3 +17,64 @@ It isn't really clear to me what the differences and implications of the first t
1517
So, I'm going to try to figure out the LLDB issue.
1618

1719
For debugging program headers, `readelf -l binary` is useful.
20+
21+
## Getting a "proper" symbol file
22+
Get an actual minimal working symbols file for LLDB like this:
23+
```bash
24+
gcc thing.c -o thing
25+
strip --only-keep-debug thing -o thing.bloatedsyms
26+
strip thing -o thing.nosyms
27+
objcopy --remove-section=.note.gnu.property --remove-section=.note.gnu.build-id --remove-section=.interp --remove-section=.gnu.hash --remove-section=.dynsym --remove-section=.dynstr --remove-section=.gnu.version --remove-section=.gnu.version_r --remove-section=.rela.dyn --remove-section=.rela.plt --remove-section=.init --remove-section=.plt --remove-section=.fini --remove-section=.rodata --remove-section=.eh_frame_hdr --remove-section=.eh_frame --remove-section=.note.ABI-tag --remove-section=.init_array --remove-section=.fini_array --remove-section=.dynamic --remove-section=.got --remove-section=.got.plt --remove-section=.data --remove-section=.bss --remove-section=.comment thing.bloatedsyms thing.syms
28+
```
29+
After this you will be left with only the following sections: `NULL`, `.text`, `.symtab`, `.strtab`, `.shstrtab`, which you can verify with `readelf -S thing.syms`.
30+
You can test that this does in fact work with LLDB:
31+
```bash
32+
~❯ lldb thing.nosyms
33+
(lldb) target create "thing.nosyms"
34+
Current executable set to '/thing.nosyms' (x86_64).
35+
(lldb) b main
36+
Breakpoint 1: no locations (pending).
37+
WARNING: Unable to resolve breakpoint to any actual locations.
38+
(lldb) target symbols add thing.syms -s thing.nosyms
39+
symbol file '/thing.syms' has been added to '/thing.nosyms'
40+
1 location added to breakpoint 1
41+
(lldb) r
42+
Process 29082 launched: '/thing.nosyms' (x86_64)
43+
Process 29082 stopped
44+
* thread #1, name = 'thing.nosyms', stop reason = breakpoint 1.1
45+
frame #0: 0x00005555555553a4 thing.nosyms`main
46+
thing.nosyms`main:
47+
-> 0x5555555553a4 <+0>: pushq %rbp
48+
0x5555555553a5 <+1>: movq %rsp, %rbp
49+
0x5555555553a8 <+4>: subq $0x30, %rsp
50+
0x5555555553ac <+8>: movq %fs:0x28, %rax
51+
(lldb) ^D
52+
```
53+
54+
But for some god-forsaken reason this does not work with GDB:
55+
```bash
56+
~> gdb --nx thing.nosyms
57+
(gdb) starti
58+
(gdb) info proc mappings
59+
# Both using 0x0000555555554000 (start of objfile)
60+
# and 0x0000555555555000 (start of text segment) doesn't work.
61+
(gdb) add-symbol-file thing.syms 0x0000555555555000
62+
(gdb) b main
63+
Breakpoint 1 at 0x555555555334
64+
(gdb) continue
65+
# ....
66+
```
67+
Clearly the breakpoint was set at the wrong place, and it doesn't stop when it should.
68+
69+
## The program header table
70+
By playing around and comparing the ELF that niche-elf generates versus the one generated like above, I figured out that the problem for LLDB is the lack of a program header table. I added this table and have a working LLDB setup which you can look at on the `lldb-support` branch.
71+
72+
There are lots of hardcoded values on that branch so it won't work in general but if you set the proper values (same as in the reference binary, `thing.syms`) it does work.
73+
74+
There are two huge problems though:
75+
1. It doesn't work with GDB for some reason
76+
2. The text segment program header requires a precise `p_memsz` value.
77+
78+
Regarding the second point: I took this value from `thing.syms`, and using any other value than exactly that one, makes LLDB not work (breakpoints don't work). The problem is that, that value is not even the same one as in `thing` nor `thing.syms` (0x521 in my case). Somehow, `objcopy` sets it (to 0x4a2 in my case), and I don't know based on what. As such, I literarly cannot produce a binary that works for LLDB given an original ELF without invoking `objcopy` (and not invoking `objcopy` is kinda the point of niche-elf).
79+
80+
I am tired of essentially black-box fuzzing GDB's and LLDB's ELF parsers, so I think the only feasible solution at this point is using the JSON solution if we want to support LLDB.

niche_elf/builder.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ def write(self, path: str) -> None:
246246
p_paddr=0,
247247
# .text is NOBITS
248248
p_filesz=0,
249+
# For some reason this is the most important thing in the world.
250+
# https://github.com/llvm/llvm-project/issues/179839#issuecomment-3868134550
249251
p_memsz=0x4a2,
250252
p_align=self.sections[1].header.sh_addralign,
251253
)

0 commit comments

Comments
 (0)