]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/compact-unwind/compact-unwind-dumper.c
Vendor import of lldb release_39 branch r276489:
[FreeBSD/FreeBSD.git] / tools / compact-unwind / compact-unwind-dumper.c
1 #include <stdint.h>
2 #include <mach-o/loader.h>
3 #include <mach-o/compact_unwind_encoding.h>
4 #include <mach/machine.h>
5 #include <stdlib.h>
6 #include <stdbool.h>
7 #include <string.h>
8 #include <fcntl.h>
9 #include <sys/types.h>
10 #include <sys/mman.h>
11 #include <sys/errno.h>
12 #include <sys/stat.h>
13 #include <inttypes.h>
14 #include <stdio.h>
15 #include <mach-o/nlist.h>
16
17
18 enum {
19     UNWIND_ARM64_MODE_MASK                     = 0x0F000000,
20     UNWIND_ARM64_MODE_FRAMELESS                = 0x02000000,
21     UNWIND_ARM64_MODE_DWARF                    = 0x03000000,
22     UNWIND_ARM64_MODE_FRAME                    = 0x04000000,
23
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,
33
34     UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK     = 0x00FFF000,
35     UNWIND_ARM64_DWARF_SECTION_OFFSET          = 0x00FFFFFF,
36 };
37
38 enum {
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,
43
44   UNWIND_ARM_FRAME_STACK_ADJUST_MASK           = 0x00C00000,
45
46   UNWIND_ARM_FRAME_FIRST_PUSH_R4               = 0x00000001,
47   UNWIND_ARM_FRAME_FIRST_PUSH_R5               = 0x00000002,
48   UNWIND_ARM_FRAME_FIRST_PUSH_R6               = 0x00000004,
49
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,
55
56   UNWIND_ARM_FRAME_D_REG_COUNT_MASK            = 0x00000700,
57
58   UNWIND_ARM_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
59 };
60
61 #define EXTRACT_BITS(value, mask) \
62         ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
63
64
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
69 // correctly.
70
71 struct symbol
72 {
73     uint64_t file_address;
74     const char *name;
75 };
76
77 int
78 symbol_compare (const void *a, const void *b)
79 {
80     return (int) ((struct symbol *)a)->file_address - ((struct symbol *)b)->file_address;
81 }
82
83 struct baton
84 {
85     cpu_type_t cputype;
86
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
89
90     int addr_size;                   // 4 or 8 bytes, the size of addresses in this file
91
92     uint64_t text_segment_vmaddr;    // __TEXT segment vmaddr
93     uint64_t text_segment_file_offset;
94
95     uint64_t text_section_vmaddr;    // __TEXT,__text section vmaddr
96     uint64_t text_section_file_offset;
97
98     uint64_t eh_section_file_address; // the file address of the __TEXT,__eh_frame section
99
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
102
103     struct symbol *symbols;
104     int    symbols_count;
105
106     uint64_t *function_start_addresses;
107     int function_start_addresses_count;
108
109     int current_index_table_number;
110
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;
115 };
116
117
118 uint64_t 
119 read_leb128 (uint8_t **offset)
120 {
121     uint64_t result = 0;
122     int shift = 0;
123     while (1) 
124     {
125         uint8_t byte = **offset;
126         *offset = *offset + 1;
127         result |= (byte & 0x7f) << shift;
128         if ((byte & 0x80) == 0)
129             break;
130         shift += 7;
131     }
132
133     return result;
134 }
135
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.
139
140 static void
141 scan_macho_load_commands (struct baton *baton)
142 {
143     struct symtab_command symtab_cmd;
144     uint64_t linkedit_segment_vmaddr;
145     uint64_t linkedit_segment_file_offset;
146
147     baton->compact_unwind_start = 0;
148
149     uint32_t *magic = (uint32_t *) baton->mach_header_start;
150
151     if (*magic != MH_MAGIC && *magic != MH_MAGIC_64)
152     {
153         printf ("Unexpected magic number 0x%x in header, exiting.", *magic);
154         exit (1);
155     }
156
157     bool is_64bit = false;
158     if (*magic == MH_MAGIC_64)
159         is_64bit = true;
160
161     uint8_t *offset = baton->mach_header_start;
162
163     struct mach_header mh;
164     memcpy (&mh, offset, sizeof (struct mach_header));
165     if (is_64bit)
166         offset += sizeof (struct mach_header_64);
167     else
168         offset += sizeof (struct mach_header);
169
170     if (is_64bit)
171         baton->addr_size = 8;
172     else
173         baton->addr_size = 4;
174
175     baton->cputype = mh.cputype;
176
177     uint8_t *start_of_load_commands = offset;
178
179     uint32_t cur_cmd = 0;
180     while (cur_cmd < mh.ncmds && (offset - start_of_load_commands) < mh.sizeofcmds)
181     {
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;
186
187         if (*lc_cmd == LC_SEGMENT || *lc_cmd == LC_SEGMENT_64)
188         {
189             char segment_name[17];
190             segment_name[0] = '\0';
191             uint32_t nsects = 0;
192             uint64_t segment_offset = 0;
193             uint64_t segment_vmaddr = 0;
194
195             if (*lc_cmd == LC_SEGMENT_64)
196             {
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';
201                 nsects = seg.nsects;
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)
206                 {
207                     printf ("Segment '%s' is encrypted.\n", segment_name);
208                 }
209             }
210
211             if (*lc_cmd == LC_SEGMENT)
212             {
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';
217                 nsects = seg.nsects;
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)
222                 {
223                     printf ("Segment '%s' is encrypted.\n", segment_name);
224                 }
225             }
226
227             if (nsects != 0 && strcmp (segment_name, "__TEXT") == 0)
228             {
229                 baton->text_segment_vmaddr = segment_vmaddr;
230                 baton->text_segment_file_offset = segment_offset;
231
232                 uint32_t current_sect = 0;
233                 while (current_sect < nsects && (offset - start_of_this_load_cmd) < *lc_cmdsize)
234                 {
235                     char sect_name[17];
236                     memcpy (&sect_name, offset, 16);
237                     sect_name[16] = '\0';
238                     if (strcmp (sect_name, "__unwind_info") == 0)
239                     {
240                         if (is_64bit)
241                         {
242                             struct section_64 sect;
243                             memset (&sect, 0, sizeof (struct section_64));
244                             memcpy (&sect, offset, sizeof (struct section_64));
245                             baton->compact_unwind_start = baton->mach_header_start + sect.offset;
246                         }
247                         else
248                         {
249                             struct section sect;
250                             memset (&sect, 0, sizeof (struct section));
251                             memcpy (&sect, offset, sizeof (struct section));
252                             baton->compact_unwind_start = baton->mach_header_start + sect.offset;
253                         }
254                     }
255                     if (strcmp (sect_name, "__eh_frame") == 0)
256                     {
257                         if (is_64bit)
258                         {
259                             struct section_64 sect;
260                             memset (&sect, 0, sizeof (struct section_64));
261                             memcpy (&sect, offset, sizeof (struct section_64));
262                             baton->eh_section_file_address = sect.addr;
263                         }
264                         else
265                         {
266                             struct section sect;
267                             memset (&sect, 0, sizeof (struct section));
268                             memcpy (&sect, offset, sizeof (struct section));
269                             baton->eh_section_file_address = sect.addr;
270                         }
271                     }
272                     if (strcmp (sect_name, "__text") == 0)
273                     {
274                         if (is_64bit)
275                         {
276                             struct section_64 sect;
277                             memset (&sect, 0, sizeof (struct section_64));
278                             memcpy (&sect, offset, sizeof (struct section_64));
279                             baton->text_section_vmaddr = sect.addr;
280                             baton->text_section_file_offset = sect.offset;
281                         }
282                         else
283                         {
284                             struct section sect;
285                             memset (&sect, 0, sizeof (struct section));
286                             memcpy (&sect, offset, sizeof (struct section));
287                             baton->text_section_vmaddr = sect.addr;
288                         }
289                     }
290                     if (is_64bit)
291                     {
292                         offset += sizeof (struct section_64);
293                     }
294                     else
295                     {
296                         offset += sizeof (struct section);
297                     }
298                 }
299             }
300
301             if (strcmp (segment_name, "__LINKEDIT") == 0)
302             {
303                 linkedit_segment_vmaddr = segment_vmaddr;
304                 linkedit_segment_file_offset = segment_offset;
305             }
306         }
307
308         if (*lc_cmd == LC_SYMTAB)
309         {
310             memcpy (&symtab_cmd, offset, sizeof (struct symtab_command));
311         }
312
313         if (*lc_cmd == LC_DYSYMTAB)
314         {
315             struct dysymtab_command dysymtab_cmd;
316             memcpy (&dysymtab_cmd, offset, sizeof (struct dysymtab_command));
317
318             int nlist_size = 12;
319             if (is_64bit)
320                 nlist_size = 16;
321
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;
327
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;
332
333             for (int i = 0; i < local_syms_count; i++)
334             {
335                 struct nlist_64 nlist;
336                 memset (&nlist, 0, sizeof (struct nlist_64));
337                 if (is_64bit)
338                 {
339                     memcpy (&nlist, local_syms + (i * nlist_size), sizeof (struct nlist_64));
340                 }
341                 else
342                 {
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;
351                 }
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)
357                 {
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++;
363                 }
364             }
365
366             for (int i = 0; i < exported_syms_count; i++)
367             {
368                 struct nlist_64 nlist;
369                 memset (&nlist, 0, sizeof (struct nlist_64));
370                 if (is_64bit)
371                 {
372                     memcpy (&nlist, exported_syms + (i * nlist_size), sizeof (struct nlist_64));
373                 }
374                 else
375                 {
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;
383                 }
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)
389                 {
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++;
395                 }
396             }
397
398             qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
399         }
400
401         if (*lc_cmd == LC_FUNCTION_STARTS)
402         {
403             struct linkedit_data_command function_starts_cmd;
404             memcpy (&function_starts_cmd, offset, sizeof (struct linkedit_data_command));
405
406             uint8_t *funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
407             uint8_t *function_end = funcstarts_offset + function_starts_cmd.datasize;
408             int count = 0;
409
410             while (funcstarts_offset < function_end)
411             {
412                 if (read_leb128 (&funcstarts_offset) != 0)
413                 {
414                     count++;
415                 }
416             }
417
418             baton->function_start_addresses = (uint64_t *) malloc (sizeof (uint64_t) * count);
419             baton->function_start_addresses_count = count;
420
421             funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
422             uint64_t current_pc = baton->text_segment_vmaddr;
423             int i = 0;
424             while (funcstarts_offset < function_end)
425             {
426                 uint64_t func_start = read_leb128 (&funcstarts_offset);
427                 if (func_start != 0)
428                 {
429                     current_pc += func_start;
430                     baton->function_start_addresses[i++] = current_pc;
431                 }
432             }
433         }
434
435         offset = start_of_this_load_cmd + *lc_cmdsize;
436         cur_cmd++;
437     }
438
439
440     // Augment the symbol table with the function starts table -- adding symbol entries
441     // for functions that were stripped.
442
443     int unnamed_functions_to_add = 0;
444     for (int i = 0; i < baton->function_start_addresses_count; i++)
445     {
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);
451         if (sym == NULL)
452             unnamed_functions_to_add++;
453     }
454
455     baton->symbols = (struct symbol *) realloc (baton->symbols, sizeof (struct symbol) * (baton->symbols_count + unnamed_functions_to_add));
456
457     int current_unnamed_symbol = 1;
458     int number_symbols_added = 0;
459     for (int i = 0; i < baton->function_start_addresses_count; i++)
460     {
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);
466         if (sym == NULL)
467         {
468             char *name;
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++;
473         }
474     }
475     baton->symbols_count += number_symbols_added;
476     qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
477
478
479 //    printf ("function start addresses\n");
480 //    for (int i = 0; i < baton->function_start_addresses_count; i++)
481 //    {
482 //        printf ("0x%012llx\n", baton->function_start_addresses[i]);
483 //    }
484
485 //    printf ("symbol table names & addresses\n");
486 //    for (int i = 0; i < baton->symbols_count; i++)
487 //    {
488 //        printf ("0x%012llx %s\n", baton->symbols[i].file_address, baton->symbols[i].name);
489 //    }
490
491 }
492
493 void
494 print_encoding_x86_64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
495 {
496     int mode = encoding & UNWIND_X86_64_MODE_MASK;
497     switch (mode)
498     {
499         case UNWIND_X86_64_MODE_RBP_FRAME:
500         {
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);
504
505             uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
506
507
508             saved_registers_offset += 2;
509
510             for (int i = 0; i < 5; i++)
511             {
512                 switch (saved_registers_locations & 0x7)
513                 {
514                     case UNWIND_X86_64_REG_NONE:
515                         break;
516                     case UNWIND_X86_64_REG_RBX:
517                         printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
518                         break;
519                     case UNWIND_X86_64_REG_R12:
520                         printf (" r12=[CFA-%d]", saved_registers_offset * 8);
521                         break;
522                     case UNWIND_X86_64_REG_R13:
523                         printf (" r13=[CFA-%d]", saved_registers_offset * 8);
524                         break;
525                     case UNWIND_X86_64_REG_R14:
526                         printf (" r14=[CFA-%d]", saved_registers_offset * 8);
527                         break;
528                     case UNWIND_X86_64_REG_R15:
529                         printf (" r15=[CFA-%d]", saved_registers_offset * 8);
530                         break;
531                 }
532                 saved_registers_offset--;
533                 saved_registers_locations >>= 3;
534             }
535         }
536         break;
537
538         case UNWIND_X86_64_MODE_STACK_IND:
539         case UNWIND_X86_64_MODE_STACK_IMMD:
540         {
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);
544
545             if (mode == UNWIND_X86_64_MODE_STACK_IND && function_start)
546             {
547                 uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
548
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);
551
552                 stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
553
554                 stack_size += stack_adjust * 8;
555
556                 printf ("large stack ");
557             }
558             
559             if (mode == UNWIND_X86_64_MODE_STACK_IND)
560             {
561                 printf ("frameless function: stack size %d, register count %d ", stack_size * 8, register_count);
562             }
563             else
564             {
565                 printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
566             }
567
568             if (register_count == 0)
569             {
570                 printf (" no registers saved");
571             }
572             else
573             {
574
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. 
578                 //
579                 // This is done with Lehmer code permutation, e.g. see
580                 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
581                 int permunreg[6];
582
583                 // This decodes the variable-base number in the 10 bits
584                 // and gives us the Lehmer code sequence which can then
585                 // be decoded.
586
587                 switch (register_count) 
588                 {
589                     case 6:
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!
599                         permunreg[5] = 0;
600                         break;
601                     case 5:
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;
611                         break;
612                     case 4:
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;
620                         break;
621                     case 3:
622                         permunreg[0] = permutation/20;
623                         permutation -= (permunreg[0]*20);
624                         permunreg[1] = permutation/4;
625                         permutation -= (permunreg[1]*4);
626                         permunreg[2] = permutation;
627                         break;
628                     case 2:
629                         permunreg[0] = permutation/5;
630                         permutation -= (permunreg[0]*5);
631                         permunreg[1] = permutation;
632                         break;
633                     case 1:
634                         permunreg[0] = permutation;
635                         break;
636                 }
637                 
638                 // Decode the Lehmer code for this permutation of
639                 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
640
641                 int registers[6];
642                 bool used[7] = { false, false, false, false, false, false, false };
643                 for (int i = 0; i < register_count; i++)
644                 {
645                     int renum = 0;
646                     for (int j = 1; j < 7; j++)
647                     {
648                         if (used[j] == false)
649                         {
650                             if (renum == permunreg[i])
651                             {
652                                 registers[i] = j;
653                                 used[j] = true;
654                                 break;
655                             }
656                             renum++;
657                         }
658                     }
659                 }
660
661
662                 if (mode == UNWIND_X86_64_MODE_STACK_IND)
663                 {
664                     printf (" CFA is rsp+%d ", stack_size);
665                 }
666                 else
667                 {
668                     printf (" CFA is rsp+%d ", stack_size * 8);
669                 }
670
671                 uint32_t saved_registers_offset = 1;
672                 printf (" rip=[CFA-%d]", saved_registers_offset * 8);
673                 saved_registers_offset++;
674
675                 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
676                 {
677                     switch (registers[i])
678                     {
679                         case UNWIND_X86_64_REG_NONE:
680                             break;
681                         case UNWIND_X86_64_REG_RBX:
682                             printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
683                             saved_registers_offset++;
684                             break;
685                         case UNWIND_X86_64_REG_R12:
686                             printf (" r12=[CFA-%d]", saved_registers_offset * 8);
687                             saved_registers_offset++;
688                             break;
689                         case UNWIND_X86_64_REG_R13:
690                             printf (" r13=[CFA-%d]", saved_registers_offset * 8);
691                             saved_registers_offset++;
692                             break;
693                         case UNWIND_X86_64_REG_R14:
694                             printf (" r14=[CFA-%d]", saved_registers_offset * 8);
695                             saved_registers_offset++;
696                             break;
697                         case UNWIND_X86_64_REG_R15:
698                             printf (" r15=[CFA-%d]", saved_registers_offset * 8);
699                             saved_registers_offset++;
700                             break;
701                         case UNWIND_X86_64_REG_RBP:
702                             printf (" rbp=[CFA-%d]", saved_registers_offset * 8);
703                             saved_registers_offset++;
704                             break;
705                     }
706                 }
707
708             }
709
710         }
711         break;
712
713         case UNWIND_X86_64_MODE_DWARF:
714         {
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);
718         }
719         break;
720
721         case 0:
722         {
723             printf (" no unwind information");
724         }
725         break;
726     }
727 }
728
729 void
730 print_encoding_i386 (struct baton baton, uint8_t *function_start, uint32_t encoding)
731 {
732     int mode = encoding & UNWIND_X86_MODE_MASK;
733     switch (mode)
734     {
735         case UNWIND_X86_MODE_EBP_FRAME:
736         {
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);
740
741             uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
742
743
744             saved_registers_offset += 2;
745
746             for (int i = 0; i < 5; i++)
747             {
748                 switch (saved_registers_locations & 0x7)
749                 {
750                     case UNWIND_X86_REG_NONE:
751                         break;
752                     case UNWIND_X86_REG_EBX:
753                         printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
754                         break;
755                     case UNWIND_X86_REG_ECX:
756                         printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
757                         break;
758                     case UNWIND_X86_REG_EDX:
759                         printf (" edx=[CFA-%d]", saved_registers_offset * 4);
760                         break;
761                     case UNWIND_X86_REG_EDI:
762                         printf (" edi=[CFA-%d]", saved_registers_offset * 4);
763                         break;
764                     case UNWIND_X86_REG_ESI:
765                         printf (" esi=[CFA-%d]", saved_registers_offset * 4);
766                         break;
767                 }
768                 saved_registers_offset--;
769                 saved_registers_locations >>= 3;
770             }
771         }
772         break;
773
774         case UNWIND_X86_MODE_STACK_IND:
775         case UNWIND_X86_MODE_STACK_IMMD:
776         {
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);
780
781             if (mode == UNWIND_X86_MODE_STACK_IND && function_start)
782             {
783                 uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
784
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);
787
788                 stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
789
790                 stack_size += stack_adjust * 4;
791
792                 printf ("large stack ");
793             }
794             
795             if (mode == UNWIND_X86_MODE_STACK_IND)
796             {
797                 printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
798             }
799             else
800             {
801                 printf ("frameless function: stack size %d, register count %d ", stack_size * 4, register_count);
802             }
803
804             if (register_count == 0)
805             {
806                 printf (" no registers saved");
807             }
808             else
809             {
810
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. 
814                 //
815                 // This is done with Lehmer code permutation, e.g. see
816                 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
817                 int permunreg[6];
818
819                 // This decodes the variable-base number in the 10 bits
820                 // and gives us the Lehmer code sequence which can then
821                 // be decoded.
822
823                 switch (register_count) 
824                 {
825                     case 6:
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!
835                         permunreg[5] = 0;
836                         break;
837                     case 5:
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;
847                         break;
848                     case 4:
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;
856                         break;
857                     case 3:
858                         permunreg[0] = permutation/20;
859                         permutation -= (permunreg[0]*20);
860                         permunreg[1] = permutation/4;
861                         permutation -= (permunreg[1]*4);
862                         permunreg[2] = permutation;
863                         break;
864                     case 2:
865                         permunreg[0] = permutation/5;
866                         permutation -= (permunreg[0]*5);
867                         permunreg[1] = permutation;
868                         break;
869                     case 1:
870                         permunreg[0] = permutation;
871                         break;
872                 }
873                 
874                 // Decode the Lehmer code for this permutation of
875                 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
876
877                 int registers[6];
878                 bool used[7] = { false, false, false, false, false, false, false };
879                 for (int i = 0; i < register_count; i++)
880                 {
881                     int renum = 0;
882                     for (int j = 1; j < 7; j++)
883                     {
884                         if (used[j] == false)
885                         {
886                             if (renum == permunreg[i])
887                             {
888                                 registers[i] = j;
889                                 used[j] = true;
890                                 break;
891                             }
892                             renum++;
893                         }
894                     }
895                 }
896
897
898                 if (mode == UNWIND_X86_MODE_STACK_IND)
899                 {
900                     printf (" CFA is esp+%d ", stack_size);
901                 }
902                 else
903                 {
904                     printf (" CFA is esp+%d ", stack_size * 4);
905                 }
906
907                 uint32_t saved_registers_offset = 1;
908                 printf (" eip=[CFA-%d]", saved_registers_offset * 4);
909                 saved_registers_offset++;
910
911                 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
912                 {
913                     switch (registers[i])
914                     {
915                         case UNWIND_X86_REG_NONE:
916                             break;
917                         case UNWIND_X86_REG_EBX:
918                             printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
919                             saved_registers_offset++;
920                             break;
921                         case UNWIND_X86_REG_ECX:
922                             printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
923                             saved_registers_offset++;
924                             break;
925                         case UNWIND_X86_REG_EDX:
926                             printf (" edx=[CFA-%d]", saved_registers_offset * 4);
927                             saved_registers_offset++;
928                             break;
929                         case UNWIND_X86_REG_EDI:
930                             printf (" edi=[CFA-%d]", saved_registers_offset * 4);
931                             saved_registers_offset++;
932                             break;
933                         case UNWIND_X86_REG_ESI:
934                             printf (" esi=[CFA-%d]", saved_registers_offset * 4);
935                             saved_registers_offset++;
936                             break;
937                         case UNWIND_X86_REG_EBP:
938                             printf (" ebp=[CFA-%d]", saved_registers_offset * 4);
939                             saved_registers_offset++;
940                             break;
941                     }
942                 }
943
944             }
945
946         }
947         break;
948
949         case UNWIND_X86_MODE_DWARF:
950         {
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);
954         }
955         break;
956
957         case 0:
958         {
959             printf (" no unwind information");
960         }
961         break;
962     }
963 }
964
965 void
966 print_encoding_arm64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
967 {
968     const int wordsize = 8;
969     int mode = encoding & UNWIND_ARM64_MODE_MASK;
970     switch (mode)
971     {
972         case UNWIND_ARM64_MODE_FRAME:
973         {
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)
979             {
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++;
986             }
987             if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR)
988             {
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++;
995             }
996             if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR)
997             {
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++;
1004             }
1005             if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR)
1006             {
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++;
1013             }
1014             if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR)
1015             {
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++;
1022             }
1023             if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR)
1024             {
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++;
1031             }
1032             if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR)
1033             {
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++;
1040             }
1041             if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR)
1042             {
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++;
1049             }
1050             if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR)
1051             {
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++;
1058             }
1059
1060         }
1061         break;
1062
1063         case UNWIND_ARM64_MODE_FRAMELESS:
1064         {
1065             uint32_t stack_size = encoding & UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK;
1066             printf ("frameless function: stack size %d ", stack_size * 16);
1067
1068         }
1069         break;
1070
1071         case UNWIND_ARM64_MODE_DWARF:
1072         {
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);
1076         }
1077         break;
1078
1079         case 0:
1080         {
1081             printf (" no unwind information");
1082         }
1083         break;
1084     }
1085 }
1086
1087 void
1088 print_encoding_armv7 (struct baton baton, uint8_t *function_start, uint32_t encoding)
1089 {
1090     const int wordsize = 4;
1091     int mode = encoding & UNWIND_ARM_MODE_MASK;
1092     switch (mode)
1093     {
1094         case UNWIND_ARM_MODE_FRAME_D:
1095         case UNWIND_ARM_MODE_FRAME:
1096         {
1097             int stack_adjust = EXTRACT_BITS (encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK) * wordsize;
1098
1099             printf ("frame func: CFA is fp+%d ", (2 * wordsize) + stack_adjust);
1100             int cfa_offset = -stack_adjust;
1101
1102             cfa_offset -= wordsize;
1103             printf (" pc=[CFA%d]", cfa_offset);
1104             cfa_offset -= wordsize;
1105             printf (" fp=[CFA%d]", cfa_offset);
1106
1107             uint32_t saved_register_bits = encoding & 0xff;
1108             if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6)
1109             {
1110                 cfa_offset -= wordsize;
1111                 printf (" r6=[CFA%d]", cfa_offset);
1112             }
1113             if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5)
1114             {
1115                 cfa_offset -= wordsize;
1116                 printf (" r5=[CFA%d]", cfa_offset);
1117             }
1118             if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4)
1119             {
1120                 cfa_offset -= wordsize;
1121                 printf (" r4=[CFA%d]", cfa_offset);
1122             }
1123             if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12)
1124             {
1125                 cfa_offset -= wordsize;
1126                 printf (" r12=[CFA%d]", cfa_offset);
1127             }
1128             if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11)
1129             {
1130                 cfa_offset -= wordsize;
1131                 printf (" r11=[CFA%d]", cfa_offset);
1132             }
1133             if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10)
1134             {
1135                 cfa_offset -= wordsize;
1136                 printf (" r10=[CFA%d]", cfa_offset);
1137             }
1138             if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9)
1139             {
1140                 cfa_offset -= wordsize;
1141                 printf (" r9=[CFA%d]", cfa_offset);
1142             }
1143             if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8)
1144             {
1145                 cfa_offset -= wordsize;
1146                 printf (" r8=[CFA%d]", cfa_offset);
1147             }
1148
1149             if (mode == UNWIND_ARM_MODE_FRAME_D)
1150             {
1151                 uint32_t d_reg_bits = EXTRACT_BITS (encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1152                 switch (d_reg_bits)
1153                 {
1154                     case 0:
1155                         // vpush {d8}
1156                         cfa_offset -= 8;
1157                         printf (" d8=[CFA%d]", cfa_offset);
1158                         break;
1159                     case 1:
1160                         // vpush {d10}
1161                         // vpush {d8}
1162                         cfa_offset -= 8;
1163                         printf (" d10=[CFA%d]", cfa_offset);
1164                         cfa_offset -= 8;
1165                         printf (" d8=[CFA%d]", cfa_offset);
1166                         break;
1167                     case 2:
1168                         // vpush {d12}
1169                         // vpush {d10}
1170                         // vpush {d8}
1171                         cfa_offset -= 8;
1172                         printf (" d12=[CFA%d]", cfa_offset);
1173                         cfa_offset -= 8;
1174                         printf (" d10=[CFA%d]", cfa_offset);
1175                         cfa_offset -= 8;
1176                         printf (" d8=[CFA%d]", cfa_offset);
1177                         break;
1178                     case 3:
1179                         // vpush {d14}
1180                         // vpush {d12}
1181                         // vpush {d10}
1182                         // vpush {d8}
1183                         cfa_offset -= 8;
1184                         printf (" d14=[CFA%d]", cfa_offset);
1185                         cfa_offset -= 8;
1186                         printf (" d12=[CFA%d]", cfa_offset);
1187                         cfa_offset -= 8;
1188                         printf (" d10=[CFA%d]", cfa_offset);
1189                         cfa_offset -= 8;
1190                         printf (" d8=[CFA%d]", cfa_offset);
1191                         break;
1192                     case 4:
1193                         // vpush {d14}
1194                         // vpush {d12}
1195                         // sp = (sp - 24) & (-16);
1196                         // vst   {d8, d9, d10}
1197                         printf (" d14, d12, d10, d9, d8");
1198                         break;
1199                     case 5:
1200                         // vpush {d14}
1201                         // sp = (sp - 40) & (-16);
1202                         // vst   {d8, d9, d10, d11}
1203                         // vst   {d12}
1204                         printf (" d14, d11, d10, d9, d8, d12");
1205                         break;
1206                     case 6:
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");
1211                         break;
1212                     case 7:
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");
1217                         break;
1218                 }
1219             }
1220         }
1221         break;
1222
1223         case UNWIND_ARM_MODE_DWARF:
1224         {
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);
1228         }
1229         break;
1230
1231         case 0:
1232         {
1233             printf (" no unwind information");
1234         }
1235         break;
1236     }
1237 }
1238
1239
1240
1241
1242 void print_encoding (struct baton baton, uint8_t *function_start, uint32_t encoding)
1243 {
1244
1245     if (baton.cputype == CPU_TYPE_X86_64)
1246     {
1247         print_encoding_x86_64 (baton, function_start, encoding);
1248     }
1249     else if (baton.cputype == CPU_TYPE_I386)
1250     {
1251         print_encoding_i386 (baton, function_start, encoding);
1252     }
1253     else if (baton.cputype == CPU_TYPE_ARM64)
1254     {
1255         print_encoding_arm64 (baton, function_start, encoding);
1256     }
1257     else if (baton.cputype == CPU_TYPE_ARM)
1258     {
1259         print_encoding_armv7 (baton, function_start, encoding);
1260     }
1261     else
1262     {
1263         printf (" -- unsupported encoding arch -- ");
1264     }
1265 }
1266
1267 void
1268 print_function_encoding (struct baton baton, uint32_t idx, uint32_t encoding, uint32_t entry_encoding_index, uint32_t entry_func_offset)
1269 {
1270
1271     char *entry_encoding_index_str = "";
1272     if (entry_encoding_index != (uint32_t) -1)
1273     {
1274         asprintf (&entry_encoding_index_str, ", encoding #%d", entry_encoding_index);
1275     }
1276     else
1277     {
1278         asprintf (&entry_encoding_index_str, "");
1279     }
1280
1281     uint64_t file_address = baton.first_level_index_entry.functionOffset + entry_func_offset + baton.text_segment_vmaddr;
1282
1283     if (baton.cputype == CPU_TYPE_ARM)
1284         file_address = file_address & ~1;
1285
1286     printf ("    func [%d] offset %d (file addr 0x%" PRIx64 ")%s, encoding is 0x%x", 
1287             idx, entry_func_offset, 
1288             file_address,
1289             entry_encoding_index_str, 
1290             encoding);
1291
1292     struct symbol *symbol = NULL;
1293     for (int i = 0; i < baton.symbols_count; i++)
1294     {
1295         if (i == baton.symbols_count - 1 && baton.symbols[i].file_address <= file_address)
1296         {
1297             symbol = &(baton.symbols[i]);
1298             break;
1299         }
1300         else
1301         {
1302             if (baton.symbols[i].file_address <= file_address && baton.symbols[i + 1].file_address > file_address)
1303             {
1304                 symbol = &(baton.symbols[i]);
1305                 break;
1306             }
1307         }
1308     }
1309
1310     printf ("\n         ");
1311     if (symbol)
1312     {
1313         int offset = file_address - symbol->file_address;
1314
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 
1318         // function bounds.
1319         if (offset >= 0)
1320         {
1321             printf ("name: %s", symbol->name);
1322             if (offset > 0)
1323             {
1324                 printf (" + %d", offset);
1325             }
1326         }
1327         printf ("\n         ");
1328     }
1329
1330     print_encoding (baton, baton.mach_header_start + baton.first_level_index_entry.functionOffset + baton.text_section_file_offset + entry_func_offset, encoding);
1331
1332     bool has_lsda = encoding & UNWIND_HAS_LSDA;
1333
1334     if (has_lsda)
1335     {
1336         uint32_t func_offset = entry_func_offset + baton.first_level_index_entry.functionOffset;
1337
1338         int lsda_entry_number = -1;
1339
1340         uint32_t low = 0;
1341         uint32_t high = (baton.lsda_array_end - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
1342
1343         while (low < high)
1344         {
1345             uint32_t mid = (low + high) / 2;
1346
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)
1351             {
1352                 lsda_entry_number = (mid_lsda_entry_addr - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
1353                 break;
1354             }
1355             else if (mid_lsda_entry.functionOffset < func_offset)
1356             {
1357                 low = mid + 1;
1358             }
1359             else
1360             {
1361                 high = mid;
1362             }
1363         }
1364
1365         if (lsda_entry_number != -1)
1366         {
1367             printf (", LSDA entry #%d", lsda_entry_number);
1368         }
1369         else
1370         {
1371             printf (", LSDA entry not found");
1372         }
1373     }
1374
1375     uint32_t pers_idx = EXTRACT_BITS (encoding, UNWIND_PERSONALITY_MASK);
1376     if (pers_idx != 0)
1377     {
1378         pers_idx--;  // Change 1-based to 0-based index
1379         printf (", personality entry #%d", pers_idx);
1380     }
1381
1382     printf ("\n");
1383 }
1384
1385 void
1386 print_second_level_index_regular (struct baton baton)
1387 {
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;
1390
1391     uint8_t *offset = page_entries;
1392
1393     uint32_t idx = 0;
1394     while (idx < entries_count)
1395     {
1396         uint32_t func_offset = *((uint32_t *) (offset));
1397         uint32_t encoding = *((uint32_t *) (offset + 4)); 
1398
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.
1404
1405         print_function_encoding (baton, idx, encoding, (uint32_t) -1, func_offset - baton.first_level_index_entry.functionOffset);
1406         idx++;
1407         offset += 8;
1408     }
1409 }
1410
1411 void
1412 print_second_level_index_compressed (struct baton baton)
1413 {
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++)
1418     {
1419         uint32_t entry = *((uint32_t*) offset);
1420         offset += 4;
1421         uint32_t encoding;
1422
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);
1425
1426         if (entry_encoding_index < baton.unwind_header.commonEncodingsArrayCount)
1427         {
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))));
1430         }
1431         else
1432         {
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))));
1436         }
1437
1438
1439         print_function_encoding (baton, idx, encoding, entry_encoding_index, entry_func_offset);
1440     }
1441 }
1442
1443 void
1444 print_second_level_index (struct baton baton)
1445 {
1446     uint8_t *index_start = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
1447
1448     if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_REGULAR)
1449     {
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);
1455     }
1456
1457     if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_COMPRESSED)
1458     {
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);
1464     }
1465 }
1466
1467
1468 void
1469 print_index_sections (struct baton baton)
1470 {    
1471     uint8_t *index_section_offset = baton.compact_unwind_start + baton.unwind_header.indexSectionOffset;
1472     uint32_t index_count = baton.unwind_header.indexCount;
1473
1474     uint32_t cur_idx = 0;
1475
1476     uint8_t *offset = index_section_offset;
1477     while (cur_idx < index_count)
1478     {
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);
1483
1484         // secondLevelPagesSectionOffset == 0 means this is a sentinel entry
1485         if (index_entry.secondLevelPagesSectionOffset != 0)
1486         {
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));
1489
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;
1492
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)
1496             {
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);
1506                 lsda_count++;
1507                 lsda_entry_offset += sizeof (struct unwind_info_section_header_lsda_index_entry);
1508             }
1509
1510             printf ("\n");
1511
1512             baton.first_level_index_entry = index_entry;
1513             print_second_level_index (baton);
1514         }
1515
1516         printf ("\n");
1517
1518         cur_idx++;
1519         offset += sizeof (struct unwind_info_section_header_index_entry);
1520     }
1521 }
1522
1523 int main (int argc, char **argv)
1524 {
1525     struct stat st;
1526     char *file = argv[0];
1527     if (argc > 1)
1528         file = argv[1];
1529     int fd = open (file, O_RDONLY);
1530     if (fd == -1)
1531     {
1532         printf ("Failed to open '%s'\n", file);
1533         exit (1);
1534     }
1535     fstat (fd, &st);
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)
1538     {
1539         printf ("Failed to mmap() '%s'\n", file);
1540     }
1541
1542     FILE *f = fopen ("a.out", "r");
1543
1544     struct baton baton;
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;
1550
1551     scan_macho_load_commands (&baton);
1552
1553     if (baton.compact_unwind_start == NULL)
1554     {
1555         printf ("could not find __TEXT,__unwind_info section\n");
1556         exit (1);
1557     }
1558
1559
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);
1570
1571     uint8_t *common_encodings = baton.compact_unwind_start + header.commonEncodingsArraySectionOffset;
1572     uint32_t encoding_idx = 0;
1573     while (encoding_idx < header.commonEncodingsArrayCount)
1574     {
1575         uint32_t encoding = *((uint32_t*) common_encodings);
1576         printf ("    Common Encoding [%d]: 0x%x ", encoding_idx, encoding);
1577         print_encoding (baton, NULL, encoding);
1578         printf ("\n");
1579         common_encodings += sizeof (uint32_t);
1580         encoding_idx++;
1581     }
1582
1583     uint8_t *pers_arr = baton.compact_unwind_start + header.personalityArraySectionOffset;
1584     uint32_t pers_idx = 0;
1585     while (pers_idx < header.personalityArrayCount)
1586     {
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);
1589         pers_idx++;
1590         pers_arr += sizeof (uint32_t);
1591     }
1592
1593     printf ("\n");
1594
1595     baton.unwind_header = header;
1596
1597     print_index_sections (baton);
1598
1599
1600     return 0;
1601 }