OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006, Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 // dump_syms.mm: Create a symbol file for use with minidumps | |
31 | |
32 #include <unistd.h> | |
33 #include <signal.h> | |
34 #include <cxxabi.h> | |
35 #include <stdlib.h> | |
36 | |
37 #include <mach/machine.h> | |
38 #include <mach-o/arch.h> | |
39 #include <mach-o/fat.h> | |
40 #include <mach-o/loader.h> | |
41 #include <mach-o/nlist.h> | |
42 #include <mach-o/stab.h> | |
43 #include <fcntl.h> | |
44 | |
45 #import <Foundation/Foundation.h> | |
46 | |
47 #import "dump_syms.h" | |
48 #import "common/mac/file_id.h" | |
49 #import "common/mac/macho_utilities.h" | |
50 #import "common/dwarf/dwarf2reader.h" | |
51 #import "common/dwarf/functioninfo.h" | |
52 #import "common/dwarf/bytereader.h" | |
53 | |
54 using google_breakpad::FileID; | |
55 | |
56 static NSString *kAddressSymbolKey = @"symbol"; | |
57 static NSString *kAddressConvertedSymbolKey = @"converted_symbol"; | |
58 static NSString *kAddressSourceLineKey = @"line"; | |
59 static NSString *kFunctionSizeKey = @"size"; | |
60 static NSString *kFunctionFileKey = @"source_file"; | |
61 static NSString *kHeaderBaseAddressKey = @"baseAddr"; | |
62 static NSString *kHeaderSizeKey = @"size"; | |
63 static NSString *kHeaderOffsetKey = @"offset"; // Offset to the header | |
64 static NSString *kHeaderIs64BitKey = @"is64"; | |
65 static NSString *kHeaderCPUTypeKey = @"cpuType"; | |
66 | |
67 // The section for __TEXT, __text seems to be always 1. This is useful | |
68 // for pruning out extraneous non-function symbols. | |
69 static const int kTextSection = 1; | |
70 | |
71 // Dump FunctionMap to stdout. Print address, function name, file | |
72 // name, line number, lowpc, and highpc if available. | |
73 void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { | |
74 for (dwarf2reader::FunctionMap::const_iterator iter = function_map.begin(); | |
75 iter != function_map.end(); ++iter) { | |
76 if (iter->second->name.empty()) { | |
77 continue; | |
78 } | |
79 printf("%08llx: %s", iter->first, | |
80 iter->second->name.data()); | |
81 if (!iter->second->file.empty()) { | |
82 printf(" - %s", iter->second->file.data()); | |
83 if (iter->second->line != 0) { | |
84 printf(":%u", iter->second->line); | |
85 } | |
86 } | |
87 if (iter->second->lowpc != 0 && iter->second->highpc != 0) { | |
88 printf(" (%08llx - %08llx)\n", | |
89 iter->second->lowpc, | |
90 iter->second->highpc); | |
91 } | |
92 } | |
93 } | |
94 | |
95 | |
96 @interface DumpSymbols(PrivateMethods) | |
97 - (NSString *)convertCPlusPlusSymbol:(NSString *)symbol; | |
98 - (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address se
ction:(int)section; | |
99 - (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table; | |
100 - (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset; | |
101 - (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset; | |
102 - (BOOL)loadSymbolInfoForArchitecture; | |
103 - (BOOL)loadDWARFSymbolInfo:(void *)base offset:(uint32_t)offset; | |
104 - (BOOL)loadSTABSSymbolInfo:(void *)base offset:(uint32_t)offset; | |
105 - (void)generateSectionDictionary:(struct mach_header*)header; | |
106 - (BOOL)loadHeader:(void *)base offset:(uint32_t)offset; | |
107 - (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset; | |
108 - (BOOL)loadModuleInfo; | |
109 - (void)processDWARFLineNumberInfo:(dwarf2reader::LineMap*)line_map; | |
110 - (void)processDWARFFunctionInfo:(dwarf2reader::FunctionMap*)address_to_funcinfo
; | |
111 - (void)processDWARFSourceFileInfo:(vector<dwarf2reader::SourceFileInfo>*) files
; | |
112 - (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset; | |
113 - (dwarf2reader::SectionMap*)getSectionMapForArchitecture:(NSString*)architectur
e; | |
114 @end | |
115 | |
116 @implementation DumpSymbols | |
117 //============================================================================= | |
118 - (NSString *)convertCPlusPlusSymbol:(NSString *)symbol { | |
119 // __cxa_demangle will realloc this if needed | |
120 char *buffer = (char *)malloc(1024); | |
121 size_t buffer_size = 1024; | |
122 int result; | |
123 | |
124 const char *sym = [symbol UTF8String]; | |
125 NSString *demangled = nil; | |
126 buffer = abi::__cxa_demangle(sym, buffer, &buffer_size, &result); | |
127 if (result == 0) { | |
128 demangled = [NSString stringWithUTF8String:buffer]; | |
129 } | |
130 free(buffer); | |
131 return demangled; | |
132 } | |
133 | |
134 //============================================================================= | |
135 - (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address se
ction:(int)section { | |
136 NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:address]; | |
137 | |
138 if (!address) | |
139 return; | |
140 | |
141 // If the function starts with "_Z" or "__Z" then demangle it. | |
142 BOOL isCPP = NO; | |
143 | |
144 if ([name hasPrefix:@"__Z"]) { | |
145 // Remove the leading underscore | |
146 name = [name substringFromIndex:1]; | |
147 isCPP = YES; | |
148 } else if ([name hasPrefix:@"_Z"]) { | |
149 isCPP = YES; | |
150 } | |
151 | |
152 // Filter out non-functions | |
153 if ([name hasSuffix:@".eh"]) | |
154 return; | |
155 | |
156 if ([name hasSuffix:@"__func__"]) | |
157 return; | |
158 | |
159 if ([name hasSuffix:@"GCC_except_table"]) | |
160 return; | |
161 | |
162 if (isCPP) { | |
163 // OBJCPP_MANGLING_HACK | |
164 // There are cases where ObjC++ mangles up an ObjC name using quasi-C++ | |
165 // mangling: | |
166 // @implementation Foozles + (void)barzles { | |
167 // static int Baz = 0; | |
168 // } @end | |
169 // gives you _ZZ18+[Foozles barzles]E3Baz | |
170 // c++filt won't parse this properly, and will crash in certain cases. | |
171 // Logged as radar: | |
172 // 5129938: c++filt does not deal with ObjC++ symbols | |
173 // If 5129938 ever gets fixed, we can remove this, but for now this prevents | |
174 // c++filt from attempting to demangle names it doesn't know how to handle. | |
175 // This is with c++filt 2.16 | |
176 NSCharacterSet *objcppCharSet = [NSCharacterSet characterSetWithCharactersIn
String:@"-+[]: "]; | |
177 NSRange emptyRange = { NSNotFound, 0 }; | |
178 NSRange objcppRange = [name rangeOfCharacterFromSet:objcppCharSet]; | |
179 isCPP = NSEqualRanges(objcppRange, emptyRange); | |
180 } else if ([name characterAtIndex:0] == '_') { | |
181 // Remove the leading underscore | |
182 name = [name substringFromIndex:1]; | |
183 } | |
184 | |
185 // If there's already an entry for this address, check and see if we can add | |
186 // either the symbol, or a missing line # | |
187 NSMutableDictionary *dict = [addresses_ objectForKey:addressNum]; | |
188 | |
189 if (!dict) { | |
190 dict = [[NSMutableDictionary alloc] init]; | |
191 [addresses_ setObject:dict forKey:addressNum]; | |
192 [dict release]; | |
193 } | |
194 | |
195 if (name && ![dict objectForKey:kAddressSymbolKey]) { | |
196 [dict setObject:name forKey:kAddressSymbolKey]; | |
197 | |
198 // only functions, not line number addresses | |
199 [functionAddresses_ addObject:addressNum]; | |
200 } | |
201 | |
202 if (isCPP) { | |
203 // try demangling | |
204 NSString *demangled = [self convertCPlusPlusSymbol:name]; | |
205 if (demangled != nil) | |
206 [dict setObject:demangled forKey:kAddressConvertedSymbolKey]; | |
207 } | |
208 | |
209 if (line && ![dict objectForKey:kAddressSourceLineKey]) | |
210 [dict setObject:[NSNumber numberWithUnsignedInt:line] | |
211 forKey:kAddressSourceLineKey]; | |
212 | |
213 } | |
214 | |
215 //============================================================================= | |
216 - (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table { | |
217 uint32_t n_strx = list->n_un.n_strx; | |
218 BOOL result = NO; | |
219 | |
220 // We don't care about non-section specific information except function length | |
221 if (list->n_sect == 0 && list->n_type != N_FUN ) | |
222 return NO; | |
223 | |
224 if (list->n_type == N_FUN) { | |
225 if (list->n_sect != 0) { | |
226 // we get the function address from the first N_FUN | |
227 lastStartAddress_ = list->n_value; | |
228 } | |
229 else { | |
230 // an N_FUN from section 0 may follow the initial N_FUN | |
231 // giving us function length information | |
232 NSMutableDictionary *dict = [addresses_ objectForKey: | |
233 [NSNumber numberWithUnsignedLong:lastStartAddress_]]; | |
234 | |
235 assert(dict); | |
236 | |
237 // only set the function size the first time | |
238 // (sometimes multiple section 0 N_FUN entries appear!) | |
239 if (![dict objectForKey:kFunctionSizeKey]) { | |
240 [dict setObject:[NSNumber numberWithUnsignedLongLong:list->n_value] | |
241 forKey:kFunctionSizeKey]; | |
242 } | |
243 } | |
244 } | |
245 | |
246 int line = list->n_desc; | |
247 | |
248 // __TEXT __text section | |
249 NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_]; | |
250 | |
251 uint32_t mainSection = [[archSections objectForKey:@"__TEXT__text" ] sectionNu
mber]; | |
252 | |
253 // Extract debugging information: | |
254 // Doc: http://developer.apple.com/documentation/DeveloperTools/gdb/stabs/stab
s_toc.html | |
255 // Header: /usr/include/mach-o/stab.h: | |
256 if (list->n_type == N_SO) { | |
257 NSString *src = [NSString stringWithUTF8String:&table[n_strx]]; | |
258 NSString *ext = [src pathExtension]; | |
259 NSNumber *address = [NSNumber numberWithUnsignedLongLong:list->n_value]; | |
260 | |
261 // Leopard puts .c files with no code as an offset of 0, but a | |
262 // crash can't happen here and it throws off our code that matches | |
263 // symbols to line numbers so we ignore them.. | |
264 // Return YES because this isn't an error, just something we don't | |
265 // care to handle. | |
266 if ([address unsignedLongValue] == 0) { | |
267 return YES; | |
268 } | |
269 // TODO(waylonis):Ensure that we get the full path for the source file | |
270 // from the first N_SO record | |
271 // If there is an extension, we'll consider it source code | |
272 if ([ext length]) { | |
273 if (!sources_) | |
274 sources_ = [[NSMutableDictionary alloc] init]; | |
275 // Save the source associated with an address | |
276 [sources_ setObject:src forKey:address]; | |
277 result = YES; | |
278 } | |
279 } else if (list->n_type == N_FUN) { | |
280 NSString *fn = [NSString stringWithUTF8String:&table[n_strx]]; | |
281 NSRange range = [fn rangeOfString:@":" options:NSBackwardsSearch]; | |
282 | |
283 if (![fn length]) | |
284 return NO; | |
285 | |
286 if (range.length > 0) { | |
287 // The function has a ":" followed by some stuff, so strip it off | |
288 fn = [fn substringToIndex:range.location]; | |
289 } | |
290 | |
291 [self addFunction:fn line:line address:list->n_value section:list->n_sect ]; | |
292 | |
293 result = YES; | |
294 } else if (list->n_type == N_SLINE && list->n_sect == mainSection) { | |
295 [self addFunction:nil line:line address:list->n_value section:list->n_sect ]
; | |
296 result = YES; | |
297 } else if (((list->n_type & N_TYPE) == N_SECT) && !(list->n_type & N_STAB)) { | |
298 // Regular symbols or ones that are external | |
299 NSString *fn = [NSString stringWithUTF8String:&table[n_strx]]; | |
300 | |
301 [self addFunction:fn line:0 address:list->n_value section:list->n_sect ]; | |
302 result = YES; | |
303 } | |
304 | |
305 return result; | |
306 } | |
307 | |
308 #define SwapLongLongIfNeeded(a) (swap ? NXSwapLongLong(a) : (a)) | |
309 #define SwapLongIfNeeded(a) (swap ? NXSwapLong(a) : (a)) | |
310 #define SwapIntIfNeeded(a) (swap ? NXSwapInt(a) : (a)) | |
311 #define SwapShortIfNeeded(a) (swap ? NXSwapShort(a) : (a)) | |
312 | |
313 //============================================================================= | |
314 - (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset { | |
315 BOOL loadedStabs = [self loadSTABSSymbolInfo:base offset:offset]; | |
316 | |
317 NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_]; | |
318 BOOL loadedDWARF = NO; | |
319 if ([archSections objectForKey:@"__DWARF__debug_info"]) { | |
320 // Treat this this as debug information | |
321 loadedDWARF = [self loadDWARFSymbolInfo:base offset:offset]; | |
322 } | |
323 | |
324 return loadedDWARF || loadedStabs; | |
325 } | |
326 | |
327 //============================================================================= | |
328 - (BOOL)loadDWARFSymbolInfo:(void *)base offset:(uint32_t)offset { | |
329 | |
330 struct mach_header *header = (struct mach_header *) | |
331 ((uint32_t)base + offset); | |
332 BOOL swap = (header->magic == MH_CIGAM); | |
333 | |
334 NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_]; | |
335 assert (archSections != nil); | |
336 section *dbgInfoSection = [[archSections objectForKey:@"__DWARF__debug_info"]
sectionPointer]; | |
337 uint32_t debugInfoSize = SwapLongIfNeeded(dbgInfoSection->size); | |
338 | |
339 #if __BIG_ENDIAN__ | |
340 dwarf2reader::ByteReader byte_reader(swap ? | |
341 dwarf2reader::ENDIANNESS_LITTLE : | |
342 dwarf2reader::ENDIANNESS_BIG); | |
343 #elif __LITTLE_ENDIAN__ | |
344 dwarf2reader::ByteReader byte_reader(swap ? | |
345 dwarf2reader::ENDIANNESS_BIG : | |
346 dwarf2reader::ENDIANNESS_LITTLE); | |
347 #endif | |
348 uint64_t dbgOffset = 0; | |
349 | |
350 dwarf2reader::SectionMap* oneArchitectureSectionMap = [self getSectionMapForAr
chitecture:architecture_]; | |
351 | |
352 while (dbgOffset < debugInfoSize) { | |
353 // Prepare necessary objects. | |
354 dwarf2reader::FunctionMap off_to_funcinfo; | |
355 dwarf2reader::FunctionMap address_to_funcinfo; | |
356 dwarf2reader::LineMap line_map; | |
357 vector<dwarf2reader::SourceFileInfo> files; | |
358 vector<string> dirs; | |
359 | |
360 dwarf2reader::CULineInfoHandler line_info_handler(&files, &dirs, | |
361 &line_map); | |
362 | |
363 dwarf2reader::CUFunctionInfoHandler function_info_handler(&files, &dirs, | |
364 &line_map, | |
365 &off_to_funcinfo, | |
366 &address_to_funcin
fo, | |
367 &line_info_handler
, | |
368 *oneArchitectureSe
ctionMap, | |
369 &byte_reader); | |
370 | |
371 dwarf2reader::CompilationUnit compilation_unit(*oneArchitectureSectionMap, | |
372 dbgOffset, | |
373 &byte_reader, | |
374 &function_info_handler); | |
375 | |
376 dbgOffset += compilation_unit.Start(); | |
377 | |
378 // The next 3 functions take the info that the dwarf reader | |
379 // gives and massages them into the data structures that | |
380 // dump_syms uses | |
381 [self processDWARFSourceFileInfo:&files]; | |
382 [self processDWARFFunctionInfo:&address_to_funcinfo]; | |
383 [self processDWARFLineNumberInfo:&line_map]; | |
384 } | |
385 | |
386 return YES; | |
387 } | |
388 | |
389 - (void)processDWARFSourceFileInfo:(vector<dwarf2reader::SourceFileInfo>*) files
{ | |
390 if (!sources_) | |
391 sources_ = [[NSMutableDictionary alloc] init]; | |
392 // Save the source associated with an address | |
393 vector<dwarf2reader::SourceFileInfo>::const_iterator iter = files->begin(); | |
394 for (; iter != files->end(); iter++) { | |
395 NSString *sourceFile = [NSString stringWithUTF8String:(*iter).name.c_str()]; | |
396 if ((*iter).lowpc != ULLONG_MAX) { | |
397 NSNumber *address = [NSNumber numberWithUnsignedLongLong:(*iter).lowpc]; | |
398 if ([address unsignedLongLongValue] == 0) { | |
399 continue; | |
400 } | |
401 [sources_ setObject:sourceFile forKey:address]; | |
402 } | |
403 } | |
404 } | |
405 | |
406 - (void)processDWARFFunctionInfo:(dwarf2reader::FunctionMap*)address_to_funcinfo
{ | |
407 for (dwarf2reader::FunctionMap::const_iterator iter = address_to_funcinfo->beg
in(); | |
408 iter != address_to_funcinfo->end(); ++iter) { | |
409 if (iter->second->name.empty()) { | |
410 continue; | |
411 } | |
412 | |
413 if (!addresses_) | |
414 addresses_ = [[NSMutableDictionary alloc] init]; | |
415 | |
416 NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:(*iter).second->
lowpc]; | |
417 | |
418 [functionAddresses_ addObject:addressNum]; | |
419 | |
420 NSMutableDictionary *dict = [addresses_ objectForKey:addressNum]; | |
421 | |
422 if (!dict) { | |
423 dict = [[NSMutableDictionary alloc] init]; | |
424 [addresses_ setObject:dict forKey:addressNum]; | |
425 [dict release]; | |
426 } | |
427 | |
428 // set name of function if it isn't already set | |
429 if (![dict objectForKey:kAddressSymbolKey]) { | |
430 NSString *symbolName = [NSString stringWithUTF8String:iter->second->name.c
_str()]; | |
431 [dict setObject:symbolName forKey:kAddressSymbolKey]; | |
432 } | |
433 | |
434 // try demangling function name if we have a mangled name | |
435 if (![dict objectForKey:kAddressConvertedSymbolKey] && | |
436 !iter->second->mangled_name.empty()) { | |
437 NSString *mangled = [NSString stringWithUTF8String:iter->second->mangled_n
ame.c_str()]; | |
438 NSString *demangled = [self convertCPlusPlusSymbol:mangled]; | |
439 if (demangled != nil) | |
440 [dict setObject:demangled forKey:kAddressConvertedSymbolKey]; | |
441 } | |
442 | |
443 // set line number for beginning of function | |
444 if (iter->second->line && ![dict objectForKey:kAddressSourceLineKey]) | |
445 [dict setObject:[NSNumber numberWithUnsignedInt:iter->second->line] | |
446 forKey:kAddressSourceLineKey]; | |
447 | |
448 // set function size by subtracting low PC from high PC | |
449 if (![dict objectForKey:kFunctionSizeKey]) { | |
450 [dict setObject:[NSNumber numberWithUnsignedLongLong:iter->second->highpc
- iter->second->lowpc] | |
451 forKey:kFunctionSizeKey]; | |
452 } | |
453 | |
454 // Set the file that the function is in | |
455 if (![dict objectForKey:kFunctionFileKey]) { | |
456 [dict setObject:[NSString stringWithUTF8String:iter->second->file.c_str()] | |
457 forKey:kFunctionFileKey]; | |
458 } | |
459 } | |
460 } | |
461 | |
462 - (void)processDWARFLineNumberInfo:(dwarf2reader::LineMap*)line_map { | |
463 for (dwarf2reader::LineMap::const_iterator iter = line_map->begin(); | |
464 iter != line_map->end(); | |
465 ++iter) { | |
466 | |
467 NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:iter->first]; | |
468 NSMutableDictionary *dict = [addresses_ objectForKey:addressNum]; | |
469 | |
470 if (!dict) { | |
471 dict = [[NSMutableDictionary alloc] init]; | |
472 [addresses_ setObject:dict forKey:addressNum]; | |
473 [dict release]; | |
474 } | |
475 | |
476 if (iter->second.second && ![dict objectForKey:kAddressSourceLineKey]) { | |
477 [dict setObject:[NSNumber numberWithUnsignedInt:iter->second.second] | |
478 forKey:kAddressSourceLineKey]; | |
479 } | |
480 | |
481 // Set the file that the function's address is in | |
482 if (![dict objectForKey:kFunctionFileKey]) { | |
483 [dict setObject:[NSString stringWithUTF8String:iter->second.first.c_str()] | |
484 forKey:kFunctionFileKey]; | |
485 } | |
486 } | |
487 } | |
488 | |
489 //============================================================================= | |
490 - (BOOL)loadSTABSSymbolInfo:(void *)base offset:(uint32_t)offset { | |
491 struct mach_header *header = (struct mach_header *)((uint32_t)base + offset); | |
492 BOOL swap = (header->magic == MH_CIGAM); | |
493 uint32_t count = SwapLongIfNeeded(header->ncmds); | |
494 struct load_command *cmd = | |
495 (struct load_command *)((uint32_t)header + sizeof(struct mach_header)); | |
496 uint32_t symbolTableCommand = SwapLongIfNeeded(LC_SYMTAB); | |
497 BOOL result = NO; | |
498 | |
499 if (!addresses_) | |
500 addresses_ = [[NSMutableDictionary alloc] init]; | |
501 | |
502 for (uint32_t i = 0; cmd && (i < count); ++i) { | |
503 if (cmd->cmd == symbolTableCommand) { | |
504 struct symtab_command *symtab = (struct symtab_command *)cmd; | |
505 uint32_t ncmds = SwapLongIfNeeded(symtab->nsyms); | |
506 uint32_t symoff = SwapLongIfNeeded(symtab->symoff); | |
507 uint32_t stroff = SwapLongIfNeeded(symtab->stroff); | |
508 struct nlist *list = (struct nlist *)((uint32_t)base + symoff + offset); | |
509 char *strtab = ((char *)header + stroff); | |
510 | |
511 // Process each command, looking for debugging stuff | |
512 for (uint32_t j = 0; j < ncmds; ++j, ++list) { | |
513 // Fill in an nlist_64 structure and process with that | |
514 struct nlist_64 nlist64; | |
515 nlist64.n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx); | |
516 nlist64.n_type = list->n_type; | |
517 nlist64.n_sect = list->n_sect; | |
518 nlist64.n_desc = SwapShortIfNeeded(list->n_desc); | |
519 nlist64.n_value = (uint64_t)SwapLongIfNeeded(list->n_value); | |
520 | |
521 // TODO(nealsid): is this broken? we get NO if one symbol fails | |
522 // but then we lose that information if another suceeeds | |
523 if ([self processSymbolItem:&nlist64 stringTable:strtab]) | |
524 result = YES; | |
525 } | |
526 } | |
527 | |
528 uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); | |
529 cmd = (struct load_command *)((uint32_t)cmd + cmdSize); | |
530 } | |
531 | |
532 return result; | |
533 } | |
534 | |
535 //============================================================================= | |
536 - (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset { | |
537 struct mach_header_64 *header = (struct mach_header_64 *) | |
538 ((uint32_t)base + offset); | |
539 BOOL swap = (header->magic == MH_CIGAM_64); | |
540 uint32_t count = SwapLongIfNeeded(header->ncmds); | |
541 struct load_command *cmd = | |
542 (struct load_command *)((uint32_t)header + sizeof(struct mach_header)); | |
543 uint32_t symbolTableCommand = SwapLongIfNeeded(LC_SYMTAB); | |
544 BOOL result = NO; | |
545 | |
546 for (uint32_t i = 0; cmd && (i < count); i++) { | |
547 if (cmd->cmd == symbolTableCommand) { | |
548 struct symtab_command *symtab = (struct symtab_command *)cmd; | |
549 uint32_t ncmds = SwapLongIfNeeded(symtab->nsyms); | |
550 uint32_t symoff = SwapLongIfNeeded(symtab->symoff); | |
551 uint32_t stroff = SwapLongIfNeeded(symtab->stroff); | |
552 struct nlist_64 *list = (struct nlist_64 *)((uint32_t)base + symoff); | |
553 char *strtab = ((char *)header + stroff); | |
554 | |
555 // Process each command, looking for debugging stuff | |
556 for (uint32_t j = 0; j < ncmds; ++j, ++list) { | |
557 if (!(list->n_type & (N_STAB | N_TYPE))) | |
558 continue; | |
559 | |
560 // Fill in an nlist_64 structure and process with that | |
561 struct nlist_64 nlist64; | |
562 nlist64.n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx); | |
563 nlist64.n_type = list->n_type; | |
564 nlist64.n_sect = list->n_sect; | |
565 nlist64.n_desc = SwapShortIfNeeded(list->n_desc); | |
566 nlist64.n_value = SwapLongLongIfNeeded(list->n_value); | |
567 | |
568 if ([self processSymbolItem:&nlist64 stringTable:strtab]) | |
569 result = YES; | |
570 } | |
571 } | |
572 | |
573 uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); | |
574 cmd = (struct load_command *)((uint32_t)cmd + cmdSize); | |
575 } | |
576 | |
577 return result; | |
578 } | |
579 | |
580 //============================================================================= | |
581 - (BOOL)loadSymbolInfoForArchitecture { | |
582 NSMutableData *data = [[NSMutableData alloc] | |
583 initWithContentsOfMappedFile:sourcePath_]; | |
584 | |
585 NSDictionary *headerInfo = [headers_ objectForKey:architecture_]; | |
586 void *base = [data mutableBytes]; | |
587 uint32_t offset = | |
588 [[headerInfo objectForKey:kHeaderOffsetKey] unsignedLongValue]; | |
589 BOOL is64 = [[headerInfo objectForKey:kHeaderIs64BitKey] boolValue]; | |
590 BOOL result = is64 ? [self loadSymbolInfo64:base offset:offset] : | |
591 [self loadSymbolInfo:base offset:offset]; | |
592 | |
593 [data release]; | |
594 return result; | |
595 } | |
596 | |
597 - (dwarf2reader::SectionMap*)getSectionMapForArchitecture:(NSString*)architectur
e { | |
598 | |
599 string currentArch([architecture UTF8String]); | |
600 dwarf2reader::SectionMap *oneArchitectureSectionMap; | |
601 | |
602 ArchSectionMap::const_iterator iter = sectionsForArch_->find(currentArch); | |
603 | |
604 if (iter == sectionsForArch_->end()) { | |
605 oneArchitectureSectionMap = new dwarf2reader::SectionMap(); | |
606 sectionsForArch_->insert(make_pair(currentArch, oneArchitectureSectionMap)); | |
607 } else { | |
608 oneArchitectureSectionMap = iter->second; | |
609 } | |
610 | |
611 return oneArchitectureSectionMap; | |
612 } | |
613 | |
614 //============================================================================= | |
615 // build a dictionary of section numbers keyed off a string | |
616 // which is the concatenation of the segment name and the section name | |
617 - (void)generateSectionDictionary:(struct mach_header*)header { | |
618 | |
619 BOOL swap = (header->magic == MH_CIGAM); | |
620 uint32_t count = SwapLongIfNeeded(header->ncmds); | |
621 struct load_command *cmd = | |
622 (struct load_command *)((uint32_t)header + sizeof(struct mach_header)); | |
623 uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT); | |
624 uint32_t sectionNumber = 1; // section numbers are counted from 1 | |
625 | |
626 cpu_type_t cpu = SwapIntIfNeeded(header->cputype); | |
627 | |
628 NSString *arch; | |
629 | |
630 if (cpu & CPU_ARCH_ABI64) | |
631 arch = ((cpu & ~CPU_ARCH_ABI64) == CPU_TYPE_X86) ? | |
632 @"x86_64" : @"ppc64"; | |
633 else | |
634 arch = (cpu == CPU_TYPE_X86) ? @"x86" : @"ppc"; | |
635 | |
636 NSMutableDictionary *archSections; | |
637 | |
638 if (!sectionData_) { | |
639 sectionData_ = [[NSMutableDictionary alloc] init]; | |
640 } | |
641 | |
642 if (![sectionData_ objectForKey:architecture_]) { | |
643 [sectionData_ setObject:[[NSMutableDictionary alloc] init] forKey:arch]; | |
644 } | |
645 | |
646 archSections = [sectionData_ objectForKey:arch]; | |
647 | |
648 dwarf2reader::SectionMap* oneArchitectureSectionMap = [self getSectionMapForAr
chitecture:arch]; | |
649 | |
650 // loop through every segment command, then through every section | |
651 // contained inside each of them | |
652 for (uint32_t i = 0; cmd && (i < count); ++i) { | |
653 if (cmd->cmd == segmentCommand) { | |
654 struct segment_command *seg = (struct segment_command *)cmd; | |
655 section *sect = (section *)((uint32_t)cmd + sizeof(segment_command)); | |
656 uint32_t nsects = SwapLongIfNeeded(seg->nsects); | |
657 | |
658 for (uint32_t j = 0; j < nsects; ++j) { | |
659 NSString *segSectName = [NSString stringWithFormat:@"%s%s", | |
660 seg->segname, sect->sectname]; | |
661 | |
662 [archSections setObject:[[MachSection alloc] initWithMachSection:sect an
dNumber:sectionNumber] | |
663 forKey:segSectName]; | |
664 | |
665 // filter out sections with size 0, offset 0 | |
666 if (sect->offset != 0 && sect->size != 0) { | |
667 // fill sectionmap for dwarf reader | |
668 oneArchitectureSectionMap->insert(make_pair(sect->sectname,make_pair((
(const char*)header) + SwapLongIfNeeded(sect->offset), (size_t)SwapLongIfNeeded(
sect->size)))); | |
669 } | |
670 | |
671 ++sect; | |
672 ++sectionNumber; | |
673 } | |
674 } | |
675 | |
676 uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); | |
677 cmd = (struct load_command *)((uint32_t)cmd + cmdSize); | |
678 } | |
679 } | |
680 | |
681 //============================================================================= | |
682 - (BOOL)loadHeader:(void *)base offset:(uint32_t)offset { | |
683 struct mach_header *header = (struct mach_header *)((uint32_t)base + offset); | |
684 BOOL swap = (header->magic == MH_CIGAM); | |
685 uint32_t count = SwapLongIfNeeded(header->ncmds); | |
686 struct load_command *cmd = | |
687 (struct load_command *)((uint32_t)header + sizeof(struct mach_header)); | |
688 uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT); | |
689 | |
690 [self generateSectionDictionary:header]; | |
691 | |
692 for (uint32_t i = 0; cmd && (i < count); ++i) { | |
693 if (cmd->cmd == segmentCommand) { | |
694 struct segment_command *seg = (struct segment_command *)cmd; | |
695 | |
696 if (!strcmp(seg->segname, "__TEXT")) { | |
697 uint32_t addr = SwapLongIfNeeded(seg->vmaddr); | |
698 uint32_t size = SwapLongIfNeeded(seg->vmsize); | |
699 cpu_type_t cpu = SwapIntIfNeeded(header->cputype); | |
700 NSString *cpuStr = (cpu == CPU_TYPE_I386) ? @"x86" : @"ppc"; | |
701 | |
702 [headers_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: | |
703 [NSNumber numberWithUnsignedLongLong:(uint64_t)addr], | |
704 kHeaderBaseAddressKey, | |
705 [NSNumber numberWithUnsignedLongLong:(uint64_t)size], kHeaderSizeKey, | |
706 [NSNumber numberWithUnsignedLong:offset], kHeaderOffsetKey, | |
707 [NSNumber numberWithBool:NO], kHeaderIs64BitKey, | |
708 [NSNumber numberWithUnsignedLong:cpu], kHeaderCPUTypeKey, | |
709 nil] forKey:cpuStr]; | |
710 | |
711 return YES; | |
712 } | |
713 } | |
714 | |
715 uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); | |
716 cmd = (struct load_command *)((uint32_t)cmd + cmdSize); | |
717 } | |
718 | |
719 return NO; | |
720 } | |
721 | |
722 //============================================================================= | |
723 - (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset { | |
724 struct mach_header_64 *header = | |
725 (struct mach_header_64 *)((uint32_t)base + offset); | |
726 BOOL swap = (header->magic == MH_CIGAM_64); | |
727 uint32_t count = SwapLongIfNeeded(header->ncmds); | |
728 struct load_command *cmd = | |
729 (struct load_command *)((uint32_t)header + sizeof(struct mach_header_64)); | |
730 | |
731 for (uint32_t i = 0; cmd && (i < count); ++i) { | |
732 uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT_64); | |
733 if (cmd->cmd == segmentCommand) { | |
734 struct segment_command_64 *seg = (struct segment_command_64 *)cmd; | |
735 if (!strcmp(seg->segname, "__TEXT")) { | |
736 uint64_t addr = SwapLongLongIfNeeded(seg->vmaddr); | |
737 uint64_t size = SwapLongLongIfNeeded(seg->vmsize); | |
738 cpu_type_t cpu = SwapIntIfNeeded(header->cputype); | |
739 cpu &= (~CPU_ARCH_ABI64); | |
740 NSString *cpuStr = (cpu == CPU_TYPE_I386) ? @"x86_64" : @"ppc64"; | |
741 | |
742 [headers_ setObject:[NSDictionary dictionaryWithObjectsAndKeys: | |
743 [NSNumber numberWithUnsignedLongLong:addr], kHeaderBaseAddressKey, | |
744 [NSNumber numberWithUnsignedLongLong:size], kHeaderSizeKey, | |
745 [NSNumber numberWithUnsignedLong:offset], kHeaderOffsetKey, | |
746 [NSNumber numberWithBool:YES], kHeaderIs64BitKey, | |
747 [NSNumber numberWithUnsignedLong:cpu], kHeaderCPUTypeKey, | |
748 nil] forKey:cpuStr]; | |
749 return YES; | |
750 } | |
751 } | |
752 | |
753 uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); | |
754 cmd = (struct load_command *)((uint32_t)cmd + cmdSize); | |
755 } | |
756 | |
757 return NO; | |
758 } | |
759 | |
760 //============================================================================= | |
761 - (BOOL)loadModuleInfo { | |
762 uint64_t result = 0; | |
763 NSMutableData *data = [[NSMutableData alloc] | |
764 initWithContentsOfMappedFile:sourcePath_]; | |
765 void *bytes = [data mutableBytes]; | |
766 struct fat_header *fat = (struct fat_header *)bytes; | |
767 | |
768 if (!fat) { | |
769 [data release]; | |
770 return 0; | |
771 } | |
772 | |
773 // Gather some information based on the header | |
774 BOOL isFat = fat->magic == FAT_MAGIC || fat->magic == FAT_CIGAM; | |
775 BOOL is64 = fat->magic == MH_MAGIC_64 || fat->magic == MH_CIGAM_64; | |
776 BOOL is32 = fat->magic == MH_MAGIC || fat->magic == MH_CIGAM; | |
777 BOOL swap = fat->magic == FAT_CIGAM || fat->magic == MH_CIGAM_64 || | |
778 fat->magic == MH_CIGAM; | |
779 | |
780 if (!is64 && !is32 && !isFat) { | |
781 [data release]; | |
782 return 0; | |
783 } | |
784 | |
785 // Load any available architectures and save the information | |
786 headers_ = [[NSMutableDictionary alloc] init]; | |
787 | |
788 if (isFat) { | |
789 struct fat_arch *archs = | |
790 (struct fat_arch *)((uint32_t)fat + sizeof(struct fat_header)); | |
791 uint32_t count = SwapLongIfNeeded(fat->nfat_arch); | |
792 | |
793 for (uint32_t i = 0; i < count; ++i) { | |
794 archs[i].cputype = SwapIntIfNeeded(archs[i].cputype); | |
795 archs[i].cpusubtype = SwapIntIfNeeded(archs[i].cpusubtype); | |
796 archs[i].offset = SwapLongIfNeeded(archs[i].offset); | |
797 archs[i].size = SwapLongIfNeeded(archs[i].size); | |
798 archs[i].align = SwapLongIfNeeded(archs[i].align); | |
799 | |
800 if (archs[i].cputype & CPU_ARCH_ABI64) | |
801 result = [self loadHeader64:bytes offset:archs[i].offset]; | |
802 else | |
803 result = [self loadHeader:bytes offset:archs[i].offset]; | |
804 } | |
805 } else if (is32) { | |
806 result = [self loadHeader:bytes offset:0]; | |
807 } else { | |
808 result = [self loadHeader64:bytes offset:0]; | |
809 } | |
810 | |
811 [data release]; | |
812 return result; | |
813 } | |
814 | |
815 //============================================================================= | |
816 static BOOL WriteFormat(int fd, const char *fmt, ...) { | |
817 va_list list; | |
818 char buffer[4096]; | |
819 ssize_t expected, written; | |
820 | |
821 va_start(list, fmt); | |
822 vsnprintf(buffer, sizeof(buffer), fmt, list); | |
823 expected = strlen(buffer); | |
824 written = write(fd, buffer, strlen(buffer)); | |
825 va_end(list); | |
826 | |
827 return expected == written; | |
828 } | |
829 | |
830 //============================================================================= | |
831 - (BOOL)outputSymbolFile:(int)fd { | |
832 // Get the baseAddress for this architecture | |
833 NSDictionary *archDict = [headers_ objectForKey:architecture_]; | |
834 NSNumber *baseAddressNum = [archDict objectForKey:kHeaderBaseAddressKey]; | |
835 uint64_t baseAddress = | |
836 baseAddressNum ? [baseAddressNum unsignedLongLongValue] : 0; | |
837 NSNumber *moduleSizeNum = [archDict objectForKey:kHeaderSizeKey]; | |
838 uint64_t moduleSize = | |
839 moduleSizeNum ? [moduleSizeNum unsignedLongLongValue] : 0; | |
840 | |
841 // UUID | |
842 FileID file_id([sourcePath_ fileSystemRepresentation]); | |
843 unsigned char identifier[16]; | |
844 char identifierStr[40]; | |
845 const char *moduleName = [[sourcePath_ lastPathComponent] UTF8String]; | |
846 int cpu_type = [[archDict objectForKey:kHeaderCPUTypeKey] unsignedLongValue]; | |
847 if (file_id.MachoIdentifier(cpu_type, identifier)) { | |
848 FileID::ConvertIdentifierToString(identifier, identifierStr, | |
849 sizeof(identifierStr)); | |
850 } | |
851 else { | |
852 fprintf(stderr, "Unable to calculate UUID of mach-o binary!\n"); | |
853 return NO; | |
854 } | |
855 | |
856 // keep track exclusively of function addresses | |
857 // for sanity checking function lengths | |
858 functionAddresses_ = [[NSMutableSet alloc] init]; | |
859 | |
860 // Gather the information | |
861 [self loadSymbolInfoForArchitecture]; | |
862 | |
863 NSArray *sortedAddresses = [[addresses_ allKeys] | |
864 sortedArrayUsingSelector:@selector(compare:)]; | |
865 | |
866 NSArray *sortedFunctionAddresses = [[functionAddresses_ allObjects] | |
867 sortedArrayUsingSelector:@selector(compare:)]; | |
868 | |
869 // position ourselves at the 2nd function | |
870 unsigned int funcIndex = 1; | |
871 | |
872 // Remove the dashes from the string | |
873 NSMutableString *compactedStr = | |
874 [NSMutableString stringWithCString:identifierStr encoding:NSASCIIStringEncod
ing]; | |
875 [compactedStr replaceOccurrencesOfString:@"-" withString:@"" options:0 | |
876 range:NSMakeRange(0, [compactedStr length])
]; | |
877 | |
878 if (!WriteFormat(fd, "MODULE mac %s %s0 %s\n", [architecture_ UTF8String], | |
879 [compactedStr UTF8String], moduleName)) { | |
880 return NO; | |
881 } | |
882 | |
883 // Sources ordered by address | |
884 NSArray *sources = [[sources_ allKeys] | |
885 sortedArrayUsingSelector:@selector(compare:)]; | |
886 NSMutableDictionary *fileNameToFileIndex = [[NSMutableDictionary alloc] init]; | |
887 unsigned int sourceCount = [sources count]; | |
888 for (unsigned int i = 0; i < sourceCount; ++i) { | |
889 NSString *file = [sources_ objectForKey:[sources objectAtIndex:i]]; | |
890 if (!WriteFormat(fd, "FILE %d %s\n", i + 1, [file UTF8String])) | |
891 return NO; | |
892 | |
893 [fileNameToFileIndex setObject:[NSNumber numberWithUnsignedInt:i+1] | |
894 forKey:file]; | |
895 } | |
896 | |
897 // Symbols | |
898 char terminatingChar = '\n'; | |
899 uint32_t fileIdx = 0, nextFileIdx = 0; | |
900 uint64_t nextSourceFileAddress = 0; | |
901 NSNumber *nextAddress; | |
902 uint64_t nextAddressVal; | |
903 unsigned int addressCount = [sortedAddresses count]; | |
904 | |
905 bool insideFunction = false; | |
906 | |
907 for (unsigned int i = 0; i < addressCount; ++i) { | |
908 NSNumber *address = [sortedAddresses objectAtIndex:i]; | |
909 // skip sources that have a starting address of 0 | |
910 if ([address unsignedLongValue] == 0) { | |
911 continue; | |
912 } | |
913 | |
914 uint64_t addressVal = [address unsignedLongLongValue] - baseAddress; | |
915 | |
916 // Get the next address to calculate the length | |
917 if (i + 1 < addressCount) { | |
918 nextAddress = [sortedAddresses objectAtIndex:i + 1]; | |
919 nextAddressVal = [nextAddress unsignedLongLongValue] - baseAddress; | |
920 } else { | |
921 nextAddressVal = baseAddress + moduleSize; | |
922 // The symbol reader doesn't want a trailing newline | |
923 terminatingChar = '\0'; | |
924 } | |
925 | |
926 NSDictionary *dict = [addresses_ objectForKey:address]; | |
927 NSNumber *line = [dict objectForKey:kAddressSourceLineKey]; | |
928 NSString *symbol = [dict objectForKey:kAddressConvertedSymbolKey]; | |
929 | |
930 if (!symbol) | |
931 symbol = [dict objectForKey:kAddressSymbolKey]; | |
932 | |
933 // sanity check the function length by making sure it doesn't | |
934 // run beyond the next function entry | |
935 uint64_t nextFunctionAddress = 0; | |
936 if (symbol && funcIndex < [sortedFunctionAddresses count]) { | |
937 nextFunctionAddress = [[sortedFunctionAddresses objectAtIndex:funcIndex] | |
938 unsignedLongLongValue] - baseAddress; | |
939 ++funcIndex; | |
940 } | |
941 | |
942 // Skip some symbols | |
943 if ([symbol hasPrefix:@"vtable for"]) | |
944 continue; | |
945 | |
946 if ([symbol hasPrefix:@"__static_initialization_and_destruction_0"]) | |
947 continue; | |
948 | |
949 if ([symbol hasPrefix:@"_GLOBAL__I_"]) | |
950 continue; | |
951 | |
952 if ([symbol hasPrefix:@"__func__."]) | |
953 continue; | |
954 | |
955 if ([symbol hasPrefix:@"__gnu"]) | |
956 continue; | |
957 | |
958 if ([symbol hasPrefix:@"typeinfo "]) | |
959 continue; | |
960 | |
961 if ([symbol hasPrefix:@"EH_frame"]) | |
962 continue; | |
963 | |
964 if ([symbol hasPrefix:@"GCC_except_table"]) | |
965 continue; | |
966 | |
967 if ([symbol hasPrefix:@"__tcf"]) | |
968 continue; | |
969 | |
970 if ([symbol hasPrefix:@"non-virtual thunk"]) | |
971 continue; | |
972 | |
973 // Find the source file (if any) that contains this address | |
974 while (sourceCount && (addressVal >= nextSourceFileAddress)) { | |
975 fileIdx = nextFileIdx; | |
976 | |
977 if (nextFileIdx < sourceCount) { | |
978 NSNumber *addr = [sources objectAtIndex:nextFileIdx]; | |
979 ++nextFileIdx; | |
980 nextSourceFileAddress = [addr unsignedLongLongValue] - baseAddress; | |
981 } else { | |
982 nextSourceFileAddress = baseAddress + moduleSize; | |
983 break; | |
984 } | |
985 } | |
986 | |
987 NSNumber *functionLength = [dict objectForKey:kFunctionSizeKey]; | |
988 | |
989 if (line) { | |
990 if (symbol && functionLength) { | |
991 | |
992 uint64_t functionLengthVal = [functionLength unsignedLongLongValue]; | |
993 | |
994 insideFunction = true; | |
995 // sanity check to make sure the length we were told does not exceed | |
996 // the space between this function and the next | |
997 if (nextFunctionAddress != 0) { | |
998 uint64_t functionLengthVal2 = nextFunctionAddress - addressVal; | |
999 | |
1000 if(functionLengthVal > functionLengthVal2 ) { | |
1001 functionLengthVal = functionLengthVal2; | |
1002 } | |
1003 } | |
1004 | |
1005 // Function | |
1006 if (!WriteFormat(fd, "FUNC %llx %llx 0 %s\n", addressVal, | |
1007 functionLengthVal, [symbol UTF8String])) | |
1008 return NO; | |
1009 } | |
1010 | |
1011 // Throw out line number information that doesn't correspond to | |
1012 // any function | |
1013 if (insideFunction) { | |
1014 // Source line | |
1015 uint64_t length = nextAddressVal - addressVal; | |
1016 | |
1017 // if fileNameToFileIndex/dict has an entry for the | |
1018 // file/kFunctionFileKey, we're processing DWARF and have stored | |
1019 // files for each program counter. If there is no entry, we're | |
1020 // processing STABS and can use the old method of mapping | |
1021 // addresses to files(which was basically iterating over a set | |
1022 // of addresses until we reached one that was greater than the | |
1023 // high PC of the current file, then moving on to the next file) | |
1024 NSNumber *fileIndex = [fileNameToFileIndex objectForKey:[dict objectForK
ey:kFunctionFileKey]]; | |
1025 if (!WriteFormat(fd, "%llx %llx %d %d\n", addressVal, length, | |
1026 [line unsignedIntValue], fileIndex ? [fileIndex unsigne
dIntValue] : fileIdx)) | |
1027 return NO; | |
1028 } | |
1029 } else { | |
1030 // PUBLIC <address> <stack-size> <name> | |
1031 if (!WriteFormat(fd, "PUBLIC %llx 0 %s\n", addressVal, | |
1032 [symbol UTF8String])) | |
1033 return NO; | |
1034 insideFunction = false; | |
1035 } | |
1036 } | |
1037 | |
1038 return YES; | |
1039 } | |
1040 | |
1041 //============================================================================= | |
1042 - (id)initWithContentsOfFile:(NSString *)path { | |
1043 if ((self = [super init])) { | |
1044 | |
1045 if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { | |
1046 [self autorelease]; | |
1047 return nil; | |
1048 } | |
1049 | |
1050 sourcePath_ = [path copy]; | |
1051 | |
1052 // Test for .DSYM bundle | |
1053 NSBundle *dsymBundle = [NSBundle bundleWithPath:sourcePath_]; | |
1054 | |
1055 if (dsymBundle) { | |
1056 | |
1057 // we need to take the DSYM bundle path and remove it's | |
1058 // extension to get the name of the file inside the resources | |
1059 // directory of the bundle that actually has the DWARF | |
1060 // information | |
1061 // But, Xcode supports something called "Wrapper extension"(see | |
1062 // build settings), which would make the bundle name | |
1063 // /tmp/foo/test.kext.dSYM, but the dwarf binary name would | |
1064 // still be "test". so, now we loop through until deleting the | |
1065 // extension doesn't change the string | |
1066 | |
1067 // e.g. suppose sourcepath_ is /tmp/foo/test.dSYM | |
1068 | |
1069 NSString *dwarfBinName = [sourcePath_ lastPathComponent]; | |
1070 NSString *dwarfBinPath; | |
1071 | |
1072 // We use a do/while loop so we can handle files without an extension | |
1073 do { | |
1074 dwarfBinName = [dwarfBinName stringByDeletingPathExtension]; | |
1075 // now, dwarfBinName is "test" | |
1076 dwarfBinPath = [dsymBundle pathForResource:dwarfBinName ofType:nil inDir
ectory:@"DWARF"]; | |
1077 if (dwarfBinPath != nil) | |
1078 break; | |
1079 } while (![[dwarfBinName stringByDeletingPathExtension] isEqualToString:dw
arfBinName]); | |
1080 | |
1081 if (dwarfBinPath == nil) { | |
1082 NSLog(@"The bundle passed on the command line does not appear to be a DW
ARF dSYM bundle"); | |
1083 [self autorelease]; | |
1084 return nil; | |
1085 } | |
1086 | |
1087 // otherwise we're good to go | |
1088 [sourcePath_ release]; | |
1089 | |
1090 sourcePath_ = [dwarfBinPath copy]; | |
1091 NSLog(@"Loading DWARF dSYM file from %@", sourcePath_); | |
1092 } | |
1093 | |
1094 sectionsForArch_ = new ArchSectionMap(); | |
1095 | |
1096 if (![self loadModuleInfo]) { | |
1097 [self autorelease]; | |
1098 return nil; | |
1099 } | |
1100 | |
1101 // If there's more than one, use the native one | |
1102 if ([headers_ count] > 1) { | |
1103 const NXArchInfo *localArchInfo = NXGetLocalArchInfo(); | |
1104 | |
1105 if (localArchInfo) { | |
1106 cpu_type_t cpu = localArchInfo->cputype; | |
1107 NSString *arch; | |
1108 | |
1109 if (cpu & CPU_ARCH_ABI64) | |
1110 arch = ((cpu & ~CPU_ARCH_ABI64) == CPU_TYPE_X86) ? | |
1111 @"x86_64" : @"ppc64"; | |
1112 else | |
1113 arch = (cpu == CPU_TYPE_X86) ? @"x86" : @"ppc"; | |
1114 | |
1115 [self setArchitecture:arch]; | |
1116 } | |
1117 } else { | |
1118 // Specify the default architecture | |
1119 [self setArchitecture:[[headers_ allKeys] objectAtIndex:0]]; | |
1120 } | |
1121 } | |
1122 | |
1123 return self; | |
1124 } | |
1125 | |
1126 //============================================================================= | |
1127 - (NSArray *)availableArchitectures { | |
1128 return [headers_ allKeys]; | |
1129 } | |
1130 | |
1131 //============================================================================= | |
1132 - (void)dealloc { | |
1133 [sourcePath_ release]; | |
1134 [architecture_ release]; | |
1135 [addresses_ release]; | |
1136 [functionAddresses_ release]; | |
1137 [sources_ release]; | |
1138 [headers_ release]; | |
1139 delete sectionsForArch_; | |
1140 | |
1141 [super dealloc]; | |
1142 } | |
1143 | |
1144 //============================================================================= | |
1145 - (BOOL)setArchitecture:(NSString *)architecture { | |
1146 NSString *normalized = [architecture lowercaseString]; | |
1147 BOOL isValid = NO; | |
1148 | |
1149 if ([normalized isEqualToString:@"ppc"]) { | |
1150 isValid = YES; | |
1151 } | |
1152 else if ([normalized isEqualToString:@"i386"]) { | |
1153 normalized = @"x86"; | |
1154 isValid = YES; | |
1155 } | |
1156 else if ([normalized isEqualToString:@"x86"]) { | |
1157 isValid = YES; | |
1158 } | |
1159 else if ([normalized isEqualToString:@"ppc64"]) { | |
1160 isValid = YES; | |
1161 } | |
1162 else if ([normalized isEqualToString:@"x86_64"]) { | |
1163 isValid = YES; | |
1164 } | |
1165 | |
1166 if (isValid) { | |
1167 if (![headers_ objectForKey:normalized]) | |
1168 return NO; | |
1169 | |
1170 [architecture_ autorelease]; | |
1171 architecture_ = [normalized copy]; | |
1172 } | |
1173 | |
1174 return isValid; | |
1175 } | |
1176 | |
1177 //============================================================================= | |
1178 - (NSString *)architecture { | |
1179 return architecture_; | |
1180 } | |
1181 | |
1182 //============================================================================= | |
1183 - (BOOL)writeSymbolFile:(NSString *)destinationPath { | |
1184 const char *dest = [destinationPath fileSystemRepresentation]; | |
1185 int fd; | |
1186 | |
1187 if ([[destinationPath substringToIndex:1] isEqualToString:@"-"]) | |
1188 fd = STDOUT_FILENO; | |
1189 else | |
1190 fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666); | |
1191 | |
1192 if (fd == -1) | |
1193 return NO; | |
1194 | |
1195 BOOL result = [self outputSymbolFile:fd]; | |
1196 | |
1197 close(fd); | |
1198 | |
1199 return result; | |
1200 } | |
1201 | |
1202 @end | |
1203 | |
1204 @implementation MachSection | |
1205 | |
1206 - (id)initWithMachSection:(section *)sect andNumber:(uint32_t)sectionNumber { | |
1207 if ((self = [super init])) { | |
1208 sect_ = sect; | |
1209 sectionNumber_ = sectionNumber; | |
1210 } | |
1211 | |
1212 return self; | |
1213 } | |
1214 | |
1215 - (section*)sectionPointer { | |
1216 return sect_; | |
1217 } | |
1218 | |
1219 - (uint32_t)sectionNumber { | |
1220 return sectionNumber_; | |
1221 } | |
1222 @end | |
OLD | NEW |