2 #include <mach-o/loader.h>
3 #include <mach-o/compact_unwind_encoding.h>
4 #include <mach/machine.h>
11 #include <sys/errno.h>
15 #include <mach-o/nlist.h>
19 UNWIND_ARM64_MODE_MASK = 0x0F000000,
20 UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
21 UNWIND_ARM64_MODE_DWARF = 0x03000000,
22 UNWIND_ARM64_MODE_FRAME = 0x04000000,
24 UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
25 UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
26 UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
27 UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
28 UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
29 UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
30 UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
31 UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
32 UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
34 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
35 UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
39 UNWIND_ARM_MODE_MASK = 0x0F000000,
40 UNWIND_ARM_MODE_FRAME = 0x01000000,
41 UNWIND_ARM_MODE_FRAME_D = 0x02000000,
42 UNWIND_ARM_MODE_DWARF = 0x04000000,
44 UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
46 UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
47 UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
48 UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
50 UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
51 UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
52 UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
53 UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
54 UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
56 UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
58 UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
61 #define EXTRACT_BITS(value, mask) \
62 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
65 // A quick sketch of a program which can parse the compact unwind info
66 // used on Darwin systems for exception handling. The output of
67 // unwinddump will be more authoritative/reliable but this program
68 // can dump at least the UNWIND_X86_64_MODE_RBP_FRAME format entries
73 uint64_t file_address;
78 symbol_compare (const void *a, const void *b)
80 return (int) ((struct symbol *)a)->file_address - ((struct symbol *)b)->file_address;
87 uint8_t *mach_header_start; // pointer into this program's address space
88 uint8_t *compact_unwind_start; // pointer into this program's address space
90 int addr_size; // 4 or 8 bytes, the size of addresses in this file
92 uint64_t text_segment_vmaddr; // __TEXT segment vmaddr
93 uint64_t text_segment_file_offset;
95 uint64_t text_section_vmaddr; // __TEXT,__text section vmaddr
96 uint64_t text_section_file_offset;
98 uint64_t eh_section_file_address; // the file address of the __TEXT,__eh_frame section
100 uint8_t *lsda_array_start; // for the currently-being-processed first-level index
101 uint8_t *lsda_array_end; // the lsda_array_start for the NEXT first-level index
103 struct symbol *symbols;
106 uint64_t *function_start_addresses;
107 int function_start_addresses_count;
109 int current_index_table_number;
111 struct unwind_info_section_header unwind_header;
112 struct unwind_info_section_header_index_entry first_level_index_entry;
113 struct unwind_info_compressed_second_level_page_header compressed_second_level_page_header;
114 struct unwind_info_regular_second_level_page_header regular_second_level_page_header;
119 read_leb128 (uint8_t **offset)
125 uint8_t byte = **offset;
126 *offset = *offset + 1;
127 result |= (byte & 0x7f) << shift;
128 if ((byte & 0x80) == 0)
136 // step through the load commands in a thin mach-o binary,
137 // find the cputype and the start of the __TEXT,__unwind_info
138 // section, return a pointer to that section or NULL if not found.
141 scan_macho_load_commands (struct baton *baton)
143 struct symtab_command symtab_cmd;
144 uint64_t linkedit_segment_vmaddr;
145 uint64_t linkedit_segment_file_offset;
147 baton->compact_unwind_start = 0;
149 uint32_t *magic = (uint32_t *) baton->mach_header_start;
151 if (*magic != MH_MAGIC && *magic != MH_MAGIC_64)
153 printf ("Unexpected magic number 0x%x in header, exiting.", *magic);
157 bool is_64bit = false;
158 if (*magic == MH_MAGIC_64)
161 uint8_t *offset = baton->mach_header_start;
163 struct mach_header mh;
164 memcpy (&mh, offset, sizeof (struct mach_header));
166 offset += sizeof (struct mach_header_64);
168 offset += sizeof (struct mach_header);
171 baton->addr_size = 8;
173 baton->addr_size = 4;
175 baton->cputype = mh.cputype;
177 uint8_t *start_of_load_commands = offset;
179 uint32_t cur_cmd = 0;
180 while (cur_cmd < mh.ncmds && (offset - start_of_load_commands) < mh.sizeofcmds)
182 struct load_command lc;
183 uint32_t *lc_cmd = (uint32_t *) offset;
184 uint32_t *lc_cmdsize = (uint32_t *) offset + 1;
185 uint8_t *start_of_this_load_cmd = offset;
187 if (*lc_cmd == LC_SEGMENT || *lc_cmd == LC_SEGMENT_64)
189 char segment_name[17];
190 segment_name[0] = '\0';
192 uint64_t segment_offset = 0;
193 uint64_t segment_vmaddr = 0;
195 if (*lc_cmd == LC_SEGMENT_64)
197 struct segment_command_64 seg;
198 memcpy (&seg, offset, sizeof (struct segment_command_64));
199 memcpy (&segment_name, &seg.segname, 16);
200 segment_name[16] = '\0';
202 segment_offset = seg.fileoff;
203 segment_vmaddr = seg.vmaddr;
204 offset += sizeof (struct segment_command_64);
205 if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1)
207 printf ("Segment '%s' is encrypted.\n", segment_name);
211 if (*lc_cmd == LC_SEGMENT)
213 struct segment_command seg;
214 memcpy (&seg, offset, sizeof (struct segment_command));
215 memcpy (&segment_name, &seg.segname, 16);
216 segment_name[16] = '\0';
218 segment_offset = seg.fileoff;
219 segment_vmaddr = seg.vmaddr;
220 offset += sizeof (struct segment_command);
221 if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1)
223 printf ("Segment '%s' is encrypted.\n", segment_name);
227 if (nsects != 0 && strcmp (segment_name, "__TEXT") == 0)
229 baton->text_segment_vmaddr = segment_vmaddr;
230 baton->text_segment_file_offset = segment_offset;
232 uint32_t current_sect = 0;
233 while (current_sect < nsects && (offset - start_of_this_load_cmd) < *lc_cmdsize)
236 memcpy (§_name, offset, 16);
237 sect_name[16] = '\0';
238 if (strcmp (sect_name, "__unwind_info") == 0)
242 struct section_64 sect;
243 memset (§, 0, sizeof (struct section_64));
244 memcpy (§, offset, sizeof (struct section_64));
245 baton->compact_unwind_start = baton->mach_header_start + sect.offset;
250 memset (§, 0, sizeof (struct section));
251 memcpy (§, offset, sizeof (struct section));
252 baton->compact_unwind_start = baton->mach_header_start + sect.offset;
255 if (strcmp (sect_name, "__eh_frame") == 0)
259 struct section_64 sect;
260 memset (§, 0, sizeof (struct section_64));
261 memcpy (§, offset, sizeof (struct section_64));
262 baton->eh_section_file_address = sect.addr;
267 memset (§, 0, sizeof (struct section));
268 memcpy (§, offset, sizeof (struct section));
269 baton->eh_section_file_address = sect.addr;
272 if (strcmp (sect_name, "__text") == 0)
276 struct section_64 sect;
277 memset (§, 0, sizeof (struct section_64));
278 memcpy (§, offset, sizeof (struct section_64));
279 baton->text_section_vmaddr = sect.addr;
280 baton->text_section_file_offset = sect.offset;
285 memset (§, 0, sizeof (struct section));
286 memcpy (§, offset, sizeof (struct section));
287 baton->text_section_vmaddr = sect.addr;
292 offset += sizeof (struct section_64);
296 offset += sizeof (struct section);
301 if (strcmp (segment_name, "__LINKEDIT") == 0)
303 linkedit_segment_vmaddr = segment_vmaddr;
304 linkedit_segment_file_offset = segment_offset;
308 if (*lc_cmd == LC_SYMTAB)
310 memcpy (&symtab_cmd, offset, sizeof (struct symtab_command));
313 if (*lc_cmd == LC_DYSYMTAB)
315 struct dysymtab_command dysymtab_cmd;
316 memcpy (&dysymtab_cmd, offset, sizeof (struct dysymtab_command));
322 char *string_table = (char *) (baton->mach_header_start + symtab_cmd.stroff);
323 uint8_t *local_syms = baton->mach_header_start + symtab_cmd.symoff + (dysymtab_cmd.ilocalsym * nlist_size);
324 int local_syms_count = dysymtab_cmd.nlocalsym;
325 uint8_t *exported_syms = baton->mach_header_start + symtab_cmd.symoff + (dysymtab_cmd.iextdefsym * nlist_size);
326 int exported_syms_count = dysymtab_cmd.nextdefsym;
328 // We're only going to create records for a small number of these symbols but to
329 // simplify the memory management I'll allocate enough space to store all of them.
330 baton->symbols = (struct symbol *) malloc (sizeof (struct symbol) * (local_syms_count + exported_syms_count));
331 baton->symbols_count = 0;
333 for (int i = 0; i < local_syms_count; i++)
335 struct nlist_64 nlist;
336 memset (&nlist, 0, sizeof (struct nlist_64));
339 memcpy (&nlist, local_syms + (i * nlist_size), sizeof (struct nlist_64));
343 struct nlist nlist_32;
344 memset (&nlist_32, 0, sizeof (struct nlist));
345 memcpy (&nlist_32, local_syms + (i * nlist_size), sizeof (struct nlist));
346 nlist.n_un.n_strx = nlist_32.n_un.n_strx;
347 nlist.n_type = nlist_32.n_type;
348 nlist.n_sect = nlist_32.n_sect;
349 nlist.n_desc = nlist_32.n_desc;
350 nlist.n_value = nlist_32.n_value;
352 if ((nlist.n_type & N_STAB) == 0
353 && ((nlist.n_type & N_EXT) == 1 ||
354 ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT))
355 && nlist.n_value != 0
356 && nlist.n_value != baton->text_segment_vmaddr)
358 baton->symbols[baton->symbols_count].file_address = nlist.n_value;
359 if (baton->cputype == CPU_TYPE_ARM)
360 baton->symbols[baton->symbols_count].file_address = baton->symbols[baton->symbols_count].file_address & ~1;
361 baton->symbols[baton->symbols_count].name = string_table + nlist.n_un.n_strx;
362 baton->symbols_count++;
366 for (int i = 0; i < exported_syms_count; i++)
368 struct nlist_64 nlist;
369 memset (&nlist, 0, sizeof (struct nlist_64));
372 memcpy (&nlist, exported_syms + (i * nlist_size), sizeof (struct nlist_64));
376 struct nlist nlist_32;
377 memcpy (&nlist_32, exported_syms + (i * nlist_size), sizeof (struct nlist));
378 nlist.n_un.n_strx = nlist_32.n_un.n_strx;
379 nlist.n_type = nlist_32.n_type;
380 nlist.n_sect = nlist_32.n_sect;
381 nlist.n_desc = nlist_32.n_desc;
382 nlist.n_value = nlist_32.n_value;
384 if ((nlist.n_type & N_STAB) == 0
385 && ((nlist.n_type & N_EXT) == 1 ||
386 ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT))
387 && nlist.n_value != 0
388 && nlist.n_value != baton->text_segment_vmaddr)
390 baton->symbols[baton->symbols_count].file_address = nlist.n_value;
391 if (baton->cputype == CPU_TYPE_ARM)
392 baton->symbols[baton->symbols_count].file_address = baton->symbols[baton->symbols_count].file_address & ~1;
393 baton->symbols[baton->symbols_count].name = string_table + nlist.n_un.n_strx;
394 baton->symbols_count++;
398 qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
401 if (*lc_cmd == LC_FUNCTION_STARTS)
403 struct linkedit_data_command function_starts_cmd;
404 memcpy (&function_starts_cmd, offset, sizeof (struct linkedit_data_command));
406 uint8_t *funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
407 uint8_t *function_end = funcstarts_offset + function_starts_cmd.datasize;
410 while (funcstarts_offset < function_end)
412 if (read_leb128 (&funcstarts_offset) != 0)
418 baton->function_start_addresses = (uint64_t *) malloc (sizeof (uint64_t) * count);
419 baton->function_start_addresses_count = count;
421 funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
422 uint64_t current_pc = baton->text_segment_vmaddr;
424 while (funcstarts_offset < function_end)
426 uint64_t func_start = read_leb128 (&funcstarts_offset);
429 current_pc += func_start;
430 baton->function_start_addresses[i++] = current_pc;
435 offset = start_of_this_load_cmd + *lc_cmdsize;
440 // Augment the symbol table with the function starts table -- adding symbol entries
441 // for functions that were stripped.
443 int unnamed_functions_to_add = 0;
444 for (int i = 0; i < baton->function_start_addresses_count; i++)
446 struct symbol search_key;
447 search_key.file_address = baton->function_start_addresses[i];
448 if (baton->cputype == CPU_TYPE_ARM)
449 search_key.file_address = search_key.file_address & ~1;
450 struct symbol *sym = bsearch (&search_key, baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
452 unnamed_functions_to_add++;
455 baton->symbols = (struct symbol *) realloc (baton->symbols, sizeof (struct symbol) * (baton->symbols_count + unnamed_functions_to_add));
457 int current_unnamed_symbol = 1;
458 int number_symbols_added = 0;
459 for (int i = 0; i < baton->function_start_addresses_count; i++)
461 struct symbol search_key;
462 search_key.file_address = baton->function_start_addresses[i];
463 if (baton->cputype == CPU_TYPE_ARM)
464 search_key.file_address = search_key.file_address & ~1;
465 struct symbol *sym = bsearch (&search_key, baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
469 asprintf (&name, "unnamed function #%d", current_unnamed_symbol++);
470 baton->symbols[baton->symbols_count + number_symbols_added].file_address = baton->function_start_addresses[i];
471 baton->symbols[baton->symbols_count + number_symbols_added].name = name;
472 number_symbols_added++;
475 baton->symbols_count += number_symbols_added;
476 qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
479 // printf ("function start addresses\n");
480 // for (int i = 0; i < baton->function_start_addresses_count; i++)
482 // printf ("0x%012llx\n", baton->function_start_addresses[i]);
485 // printf ("symbol table names & addresses\n");
486 // for (int i = 0; i < baton->symbols_count; i++)
488 // printf ("0x%012llx %s\n", baton->symbols[i].file_address, baton->symbols[i].name);
494 print_encoding_x86_64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
496 int mode = encoding & UNWIND_X86_64_MODE_MASK;
499 case UNWIND_X86_64_MODE_RBP_FRAME:
501 printf ("frame func: CFA is rbp+%d ", 16);
502 printf (" rip=[CFA-8] rbp=[CFA-16]");
503 uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
505 uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
508 saved_registers_offset += 2;
510 for (int i = 0; i < 5; i++)
512 switch (saved_registers_locations & 0x7)
514 case UNWIND_X86_64_REG_NONE:
516 case UNWIND_X86_64_REG_RBX:
517 printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
519 case UNWIND_X86_64_REG_R12:
520 printf (" r12=[CFA-%d]", saved_registers_offset * 8);
522 case UNWIND_X86_64_REG_R13:
523 printf (" r13=[CFA-%d]", saved_registers_offset * 8);
525 case UNWIND_X86_64_REG_R14:
526 printf (" r14=[CFA-%d]", saved_registers_offset * 8);
528 case UNWIND_X86_64_REG_R15:
529 printf (" r15=[CFA-%d]", saved_registers_offset * 8);
532 saved_registers_offset--;
533 saved_registers_locations >>= 3;
538 case UNWIND_X86_64_MODE_STACK_IND:
539 case UNWIND_X86_64_MODE_STACK_IMMD:
541 uint32_t stack_size = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
542 uint32_t register_count = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
543 uint32_t permutation = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
545 if (mode == UNWIND_X86_64_MODE_STACK_IND && function_start)
547 uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
549 // offset into the function instructions; 0 == beginning of first instruction
550 uint32_t offset_to_subl_insn = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
552 stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
554 stack_size += stack_adjust * 8;
556 printf ("large stack ");
559 if (mode == UNWIND_X86_64_MODE_STACK_IND)
561 printf ("frameless function: stack size %d, register count %d ", stack_size * 8, register_count);
565 printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
568 if (register_count == 0)
570 printf (" no registers saved");
575 // We need to include (up to) 6 registers in 10 bits.
576 // That would be 18 bits if we just used 3 bits per reg to indicate
577 // the order they're saved on the stack.
579 // This is done with Lehmer code permutation, e.g. see
580 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
583 // This decodes the variable-base number in the 10 bits
584 // and gives us the Lehmer code sequence which can then
587 switch (register_count)
590 permunreg[0] = permutation/120; // 120 == 5!
591 permutation -= (permunreg[0]*120);
592 permunreg[1] = permutation/24; // 24 == 4!
593 permutation -= (permunreg[1]*24);
594 permunreg[2] = permutation/6; // 6 == 3!
595 permutation -= (permunreg[2]*6);
596 permunreg[3] = permutation/2; // 2 == 2!
597 permutation -= (permunreg[3]*2);
598 permunreg[4] = permutation; // 1 == 1!
602 permunreg[0] = permutation/120;
603 permutation -= (permunreg[0]*120);
604 permunreg[1] = permutation/24;
605 permutation -= (permunreg[1]*24);
606 permunreg[2] = permutation/6;
607 permutation -= (permunreg[2]*6);
608 permunreg[3] = permutation/2;
609 permutation -= (permunreg[3]*2);
610 permunreg[4] = permutation;
613 permunreg[0] = permutation/60;
614 permutation -= (permunreg[0]*60);
615 permunreg[1] = permutation/12;
616 permutation -= (permunreg[1]*12);
617 permunreg[2] = permutation/3;
618 permutation -= (permunreg[2]*3);
619 permunreg[3] = permutation;
622 permunreg[0] = permutation/20;
623 permutation -= (permunreg[0]*20);
624 permunreg[1] = permutation/4;
625 permutation -= (permunreg[1]*4);
626 permunreg[2] = permutation;
629 permunreg[0] = permutation/5;
630 permutation -= (permunreg[0]*5);
631 permunreg[1] = permutation;
634 permunreg[0] = permutation;
638 // Decode the Lehmer code for this permutation of
639 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
642 bool used[7] = { false, false, false, false, false, false, false };
643 for (int i = 0; i < register_count; i++)
646 for (int j = 1; j < 7; j++)
648 if (used[j] == false)
650 if (renum == permunreg[i])
662 if (mode == UNWIND_X86_64_MODE_STACK_IND)
664 printf (" CFA is rsp+%d ", stack_size);
668 printf (" CFA is rsp+%d ", stack_size * 8);
671 uint32_t saved_registers_offset = 1;
672 printf (" rip=[CFA-%d]", saved_registers_offset * 8);
673 saved_registers_offset++;
675 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
677 switch (registers[i])
679 case UNWIND_X86_64_REG_NONE:
681 case UNWIND_X86_64_REG_RBX:
682 printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
683 saved_registers_offset++;
685 case UNWIND_X86_64_REG_R12:
686 printf (" r12=[CFA-%d]", saved_registers_offset * 8);
687 saved_registers_offset++;
689 case UNWIND_X86_64_REG_R13:
690 printf (" r13=[CFA-%d]", saved_registers_offset * 8);
691 saved_registers_offset++;
693 case UNWIND_X86_64_REG_R14:
694 printf (" r14=[CFA-%d]", saved_registers_offset * 8);
695 saved_registers_offset++;
697 case UNWIND_X86_64_REG_R15:
698 printf (" r15=[CFA-%d]", saved_registers_offset * 8);
699 saved_registers_offset++;
701 case UNWIND_X86_64_REG_RBP:
702 printf (" rbp=[CFA-%d]", saved_registers_offset * 8);
703 saved_registers_offset++;
713 case UNWIND_X86_64_MODE_DWARF:
715 uint32_t dwarf_offset = encoding & UNWIND_X86_DWARF_SECTION_OFFSET;
716 printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
717 dwarf_offset, dwarf_offset + baton.eh_section_file_address);
723 printf (" no unwind information");
730 print_encoding_i386 (struct baton baton, uint8_t *function_start, uint32_t encoding)
732 int mode = encoding & UNWIND_X86_MODE_MASK;
735 case UNWIND_X86_MODE_EBP_FRAME:
737 printf ("frame func: CFA is ebp+%d ", 8);
738 printf (" eip=[CFA-4] ebp=[CFA-8]");
739 uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_OFFSET);
741 uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
744 saved_registers_offset += 2;
746 for (int i = 0; i < 5; i++)
748 switch (saved_registers_locations & 0x7)
750 case UNWIND_X86_REG_NONE:
752 case UNWIND_X86_REG_EBX:
753 printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
755 case UNWIND_X86_REG_ECX:
756 printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
758 case UNWIND_X86_REG_EDX:
759 printf (" edx=[CFA-%d]", saved_registers_offset * 4);
761 case UNWIND_X86_REG_EDI:
762 printf (" edi=[CFA-%d]", saved_registers_offset * 4);
764 case UNWIND_X86_REG_ESI:
765 printf (" esi=[CFA-%d]", saved_registers_offset * 4);
768 saved_registers_offset--;
769 saved_registers_locations >>= 3;
774 case UNWIND_X86_MODE_STACK_IND:
775 case UNWIND_X86_MODE_STACK_IMMD:
777 uint32_t stack_size = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
778 uint32_t register_count = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
779 uint32_t permutation = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
781 if (mode == UNWIND_X86_MODE_STACK_IND && function_start)
783 uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
785 // offset into the function instructions; 0 == beginning of first instruction
786 uint32_t offset_to_subl_insn = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
788 stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
790 stack_size += stack_adjust * 4;
792 printf ("large stack ");
795 if (mode == UNWIND_X86_MODE_STACK_IND)
797 printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
801 printf ("frameless function: stack size %d, register count %d ", stack_size * 4, register_count);
804 if (register_count == 0)
806 printf (" no registers saved");
811 // We need to include (up to) 6 registers in 10 bits.
812 // That would be 18 bits if we just used 3 bits per reg to indicate
813 // the order they're saved on the stack.
815 // This is done with Lehmer code permutation, e.g. see
816 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
819 // This decodes the variable-base number in the 10 bits
820 // and gives us the Lehmer code sequence which can then
823 switch (register_count)
826 permunreg[0] = permutation/120; // 120 == 5!
827 permutation -= (permunreg[0]*120);
828 permunreg[1] = permutation/24; // 24 == 4!
829 permutation -= (permunreg[1]*24);
830 permunreg[2] = permutation/6; // 6 == 3!
831 permutation -= (permunreg[2]*6);
832 permunreg[3] = permutation/2; // 2 == 2!
833 permutation -= (permunreg[3]*2);
834 permunreg[4] = permutation; // 1 == 1!
838 permunreg[0] = permutation/120;
839 permutation -= (permunreg[0]*120);
840 permunreg[1] = permutation/24;
841 permutation -= (permunreg[1]*24);
842 permunreg[2] = permutation/6;
843 permutation -= (permunreg[2]*6);
844 permunreg[3] = permutation/2;
845 permutation -= (permunreg[3]*2);
846 permunreg[4] = permutation;
849 permunreg[0] = permutation/60;
850 permutation -= (permunreg[0]*60);
851 permunreg[1] = permutation/12;
852 permutation -= (permunreg[1]*12);
853 permunreg[2] = permutation/3;
854 permutation -= (permunreg[2]*3);
855 permunreg[3] = permutation;
858 permunreg[0] = permutation/20;
859 permutation -= (permunreg[0]*20);
860 permunreg[1] = permutation/4;
861 permutation -= (permunreg[1]*4);
862 permunreg[2] = permutation;
865 permunreg[0] = permutation/5;
866 permutation -= (permunreg[0]*5);
867 permunreg[1] = permutation;
870 permunreg[0] = permutation;
874 // Decode the Lehmer code for this permutation of
875 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
878 bool used[7] = { false, false, false, false, false, false, false };
879 for (int i = 0; i < register_count; i++)
882 for (int j = 1; j < 7; j++)
884 if (used[j] == false)
886 if (renum == permunreg[i])
898 if (mode == UNWIND_X86_MODE_STACK_IND)
900 printf (" CFA is esp+%d ", stack_size);
904 printf (" CFA is esp+%d ", stack_size * 4);
907 uint32_t saved_registers_offset = 1;
908 printf (" eip=[CFA-%d]", saved_registers_offset * 4);
909 saved_registers_offset++;
911 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
913 switch (registers[i])
915 case UNWIND_X86_REG_NONE:
917 case UNWIND_X86_REG_EBX:
918 printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
919 saved_registers_offset++;
921 case UNWIND_X86_REG_ECX:
922 printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
923 saved_registers_offset++;
925 case UNWIND_X86_REG_EDX:
926 printf (" edx=[CFA-%d]", saved_registers_offset * 4);
927 saved_registers_offset++;
929 case UNWIND_X86_REG_EDI:
930 printf (" edi=[CFA-%d]", saved_registers_offset * 4);
931 saved_registers_offset++;
933 case UNWIND_X86_REG_ESI:
934 printf (" esi=[CFA-%d]", saved_registers_offset * 4);
935 saved_registers_offset++;
937 case UNWIND_X86_REG_EBP:
938 printf (" ebp=[CFA-%d]", saved_registers_offset * 4);
939 saved_registers_offset++;
949 case UNWIND_X86_MODE_DWARF:
951 uint32_t dwarf_offset = encoding & UNWIND_X86_DWARF_SECTION_OFFSET;
952 printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
953 dwarf_offset, dwarf_offset + baton.eh_section_file_address);
959 printf (" no unwind information");
966 print_encoding_arm64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
968 const int wordsize = 8;
969 int mode = encoding & UNWIND_ARM64_MODE_MASK;
972 case UNWIND_ARM64_MODE_FRAME:
974 printf ("frame func: CFA is fp+%d ", 16);
975 printf (" pc=[CFA-8] fp=[CFA-16]");
976 int reg_pairs_saved_count = 1;
977 uint32_t saved_register_bits = encoding & 0xfff;
978 if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR)
980 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
981 cfa_offset -= wordsize;
982 printf (" x19=[CFA%d]", cfa_offset);
983 cfa_offset -= wordsize;
984 printf (" x20=[CFA%d]", cfa_offset);
985 reg_pairs_saved_count++;
987 if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR)
989 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
990 cfa_offset -= wordsize;
991 printf (" x21=[CFA%d]", cfa_offset);
992 cfa_offset -= wordsize;
993 printf (" x22=[CFA%d]", cfa_offset);
994 reg_pairs_saved_count++;
996 if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR)
998 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
999 cfa_offset -= wordsize;
1000 printf (" x23=[CFA%d]", cfa_offset);
1001 cfa_offset -= wordsize;
1002 printf (" x24=[CFA%d]", cfa_offset);
1003 reg_pairs_saved_count++;
1005 if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR)
1007 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1008 cfa_offset -= wordsize;
1009 printf (" x25=[CFA%d]", cfa_offset);
1010 cfa_offset -= wordsize;
1011 printf (" x26=[CFA%d]", cfa_offset);
1012 reg_pairs_saved_count++;
1014 if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR)
1016 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1017 cfa_offset -= wordsize;
1018 printf (" x27=[CFA%d]", cfa_offset);
1019 cfa_offset -= wordsize;
1020 printf (" x28=[CFA%d]", cfa_offset);
1021 reg_pairs_saved_count++;
1023 if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR)
1025 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1026 cfa_offset -= wordsize;
1027 printf (" d8=[CFA%d]", cfa_offset);
1028 cfa_offset -= wordsize;
1029 printf (" d9=[CFA%d]", cfa_offset);
1030 reg_pairs_saved_count++;
1032 if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR)
1034 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1035 cfa_offset -= wordsize;
1036 printf (" d10=[CFA%d]", cfa_offset);
1037 cfa_offset -= wordsize;
1038 printf (" d11=[CFA%d]", cfa_offset);
1039 reg_pairs_saved_count++;
1041 if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR)
1043 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1044 cfa_offset -= wordsize;
1045 printf (" d12=[CFA%d]", cfa_offset);
1046 cfa_offset -= wordsize;
1047 printf (" d13=[CFA%d]", cfa_offset);
1048 reg_pairs_saved_count++;
1050 if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR)
1052 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1053 cfa_offset -= wordsize;
1054 printf (" d14=[CFA%d]", cfa_offset);
1055 cfa_offset -= wordsize;
1056 printf (" d15=[CFA%d]", cfa_offset);
1057 reg_pairs_saved_count++;
1063 case UNWIND_ARM64_MODE_FRAMELESS:
1065 uint32_t stack_size = encoding & UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK;
1066 printf ("frameless function: stack size %d ", stack_size * 16);
1071 case UNWIND_ARM64_MODE_DWARF:
1073 uint32_t dwarf_offset = encoding & UNWIND_ARM64_DWARF_SECTION_OFFSET;
1074 printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
1075 dwarf_offset, dwarf_offset + baton.eh_section_file_address);
1081 printf (" no unwind information");
1088 print_encoding_armv7 (struct baton baton, uint8_t *function_start, uint32_t encoding)
1090 const int wordsize = 4;
1091 int mode = encoding & UNWIND_ARM_MODE_MASK;
1094 case UNWIND_ARM_MODE_FRAME_D:
1095 case UNWIND_ARM_MODE_FRAME:
1097 int stack_adjust = EXTRACT_BITS (encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK) * wordsize;
1099 printf ("frame func: CFA is fp+%d ", (2 * wordsize) + stack_adjust);
1100 int cfa_offset = -stack_adjust;
1102 cfa_offset -= wordsize;
1103 printf (" pc=[CFA%d]", cfa_offset);
1104 cfa_offset -= wordsize;
1105 printf (" fp=[CFA%d]", cfa_offset);
1107 uint32_t saved_register_bits = encoding & 0xff;
1108 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6)
1110 cfa_offset -= wordsize;
1111 printf (" r6=[CFA%d]", cfa_offset);
1113 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5)
1115 cfa_offset -= wordsize;
1116 printf (" r5=[CFA%d]", cfa_offset);
1118 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4)
1120 cfa_offset -= wordsize;
1121 printf (" r4=[CFA%d]", cfa_offset);
1123 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12)
1125 cfa_offset -= wordsize;
1126 printf (" r12=[CFA%d]", cfa_offset);
1128 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11)
1130 cfa_offset -= wordsize;
1131 printf (" r11=[CFA%d]", cfa_offset);
1133 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10)
1135 cfa_offset -= wordsize;
1136 printf (" r10=[CFA%d]", cfa_offset);
1138 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9)
1140 cfa_offset -= wordsize;
1141 printf (" r9=[CFA%d]", cfa_offset);
1143 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8)
1145 cfa_offset -= wordsize;
1146 printf (" r8=[CFA%d]", cfa_offset);
1149 if (mode == UNWIND_ARM_MODE_FRAME_D)
1151 uint32_t d_reg_bits = EXTRACT_BITS (encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1157 printf (" d8=[CFA%d]", cfa_offset);
1163 printf (" d10=[CFA%d]", cfa_offset);
1165 printf (" d8=[CFA%d]", cfa_offset);
1172 printf (" d12=[CFA%d]", cfa_offset);
1174 printf (" d10=[CFA%d]", cfa_offset);
1176 printf (" d8=[CFA%d]", cfa_offset);
1184 printf (" d14=[CFA%d]", cfa_offset);
1186 printf (" d12=[CFA%d]", cfa_offset);
1188 printf (" d10=[CFA%d]", cfa_offset);
1190 printf (" d8=[CFA%d]", cfa_offset);
1195 // sp = (sp - 24) & (-16);
1196 // vst {d8, d9, d10}
1197 printf (" d14, d12, d10, d9, d8");
1201 // sp = (sp - 40) & (-16);
1202 // vst {d8, d9, d10, d11}
1204 printf (" d14, d11, d10, d9, d8, d12");
1207 // sp = (sp - 56) & (-16);
1208 // vst {d8, d9, d10, d11}
1209 // vst {d12, d13, d14}
1210 printf (" d11, d10, d9, d8, d14, d13, d12");
1213 // sp = (sp - 64) & (-16);
1214 // vst {d8, d9, d10, d11}
1215 // vst {d12, d13, d14, d15}
1216 printf (" d11, d10, d9, d8, d15, d14, d13, d12");
1223 case UNWIND_ARM_MODE_DWARF:
1225 uint32_t dwarf_offset = encoding & UNWIND_ARM_DWARF_SECTION_OFFSET;
1226 printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
1227 dwarf_offset, dwarf_offset + baton.eh_section_file_address);
1233 printf (" no unwind information");
1242 void print_encoding (struct baton baton, uint8_t *function_start, uint32_t encoding)
1245 if (baton.cputype == CPU_TYPE_X86_64)
1247 print_encoding_x86_64 (baton, function_start, encoding);
1249 else if (baton.cputype == CPU_TYPE_I386)
1251 print_encoding_i386 (baton, function_start, encoding);
1253 else if (baton.cputype == CPU_TYPE_ARM64)
1255 print_encoding_arm64 (baton, function_start, encoding);
1257 else if (baton.cputype == CPU_TYPE_ARM)
1259 print_encoding_armv7 (baton, function_start, encoding);
1263 printf (" -- unsupported encoding arch -- ");
1268 print_function_encoding (struct baton baton, uint32_t idx, uint32_t encoding, uint32_t entry_encoding_index, uint32_t entry_func_offset)
1271 char *entry_encoding_index_str = "";
1272 if (entry_encoding_index != (uint32_t) -1)
1274 asprintf (&entry_encoding_index_str, ", encoding #%d", entry_encoding_index);
1278 asprintf (&entry_encoding_index_str, "");
1281 uint64_t file_address = baton.first_level_index_entry.functionOffset + entry_func_offset + baton.text_segment_vmaddr;
1283 if (baton.cputype == CPU_TYPE_ARM)
1284 file_address = file_address & ~1;
1286 printf (" func [%d] offset %d (file addr 0x%" PRIx64 ")%s, encoding is 0x%x",
1287 idx, entry_func_offset,
1289 entry_encoding_index_str,
1292 struct symbol *symbol = NULL;
1293 for (int i = 0; i < baton.symbols_count; i++)
1295 if (i == baton.symbols_count - 1 && baton.symbols[i].file_address <= file_address)
1297 symbol = &(baton.symbols[i]);
1302 if (baton.symbols[i].file_address <= file_address && baton.symbols[i + 1].file_address > file_address)
1304 symbol = &(baton.symbols[i]);
1313 int offset = file_address - symbol->file_address;
1315 // FIXME this is a poor heuristic - if we're greater than 16 bytes past the
1316 // start of the function, this is the unwind info for a stripped function.
1317 // In reality the compact unwind entry may not line up exactly with the
1321 printf ("name: %s", symbol->name);
1324 printf (" + %d", offset);
1330 print_encoding (baton, baton.mach_header_start + baton.first_level_index_entry.functionOffset + baton.text_section_file_offset + entry_func_offset, encoding);
1332 bool has_lsda = encoding & UNWIND_HAS_LSDA;
1336 uint32_t func_offset = entry_func_offset + baton.first_level_index_entry.functionOffset;
1338 int lsda_entry_number = -1;
1341 uint32_t high = (baton.lsda_array_end - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
1345 uint32_t mid = (low + high) / 2;
1347 uint8_t *mid_lsda_entry_addr = (baton.lsda_array_start + (mid * sizeof (struct unwind_info_section_header_lsda_index_entry)));
1348 struct unwind_info_section_header_lsda_index_entry mid_lsda_entry;
1349 memcpy (&mid_lsda_entry, mid_lsda_entry_addr, sizeof (struct unwind_info_section_header_lsda_index_entry));
1350 if (mid_lsda_entry.functionOffset == func_offset)
1352 lsda_entry_number = (mid_lsda_entry_addr - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
1355 else if (mid_lsda_entry.functionOffset < func_offset)
1365 if (lsda_entry_number != -1)
1367 printf (", LSDA entry #%d", lsda_entry_number);
1371 printf (", LSDA entry not found");
1375 uint32_t pers_idx = EXTRACT_BITS (encoding, UNWIND_PERSONALITY_MASK);
1378 pers_idx--; // Change 1-based to 0-based index
1379 printf (", personality entry #%d", pers_idx);
1386 print_second_level_index_regular (struct baton baton)
1388 uint8_t *page_entries = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset + baton.regular_second_level_page_header.entryPageOffset;
1389 uint32_t entries_count = baton.regular_second_level_page_header.entryCount;
1391 uint8_t *offset = page_entries;
1394 while (idx < entries_count)
1396 uint32_t func_offset = *((uint32_t *) (offset));
1397 uint32_t encoding = *((uint32_t *) (offset + 4));
1399 // UNWIND_SECOND_LEVEL_REGULAR entries have a funcOffset which includes the
1400 // functionOffset from the containing index table already. UNWIND_SECOND_LEVEL_COMPRESSED
1401 // entries only have the offset from the containing index table functionOffset.
1402 // So strip off the containing index table functionOffset value here so they can
1403 // be treated the same at the lower layers.
1405 print_function_encoding (baton, idx, encoding, (uint32_t) -1, func_offset - baton.first_level_index_entry.functionOffset);
1412 print_second_level_index_compressed (struct baton baton)
1414 uint8_t *this_index = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
1415 uint8_t *start_of_entries = this_index + baton.compressed_second_level_page_header.entryPageOffset;
1416 uint8_t *offset = start_of_entries;
1417 for (uint16_t idx = 0; idx < baton.compressed_second_level_page_header.entryCount; idx++)
1419 uint32_t entry = *((uint32_t*) offset);
1423 uint32_t entry_encoding_index = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
1424 uint32_t entry_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry);
1426 if (entry_encoding_index < baton.unwind_header.commonEncodingsArrayCount)
1428 // encoding is in common table in section header
1429 encoding = *((uint32_t*) (baton.compact_unwind_start + baton.unwind_header.commonEncodingsArraySectionOffset + (entry_encoding_index * sizeof (uint32_t))));
1433 // encoding is in page specific table
1434 uint32_t page_encoding_index = entry_encoding_index - baton.unwind_header.commonEncodingsArrayCount;
1435 encoding = *((uint32_t*) (this_index + baton.compressed_second_level_page_header.encodingsPageOffset + (page_encoding_index * sizeof (uint32_t))));
1439 print_function_encoding (baton, idx, encoding, entry_encoding_index, entry_func_offset);
1444 print_second_level_index (struct baton baton)
1446 uint8_t *index_start = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
1448 if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_REGULAR)
1450 struct unwind_info_regular_second_level_page_header header;
1451 memcpy (&header, index_start, sizeof (struct unwind_info_regular_second_level_page_header));
1452 printf (" UNWIND_SECOND_LEVEL_REGULAR #%d entryPageOffset %d, entryCount %d\n", baton.current_index_table_number, header.entryPageOffset, header.entryCount);
1453 baton.regular_second_level_page_header = header;
1454 print_second_level_index_regular (baton);
1457 if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_COMPRESSED)
1459 struct unwind_info_compressed_second_level_page_header header;
1460 memcpy (&header, index_start, sizeof (struct unwind_info_compressed_second_level_page_header));
1461 printf (" UNWIND_SECOND_LEVEL_COMPRESSED #%d entryPageOffset %d, entryCount %d, encodingsPageOffset %d, encodingsCount %d\n", baton.current_index_table_number, header.entryPageOffset, header.entryCount, header.encodingsPageOffset, header.encodingsCount);
1462 baton.compressed_second_level_page_header = header;
1463 print_second_level_index_compressed (baton);
1469 print_index_sections (struct baton baton)
1471 uint8_t *index_section_offset = baton.compact_unwind_start + baton.unwind_header.indexSectionOffset;
1472 uint32_t index_count = baton.unwind_header.indexCount;
1474 uint32_t cur_idx = 0;
1476 uint8_t *offset = index_section_offset;
1477 while (cur_idx < index_count)
1479 baton.current_index_table_number = cur_idx;
1480 struct unwind_info_section_header_index_entry index_entry;
1481 memcpy (&index_entry, offset, sizeof (struct unwind_info_section_header_index_entry));
1482 printf ("index section #%d: functionOffset %d, secondLevelPagesSectionOffset %d, lsdaIndexArraySectionOffset %d\n", cur_idx, index_entry.functionOffset, index_entry.secondLevelPagesSectionOffset, index_entry.lsdaIndexArraySectionOffset);
1484 // secondLevelPagesSectionOffset == 0 means this is a sentinel entry
1485 if (index_entry.secondLevelPagesSectionOffset != 0)
1487 struct unwind_info_section_header_index_entry next_index_entry;
1488 memcpy (&next_index_entry, offset + sizeof (struct unwind_info_section_header_index_entry), sizeof (struct unwind_info_section_header_index_entry));
1490 baton.lsda_array_start = baton.compact_unwind_start + index_entry.lsdaIndexArraySectionOffset;
1491 baton.lsda_array_end = baton.compact_unwind_start + next_index_entry.lsdaIndexArraySectionOffset;
1493 uint8_t *lsda_entry_offset = baton.lsda_array_start;
1494 uint32_t lsda_count = 0;
1495 while (lsda_entry_offset < baton.lsda_array_end)
1497 struct unwind_info_section_header_lsda_index_entry lsda_entry;
1498 memcpy (&lsda_entry, lsda_entry_offset, sizeof (struct unwind_info_section_header_lsda_index_entry));
1499 uint64_t function_file_address = baton.first_level_index_entry.functionOffset + lsda_entry.functionOffset + baton.text_segment_vmaddr;
1500 uint64_t lsda_file_address = lsda_entry.lsdaOffset + baton.text_segment_vmaddr;
1501 printf (" LSDA [%d] functionOffset %d (%d) (file address 0x%" PRIx64 "), lsdaOffset %d (file address 0x%" PRIx64 ")\n",
1502 lsda_count, lsda_entry.functionOffset,
1503 lsda_entry.functionOffset - index_entry.functionOffset,
1504 function_file_address,
1505 lsda_entry.lsdaOffset, lsda_file_address);
1507 lsda_entry_offset += sizeof (struct unwind_info_section_header_lsda_index_entry);
1512 baton.first_level_index_entry = index_entry;
1513 print_second_level_index (baton);
1519 offset += sizeof (struct unwind_info_section_header_index_entry);
1523 int main (int argc, char **argv)
1526 char *file = argv[0];
1529 int fd = open (file, O_RDONLY);
1532 printf ("Failed to open '%s'\n", file);
1536 uint8_t *file_mem = (uint8_t*) mmap (0, st.st_size, PROT_READ, MAP_PRIVATE | MAP_FILE, fd, 0);
1537 if (file_mem == MAP_FAILED)
1539 printf ("Failed to mmap() '%s'\n", file);
1542 FILE *f = fopen ("a.out", "r");
1545 baton.mach_header_start = file_mem;
1546 baton.symbols = NULL;
1547 baton.symbols_count = 0;
1548 baton.function_start_addresses = NULL;
1549 baton.function_start_addresses_count = 0;
1551 scan_macho_load_commands (&baton);
1553 if (baton.compact_unwind_start == NULL)
1555 printf ("could not find __TEXT,__unwind_info section\n");
1560 struct unwind_info_section_header header;
1561 memcpy (&header, baton.compact_unwind_start, sizeof (struct unwind_info_section_header));
1562 printf ("Header:\n");
1563 printf (" version %u\n", header.version);
1564 printf (" commonEncodingsArraySectionOffset is %d\n", header.commonEncodingsArraySectionOffset);
1565 printf (" commonEncodingsArrayCount is %d\n", header.commonEncodingsArrayCount);
1566 printf (" personalityArraySectionOffset is %d\n", header.personalityArraySectionOffset);
1567 printf (" personalityArrayCount is %d\n", header.personalityArrayCount);
1568 printf (" indexSectionOffset is %d\n", header.indexSectionOffset);
1569 printf (" indexCount is %d\n", header.indexCount);
1571 uint8_t *common_encodings = baton.compact_unwind_start + header.commonEncodingsArraySectionOffset;
1572 uint32_t encoding_idx = 0;
1573 while (encoding_idx < header.commonEncodingsArrayCount)
1575 uint32_t encoding = *((uint32_t*) common_encodings);
1576 printf (" Common Encoding [%d]: 0x%x ", encoding_idx, encoding);
1577 print_encoding (baton, NULL, encoding);
1579 common_encodings += sizeof (uint32_t);
1583 uint8_t *pers_arr = baton.compact_unwind_start + header.personalityArraySectionOffset;
1584 uint32_t pers_idx = 0;
1585 while (pers_idx < header.personalityArrayCount)
1587 int32_t pers_delta = *((int32_t*) (baton.compact_unwind_start + header.personalityArraySectionOffset + (pers_idx * sizeof (uint32_t))));
1588 printf (" Personality [%d]: personality function ptr @ offset %d (file address 0x%" PRIx64 ")\n", pers_idx, pers_delta, baton.text_segment_vmaddr + pers_delta);
1590 pers_arr += sizeof (uint32_t);
1595 baton.unwind_header = header;
1597 print_index_sections (baton);