I want to make sure my executable has debug info, trying the linux equivalent doesn't help:
$ file ./my_lovely_program
./my_lovely_program: Mach-O 64-bit executable arm64 # with debug info? without?
EDIT (from the answer of @haggbart)
It seems that my executable has no debug info (?)
$ dwarfdump --debug-info ./compi
./compi: file format Mach-O arm64
.debug_info contents: # <--- empty, right?
And with the other option, I'm not sure:
$ otool -hv ./compi
./compi:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 19 1816 NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE
This is very weird because I can perfectly debug it with lldb
(lldb) b main
Breakpoint 1: where = compi`main + 24 at main.cpp:50:9, address = 0x0000000100018650
(lldb) run
Process 6067 launched: '/Users/oren/Downloads/compi' (arm64)
Process 6067 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100018650 compi`main(argc=3, argv=0x000000016fdff7b8) at main.cpp:50:9
47 /*****************/
48 int main(int argc, char **argv)
49 {
-> 50 if (argc == 3)
51 {
52 const char *input = argv[1];
53 const char *output = argv[2];
Target 0: (compi) stopped.
Mach-O isn't like ELF: Its debug info is "sold separately" in a .dSYM file. When you compile with -g you'll see a file gets generated along side your output, such that:
(~) gcc a.c -o /tmp/a -g2
(~) %ls -lFd /tmp/a /tmp/a.dSYM
-rwxr-xr-x 1 morpheus wheel 34078 Dec 6 12:56 /tmp/a*
drwxr-xr-x 3 morpheus wheel 96 Dec 6 12:56 /tmp/a.dSYM/
The .dSYM is a bundle (i.e. a directory structure) whose Contents/Resources/DWARF has the "companion file":
(~) %file /tmp/a.dSYM/Contents/Resources/DWARF/a
/tmp/a.dSYM/Contents/Resources/DWARF/a: Mach-O 64-bit dSYM companion file arm64
(~) %jtool2 -l /tmp/a.dSYM/Contents/Resources/DWARF/a | grep UUID
LC 00: LC_UUID UUID: BDD5C13E-F7B8-3B4D-BAF9-14DF3CD03724
(~) %jtool2 -l /tmp/a | grep UUID
LC 09: LC_UUID UUID: BDD5C13E-F7B8-3B4D-BAF9-14DF3CD03724
tools like lldb can figure out the debug data by trying for the companion file directory (usually in same location as the binary, or specified in a path), and then check the LC_UUID matches. This enables you to ship the binary without its dSym, and use the dSym when symbolicating a crash report (this is what Apple does). The debug info includes all local variable names, as well as debug_aranges (addr2line), etc:
(~) %jtool2 -l /tmp/a.dSYM/Contents/Resources/DWARF/a | grep DWARF
LC 07: LC_SEGMENT_64 Mem: 0x100009000-0x10000a000 __DWARF
Mem: 0x100009000-0x10000921f __DWARF.__debug_line
Mem: 0x10000921f-0x10000924f __DWARF.__debug_aranges
Mem: 0x10000924f-0x1000093dc __DWARF.__debug_info
Mem: 0x1000093dc-0x100009478 __DWARF.__debug_abbrev
Mem: 0x100009478-0x100009590 __DWARF.__debug_str
Mem: 0x100009590-0x1000095e8 __DWARF.__apple_names
Mem: 0x1000095e8-0x10000960c __DWARF.__apple_namespac
Mem: 0x10000960c-0x100009773 __DWARF.__apple_types
Mem: 0x100009773-0x100009797 __DWARF.__apple_objc
If you really want to get of any debug info - including, say, local function symbols (which are included by default in the binary), strip -d -x is your friend. This operates on the binary.
Note that running "dsymutil" (As suggested in other answers) can be a bit misleading, since in order to display information it will track down the accompanying dSym - which will be present on your machine, but not if you move the binary elsewhere.