binutils Binary inspection tools

Version 2.44 · source

Start here

file <bin>
What kind of binary
readelf -h <bin>
ELF header
nm -C <bin>
List symbols
objdump -d -C <bin>
Disassemble code
strings -n 8 <bin>
Printable text
ldd <bin>
Shared libraries
addr2line -e <bin> -f <addr>
Address to source line
size <bin>
Text, data, bss sizes

Concepts

  1. Source cc -g -c
  2. Object .o nm, objdump
  3. Archive .a / ELF readelf, size
  4. Process ldd, addr2line

Symbols (nm)

nm -C <file>
List symbols, demangled
nm -D <file>
Dynamic symbols of a shared lib
nm -u <file>
Undefined symbols it needs
nm --defined-only <file>
Only symbols it provides
nm -S --size-sort -C <file>
Biggest symbols last, with size
nm -n <file>
Sort by address
nm -A <file>...
Prefix each line with file name
Handy with shell globs: find which .o or .a member defines a symbol.
nm -g <file>
External (global) symbols only
nm -l <file>
Add source file and line
nm --print-armap <lib.a>
Archive index: symbol to member
nm type letters
Letter Meaning
T / t code, global / local
D / d initialised data
B / b zero-filled bss
R / r read-only data
U undefined, resolved later
W / w weak symbol

ELF structure (readelf)

readelf -h <elf>
ELF header: type, arch, entry
readelf -S <elf>
Section headers
readelf -l <elf>
Program headers (segments)
readelf -d <elf>
Dynamic section: NEEDED, RPATH
readelf -s -W <elf>
Symbol tables, wide lines
readelf --dyn-syms <elf>
Dynamic symbols only
readelf -r <elf>
Relocations
readelf -n <elf>
Notes such as the build ID
readelf -p .comment <elf>
Dump a section as strings
Shows the compiler that built the file.
readelf -x .rodata <elf>
Hex dump of a section
readelf --debug-dump=info <elf>
DWARF debug info
readelf -a <elf>
Everything at once
readelf -W <elf>
Do not wrap wide output

Disassembly (objdump)

objdump -d <file>
Disassemble code sections
objdump -d -C <file>
Disassemble, demangled names
objdump -d -M intel <file>
Intel syntax instead of AT&T
objdump -D <file>
Disassemble all sections, even data
objdump -S <file>
Interleave source (needs -g)
objdump -d --no-show-raw-insn <file>
Hide the opcode bytes
objdump -d --disassemble=<sym> <file>
Only one function
Older releases lack the =<sym> form; use -d and grep -A there.
objdump -d --start-address=<a> --stop-address=<b> <file>
Only an address range
objdump -h <file>
Section headers with sizes
objdump -x <file>
All headers
objdump -t <file>
Symbol table
objdump -T <file>
Dynamic symbol table
objdump -R <file>
Dynamic relocations
objdump -s -j <sect> <file>
Hex dump of one section
objdump -p <file>
Private headers, NEEDED libs
objdump -r -d <obj.o>
Show relocations inside code
objdump -f <file>
File header, start address

Strings and sizes

strings <file>
Printable strings, 4+ chars
strings -n <len> <file>
Set minimum string length
strings -a <file>
Scan the whole file (default)
Default since 2.14; -d scans only data sections.
strings -t x <file>
Prefix each with hex offset
strings -e l <file>
16-bit little-endian text
size <file>
Text, data, bss totals
size -A <file>
Per-section sizes
size -t <file>...
Totals over many files
c++filt <name>
Demangle a C++ name

Addresses and libraries

addr2line -e <elf> <addr>
Address to file:line
addr2line -e <elf> -f -C -i <addr>
Add function, demangle, inlines
addr2line -e <lib.so> -a <off>
Print address, for shared lib offsets
PIE and .so crashes log runtime addresses: subtract the load base first.
ldd <bin>
Shared libs it needs
ldd -v <bin>
Also versions required
ldd -r <bin>
Report missing functions too
readelf -d <bin> | grep NEEDED
Direct dependencies, no execution
Safe alternative to ldd on untrusted files.
objdump -p <bin> | grep -E 'NEEDED|RPATH|RUNPATH'
Libs and search paths
file <bin>
Type, arch, stripped or not

Strip, copy, archives

strip <file>
Remove all symbols and debug info
strip --strip-debug <file>
Keep symbols, drop debug info
strip -o <out> <file>
Write result to another file
strip --strip-unneeded <file>
Drop symbols not needed for relocation
objcopy --only-keep-debug <elf> <elf>.dbg
Split debug info into a file
objcopy --add-gnu-debuglink=<elf>.dbg <elf>
Point stripped binary at it
objcopy -O binary <elf> <out.bin>
Raw image of the sections
objcopy -j <sect> -O binary <elf> <out>
Extract one section
ar t <lib.a>
List archive members
ar rcs <lib.a> <obj.o>...
Create or update static lib
ar x <lib.a> [<member>]
Extract members
ar d <lib.a> <member>
Delete a member
ar tv <lib.a>
Members with size and date
ranlib <lib.a>
Rebuild archive symbol index

Recipes

Which library defines a symbol?
# search every static lib in the treenm -A -C --defined-only $(find . -name '*.a') | grep ' T .*parse_args'# or dynamic: shared libs exporting itfor f in /usr/lib/x86_64-linux-gnu/*.so*; do nm -D --defined-only "$f" 2>/dev/null | grep -q ' T malloc$' && echo "$f"; done
Resolve a crash address
# from a crash log: binary+0x1a2b3addr2line -e ./app -f -C -i 0x1a2b3# find the surrounding codeobjdump -d -C -S --start-address=0x1a280 --stop-address=0x1a2c0 ./app
Split debug info before shipping
objcopy --only-keep-debug app app.dbgstrip --strip-debug --strip-unneeded appobjcopy --add-gnu-debuglink=app.dbg appreadelf -n app | grep 'Build ID'
Find what bloats a binary
size -A app | sort -k2 -n -r | headnm -S --size-sort -C -r app | head -20# then see who pulls it inreadelf -d app | grep NEEDED