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>
17 #define EXTRACT_BITS(value, mask) \
18 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
21 // A quick sketch of a program which can parse the compact unwind info
22 // used on Darwin systems for exception handling. The output of
23 // unwinddump will be more authoritative/reliable but this program
24 // can dump at least the UNWIND_X86_64_MODE_RBP_FRAME format entries
29 uint64_t file_address;
34 symbol_compare (const void *a, const void *b)
36 return (int) ((struct symbol *)a)->file_address - ((struct symbol *)b)->file_address;
43 uint8_t *mach_header_start; // pointer into this program's address space
44 uint8_t *compact_unwind_start; // pointer into this program's address space
46 int addr_size; // 4 or 8 bytes, the size of addresses in this file
48 uint64_t text_segment_vmaddr; // __TEXT segment vmaddr
49 uint64_t text_segment_file_offset;
51 uint64_t text_section_vmaddr; // __TEXT,__text section vmaddr
52 uint64_t text_section_file_offset;
54 uint64_t eh_section_file_address; // the file address of the __TEXT,__eh_frame section
56 uint8_t *lsda_array_start; // for the currently-being-processed first-level index
57 uint8_t *lsda_array_end; // the lsda_array_start for the NEXT first-level index
59 struct symbol *symbols;
62 uint64_t *function_start_addresses;
63 int function_start_addresses_count;
65 int current_index_table_number;
67 struct unwind_info_section_header unwind_header;
68 struct unwind_info_section_header_index_entry first_level_index_entry;
69 struct unwind_info_compressed_second_level_page_header compressed_second_level_page_header;
70 struct unwind_info_regular_second_level_page_header regular_second_level_page_header;
75 read_leb128 (uint8_t **offset)
81 uint8_t byte = **offset;
82 *offset = *offset + 1;
83 result |= (byte & 0x7f) << shift;
84 if ((byte & 0x80) == 0)
92 // step through the load commands in a thin mach-o binary,
93 // find the cputype and the start of the __TEXT,__unwind_info
94 // section, return a pointer to that section or NULL if not found.
97 scan_macho_load_commands (struct baton *baton)
99 struct symtab_command symtab_cmd;
100 uint64_t linkedit_segment_vmaddr;
101 uint64_t linkedit_segment_file_offset;
103 baton->compact_unwind_start = 0;
105 uint32_t *magic = (uint32_t *) baton->mach_header_start;
107 if (*magic != MH_MAGIC && *magic != MH_MAGIC_64)
109 printf ("Unexpected magic number 0x%x in header, exiting.", *magic);
113 bool is_64bit = false;
114 if (*magic == MH_MAGIC_64)
117 uint8_t *offset = baton->mach_header_start;
119 struct mach_header mh;
120 memcpy (&mh, offset, sizeof (struct mach_header));
122 offset += sizeof (struct mach_header_64);
124 offset += sizeof (struct mach_header);
127 baton->addr_size = 8;
129 baton->addr_size = 4;
131 baton->cputype = mh.cputype;
133 uint8_t *start_of_load_commands = offset;
135 uint32_t cur_cmd = 0;
136 while (cur_cmd < mh.ncmds && (offset - start_of_load_commands) < mh.sizeofcmds)
138 struct load_command lc;
139 uint32_t *lc_cmd = (uint32_t *) offset;
140 uint32_t *lc_cmdsize = (uint32_t *) offset + 1;
141 uint8_t *start_of_this_load_cmd = offset;
143 if (*lc_cmd == LC_SEGMENT || *lc_cmd == LC_SEGMENT_64)
145 char segment_name[17];
146 segment_name[0] = '\0';
148 uint64_t segment_offset = 0;
149 uint64_t segment_vmaddr = 0;
151 if (*lc_cmd == LC_SEGMENT_64)
153 struct segment_command_64 seg;
154 memcpy (&seg, offset, sizeof (struct segment_command_64));
155 memcpy (&segment_name, &seg.segname, 16);
156 segment_name[16] = '\0';
158 segment_offset = seg.fileoff;
159 segment_vmaddr = seg.vmaddr;
160 offset += sizeof (struct segment_command_64);
161 if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1)
163 printf ("Segment '%s' is encrypted.\n", segment_name);
167 if (*lc_cmd == LC_SEGMENT)
169 struct segment_command seg;
170 memcpy (&seg, offset, sizeof (struct segment_command));
171 memcpy (&segment_name, &seg.segname, 16);
172 segment_name[16] = '\0';
174 segment_offset = seg.fileoff;
175 segment_vmaddr = seg.vmaddr;
176 offset += sizeof (struct segment_command);
177 if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1)
179 printf ("Segment '%s' is encrypted.\n", segment_name);
183 if (nsects != 0 && strcmp (segment_name, "__TEXT") == 0)
185 baton->text_segment_vmaddr = segment_vmaddr;
186 baton->text_segment_file_offset = segment_offset;
188 uint32_t current_sect = 0;
189 while (current_sect < nsects && (offset - start_of_this_load_cmd) < *lc_cmdsize)
192 memcpy (§_name, offset, 16);
193 sect_name[16] = '\0';
194 if (strcmp (sect_name, "__unwind_info") == 0)
198 struct section_64 sect;
199 memcpy (§, offset, sizeof (struct section_64));
200 baton->compact_unwind_start = baton->mach_header_start + sect.offset;
205 memcpy (§, offset, sizeof (struct section));
206 baton->compact_unwind_start = baton->mach_header_start + sect.offset;
209 if (strcmp (sect_name, "__eh_frame") == 0)
213 struct section_64 sect;
214 memcpy (§, offset, sizeof (struct section_64));
215 baton->eh_section_file_address = sect.addr;
220 memcpy (§, offset, sizeof (struct section));
221 baton->eh_section_file_address = sect.addr;
224 if (strcmp (sect_name, "__text") == 0)
228 struct section_64 sect;
229 memcpy (§, offset, sizeof (struct section_64));
230 baton->text_section_vmaddr = sect.addr;
231 baton->text_section_file_offset = sect.offset;
236 memcpy (§, offset, sizeof (struct section));
237 baton->text_section_vmaddr = sect.addr;
242 offset += sizeof (struct section_64);
246 offset += sizeof (struct section);
251 if (strcmp (segment_name, "__LINKEDIT") == 0)
253 linkedit_segment_vmaddr = segment_vmaddr;
254 linkedit_segment_file_offset = segment_offset;
258 if (*lc_cmd == LC_SYMTAB)
260 memcpy (&symtab_cmd, offset, sizeof (struct symtab_command));
263 if (*lc_cmd == LC_DYSYMTAB)
265 struct dysymtab_command dysymtab_cmd;
266 memcpy (&dysymtab_cmd, offset, sizeof (struct dysymtab_command));
272 char *string_table = (char *) (baton->mach_header_start + symtab_cmd.stroff);
273 uint8_t *local_syms = baton->mach_header_start + symtab_cmd.symoff + (dysymtab_cmd.ilocalsym * nlist_size);
274 int local_syms_count = dysymtab_cmd.nlocalsym;
275 uint8_t *exported_syms = baton->mach_header_start + symtab_cmd.symoff + (dysymtab_cmd.iextdefsym * nlist_size);
276 int exported_syms_count = dysymtab_cmd.nextdefsym;
278 // We're only going to create records for a small number of these symbols but to
279 // simplify the memory management I'll allocate enough space to store all of them.
280 baton->symbols = (struct symbol *) malloc (sizeof (struct symbol) * (local_syms_count + exported_syms_count));
281 baton->symbols_count = 0;
283 for (int i = 0; i < local_syms_count; i++)
285 struct nlist_64 nlist;
288 memcpy (&nlist, local_syms + (i * nlist_size), sizeof (struct nlist_64));
292 struct nlist nlist_32;
293 memcpy (&nlist_32, local_syms + (i * nlist_size), sizeof (struct nlist));
294 nlist.n_un.n_strx = nlist_32.n_un.n_strx;
295 nlist.n_type = nlist_32.n_type;
296 nlist.n_sect = nlist_32.n_sect;
297 nlist.n_desc = nlist_32.n_desc;
298 nlist.n_value = nlist_32.n_value;
300 if ((nlist.n_type & N_STAB) == 0
301 && ((nlist.n_type & N_EXT) == 1 ||
302 ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT))
303 && nlist.n_value != 0
304 && nlist.n_value != baton->text_segment_vmaddr)
306 baton->symbols[baton->symbols_count].file_address = nlist.n_value;
307 baton->symbols[baton->symbols_count].name = string_table + nlist.n_un.n_strx;
308 baton->symbols_count++;
312 for (int i = 0; i < exported_syms_count; i++)
314 struct nlist_64 nlist;
317 memcpy (&nlist, exported_syms + (i * nlist_size), sizeof (struct nlist_64));
321 struct nlist nlist_32;
322 memcpy (&nlist_32, exported_syms + (i * nlist_size), sizeof (struct nlist));
323 nlist.n_un.n_strx = nlist_32.n_un.n_strx;
324 nlist.n_type = nlist_32.n_type;
325 nlist.n_sect = nlist_32.n_sect;
326 nlist.n_desc = nlist_32.n_desc;
327 nlist.n_value = nlist_32.n_value;
329 if ((nlist.n_type & N_STAB) == 0
330 && ((nlist.n_type & N_EXT) == 1 ||
331 ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT))
332 && nlist.n_value != 0
333 && nlist.n_value != baton->text_segment_vmaddr)
335 baton->symbols[baton->symbols_count].file_address = nlist.n_value;
336 baton->symbols[baton->symbols_count].name = string_table + nlist.n_un.n_strx;
337 baton->symbols_count++;
341 qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
344 if (*lc_cmd == LC_FUNCTION_STARTS)
346 struct linkedit_data_command function_starts_cmd;
347 memcpy (&function_starts_cmd, offset, sizeof (struct linkedit_data_command));
349 uint8_t *funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
350 uint8_t *function_end = funcstarts_offset + function_starts_cmd.datasize;
353 while (funcstarts_offset < function_end)
355 if (read_leb128 (&funcstarts_offset) != 0)
361 baton->function_start_addresses = (uint64_t *) malloc (sizeof (uint64_t) * count);
362 baton->function_start_addresses_count = count;
364 funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
365 uint64_t current_pc = baton->text_segment_vmaddr;
367 while (funcstarts_offset < function_end)
369 uint64_t func_start = read_leb128 (&funcstarts_offset);
372 current_pc += func_start;
373 baton->function_start_addresses[i++] = current_pc;
378 offset = start_of_this_load_cmd + *lc_cmdsize;
383 // Augment the symbol table with the function starts table -- adding symbol entries
384 // for functions that were stripped.
386 int unnamed_functions_to_add = 0;
387 for (int i = 0; i < baton->function_start_addresses_count; i++)
389 struct symbol search_key;
390 search_key.file_address = baton->function_start_addresses[i];
391 struct symbol *sym = bsearch (&search_key, baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
393 unnamed_functions_to_add++;
396 baton->symbols = (struct symbol *) realloc (baton->symbols, sizeof (struct symbol) * (baton->symbols_count + unnamed_functions_to_add));
398 int current_unnamed_symbol = 1;
399 int number_symbols_added = 0;
400 for (int i = 0; i < baton->function_start_addresses_count; i++)
402 struct symbol search_key;
403 search_key.file_address = baton->function_start_addresses[i];
404 struct symbol *sym = bsearch (&search_key, baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
408 asprintf (&name, "unnamed function #%d", current_unnamed_symbol++);
409 baton->symbols[baton->symbols_count + number_symbols_added].file_address = baton->function_start_addresses[i];
410 baton->symbols[baton->symbols_count + number_symbols_added].name = name;
411 number_symbols_added++;
414 baton->symbols_count += number_symbols_added;
415 qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
418 // printf ("function start addresses\n");
419 // for (int i = 0; i < baton->function_start_addresses_count; i++)
421 // printf ("0x%012llx\n", baton->function_start_addresses[i]);
424 // printf ("symbol table names & addresses\n");
425 // for (int i = 0; i < baton->symbols_count; i++)
427 // printf ("0x%012llx %s\n", baton->symbols[i].file_address, baton->symbols[i].name);
433 print_encoding_x86_64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
435 int mode = encoding & UNWIND_X86_64_MODE_MASK;
438 case UNWIND_X86_64_MODE_RBP_FRAME:
440 printf ("frame func: CFA is rbp+%d ", 16);
441 printf (" rip=[CFA-8] rbp=[CFA-16]");
442 uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
444 uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
447 saved_registers_offset += 2;
449 for (int i = 0; i < 5; i++)
451 switch (saved_registers_locations & 0x7)
453 case UNWIND_X86_64_REG_NONE:
455 case UNWIND_X86_64_REG_RBX:
456 printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
458 case UNWIND_X86_64_REG_R12:
459 printf (" r12=[CFA-%d]", saved_registers_offset * 8);
461 case UNWIND_X86_64_REG_R13:
462 printf (" r13=[CFA-%d]", saved_registers_offset * 8);
464 case UNWIND_X86_64_REG_R14:
465 printf (" r14=[CFA-%d]", saved_registers_offset * 8);
467 case UNWIND_X86_64_REG_R15:
468 printf (" r15=[CFA-%d]", saved_registers_offset * 8);
471 saved_registers_offset--;
472 saved_registers_locations >>= 3;
477 case UNWIND_X86_64_MODE_STACK_IND:
478 case UNWIND_X86_64_MODE_STACK_IMMD:
480 uint32_t stack_size = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
481 uint32_t register_count = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
482 uint32_t permutation = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
484 if (mode == UNWIND_X86_64_MODE_STACK_IND && function_start)
486 uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
488 // offset into the function instructions; 0 == beginning of first instruction
489 uint32_t offset_to_subl_insn = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
491 stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
493 stack_size += stack_adjust * 8;
495 printf ("large stack ");
498 if (mode == UNWIND_X86_64_MODE_STACK_IND)
500 printf ("frameless function: stack size %d, register count %d ", stack_size * 8, register_count);
504 printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
507 if (register_count == 0)
509 printf (" no registers saved");
514 // We need to include (up to) 6 registers in 10 bits.
515 // That would be 18 bits if we just used 3 bits per reg to indicate
516 // the order they're saved on the stack.
518 // This is done with Lehmer code permutation, e.g. see
519 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
522 // This decodes the variable-base number in the 10 bits
523 // and gives us the Lehmer code sequence which can then
526 switch (register_count)
529 permunreg[0] = permutation/120; // 120 == 5!
530 permutation -= (permunreg[0]*120);
531 permunreg[1] = permutation/24; // 24 == 4!
532 permutation -= (permunreg[1]*24);
533 permunreg[2] = permutation/6; // 6 == 3!
534 permutation -= (permunreg[2]*6);
535 permunreg[3] = permutation/2; // 2 == 2!
536 permutation -= (permunreg[3]*2);
537 permunreg[4] = permutation; // 1 == 1!
541 permunreg[0] = permutation/120;
542 permutation -= (permunreg[0]*120);
543 permunreg[1] = permutation/24;
544 permutation -= (permunreg[1]*24);
545 permunreg[2] = permutation/6;
546 permutation -= (permunreg[2]*6);
547 permunreg[3] = permutation/2;
548 permutation -= (permunreg[3]*2);
549 permunreg[4] = permutation;
552 permunreg[0] = permutation/60;
553 permutation -= (permunreg[0]*60);
554 permunreg[1] = permutation/12;
555 permutation -= (permunreg[1]*12);
556 permunreg[2] = permutation/3;
557 permutation -= (permunreg[2]*3);
558 permunreg[3] = permutation;
561 permunreg[0] = permutation/20;
562 permutation -= (permunreg[0]*20);
563 permunreg[1] = permutation/4;
564 permutation -= (permunreg[1]*4);
565 permunreg[2] = permutation;
568 permunreg[0] = permutation/5;
569 permutation -= (permunreg[0]*5);
570 permunreg[1] = permutation;
573 permunreg[0] = permutation;
577 // Decode the Lehmer code for this permutation of
578 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
581 bool used[7] = { false, false, false, false, false, false, false };
582 for (int i = 0; i < register_count; i++)
585 for (int j = 1; j < 7; j++)
587 if (used[j] == false)
589 if (renum == permunreg[i])
601 if (mode == UNWIND_X86_64_MODE_STACK_IND)
603 printf (" CFA is rsp+%d ", stack_size);
607 printf (" CFA is rsp+%d ", stack_size * 8);
610 uint32_t saved_registers_offset = 1;
611 printf (" rip=[CFA-%d]", saved_registers_offset * 8);
612 saved_registers_offset++;
614 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
616 switch (registers[i])
618 case UNWIND_X86_64_REG_NONE:
620 case UNWIND_X86_64_REG_RBX:
621 printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
622 saved_registers_offset++;
624 case UNWIND_X86_64_REG_R12:
625 printf (" r12=[CFA-%d]", saved_registers_offset * 8);
626 saved_registers_offset++;
628 case UNWIND_X86_64_REG_R13:
629 printf (" r13=[CFA-%d]", saved_registers_offset * 8);
630 saved_registers_offset++;
632 case UNWIND_X86_64_REG_R14:
633 printf (" r14=[CFA-%d]", saved_registers_offset * 8);
634 saved_registers_offset++;
636 case UNWIND_X86_64_REG_R15:
637 printf (" r15=[CFA-%d]", saved_registers_offset * 8);
638 saved_registers_offset++;
640 case UNWIND_X86_64_REG_RBP:
641 printf (" rbp=[CFA-%d]", saved_registers_offset * 8);
642 saved_registers_offset++;
652 case UNWIND_X86_64_MODE_DWARF:
654 uint32_t dwarf_offset = encoding & UNWIND_X86_DWARF_SECTION_OFFSET;
655 printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
656 dwarf_offset, dwarf_offset + baton.eh_section_file_address);
662 printf (" no unwind information");
669 print_encoding_i386 (struct baton baton, uint8_t *function_start, uint32_t encoding)
671 int mode = encoding & UNWIND_X86_MODE_MASK;
674 case UNWIND_X86_MODE_EBP_FRAME:
676 printf ("frame func: CFA is ebp+%d ", 8);
677 printf (" eip=[CFA-4] ebp=[CFA-8]");
678 uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_OFFSET);
680 uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
683 saved_registers_offset += 2;
685 for (int i = 0; i < 5; i++)
687 switch (saved_registers_locations & 0x7)
689 case UNWIND_X86_REG_NONE:
691 case UNWIND_X86_REG_EBX:
692 printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
694 case UNWIND_X86_REG_ECX:
695 printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
697 case UNWIND_X86_REG_EDX:
698 printf (" edx=[CFA-%d]", saved_registers_offset * 4);
700 case UNWIND_X86_REG_EDI:
701 printf (" edi=[CFA-%d]", saved_registers_offset * 4);
703 case UNWIND_X86_REG_ESI:
704 printf (" esi=[CFA-%d]", saved_registers_offset * 4);
707 saved_registers_offset--;
708 saved_registers_locations >>= 3;
713 case UNWIND_X86_MODE_STACK_IND:
714 case UNWIND_X86_MODE_STACK_IMMD:
716 uint32_t stack_size = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
717 uint32_t register_count = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
718 uint32_t permutation = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
720 if (mode == UNWIND_X86_MODE_STACK_IND && function_start)
722 uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
724 // offset into the function instructions; 0 == beginning of first instruction
725 uint32_t offset_to_subl_insn = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
727 stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
729 stack_size += stack_adjust * 4;
731 printf ("large stack ");
734 if (mode == UNWIND_X86_MODE_STACK_IND)
736 printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
740 printf ("frameless function: stack size %d, register count %d ", stack_size * 4, register_count);
743 if (register_count == 0)
745 printf (" no registers saved");
750 // We need to include (up to) 6 registers in 10 bits.
751 // That would be 18 bits if we just used 3 bits per reg to indicate
752 // the order they're saved on the stack.
754 // This is done with Lehmer code permutation, e.g. see
755 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
758 // This decodes the variable-base number in the 10 bits
759 // and gives us the Lehmer code sequence which can then
762 switch (register_count)
765 permunreg[0] = permutation/120; // 120 == 5!
766 permutation -= (permunreg[0]*120);
767 permunreg[1] = permutation/24; // 24 == 4!
768 permutation -= (permunreg[1]*24);
769 permunreg[2] = permutation/6; // 6 == 3!
770 permutation -= (permunreg[2]*6);
771 permunreg[3] = permutation/2; // 2 == 2!
772 permutation -= (permunreg[3]*2);
773 permunreg[4] = permutation; // 1 == 1!
777 permunreg[0] = permutation/120;
778 permutation -= (permunreg[0]*120);
779 permunreg[1] = permutation/24;
780 permutation -= (permunreg[1]*24);
781 permunreg[2] = permutation/6;
782 permutation -= (permunreg[2]*6);
783 permunreg[3] = permutation/2;
784 permutation -= (permunreg[3]*2);
785 permunreg[4] = permutation;
788 permunreg[0] = permutation/60;
789 permutation -= (permunreg[0]*60);
790 permunreg[1] = permutation/12;
791 permutation -= (permunreg[1]*12);
792 permunreg[2] = permutation/3;
793 permutation -= (permunreg[2]*3);
794 permunreg[3] = permutation;
797 permunreg[0] = permutation/20;
798 permutation -= (permunreg[0]*20);
799 permunreg[1] = permutation/4;
800 permutation -= (permunreg[1]*4);
801 permunreg[2] = permutation;
804 permunreg[0] = permutation/5;
805 permutation -= (permunreg[0]*5);
806 permunreg[1] = permutation;
809 permunreg[0] = permutation;
813 // Decode the Lehmer code for this permutation of
814 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
817 bool used[7] = { false, false, false, false, false, false, false };
818 for (int i = 0; i < register_count; i++)
821 for (int j = 1; j < 7; j++)
823 if (used[j] == false)
825 if (renum == permunreg[i])
837 if (mode == UNWIND_X86_MODE_STACK_IND)
839 printf (" CFA is esp+%d ", stack_size);
843 printf (" CFA is esp+%d ", stack_size * 4);
846 uint32_t saved_registers_offset = 1;
847 printf (" eip=[CFA-%d]", saved_registers_offset * 4);
848 saved_registers_offset++;
850 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
852 switch (registers[i])
854 case UNWIND_X86_REG_NONE:
856 case UNWIND_X86_REG_EBX:
857 printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
858 saved_registers_offset++;
860 case UNWIND_X86_REG_ECX:
861 printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
862 saved_registers_offset++;
864 case UNWIND_X86_REG_EDX:
865 printf (" edx=[CFA-%d]", saved_registers_offset * 4);
866 saved_registers_offset++;
868 case UNWIND_X86_REG_EDI:
869 printf (" edi=[CFA-%d]", saved_registers_offset * 4);
870 saved_registers_offset++;
872 case UNWIND_X86_REG_ESI:
873 printf (" esi=[CFA-%d]", saved_registers_offset * 4);
874 saved_registers_offset++;
876 case UNWIND_X86_REG_EBP:
877 printf (" ebp=[CFA-%d]", saved_registers_offset * 4);
878 saved_registers_offset++;
888 case UNWIND_X86_MODE_DWARF:
890 uint32_t dwarf_offset = encoding & UNWIND_X86_DWARF_SECTION_OFFSET;
891 printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
892 dwarf_offset, dwarf_offset + baton.eh_section_file_address);
898 printf (" no unwind information");
905 void print_encoding (struct baton baton, uint8_t *function_start, uint32_t encoding)
908 if (baton.cputype == CPU_TYPE_X86_64)
910 print_encoding_x86_64 (baton, function_start, encoding);
912 else if (baton.cputype == CPU_TYPE_I386)
914 print_encoding_i386 (baton, function_start, encoding);
918 printf (" -- unsupported encoding arch -- ");
923 print_function_encoding (struct baton baton, uint32_t idx, uint32_t encoding, uint32_t entry_encoding_index, uint32_t entry_func_offset)
926 char *entry_encoding_index_str = "";
927 if (entry_encoding_index != (uint32_t) -1)
929 asprintf (&entry_encoding_index_str, ", encoding #%d", entry_encoding_index);
933 asprintf (&entry_encoding_index_str, "");
936 uint64_t file_address = baton.first_level_index_entry.functionOffset + entry_func_offset + baton.text_segment_vmaddr;
938 printf (" func [%d] offset %d (file addr 0x%" PRIx64 ")%s, encoding is 0x%x",
939 idx, entry_func_offset,
941 entry_encoding_index_str,
944 struct symbol *symbol = NULL;
945 for (int i = 0; i < baton.symbols_count; i++)
947 if (i == baton.symbols_count - 1 && baton.symbols[i].file_address <= file_address)
949 symbol = &(baton.symbols[i]);
954 if (baton.symbols[i].file_address <= file_address && baton.symbols[i + 1].file_address > file_address)
956 symbol = &(baton.symbols[i]);
965 int offset = file_address - symbol->file_address;
967 // FIXME this is a poor heuristic - if we're greater than 16 bytes past the
968 // start of the function, this is the unwind info for a stripped function.
969 // In reality the compact unwind entry may not line up exactly with the
973 printf ("name: %s", symbol->name);
976 printf (" + %d", offset);
982 print_encoding (baton, baton.mach_header_start + baton.first_level_index_entry.functionOffset + baton.text_section_file_offset + entry_func_offset, encoding);
984 bool has_lsda = encoding & UNWIND_HAS_LSDA;
988 uint32_t func_offset = entry_func_offset + baton.first_level_index_entry.functionOffset;
990 int lsda_entry_number = -1;
993 uint32_t high = (baton.lsda_array_end - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
997 uint32_t mid = (low + high) / 2;
999 uint8_t *mid_lsda_entry_addr = (baton.lsda_array_start + (mid * sizeof (struct unwind_info_section_header_lsda_index_entry)));
1000 struct unwind_info_section_header_lsda_index_entry mid_lsda_entry;
1001 memcpy (&mid_lsda_entry, mid_lsda_entry_addr, sizeof (struct unwind_info_section_header_lsda_index_entry));
1002 if (mid_lsda_entry.functionOffset == func_offset)
1004 lsda_entry_number = (mid_lsda_entry_addr - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
1007 else if (mid_lsda_entry.functionOffset < func_offset)
1017 if (lsda_entry_number != -1)
1019 printf (", LSDA entry #%d", lsda_entry_number);
1023 printf (", LSDA entry not found");
1027 uint32_t pers_idx = EXTRACT_BITS (encoding, UNWIND_PERSONALITY_MASK);
1030 pers_idx--; // Change 1-based to 0-based index
1031 printf (", personality entry #%d", pers_idx);
1038 print_second_level_index_regular (struct baton baton)
1040 uint8_t *page_entries = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset + baton.regular_second_level_page_header.entryPageOffset;
1041 uint32_t entries_count = baton.regular_second_level_page_header.entryCount;
1043 uint8_t *offset = page_entries;
1046 while (idx < entries_count)
1048 uint32_t func_offset = *((uint32_t *) (offset));
1049 uint32_t encoding = *((uint32_t *) (offset + 4));
1051 // UNWIND_SECOND_LEVEL_REGULAR entries have a funcOffset which includes the
1052 // functionOffset from the containing index table already. UNWIND_SECOND_LEVEL_COMPRESSED
1053 // entries only have the offset from the containing index table functionOffset.
1054 // So strip off the containing index table functionOffset value here so they can
1055 // be treated the same at the lower layers.
1057 print_function_encoding (baton, idx, encoding, (uint32_t) -1, func_offset - baton.first_level_index_entry.functionOffset);
1064 print_second_level_index_compressed (struct baton baton)
1066 uint8_t *this_index = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
1067 uint8_t *start_of_entries = this_index + baton.compressed_second_level_page_header.entryPageOffset;
1068 uint8_t *offset = start_of_entries;
1069 for (uint16_t idx = 0; idx < baton.compressed_second_level_page_header.entryCount; idx++)
1071 uint32_t entry = *((uint32_t*) offset);
1075 uint32_t entry_encoding_index = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
1076 uint32_t entry_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry);
1078 if (entry_encoding_index < baton.unwind_header.commonEncodingsArrayCount)
1080 // encoding is in common table in section header
1081 encoding = *((uint32_t*) (baton.compact_unwind_start + baton.unwind_header.commonEncodingsArraySectionOffset + (entry_encoding_index * sizeof (uint32_t))));
1085 // encoding is in page specific table
1086 uint32_t page_encoding_index = entry_encoding_index - baton.unwind_header.commonEncodingsArrayCount;
1087 encoding = *((uint32_t*) (this_index + baton.compressed_second_level_page_header.encodingsPageOffset + (page_encoding_index * sizeof (uint32_t))));
1091 print_function_encoding (baton, idx, encoding, entry_encoding_index, entry_func_offset);
1096 print_second_level_index (struct baton baton)
1098 uint8_t *index_start = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
1100 if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_REGULAR)
1102 struct unwind_info_regular_second_level_page_header header;
1103 memcpy (&header, index_start, sizeof (struct unwind_info_regular_second_level_page_header));
1104 printf (" UNWIND_SECOND_LEVEL_REGULAR #%d entryPageOffset %d, entryCount %d\n", baton.current_index_table_number, header.entryPageOffset, header.entryCount);
1105 baton.regular_second_level_page_header = header;
1106 print_second_level_index_regular (baton);
1109 if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_COMPRESSED)
1111 struct unwind_info_compressed_second_level_page_header header;
1112 memcpy (&header, index_start, sizeof (struct unwind_info_compressed_second_level_page_header));
1113 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);
1114 baton.compressed_second_level_page_header = header;
1115 print_second_level_index_compressed (baton);
1121 print_index_sections (struct baton baton)
1123 uint8_t *index_section_offset = baton.compact_unwind_start + baton.unwind_header.indexSectionOffset;
1124 uint32_t index_count = baton.unwind_header.indexCount;
1126 uint32_t cur_idx = 0;
1128 uint8_t *offset = index_section_offset;
1129 while (cur_idx < index_count)
1131 baton.current_index_table_number = cur_idx;
1132 struct unwind_info_section_header_index_entry index_entry;
1133 memcpy (&index_entry, offset, sizeof (struct unwind_info_section_header_index_entry));
1134 printf ("index section #%d: functionOffset %d, secondLevelPagesSectionOffset %d, lsdaIndexArraySectionOffset %d\n", cur_idx, index_entry.functionOffset, index_entry.secondLevelPagesSectionOffset, index_entry.lsdaIndexArraySectionOffset);
1136 // secondLevelPagesSectionOffset == 0 means this is a sentinel entry
1137 if (index_entry.secondLevelPagesSectionOffset != 0)
1139 struct unwind_info_section_header_index_entry next_index_entry;
1140 memcpy (&next_index_entry, offset + sizeof (struct unwind_info_section_header_index_entry), sizeof (struct unwind_info_section_header_index_entry));
1142 baton.lsda_array_start = baton.compact_unwind_start + index_entry.lsdaIndexArraySectionOffset;
1143 baton.lsda_array_end = baton.compact_unwind_start + next_index_entry.lsdaIndexArraySectionOffset;
1145 uint8_t *lsda_entry_offset = baton.lsda_array_start;
1146 uint32_t lsda_count = 0;
1147 while (lsda_entry_offset < baton.lsda_array_end)
1149 struct unwind_info_section_header_lsda_index_entry lsda_entry;
1150 memcpy (&lsda_entry, lsda_entry_offset, sizeof (struct unwind_info_section_header_lsda_index_entry));
1151 uint64_t function_file_address = baton.first_level_index_entry.functionOffset + lsda_entry.functionOffset + baton.text_segment_vmaddr;
1152 uint64_t lsda_file_address = lsda_entry.lsdaOffset + baton.text_segment_vmaddr;
1153 printf (" LSDA [%d] functionOffset %d (%d) (file address 0x%" PRIx64 "), lsdaOffset %d (file address 0x%" PRIx64 ")\n",
1154 lsda_count, lsda_entry.functionOffset,
1155 lsda_entry.functionOffset - index_entry.functionOffset,
1156 function_file_address,
1157 lsda_entry.lsdaOffset, lsda_file_address);
1159 lsda_entry_offset += sizeof (struct unwind_info_section_header_lsda_index_entry);
1164 baton.first_level_index_entry = index_entry;
1165 print_second_level_index (baton);
1171 offset += sizeof (struct unwind_info_section_header_index_entry);
1175 int main (int argc, char **argv)
1178 char *file = argv[0];
1181 int fd = open (file, O_RDONLY);
1184 printf ("Failed to open '%s'\n", file);
1188 uint8_t *file_mem = (uint8_t*) mmap (0, st.st_size, PROT_READ, MAP_PRIVATE | MAP_FILE, fd, 0);
1189 if (file_mem == MAP_FAILED)
1191 printf ("Failed to mmap() '%s'\n", file);
1194 FILE *f = fopen ("a.out", "r");
1197 baton.mach_header_start = file_mem;
1198 baton.symbols = NULL;
1199 baton.symbols_count = 0;
1200 baton.function_start_addresses = NULL;
1201 baton.function_start_addresses_count = 0;
1203 scan_macho_load_commands (&baton);
1205 if (baton.compact_unwind_start == NULL)
1207 printf ("could not find __TEXT,__unwind_info section\n");
1212 struct unwind_info_section_header header;
1213 memcpy (&header, baton.compact_unwind_start, sizeof (struct unwind_info_section_header));
1214 printf ("Header:\n");
1215 printf (" version %u\n", header.version);
1216 printf (" commonEncodingsArraySectionOffset is %d\n", header.commonEncodingsArraySectionOffset);
1217 printf (" commonEncodingsArrayCount is %d\n", header.commonEncodingsArrayCount);
1218 printf (" personalityArraySectionOffset is %d\n", header.personalityArraySectionOffset);
1219 printf (" personalityArrayCount is %d\n", header.personalityArrayCount);
1220 printf (" indexSectionOffset is %d\n", header.indexSectionOffset);
1221 printf (" indexCount is %d\n", header.indexCount);
1223 uint8_t *common_encodings = baton.compact_unwind_start + header.commonEncodingsArraySectionOffset;
1224 uint32_t encoding_idx = 0;
1225 while (encoding_idx < header.commonEncodingsArrayCount)
1227 uint32_t encoding = *((uint32_t*) common_encodings);
1228 printf (" Common Encoding [%d]: 0x%x ", encoding_idx, encoding);
1229 print_encoding (baton, NULL, encoding);
1231 common_encodings += sizeof (uint32_t);
1235 uint8_t *pers_arr = baton.compact_unwind_start + header.personalityArraySectionOffset;
1236 uint32_t pers_idx = 0;
1237 while (pers_idx < header.personalityArrayCount)
1239 int32_t pers_delta = *((int32_t*) (baton.compact_unwind_start + header.personalityArraySectionOffset + (pers_idx * sizeof (uint32_t))));
1240 printf (" Personality [%d]: personality function ptr @ offset %d (file address 0x%" PRIx64 ")\n", pers_idx, pers_delta, baton.text_segment_vmaddr + pers_delta);
1242 pers_arr += sizeof (uint32_t);
1247 baton.unwind_header = header;
1249 print_index_sections (baton);