]> git.saurik.com Git - apple/ld64.git/blob - src/other/unwinddump.cpp
d24e62c57d471f3f19ecdb51184d74eea659a418
[apple/ld64.git] / src / other / unwinddump.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include <vector>
35 #include <set>
36 #include <ext/hash_set>
37
38
39 #include "MachOFileAbstraction.hpp"
40 #include "Architectures.hpp"
41
42
43 __attribute__((noreturn))
44 void throwf(const char* format, ...)
45 {
46 va_list list;
47 char* p;
48 va_start(list, format);
49 vasprintf(&p, format, list);
50 va_end(list);
51
52 const char* t = p;
53 throw t;
54 }
55
56
57 template <typename A>
58 class UnwindPrinter
59 {
60 public:
61 static bool validFile(const uint8_t* fileContent);
62 static UnwindPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength,
63 const char* path, bool showFunctionNames)
64 { return new UnwindPrinter<A>(fileContent, fileLength,
65 path, showFunctionNames); }
66 virtual ~UnwindPrinter() {}
67
68
69 private:
70 typedef typename A::P P;
71 typedef typename A::P::E E;
72 typedef typename A::P::uint_t pint_t;
73
74 class CStringEquals
75 {
76 public:
77 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
78 };
79
80 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
81
82 UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength,
83 const char* path, bool showFunctionNames);
84 bool findUnwindSection();
85 void printUnwindSection(bool showFunctionNames);
86 void printObjectUnwindSection(bool showFunctionNames);
87 void getSymbolTableInfo();
88 const char* functionName(pint_t addr, uint32_t* offset=NULL);
89 const char* personalityName(const macho_relocation_info<typename A::P>* reloc);
90 bool hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr=NULL);
91
92 static const char* archName();
93 static void decode(uint32_t encoding, const uint8_t* funcStart, char* str);
94
95 const char* fPath;
96 const macho_header<P>* fHeader;
97 uint64_t fLength;
98 const macho_section<P>* fUnwindSection;
99 const char* fStrings;
100 const char* fStringsEnd;
101 const macho_nlist<P>* fSymbols;
102 uint32_t fSymbolCount;
103 pint_t fMachHeaderAddress;
104 };
105
106
107 template <> const char* UnwindPrinter<ppc>::archName() { return "ppc"; }
108 template <> const char* UnwindPrinter<ppc64>::archName() { return "ppc64"; }
109 template <> const char* UnwindPrinter<x86>::archName() { return "i386"; }
110 template <> const char* UnwindPrinter<x86_64>::archName() { return "x86_64"; }
111 template <> const char* UnwindPrinter<arm>::archName() { return "arm"; }
112
113
114 template <>
115 bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
116 {
117 const macho_header<P>* header = (const macho_header<P>*)fileContent;
118 if ( header->magic() != MH_MAGIC )
119 return false;
120 if ( header->cputype() != CPU_TYPE_I386 )
121 return false;
122 switch (header->filetype()) {
123 case MH_EXECUTE:
124 case MH_DYLIB:
125 case MH_BUNDLE:
126 case MH_DYLINKER:
127 case MH_OBJECT:
128 return true;
129 }
130 return false;
131 }
132
133 template <>
134 bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
135 {
136 const macho_header<P>* header = (const macho_header<P>*)fileContent;
137 if ( header->magic() != MH_MAGIC_64 )
138 return false;
139 if ( header->cputype() != CPU_TYPE_X86_64 )
140 return false;
141 switch (header->filetype()) {
142 case MH_EXECUTE:
143 case MH_DYLIB:
144 case MH_BUNDLE:
145 case MH_DYLINKER:
146 case MH_OBJECT:
147 return true;
148 }
149 return false;
150 }
151
152
153 template <typename A>
154 UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
155 : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
156 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fMachHeaderAddress(0)
157 {
158 // sanity check
159 if ( ! validFile(fileContent) )
160 throw "not a mach-o file that can be checked";
161
162 fPath = strdup(path);
163 fHeader = (const macho_header<P>*)fileContent;
164
165 getSymbolTableInfo();
166
167 if ( findUnwindSection() ) {
168 if ( fHeader->filetype() == MH_OBJECT )
169 printObjectUnwindSection(showFunctionNames);
170 else
171 printUnwindSection(showFunctionNames);
172 }
173 }
174
175
176 template <typename A>
177 void UnwindPrinter<A>::getSymbolTableInfo()
178 {
179 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
180 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
181 const uint32_t cmd_count = fHeader->ncmds();
182 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
183 const macho_load_command<P>* cmd = cmds;
184 for (uint32_t i = 0; i < cmd_count; ++i) {
185 uint32_t size = cmd->cmdsize();
186 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
187 if ( endOfCmd > endOfLoadCommands )
188 throwf("load command #%d extends beyond the end of the load commands", i);
189 if ( endOfCmd > endOfFile )
190 throwf("load command #%d extends beyond the end of the file", i);
191 if ( cmd->cmd() == LC_SYMTAB) {
192 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
193 fSymbolCount = symtab->nsyms();
194 fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
195 fStrings = (char*)fHeader + symtab->stroff();
196 fStringsEnd = fStrings + symtab->strsize();
197 }
198 cmd = (const macho_load_command<P>*)endOfCmd;
199 }
200 }
201
202 template <typename A>
203 const char* UnwindPrinter<A>::functionName(pint_t addr, uint32_t* offset)
204 {
205 const macho_nlist<P>* closestSymbol = NULL;
206 if ( offset != NULL )
207 *offset = 0;
208 for (uint32_t i=0; i < fSymbolCount; ++i) {
209 uint8_t type = fSymbols[i].n_type();
210 if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
211 if ( fSymbols[i].n_value() == addr ) {
212 const char* r = &fStrings[fSymbols[i].n_strx()];
213 //fprintf(stderr, "addr=0x%08llX, i=%u, n_type=0x%0X, r=%s\n", (long long)(fSymbols[i].n_value()), i, fSymbols[i].n_type(), r);
214 return r;
215 }
216 else if ( offset != NULL ) {
217 if ( closestSymbol == NULL ) {
218 if ( fSymbols[i].n_value() < addr )
219 closestSymbol = &fSymbols[i];
220 }
221 else {
222 if ( (fSymbols[i].n_value() < addr) && (fSymbols[i].n_value() > closestSymbol->n_value()) )
223 closestSymbol = &fSymbols[i];
224 }
225 }
226 }
227 }
228 if ( closestSymbol != NULL ) {
229 *offset = addr - closestSymbol->n_value();
230 return &fStrings[closestSymbol->n_strx()];
231 }
232 return "--anonymous function--";
233 }
234
235
236
237 template <typename A>
238 bool UnwindPrinter<A>::findUnwindSection()
239 {
240 const char* unwindSectionName = "__unwind_info";
241 const char* unwindSegmentName = "__TEXT";
242 if ( fHeader->filetype() == MH_OBJECT ) {
243 unwindSectionName = "__compact_unwind";
244 unwindSegmentName = "__LD";
245 }
246 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
247 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
248 const uint32_t cmd_count = fHeader->ncmds();
249 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
250 const macho_load_command<P>* cmd = cmds;
251 for (uint32_t i = 0; i < cmd_count; ++i) {
252 uint32_t size = cmd->cmdsize();
253 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
254 if ( endOfCmd > endOfLoadCommands )
255 throwf("load command #%d extends beyond the end of the load commands", i);
256 if ( endOfCmd > endOfFile )
257 throwf("load command #%d extends beyond the end of the file", i);
258 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
259 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
260 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
261 const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
262 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
263 if ( (strncmp(sect->sectname(), unwindSectionName, 16) == 0) && (strcmp(sect->segname(), unwindSegmentName) == 0) ) {
264 fUnwindSection = sect;
265 fMachHeaderAddress = segCmd->vmaddr();
266 return fUnwindSection;
267 }
268 }
269 }
270 cmd = (const macho_load_command<P>*)endOfCmd;
271 }
272 return false;
273 }
274
275 #define EXTRACT_BITS(value, mask) \
276 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
277
278
279 template <>
280 void UnwindPrinter<x86_64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
281 {
282 *str = '\0';
283 switch ( encoding & UNWIND_X86_64_MODE_MASK ) {
284 case UNWIND_X86_64_MODE_RBP_FRAME:
285 {
286 uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
287 uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
288 if ( savedRegistersLocations == 0 ) {
289 strcpy(str, "rbp frame, no saved registers");
290 }
291 else {
292 sprintf(str, "rbp frame, at -%d:", savedRegistersOffset*8);
293 bool needComma = false;
294 for (int i=0; i < 5; ++i) {
295 if ( needComma )
296 strcat(str, ",");
297 else
298 needComma = true;
299 switch (savedRegistersLocations & 0x7) {
300 case UNWIND_X86_64_REG_NONE:
301 strcat(str, "-");
302 break;
303 case UNWIND_X86_64_REG_RBX:
304 strcat(str, "rbx");
305 break;
306 case UNWIND_X86_64_REG_R12:
307 strcat(str, "r12");
308 break;
309 case UNWIND_X86_64_REG_R13:
310 strcat(str, "r13");
311 break;
312 case UNWIND_X86_64_REG_R14:
313 strcat(str, "r14");
314 break;
315 case UNWIND_X86_64_REG_R15:
316 strcat(str, "r15");
317 break;
318 default:
319 strcat(str, "r?");
320 }
321 savedRegistersLocations = (savedRegistersLocations >> 3);
322 if ( savedRegistersLocations == 0 )
323 break;
324 }
325 }
326 }
327 break;
328 case UNWIND_X86_64_MODE_STACK_IMMD:
329 case UNWIND_X86_64_MODE_STACK_IND:
330 {
331 uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
332 uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
333 uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
334 uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
335 if ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND ) {
336 // stack size is encoded in subl $xxx,%esp instruction
337 uint32_t subl = x86_64::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
338 sprintf(str, "stack size=0x%08X, ", subl + 8*stackAdjust);
339 }
340 else {
341 sprintf(str, "stack size=%d, ", stackSize*8);
342 }
343 if ( regCount == 0 ) {
344 strcat(str, "no registers saved");
345 }
346 else {
347 int permunreg[6];
348 switch ( regCount ) {
349 case 6:
350 permunreg[0] = permutation/120;
351 permutation -= (permunreg[0]*120);
352 permunreg[1] = permutation/24;
353 permutation -= (permunreg[1]*24);
354 permunreg[2] = permutation/6;
355 permutation -= (permunreg[2]*6);
356 permunreg[3] = permutation/2;
357 permutation -= (permunreg[3]*2);
358 permunreg[4] = permutation;
359 permunreg[5] = 0;
360 break;
361 case 5:
362 permunreg[0] = permutation/120;
363 permutation -= (permunreg[0]*120);
364 permunreg[1] = permutation/24;
365 permutation -= (permunreg[1]*24);
366 permunreg[2] = permutation/6;
367 permutation -= (permunreg[2]*6);
368 permunreg[3] = permutation/2;
369 permutation -= (permunreg[3]*2);
370 permunreg[4] = permutation;
371 break;
372 case 4:
373 permunreg[0] = permutation/60;
374 permutation -= (permunreg[0]*60);
375 permunreg[1] = permutation/12;
376 permutation -= (permunreg[1]*12);
377 permunreg[2] = permutation/3;
378 permutation -= (permunreg[2]*3);
379 permunreg[3] = permutation;
380 break;
381 case 3:
382 permunreg[0] = permutation/20;
383 permutation -= (permunreg[0]*20);
384 permunreg[1] = permutation/4;
385 permutation -= (permunreg[1]*4);
386 permunreg[2] = permutation;
387 break;
388 case 2:
389 permunreg[0] = permutation/5;
390 permutation -= (permunreg[0]*5);
391 permunreg[1] = permutation;
392 break;
393 case 1:
394 permunreg[0] = permutation;
395 break;
396 }
397 // renumber registers back to standard numbers
398 int registers[6];
399 bool used[7] = { false, false, false, false, false, false, false };
400 for (int i=0; i < regCount; ++i) {
401 int renum = 0;
402 for (int u=1; u < 7; ++u) {
403 if ( !used[u] ) {
404 if ( renum == permunreg[i] ) {
405 registers[i] = u;
406 used[u] = true;
407 break;
408 }
409 ++renum;
410 }
411 }
412 }
413 bool needComma = false;
414 for (int i=0; i < regCount; ++i) {
415 if ( needComma )
416 strcat(str, ",");
417 else
418 needComma = true;
419 switch ( registers[i] ) {
420 case UNWIND_X86_64_REG_RBX:
421 strcat(str, "rbx");
422 break;
423 case UNWIND_X86_64_REG_R12:
424 strcat(str, "r12");
425 break;
426 case UNWIND_X86_64_REG_R13:
427 strcat(str, "r13");
428 break;
429 case UNWIND_X86_64_REG_R14:
430 strcat(str, "r14");
431 break;
432 case UNWIND_X86_64_REG_R15:
433 strcat(str, "r15");
434 break;
435 case UNWIND_X86_64_REG_RBP:
436 strcat(str, "rbp");
437 break;
438 default:
439 strcat(str, "r??");
440 }
441 }
442 }
443 }
444 break;
445 case UNWIND_X86_64_MODE_DWARF:
446 sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
447 break;
448 default:
449 if ( encoding == 0 )
450 strcat(str, "no unwind information");
451 else
452 strcat(str, "tbd ");
453 }
454 if ( encoding & UNWIND_HAS_LSDA ) {
455 strcat(str, " LSDA");
456 }
457
458 }
459
460 template <>
461 void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
462 {
463 *str = '\0';
464 switch ( encoding & UNWIND_X86_MODE_MASK ) {
465 case UNWIND_X86_MODE_EBP_FRAME:
466 {
467 uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_OFFSET);
468 uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
469 if ( savedRegistersLocations == 0 ) {
470 strcpy(str, "ebp frame, no saved registers");
471 }
472 else {
473 sprintf(str, "ebp frame, at -%d:", savedRegistersOffset*4);
474 bool needComma = false;
475 for (int i=0; i < 5; ++i) {
476 if ( needComma )
477 strcat(str, ",");
478 else
479 needComma = true;
480 switch (savedRegistersLocations & 0x7) {
481 case UNWIND_X86_REG_NONE:
482 strcat(str, "-");
483 break;
484 case UNWIND_X86_REG_EBX:
485 strcat(str, "ebx");
486 break;
487 case UNWIND_X86_REG_ECX:
488 strcat(str, "ecx");
489 break;
490 case UNWIND_X86_REG_EDX:
491 strcat(str, "edx");
492 break;
493 case UNWIND_X86_REG_EDI:
494 strcat(str, "edi");
495 break;
496 case UNWIND_X86_REG_ESI:
497 strcat(str, "esi");
498 break;
499 default:
500 strcat(str, "e??");
501 }
502 savedRegistersLocations = (savedRegistersLocations >> 3);
503 if ( savedRegistersLocations == 0 )
504 break;
505 }
506 }
507 }
508 break;
509 case UNWIND_X86_MODE_STACK_IMMD:
510 case UNWIND_X86_MODE_STACK_IND:
511 {
512 uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
513 uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
514 uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
515 uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
516 if ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_STACK_IND ) {
517 // stack size is encoded in subl $xxx,%esp instruction
518 uint32_t subl = x86::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
519 sprintf(str, "stack size=0x%08X, ", subl+4*stackAdjust);
520 }
521 else {
522 sprintf(str, "stack size=%d, ", stackSize*4);
523 }
524 if ( regCount == 0 ) {
525 strcat(str, "no saved regs");
526 }
527 else {
528 int permunreg[6];
529 switch ( regCount ) {
530 case 6:
531 permunreg[0] = permutation/120;
532 permutation -= (permunreg[0]*120);
533 permunreg[1] = permutation/24;
534 permutation -= (permunreg[1]*24);
535 permunreg[2] = permutation/6;
536 permutation -= (permunreg[2]*6);
537 permunreg[3] = permutation/2;
538 permutation -= (permunreg[3]*2);
539 permunreg[4] = permutation;
540 permunreg[5] = 0;
541 break;
542 case 5:
543 permunreg[0] = permutation/120;
544 permutation -= (permunreg[0]*120);
545 permunreg[1] = permutation/24;
546 permutation -= (permunreg[1]*24);
547 permunreg[2] = permutation/6;
548 permutation -= (permunreg[2]*6);
549 permunreg[3] = permutation/2;
550 permutation -= (permunreg[3]*2);
551 permunreg[4] = permutation;
552 break;
553 case 4:
554 permunreg[0] = permutation/60;
555 permutation -= (permunreg[0]*60);
556 permunreg[1] = permutation/12;
557 permutation -= (permunreg[1]*12);
558 permunreg[2] = permutation/3;
559 permutation -= (permunreg[2]*3);
560 permunreg[3] = permutation;
561 break;
562 case 3:
563 permunreg[0] = permutation/20;
564 permutation -= (permunreg[0]*20);
565 permunreg[1] = permutation/4;
566 permutation -= (permunreg[1]*4);
567 permunreg[2] = permutation;
568 break;
569 case 2:
570 permunreg[0] = permutation/5;
571 permutation -= (permunreg[0]*5);
572 permunreg[1] = permutation;
573 break;
574 case 1:
575 permunreg[0] = permutation;
576 break;
577 }
578 // renumber registers back to standard numbers
579 int registers[6];
580 bool used[7] = { false, false, false, false, false, false, false };
581 for (int i=0; i < regCount; ++i) {
582 int renum = 0;
583 for (int u=1; u < 7; ++u) {
584 if ( !used[u] ) {
585 if ( renum == permunreg[i] ) {
586 registers[i] = u;
587 used[u] = true;
588 break;
589 }
590 ++renum;
591 }
592 }
593 }
594 bool needComma = false;
595 for (int i=0; i < regCount; ++i) {
596 if ( needComma )
597 strcat(str, ",");
598 else
599 needComma = true;
600 switch ( registers[i] ) {
601 case UNWIND_X86_REG_EBX:
602 strcat(str, "ebx");
603 break;
604 case UNWIND_X86_REG_ECX:
605 strcat(str, "ecx");
606 break;
607 case UNWIND_X86_REG_EDX:
608 strcat(str, "edx");
609 break;
610 case UNWIND_X86_REG_EDI:
611 strcat(str, "edi");
612 break;
613 case UNWIND_X86_REG_ESI:
614 strcat(str, "esi");
615 break;
616 case UNWIND_X86_REG_EBP:
617 strcat(str, "ebp");
618 break;
619 default:
620 strcat(str, "e??");
621 }
622 }
623 }
624 }
625 break;
626 case UNWIND_X86_MODE_DWARF:
627 sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_DWARF_SECTION_OFFSET);
628 break;
629 default:
630 if ( encoding == 0 )
631 strcat(str, "no unwind information");
632 else
633 strcat(str, "tbd ");
634 }
635 if ( encoding & UNWIND_HAS_LSDA ) {
636 strcat(str, " LSDA");
637 }
638
639 }
640
641
642
643 template <>
644 const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
645 {
646 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
647 //assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
648 const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
649 return &fStrings[sym.n_strx()];
650 }
651
652 template <>
653 const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86::P>* reloc)
654 {
655 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
656 //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
657 const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
658 return &fStrings[sym.n_strx()];
659 }
660
661 template <typename A>
662 bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
663 {
664 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((uint8_t*)fHeader + fUnwindSection->reloff());
665 const macho_relocation_info<P>* relocsEnd = &relocs[fUnwindSection->nreloc()];
666 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
667 if ( reloc->r_extern() && (reloc->r_address() == sectionOffset) ) {
668 *personalityStr = this->personalityName(reloc);
669 if ( addr != NULL )
670 *addr = fSymbols[reloc->r_symbolnum()].n_value();
671 return true;
672 }
673 }
674 return false;
675 }
676
677
678 template <typename A>
679 void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
680 {
681 printf("Arch: %s, Section: __LD,__compact_unwind (size=0x%08llX, => %lld entries)\n",
682 archName(), fUnwindSection->size(), fUnwindSection->size() / sizeof(macho_compact_unwind_entry<P>));
683
684 const macho_compact_unwind_entry<P>* const entriesStart = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset());
685 const macho_compact_unwind_entry<P>* const entriesEnd = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset() + fUnwindSection->size());
686 for (const macho_compact_unwind_entry<P>* entry=entriesStart; entry < entriesEnd; ++entry) {
687 uint64_t entryAddress = ((char*)entry - (char*)entriesStart) + fUnwindSection->addr();
688 printf("0x%08llX:\n", entryAddress);
689 const char* functionNameStr;
690 pint_t funcAddress;
691 uint32_t offsetInFunction;
692 if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::codeStartFieldOffset(), &functionNameStr, &funcAddress) ) {
693 offsetInFunction = entry->codeStart();
694 }
695 else {
696 functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
697 }
698 if ( offsetInFunction == 0 )
699 printf(" start: 0x%08llX %s\n", (uint64_t)funcAddress, functionNameStr);
700 else
701 printf(" start: 0x%08llX %s+0x%X\n", (uint64_t)funcAddress+offsetInFunction, functionNameStr, offsetInFunction);
702
703 printf(" end: 0x%08llX (len=0x%08X)\n", (uint64_t)(funcAddress+offsetInFunction+entry->codeLen()), entry->codeLen());
704
705 char encodingString[200];
706 this->decode(entry->compactUnwindInfo(), ((const uint8_t*)fHeader), encodingString);
707 printf(" unwind info: 0x%08X %s\n", entry->compactUnwindInfo(), encodingString);
708
709 const char* personalityNameStr;
710 if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::personalityFieldOffset(), &personalityNameStr) ) {
711 printf(" personality: %s\n", personalityNameStr);
712 }
713 else {
714 printf(" personality:\n");
715 }
716 if ( entry->lsda() == 0 ) {
717 printf(" lsda:\n");
718 }
719 else {
720 uint32_t lsdaOffset;
721 const char* lsdaName = this->functionName(entry->lsda(), &lsdaOffset);
722 if ( lsdaOffset == 0 )
723 printf(" lsda: 0x%08llX %s\n", (uint64_t)entry->lsda(), lsdaName);
724 else
725 printf(" lsda: 0x%08llX %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
726 }
727 }
728
729 }
730
731
732
733 template <typename A>
734 void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
735 {
736 const uint8_t* sectionContent = (uint8_t*)fHeader + fUnwindSection->offset();
737 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)(sectionContent);
738
739 printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
740 archName(), fUnwindSection->addr(), fUnwindSection->size(), fUnwindSection->offset());
741 printf("\tversion=0x%08X\n", sectionHeader->version());
742 printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader->commonEncodingsArraySectionOffset());
743 printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader->commonEncodingsArrayCount());
744 printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader->personalityArraySectionOffset());
745 printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader->personalityArrayCount());
746 printf("\tindexSectionOffset=0x%08X\n", sectionHeader->indexSectionOffset());
747 printf("\tindexCount=0x%08X\n", sectionHeader->indexCount());
748 printf("\tcommon encodings: (count=%u)\n", sectionHeader->commonEncodingsArrayCount());
749 const uint32_t* commonEncodings = (uint32_t*)&sectionContent[sectionHeader->commonEncodingsArraySectionOffset()];
750 for (uint32_t i=0; i < sectionHeader->commonEncodingsArrayCount(); ++i) {
751 printf("\t\tencoding[%3u]=0x%08X\n", i, A::P::E::get32(commonEncodings[i]));
752 }
753 printf("\tpersonalities: (count=%u)\n", sectionHeader->personalityArrayCount());
754 const uint32_t* personalityArray = (uint32_t*)&sectionContent[sectionHeader->personalityArraySectionOffset()];
755 for (uint32_t i=0; i < sectionHeader->personalityArrayCount(); ++i) {
756 printf("\t\t[%2u]=0x%08X\n", i+1, A::P::E::get32(personalityArray[i]));
757 }
758 printf("\tfirst level index: (count=%u)\n", sectionHeader->indexCount());
759 macho_unwind_info_section_header_index_entry<P>* indexes = (macho_unwind_info_section_header_index_entry<P>*)&sectionContent[sectionHeader->indexSectionOffset()];
760 for (uint32_t i=0; i < sectionHeader->indexCount(); ++i) {
761 printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
762 i, indexes[i].functionOffset(), indexes[i].secondLevelPagesSectionOffset(), indexes[i].lsdaIndexArraySectionOffset());
763 }
764 uint32_t lsdaIndexArraySectionOffset = indexes[0].lsdaIndexArraySectionOffset();
765 uint32_t lsdaIndexArrayEndSectionOffset = indexes[sectionHeader->indexCount()-1].lsdaIndexArraySectionOffset();
766 uint32_t lsdaIndexArrayCount = (lsdaIndexArrayEndSectionOffset-lsdaIndexArraySectionOffset)/sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
767 printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset, lsdaIndexArrayCount);
768 macho_unwind_info_section_header_lsda_index_entry<P>* lindex = (macho_unwind_info_section_header_lsda_index_entry<P>*)&sectionContent[lsdaIndexArraySectionOffset];
769 for (uint32_t i=0; i < lsdaIndexArrayCount; ++i) {
770 const char* name = showFunctionNames ? functionName(lindex[i].functionOffset()+fMachHeaderAddress) : "";
771 printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n", i, lindex[i].functionOffset(), lindex[i].lsdaOffset(), name);
772 if ( *(((uint8_t*)fHeader) + lindex[i].lsdaOffset()) != 0xFF )
773 fprintf(stderr, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex[i].functionOffset()+fMachHeaderAddress));
774 }
775 for (uint32_t i=0; i < sectionHeader->indexCount()-1; ++i) {
776 printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i, indexes[i].secondLevelPagesSectionOffset(),
777 sectionHeader->indexCount(), fUnwindSection->offset()+indexes[i].secondLevelPagesSectionOffset());
778 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)&sectionContent[indexes[i].secondLevelPagesSectionOffset()];
779 if ( page->kind() == UNWIND_SECOND_LEVEL_REGULAR ) {
780 printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
781 printf("\t\tentryPageOffset=0x%08X\n", page->entryPageOffset());
782 printf("\t\tentryCount=0x%08X\n", page->entryCount());
783 const macho_unwind_info_regular_second_level_entry<P>* entry = (macho_unwind_info_regular_second_level_entry<P>*)((char*)page+page->entryPageOffset());
784 for (uint32_t j=0; j < page->entryCount(); ++j) {
785 uint32_t funcOffset = entry[j].functionOffset();
786 if ( entry[j].encoding() & UNWIND_HAS_LSDA ) {
787 // verify there is a corresponding entry in lsda table
788 bool found = false;
789 for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
790 if ( lindex[k].functionOffset() == funcOffset ) {
791 found = true;
792 break;
793 }
794 }
795 if ( !found ) {
796 fprintf(stderr, "MISSING LSDA entry for %s\n", functionName(funcOffset+fMachHeaderAddress));
797 }
798 }
799 char encodingString[100];
800 decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
801 const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
802 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n",
803 j, funcOffset, entry[j].encoding(), encodingString, name);
804 }
805 }
806 else if ( page->kind() == UNWIND_SECOND_LEVEL_COMPRESSED ) {
807 macho_unwind_info_compressed_second_level_page_header<P>* cp = (macho_unwind_info_compressed_second_level_page_header<P>*)page;
808 printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
809 printf("\t\tentryPageOffset=0x%08X\n", cp->entryPageOffset());
810 printf("\t\tentryCount=0x%08X\n", cp->entryCount());
811 printf("\t\tencodingsPageOffset=0x%08X\n", cp->encodingsPageOffset());
812 printf("\t\tencodingsCount=0x%08X\n", cp->encodingsCount());
813 const uint32_t* entries = (uint32_t*)(((uint8_t*)page)+cp->entryPageOffset());
814 const uint32_t* encodings = (uint32_t*)(((uint8_t*)page)+cp->encodingsPageOffset());
815 const uint32_t baseFunctionOffset = indexes[i].functionOffset();
816 for (uint32_t j=0; j < cp->entryCount(); ++j) {
817 uint8_t encodingIndex = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries[j]);
818 uint32_t encoding;
819 if ( encodingIndex < sectionHeader->commonEncodingsArrayCount() )
820 encoding = A::P::E::get32(commonEncodings[encodingIndex]);
821 else
822 encoding = A::P::E::get32(encodings[encodingIndex-sectionHeader->commonEncodingsArrayCount()]);
823 char encodingString[100];
824 uint32_t funcOff = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries[j])+baseFunctionOffset;
825 decode(encoding, ((const uint8_t*)fHeader)+funcOff, encodingString);
826 const char* name = showFunctionNames ? functionName(funcOff+fMachHeaderAddress) : "";
827 if ( encoding & UNWIND_HAS_LSDA ) {
828 // verify there is a corresponding entry in lsda table
829 bool found = false;
830 for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
831 if ( lindex[k].functionOffset() == funcOff ) {
832 found = true;
833 break;
834 }
835 }
836 if ( !found ) {
837 fprintf(stderr, "MISSING LSDA entry for %s\n", name);
838 }
839 }
840 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n",
841 j, funcOff, encodingIndex, encoding, encodingString, name);
842 }
843 }
844 else {
845 fprintf(stderr, "\t\tbad page header\n");
846 }
847 }
848
849 }
850
851 static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool showFunctionNames)
852 {
853 struct stat stat_buf;
854
855 try {
856 int fd = ::open(path, O_RDONLY, 0);
857 if ( fd == -1 )
858 throw "cannot open file";
859 if ( ::fstat(fd, &stat_buf) != 0 )
860 throwf("fstat(%s) failed, errno=%d\n", path, errno);
861 uint32_t length = stat_buf.st_size;
862 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
863 if ( p == ((uint8_t*)(-1)) )
864 throw "cannot map file";
865 ::close(fd);
866 const mach_header* mh = (mach_header*)p;
867 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
868 const struct fat_header* fh = (struct fat_header*)p;
869 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
870 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
871 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
872 size_t size = OSSwapBigToHostInt32(archs[i].size);
873 unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype);
874 if ( onlyArchs.count(cputype) ) {
875 switch(cputype) {
876 case CPU_TYPE_I386:
877 if ( UnwindPrinter<x86>::validFile(p + offset) )
878 UnwindPrinter<x86>::make(p + offset, size, path, showFunctionNames);
879 else
880 throw "in universal file, i386 slice does not contain i386 mach-o";
881 break;
882 case CPU_TYPE_X86_64:
883 if ( UnwindPrinter<x86_64>::validFile(p + offset) )
884 UnwindPrinter<x86_64>::make(p + offset, size, path, showFunctionNames);
885 else
886 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
887 break;
888 default:
889 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
890 }
891 }
892 }
893 }
894 else if ( UnwindPrinter<x86>::validFile(p) && onlyArchs.count(CPU_TYPE_I386) ) {
895 UnwindPrinter<x86>::make(p, length, path, showFunctionNames);
896 }
897 else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
898 UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
899 }
900 else {
901 throw "not a known file type";
902 }
903 }
904 catch (const char* msg) {
905 throwf("%s in %s", msg, path);
906 }
907 }
908
909
910 int main(int argc, const char* argv[])
911 {
912 std::set<cpu_type_t> onlyArchs;
913 std::vector<const char*> files;
914 bool showFunctionNames = true;
915
916 try {
917 for(int i=1; i < argc; ++i) {
918 const char* arg = argv[i];
919 if ( arg[0] == '-' ) {
920 if ( strcmp(arg, "-arch") == 0 ) {
921 const char* arch = argv[++i];
922 if ( strcmp(arch, "i386") == 0 )
923 onlyArchs.insert(CPU_TYPE_I386);
924 else if ( strcmp(arch, "x86_64") == 0 )
925 onlyArchs.insert(CPU_TYPE_X86_64);
926 else
927 throwf("unknown architecture %s", arch);
928 }
929 else if ( strcmp(arg, "-no_symbols") == 0 ) {
930 showFunctionNames = false;
931 }
932 else {
933 throwf("unknown option: %s\n", arg);
934 }
935 }
936 else {
937 files.push_back(arg);
938 }
939 }
940
941 // use all architectures if no restrictions specified
942 if ( onlyArchs.size() == 0 ) {
943 onlyArchs.insert(CPU_TYPE_I386);
944 onlyArchs.insert(CPU_TYPE_X86_64);
945 }
946
947 // process each file
948 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
949 dump(*it, onlyArchs, showFunctionNames);
950 }
951
952 }
953 catch (const char* msg) {
954 fprintf(stderr, "UnwindDump failed: %s\n", msg);
955 return 1;
956 }
957
958 return 0;
959 }
960
961
962