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