toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // -*- mode: c++ -*-
michael@0 2
michael@0 3 // Copyright (c) 2011, Google Inc.
michael@0 4 // All rights reserved.
michael@0 5 //
michael@0 6 // Redistribution and use in source and binary forms, with or without
michael@0 7 // modification, are permitted provided that the following conditions are
michael@0 8 // met:
michael@0 9 //
michael@0 10 // * Redistributions of source code must retain the above copyright
michael@0 11 // notice, this list of conditions and the following disclaimer.
michael@0 12 // * Redistributions in binary form must reproduce the above
michael@0 13 // copyright notice, this list of conditions and the following disclaimer
michael@0 14 // in the documentation and/or other materials provided with the
michael@0 15 // distribution.
michael@0 16 // * Neither the name of Google Inc. nor the names of its
michael@0 17 // contributors may be used to endorse or promote products derived from
michael@0 18 // this software without specific prior written permission.
michael@0 19 //
michael@0 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31
michael@0 32 // Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 33
michael@0 34 // dump_syms.mm: Create a symbol file for use with minidumps
michael@0 35
michael@0 36 #include "common/mac/dump_syms.h"
michael@0 37
michael@0 38 #include <Foundation/Foundation.h>
michael@0 39 #include <mach-o/arch.h>
michael@0 40 #include <mach-o/fat.h>
michael@0 41 #include <stdio.h>
michael@0 42
michael@0 43 #include <ostream>
michael@0 44 #include <string>
michael@0 45 #include <vector>
michael@0 46
michael@0 47 #include "common/dwarf/bytereader-inl.h"
michael@0 48 #include "common/dwarf/dwarf2reader.h"
michael@0 49 #include "common/dwarf_cfi_to_module.h"
michael@0 50 #include "common/dwarf_cu_to_module.h"
michael@0 51 #include "common/dwarf_line_to_module.h"
michael@0 52 #include "common/mac/file_id.h"
michael@0 53 #include "common/mac/arch_utilities.h"
michael@0 54 #include "common/mac/macho_reader.h"
michael@0 55 #include "common/module.h"
michael@0 56 #include "common/scoped_ptr.h"
michael@0 57 #include "common/stabs_reader.h"
michael@0 58 #include "common/stabs_to_module.h"
michael@0 59 #include "common/symbol_data.h"
michael@0 60
michael@0 61 #ifndef CPU_TYPE_ARM
michael@0 62 #define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
michael@0 63 #endif // CPU_TYPE_ARM
michael@0 64
michael@0 65 using dwarf2reader::ByteReader;
michael@0 66 using google_breakpad::DwarfCUToModule;
michael@0 67 using google_breakpad::DwarfLineToModule;
michael@0 68 using google_breakpad::FileID;
michael@0 69 using google_breakpad::mach_o::FatReader;
michael@0 70 using google_breakpad::mach_o::Section;
michael@0 71 using google_breakpad::mach_o::Segment;
michael@0 72 using google_breakpad::Module;
michael@0 73 using google_breakpad::StabsReader;
michael@0 74 using google_breakpad::StabsToModule;
michael@0 75 using google_breakpad::scoped_ptr;
michael@0 76 using std::make_pair;
michael@0 77 using std::pair;
michael@0 78 using std::string;
michael@0 79 using std::vector;
michael@0 80
michael@0 81 namespace google_breakpad {
michael@0 82
michael@0 83 bool DumpSymbols::Read(NSString *filename) {
michael@0 84 if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
michael@0 85 fprintf(stderr, "Object file does not exist: %s\n",
michael@0 86 [filename fileSystemRepresentation]);
michael@0 87 return false;
michael@0 88 }
michael@0 89
michael@0 90 input_pathname_ = [filename retain];
michael@0 91
michael@0 92 // Does this filename refer to a dSYM bundle?
michael@0 93 NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_];
michael@0 94
michael@0 95 if (bundle) {
michael@0 96 // Filenames referring to bundles usually have names of the form
michael@0 97 // "<basename>.dSYM"; however, if the user has specified a wrapper
michael@0 98 // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
michael@0 99 // then the name may have the form "<basename>.<extension>.dSYM". In
michael@0 100 // either case, the resource name for the file containing the DWARF
michael@0 101 // info within the bundle is <basename>.
michael@0 102 //
michael@0 103 // Since there's no way to tell how much to strip off, remove one
michael@0 104 // extension at a time, and use the first one that
michael@0 105 // pathForResource:ofType:inDirectory likes.
michael@0 106 NSString *base_name = [input_pathname_ lastPathComponent];
michael@0 107 NSString *dwarf_resource;
michael@0 108
michael@0 109 do {
michael@0 110 NSString *new_base_name = [base_name stringByDeletingPathExtension];
michael@0 111
michael@0 112 // If stringByDeletingPathExtension returned the name unchanged, then
michael@0 113 // there's nothing more for us to strip off --- lose.
michael@0 114 if ([new_base_name isEqualToString:base_name]) {
michael@0 115 fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
michael@0 116 [input_pathname_ fileSystemRepresentation]);
michael@0 117 return false;
michael@0 118 }
michael@0 119
michael@0 120 // Take the shortened result as our new base_name.
michael@0 121 base_name = new_base_name;
michael@0 122
michael@0 123 // Try to find a DWARF resource in the bundle under the new base_name.
michael@0 124 dwarf_resource = [bundle pathForResource:base_name
michael@0 125 ofType:nil inDirectory:@"DWARF"];
michael@0 126 } while (!dwarf_resource);
michael@0 127
michael@0 128 object_filename_ = [dwarf_resource retain];
michael@0 129 } else {
michael@0 130 object_filename_ = [input_pathname_ retain];
michael@0 131 }
michael@0 132
michael@0 133 // Read the file's contents into memory.
michael@0 134 //
michael@0 135 // The documentation for dataWithContentsOfMappedFile says:
michael@0 136 //
michael@0 137 // Because of file mapping restrictions, this method should only be
michael@0 138 // used if the file is guaranteed to exist for the duration of the
michael@0 139 // data object’s existence. It is generally safer to use the
michael@0 140 // dataWithContentsOfFile: method.
michael@0 141 //
michael@0 142 // I gather this means that OS X doesn't have (or at least, that method
michael@0 143 // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the
michael@0 144 // process appears to get its own copy of the data, and changes to the
michael@0 145 // file don't affect memory and vice versa).
michael@0 146 NSError *error;
michael@0 147 contents_ = [NSData dataWithContentsOfFile:object_filename_
michael@0 148 options:0
michael@0 149 error:&error];
michael@0 150 if (!contents_) {
michael@0 151 fprintf(stderr, "Error reading object file: %s: %s\n",
michael@0 152 [object_filename_ fileSystemRepresentation],
michael@0 153 [[error localizedDescription] UTF8String]);
michael@0 154 return false;
michael@0 155 }
michael@0 156 [contents_ retain];
michael@0 157
michael@0 158 // Get the list of object files present in the file.
michael@0 159 FatReader::Reporter fat_reporter([object_filename_
michael@0 160 fileSystemRepresentation]);
michael@0 161 FatReader fat_reader(&fat_reporter);
michael@0 162 if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]),
michael@0 163 [contents_ length])) {
michael@0 164 return false;
michael@0 165 }
michael@0 166
michael@0 167 // Get our own copy of fat_reader's object file list.
michael@0 168 size_t object_files_count;
michael@0 169 const struct fat_arch *object_files =
michael@0 170 fat_reader.object_files(&object_files_count);
michael@0 171 if (object_files_count == 0) {
michael@0 172 fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
michael@0 173 [object_filename_ fileSystemRepresentation]);
michael@0 174 return false;
michael@0 175 }
michael@0 176 object_files_.resize(object_files_count);
michael@0 177 memcpy(&object_files_[0], object_files,
michael@0 178 sizeof(struct fat_arch) * object_files_count);
michael@0 179
michael@0 180 return true;
michael@0 181 }
michael@0 182
michael@0 183 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
michael@0 184 cpu_subtype_t cpu_subtype) {
michael@0 185 // Find the best match for the architecture the user requested.
michael@0 186 const struct fat_arch *best_match
michael@0 187 = NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
michael@0 188 static_cast<uint32_t>(object_files_.size()));
michael@0 189 if (!best_match) return false;
michael@0 190
michael@0 191 // Record the selected object file.
michael@0 192 selected_object_file_ = best_match;
michael@0 193 return true;
michael@0 194 }
michael@0 195
michael@0 196 bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
michael@0 197 bool arch_set = false;
michael@0 198 const NXArchInfo *arch_info =
michael@0 199 google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
michael@0 200 if (arch_info) {
michael@0 201 arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
michael@0 202 }
michael@0 203 return arch_set;
michael@0 204 }
michael@0 205
michael@0 206 string DumpSymbols::Identifier() {
michael@0 207 FileID file_id([object_filename_ fileSystemRepresentation]);
michael@0 208 unsigned char identifier_bytes[16];
michael@0 209 cpu_type_t cpu_type = selected_object_file_->cputype;
michael@0 210 cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
michael@0 211 if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
michael@0 212 fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
michael@0 213 [object_filename_ fileSystemRepresentation]);
michael@0 214 return "";
michael@0 215 }
michael@0 216
michael@0 217 char identifier_string[40];
michael@0 218 FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
michael@0 219 sizeof(identifier_string));
michael@0 220
michael@0 221 string compacted(identifier_string);
michael@0 222 for(size_t i = compacted.find('-'); i != string::npos;
michael@0 223 i = compacted.find('-', i))
michael@0 224 compacted.erase(i, 1);
michael@0 225
michael@0 226 return compacted;
michael@0 227 }
michael@0 228
michael@0 229 // A line-to-module loader that accepts line number info parsed by
michael@0 230 // dwarf2reader::LineInfo and populates a Module and a line vector
michael@0 231 // with the results.
michael@0 232 class DumpSymbols::DumperLineToModule:
michael@0 233 public DwarfCUToModule::LineToModuleHandler {
michael@0 234 public:
michael@0 235 // Create a line-to-module converter using BYTE_READER.
michael@0 236 DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
michael@0 237 : byte_reader_(byte_reader) { }
michael@0 238
michael@0 239 void StartCompilationUnit(const string& compilation_dir) {
michael@0 240 compilation_dir_ = compilation_dir;
michael@0 241 }
michael@0 242
michael@0 243 void ReadProgram(const char *program, uint64 length,
michael@0 244 Module *module, vector<Module::Line> *lines) {
michael@0 245 DwarfLineToModule handler(module, compilation_dir_, lines);
michael@0 246 dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
michael@0 247 parser.Start();
michael@0 248 }
michael@0 249 private:
michael@0 250 string compilation_dir_;
michael@0 251 dwarf2reader::ByteReader *byte_reader_; // WEAK
michael@0 252 };
michael@0 253
michael@0 254 bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
michael@0 255 const mach_o::Reader &macho_reader,
michael@0 256 const mach_o::SectionMap &dwarf_sections) const {
michael@0 257 // Build a byte reader of the appropriate endianness.
michael@0 258 ByteReader byte_reader(macho_reader.big_endian()
michael@0 259 ? dwarf2reader::ENDIANNESS_BIG
michael@0 260 : dwarf2reader::ENDIANNESS_LITTLE);
michael@0 261
michael@0 262 // Construct a context for this file.
michael@0 263 DwarfCUToModule::FileContext file_context(selected_object_name_,
michael@0 264 module);
michael@0 265
michael@0 266 // Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
michael@0 267 for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
michael@0 268 it != dwarf_sections.end(); it++) {
michael@0 269 file_context.section_map[it->first] =
michael@0 270 make_pair(reinterpret_cast<const char *>(it->second.contents.start),
michael@0 271 it->second.contents.Size());
michael@0 272 }
michael@0 273
michael@0 274 // Find the __debug_info section.
michael@0 275 std::pair<const char *, uint64> debug_info_section
michael@0 276 = file_context.section_map["__debug_info"];
michael@0 277 // There had better be a __debug_info section!
michael@0 278 if (!debug_info_section.first) {
michael@0 279 fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
michael@0 280 selected_object_name_.c_str());
michael@0 281 return false;
michael@0 282 }
michael@0 283
michael@0 284 // Build a line-to-module loader for the root handler to use.
michael@0 285 DumperLineToModule line_to_module(&byte_reader);
michael@0 286
michael@0 287 // Walk the __debug_info section, one compilation unit at a time.
michael@0 288 uint64 debug_info_length = debug_info_section.second;
michael@0 289 for (uint64 offset = 0; offset < debug_info_length;) {
michael@0 290 // Make a handler for the root DIE that populates MODULE with the
michael@0 291 // debug info.
michael@0 292 DwarfCUToModule::WarningReporter reporter(selected_object_name_,
michael@0 293 offset);
michael@0 294 DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
michael@0 295 // Make a Dwarf2Handler that drives our DIEHandler.
michael@0 296 dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
michael@0 297 // Make a DWARF parser for the compilation unit at OFFSET.
michael@0 298 dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map,
michael@0 299 offset,
michael@0 300 &byte_reader,
michael@0 301 &die_dispatcher);
michael@0 302 // Process the entire compilation unit; get the offset of the next.
michael@0 303 offset += dwarf_reader.Start();
michael@0 304 }
michael@0 305
michael@0 306 return true;
michael@0 307 }
michael@0 308
michael@0 309 bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
michael@0 310 const mach_o::Reader &macho_reader,
michael@0 311 const mach_o::Section &section,
michael@0 312 bool eh_frame) const {
michael@0 313 // Find the appropriate set of register names for this file's
michael@0 314 // architecture.
michael@0 315 vector<const UniqueString*> register_names;
michael@0 316 switch (macho_reader.cpu_type()) {
michael@0 317 case CPU_TYPE_X86:
michael@0 318 register_names = DwarfCFIToModule::RegisterNames::I386();
michael@0 319 break;
michael@0 320 case CPU_TYPE_X86_64:
michael@0 321 register_names = DwarfCFIToModule::RegisterNames::X86_64();
michael@0 322 break;
michael@0 323 case CPU_TYPE_ARM:
michael@0 324 register_names = DwarfCFIToModule::RegisterNames::ARM();
michael@0 325 break;
michael@0 326 default: {
michael@0 327 const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
michael@0 328 macho_reader.cpu_type(), macho_reader.cpu_subtype());
michael@0 329 fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
michael@0 330 selected_object_name_.c_str());
michael@0 331 if (arch)
michael@0 332 fprintf(stderr, "architecture '%s'", arch->name);
michael@0 333 else
michael@0 334 fprintf(stderr, "architecture %d,%d",
michael@0 335 macho_reader.cpu_type(), macho_reader.cpu_subtype());
michael@0 336 fprintf(stderr, " to Breakpad symbol file: no register name table\n");
michael@0 337 return false;
michael@0 338 }
michael@0 339 }
michael@0 340
michael@0 341 // Find the call frame information and its size.
michael@0 342 const char *cfi = reinterpret_cast<const char *>(section.contents.start);
michael@0 343 size_t cfi_size = section.contents.Size();
michael@0 344
michael@0 345 // Plug together the parser, handler, and their entourages.
michael@0 346 DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
michael@0 347 section.section_name);
michael@0 348 DwarfCFIToModule handler(module, register_names, &module_reporter);
michael@0 349 dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
michael@0 350 dwarf2reader::ENDIANNESS_BIG :
michael@0 351 dwarf2reader::ENDIANNESS_LITTLE);
michael@0 352 byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
michael@0 353 // At the moment, according to folks at Apple and some cursory
michael@0 354 // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
michael@0 355 // this is the only base address the CFI parser will need.
michael@0 356 byte_reader.SetCFIDataBase(section.address, cfi);
michael@0 357
michael@0 358 dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
michael@0 359 section.section_name);
michael@0 360 dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
michael@0 361 &byte_reader, &handler, &dwarf_reporter,
michael@0 362 eh_frame);
michael@0 363 parser.Start();
michael@0 364 return true;
michael@0 365 }
michael@0 366
michael@0 367 // A LoadCommandHandler that loads whatever debugging data it finds into a
michael@0 368 // Module.
michael@0 369 class DumpSymbols::LoadCommandDumper:
michael@0 370 public mach_o::Reader::LoadCommandHandler {
michael@0 371 public:
michael@0 372 // Create a load command dumper handling load commands from READER's
michael@0 373 // file, and adding data to MODULE.
michael@0 374 LoadCommandDumper(const DumpSymbols &dumper,
michael@0 375 google_breakpad::Module *module,
michael@0 376 const mach_o::Reader &reader,
michael@0 377 SymbolData symbol_data)
michael@0 378 : dumper_(dumper),
michael@0 379 module_(module),
michael@0 380 reader_(reader),
michael@0 381 symbol_data_(symbol_data) { }
michael@0 382
michael@0 383 bool SegmentCommand(const mach_o::Segment &segment);
michael@0 384 bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
michael@0 385
michael@0 386 private:
michael@0 387 const DumpSymbols &dumper_;
michael@0 388 google_breakpad::Module *module_; // WEAK
michael@0 389 const mach_o::Reader &reader_;
michael@0 390 const SymbolData symbol_data_;
michael@0 391 };
michael@0 392
michael@0 393 bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
michael@0 394 mach_o::SectionMap section_map;
michael@0 395 if (!reader_.MapSegmentSections(segment, &section_map))
michael@0 396 return false;
michael@0 397
michael@0 398 if (segment.name == "__TEXT" && symbol_data_ != NO_CFI) {
michael@0 399 module_->SetLoadAddress(segment.vmaddr);
michael@0 400 mach_o::SectionMap::const_iterator eh_frame =
michael@0 401 section_map.find("__eh_frame");
michael@0 402 if (eh_frame != section_map.end()) {
michael@0 403 // If there is a problem reading this, don't treat it as a fatal error.
michael@0 404 dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
michael@0 405 }
michael@0 406 return true;
michael@0 407 }
michael@0 408
michael@0 409 if (segment.name == "__DWARF") {
michael@0 410 if (symbol_data_ != ONLY_CFI) {
michael@0 411 if (!dumper_.ReadDwarf(module_, reader_, section_map))
michael@0 412 return false;
michael@0 413 }
michael@0 414 if (symbol_data_ != NO_CFI) {
michael@0 415 mach_o::SectionMap::const_iterator debug_frame
michael@0 416 = section_map.find("__debug_frame");
michael@0 417 if (debug_frame != section_map.end()) {
michael@0 418 // If there is a problem reading this, don't treat it as a fatal error.
michael@0 419 dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
michael@0 420 }
michael@0 421 }
michael@0 422 }
michael@0 423
michael@0 424 return true;
michael@0 425 }
michael@0 426
michael@0 427 bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
michael@0 428 const ByteBuffer &strings) {
michael@0 429 StabsToModule stabs_to_module(module_);
michael@0 430 // Mac OS X STABS are never "unitized", and the size of the 'value' field
michael@0 431 // matches the address size of the executable.
michael@0 432 StabsReader stabs_reader(entries.start, entries.Size(),
michael@0 433 strings.start, strings.Size(),
michael@0 434 reader_.big_endian(),
michael@0 435 reader_.bits_64() ? 8 : 4,
michael@0 436 true,
michael@0 437 &stabs_to_module);
michael@0 438 if (!stabs_reader.Process())
michael@0 439 return false;
michael@0 440 stabs_to_module.Finalize();
michael@0 441 return true;
michael@0 442 }
michael@0 443
michael@0 444 bool DumpSymbols::ReadSymbolData(Module** out_module) {
michael@0 445 // Select an object file, if SetArchitecture hasn't been called to set one
michael@0 446 // explicitly.
michael@0 447 if (!selected_object_file_) {
michael@0 448 // If there's only one architecture, that's the one.
michael@0 449 if (object_files_.size() == 1)
michael@0 450 selected_object_file_ = &object_files_[0];
michael@0 451 else {
michael@0 452 // Look for an object file whose architecture matches our own.
michael@0 453 const NXArchInfo *local_arch = NXGetLocalArchInfo();
michael@0 454 if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
michael@0 455 fprintf(stderr, "%s: object file contains more than one"
michael@0 456 " architecture, none of which match the current"
michael@0 457 " architecture; specify an architecture explicitly"
michael@0 458 " with '-a ARCH' to resolve the ambiguity\n",
michael@0 459 [object_filename_ fileSystemRepresentation]);
michael@0 460 return false;
michael@0 461 }
michael@0 462 }
michael@0 463 }
michael@0 464
michael@0 465 assert(selected_object_file_);
michael@0 466
michael@0 467 // Find the name of the selected file's architecture, to appear in
michael@0 468 // the MODULE record and in error messages.
michael@0 469 const NXArchInfo *selected_arch_info =
michael@0 470 google_breakpad::BreakpadGetArchInfoFromCpuType(
michael@0 471 selected_object_file_->cputype, selected_object_file_->cpusubtype);
michael@0 472
michael@0 473 const char *selected_arch_name = selected_arch_info->name;
michael@0 474 if (strcmp(selected_arch_name, "i386") == 0)
michael@0 475 selected_arch_name = "x86";
michael@0 476
michael@0 477 // Produce a name to use in error messages that includes the
michael@0 478 // filename, and the architecture, if there is more than one.
michael@0 479 selected_object_name_ = [object_filename_ UTF8String];
michael@0 480 if (object_files_.size() > 1) {
michael@0 481 selected_object_name_ += ", architecture ";
michael@0 482 selected_object_name_ + selected_arch_name;
michael@0 483 }
michael@0 484
michael@0 485 // Compute a module name, to appear in the MODULE record.
michael@0 486 NSString *module_name = [object_filename_ lastPathComponent];
michael@0 487
michael@0 488 // Choose an identifier string, to appear in the MODULE record.
michael@0 489 string identifier = Identifier();
michael@0 490 if (identifier.empty())
michael@0 491 return false;
michael@0 492 identifier += "0";
michael@0 493
michael@0 494 // Create a module to hold the debugging information.
michael@0 495 scoped_ptr<Module> module(new Module([module_name UTF8String],
michael@0 496 "mac",
michael@0 497 selected_arch_name,
michael@0 498 identifier));
michael@0 499
michael@0 500 // Parse the selected object file.
michael@0 501 mach_o::Reader::Reporter reporter(selected_object_name_);
michael@0 502 mach_o::Reader reader(&reporter);
michael@0 503 if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
michael@0 504 + selected_object_file_->offset,
michael@0 505 selected_object_file_->size,
michael@0 506 selected_object_file_->cputype,
michael@0 507 selected_object_file_->cpusubtype))
michael@0 508 return false;
michael@0 509
michael@0 510 // Walk its load commands, and deal with whatever is there.
michael@0 511 LoadCommandDumper load_command_dumper(*this, module.get(), reader,
michael@0 512 symbol_data_);
michael@0 513 if (!reader.WalkLoadCommands(&load_command_dumper))
michael@0 514 return false;
michael@0 515
michael@0 516 *out_module = module.release();
michael@0 517
michael@0 518 return true;
michael@0 519 }
michael@0 520
michael@0 521 bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
michael@0 522 Module* module = NULL;
michael@0 523
michael@0 524 if (ReadSymbolData(&module) && module) {
michael@0 525 bool res = module->Write(stream, symbol_data_);
michael@0 526 delete module;
michael@0 527 return res;
michael@0 528 }
michael@0 529
michael@0 530 return false;
michael@0 531 }
michael@0 532
michael@0 533 } // namespace google_breakpad

mercurial