Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: obsolete/breakpad/common/mac/dump_syms.mm

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « obsolete/breakpad/common/mac/dump_syms.h ('k') | obsolete/breakpad/common/mac/file_id.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « obsolete/breakpad/common/mac/dump_syms.h ('k') | obsolete/breakpad/common/mac/file_id.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698