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