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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,533 @@
     1.4 +// -*- mode: c++ -*-
     1.5 +
     1.6 +// Copyright (c) 2011, Google Inc.
     1.7 +// All rights reserved.
     1.8 +//
     1.9 +// Redistribution and use in source and binary forms, with or without
    1.10 +// modification, are permitted provided that the following conditions are
    1.11 +// met:
    1.12 +//
    1.13 +//     * Redistributions of source code must retain the above copyright
    1.14 +// notice, this list of conditions and the following disclaimer.
    1.15 +//     * Redistributions in binary form must reproduce the above
    1.16 +// copyright notice, this list of conditions and the following disclaimer
    1.17 +// in the documentation and/or other materials provided with the
    1.18 +// distribution.
    1.19 +//     * Neither the name of Google Inc. nor the names of its
    1.20 +// contributors may be used to endorse or promote products derived from
    1.21 +// this software without specific prior written permission.
    1.22 +//
    1.23 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.24 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.25 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.26 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.27 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.28 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.29 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.30 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.31 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.32 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.33 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.34 +
    1.35 +// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
    1.36 +
    1.37 +// dump_syms.mm: Create a symbol file for use with minidumps
    1.38 +
    1.39 +#include "common/mac/dump_syms.h"
    1.40 +
    1.41 +#include <Foundation/Foundation.h>
    1.42 +#include <mach-o/arch.h>
    1.43 +#include <mach-o/fat.h>
    1.44 +#include <stdio.h>
    1.45 +
    1.46 +#include <ostream>
    1.47 +#include <string>
    1.48 +#include <vector>
    1.49 +
    1.50 +#include "common/dwarf/bytereader-inl.h"
    1.51 +#include "common/dwarf/dwarf2reader.h"
    1.52 +#include "common/dwarf_cfi_to_module.h"
    1.53 +#include "common/dwarf_cu_to_module.h"
    1.54 +#include "common/dwarf_line_to_module.h"
    1.55 +#include "common/mac/file_id.h"
    1.56 +#include "common/mac/arch_utilities.h"
    1.57 +#include "common/mac/macho_reader.h"
    1.58 +#include "common/module.h"
    1.59 +#include "common/scoped_ptr.h"
    1.60 +#include "common/stabs_reader.h"
    1.61 +#include "common/stabs_to_module.h"
    1.62 +#include "common/symbol_data.h"
    1.63 +
    1.64 +#ifndef CPU_TYPE_ARM
    1.65 +#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
    1.66 +#endif //  CPU_TYPE_ARM
    1.67 +
    1.68 +using dwarf2reader::ByteReader;
    1.69 +using google_breakpad::DwarfCUToModule;
    1.70 +using google_breakpad::DwarfLineToModule;
    1.71 +using google_breakpad::FileID;
    1.72 +using google_breakpad::mach_o::FatReader;
    1.73 +using google_breakpad::mach_o::Section;
    1.74 +using google_breakpad::mach_o::Segment;
    1.75 +using google_breakpad::Module;
    1.76 +using google_breakpad::StabsReader;
    1.77 +using google_breakpad::StabsToModule;
    1.78 +using google_breakpad::scoped_ptr;
    1.79 +using std::make_pair;
    1.80 +using std::pair;
    1.81 +using std::string;
    1.82 +using std::vector;
    1.83 +
    1.84 +namespace google_breakpad {
    1.85 +
    1.86 +bool DumpSymbols::Read(NSString *filename) {
    1.87 +  if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
    1.88 +    fprintf(stderr, "Object file does not exist: %s\n",
    1.89 +            [filename fileSystemRepresentation]);
    1.90 +    return false;
    1.91 +  }
    1.92 +
    1.93 +  input_pathname_ = [filename retain];
    1.94 +
    1.95 +  // Does this filename refer to a dSYM bundle?
    1.96 +  NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_];
    1.97 +
    1.98 +  if (bundle) {
    1.99 +    // Filenames referring to bundles usually have names of the form
   1.100 +    // "<basename>.dSYM"; however, if the user has specified a wrapper
   1.101 +    // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
   1.102 +    // then the name may have the form "<basename>.<extension>.dSYM". In
   1.103 +    // either case, the resource name for the file containing the DWARF
   1.104 +    // info within the bundle is <basename>.
   1.105 +    //
   1.106 +    // Since there's no way to tell how much to strip off, remove one
   1.107 +    // extension at a time, and use the first one that
   1.108 +    // pathForResource:ofType:inDirectory likes.
   1.109 +    NSString *base_name = [input_pathname_ lastPathComponent];
   1.110 +    NSString *dwarf_resource;
   1.111 +
   1.112 +    do {
   1.113 +      NSString *new_base_name = [base_name stringByDeletingPathExtension];
   1.114 +
   1.115 +      // If stringByDeletingPathExtension returned the name unchanged, then
   1.116 +      // there's nothing more for us to strip off --- lose.
   1.117 +      if ([new_base_name isEqualToString:base_name]) {
   1.118 +        fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
   1.119 +                [input_pathname_ fileSystemRepresentation]);
   1.120 +        return false;
   1.121 +      }
   1.122 +
   1.123 +      // Take the shortened result as our new base_name.
   1.124 +      base_name = new_base_name;
   1.125 +
   1.126 +      // Try to find a DWARF resource in the bundle under the new base_name.
   1.127 +      dwarf_resource = [bundle pathForResource:base_name
   1.128 +                        ofType:nil inDirectory:@"DWARF"];
   1.129 +    } while (!dwarf_resource);
   1.130 +
   1.131 +    object_filename_ = [dwarf_resource retain];
   1.132 +  } else {
   1.133 +    object_filename_ = [input_pathname_ retain];
   1.134 +  }
   1.135 +
   1.136 +  // Read the file's contents into memory.
   1.137 +  //
   1.138 +  // The documentation for dataWithContentsOfMappedFile says:
   1.139 +  //
   1.140 +  //     Because of file mapping restrictions, this method should only be
   1.141 +  //     used if the file is guaranteed to exist for the duration of the
   1.142 +  //     data object’s existence. It is generally safer to use the
   1.143 +  //     dataWithContentsOfFile: method.
   1.144 +  //
   1.145 +  // I gather this means that OS X doesn't have (or at least, that method
   1.146 +  // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the
   1.147 +  // process appears to get its own copy of the data, and changes to the
   1.148 +  // file don't affect memory and vice versa).
   1.149 +  NSError *error;
   1.150 +  contents_ = [NSData dataWithContentsOfFile:object_filename_
   1.151 +                                     options:0
   1.152 +                                       error:&error];
   1.153 +  if (!contents_) {
   1.154 +    fprintf(stderr, "Error reading object file: %s: %s\n",
   1.155 +            [object_filename_ fileSystemRepresentation],
   1.156 +            [[error localizedDescription] UTF8String]);
   1.157 +    return false;
   1.158 +  }
   1.159 +  [contents_ retain];
   1.160 +
   1.161 +  // Get the list of object files present in the file.
   1.162 +  FatReader::Reporter fat_reporter([object_filename_
   1.163 +                                    fileSystemRepresentation]);
   1.164 +  FatReader fat_reader(&fat_reporter);
   1.165 +  if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]),
   1.166 +                       [contents_ length])) {
   1.167 +    return false;
   1.168 +  }
   1.169 +
   1.170 +  // Get our own copy of fat_reader's object file list.
   1.171 +  size_t object_files_count;
   1.172 +  const struct fat_arch *object_files =
   1.173 +    fat_reader.object_files(&object_files_count);
   1.174 +  if (object_files_count == 0) {
   1.175 +    fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
   1.176 +            [object_filename_ fileSystemRepresentation]);
   1.177 +    return false;
   1.178 +  }
   1.179 +  object_files_.resize(object_files_count);
   1.180 +  memcpy(&object_files_[0], object_files,
   1.181 +         sizeof(struct fat_arch) * object_files_count);
   1.182 +
   1.183 +  return true;
   1.184 +}
   1.185 +
   1.186 +bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
   1.187 +                                  cpu_subtype_t cpu_subtype) {
   1.188 +  // Find the best match for the architecture the user requested.
   1.189 +  const struct fat_arch *best_match
   1.190 +    = NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
   1.191 +                        static_cast<uint32_t>(object_files_.size()));
   1.192 +  if (!best_match) return false;
   1.193 +
   1.194 +  // Record the selected object file.
   1.195 +  selected_object_file_ = best_match;
   1.196 +  return true;
   1.197 +}
   1.198 +
   1.199 +bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
   1.200 +  bool arch_set = false;
   1.201 +  const NXArchInfo *arch_info =
   1.202 +      google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
   1.203 +  if (arch_info) {
   1.204 +    arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
   1.205 +  }
   1.206 +  return arch_set;
   1.207 +}
   1.208 +
   1.209 +string DumpSymbols::Identifier() {
   1.210 +  FileID file_id([object_filename_ fileSystemRepresentation]);
   1.211 +  unsigned char identifier_bytes[16];
   1.212 +  cpu_type_t cpu_type = selected_object_file_->cputype;
   1.213 +  cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
   1.214 +  if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
   1.215 +    fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
   1.216 +            [object_filename_ fileSystemRepresentation]);
   1.217 +    return "";
   1.218 +  }
   1.219 +
   1.220 +  char identifier_string[40];
   1.221 +  FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
   1.222 +                                    sizeof(identifier_string));
   1.223 +
   1.224 +  string compacted(identifier_string);
   1.225 +  for(size_t i = compacted.find('-'); i != string::npos;
   1.226 +      i = compacted.find('-', i))
   1.227 +    compacted.erase(i, 1);
   1.228 +
   1.229 +  return compacted;
   1.230 +}
   1.231 +
   1.232 +// A line-to-module loader that accepts line number info parsed by
   1.233 +// dwarf2reader::LineInfo and populates a Module and a line vector
   1.234 +// with the results.
   1.235 +class DumpSymbols::DumperLineToModule:
   1.236 +      public DwarfCUToModule::LineToModuleHandler {
   1.237 + public:
   1.238 +  // Create a line-to-module converter using BYTE_READER.
   1.239 +  DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
   1.240 +      : byte_reader_(byte_reader) { }
   1.241 +
   1.242 +  void StartCompilationUnit(const string& compilation_dir) {
   1.243 +    compilation_dir_ = compilation_dir;
   1.244 +  }
   1.245 +
   1.246 +  void ReadProgram(const char *program, uint64 length,
   1.247 +                   Module *module, vector<Module::Line> *lines) {
   1.248 +    DwarfLineToModule handler(module, compilation_dir_, lines);
   1.249 +    dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
   1.250 +    parser.Start();
   1.251 +  }
   1.252 + private:
   1.253 +  string compilation_dir_;
   1.254 +  dwarf2reader::ByteReader *byte_reader_;  // WEAK
   1.255 +};
   1.256 +
   1.257 +bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
   1.258 +                            const mach_o::Reader &macho_reader,
   1.259 +                            const mach_o::SectionMap &dwarf_sections) const {
   1.260 +  // Build a byte reader of the appropriate endianness.
   1.261 +  ByteReader byte_reader(macho_reader.big_endian()
   1.262 +                         ? dwarf2reader::ENDIANNESS_BIG
   1.263 +                         : dwarf2reader::ENDIANNESS_LITTLE);
   1.264 +
   1.265 +  // Construct a context for this file.
   1.266 +  DwarfCUToModule::FileContext file_context(selected_object_name_,
   1.267 +                                            module);
   1.268 +
   1.269 +  // Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
   1.270 +  for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
   1.271 +       it != dwarf_sections.end(); it++) {
   1.272 +    file_context.section_map[it->first] =
   1.273 +      make_pair(reinterpret_cast<const char *>(it->second.contents.start),
   1.274 +                it->second.contents.Size());
   1.275 +  }
   1.276 +
   1.277 +  // Find the __debug_info section.
   1.278 +  std::pair<const char *, uint64> debug_info_section
   1.279 +      = file_context.section_map["__debug_info"];
   1.280 +  // There had better be a __debug_info section!
   1.281 +  if (!debug_info_section.first) {
   1.282 +    fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
   1.283 +            selected_object_name_.c_str());
   1.284 +    return false;
   1.285 +  }
   1.286 +
   1.287 +  // Build a line-to-module loader for the root handler to use.
   1.288 +  DumperLineToModule line_to_module(&byte_reader);
   1.289 +
   1.290 +  // Walk the __debug_info section, one compilation unit at a time.
   1.291 +  uint64 debug_info_length = debug_info_section.second;
   1.292 +  for (uint64 offset = 0; offset < debug_info_length;) {
   1.293 +    // Make a handler for the root DIE that populates MODULE with the
   1.294 +    // debug info.
   1.295 +    DwarfCUToModule::WarningReporter reporter(selected_object_name_,
   1.296 +                                              offset);
   1.297 +    DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
   1.298 +    // Make a Dwarf2Handler that drives our DIEHandler.
   1.299 +    dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
   1.300 +    // Make a DWARF parser for the compilation unit at OFFSET.
   1.301 +    dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map,
   1.302 +                                               offset,
   1.303 +                                               &byte_reader,
   1.304 +                                               &die_dispatcher);
   1.305 +    // Process the entire compilation unit; get the offset of the next.
   1.306 +    offset += dwarf_reader.Start();
   1.307 +  }
   1.308 +
   1.309 +  return true;
   1.310 +}
   1.311 +
   1.312 +bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
   1.313 +                          const mach_o::Reader &macho_reader,
   1.314 +                          const mach_o::Section &section,
   1.315 +                          bool eh_frame) const {
   1.316 +  // Find the appropriate set of register names for this file's
   1.317 +  // architecture.
   1.318 +  vector<const UniqueString*> register_names;
   1.319 +  switch (macho_reader.cpu_type()) {
   1.320 +    case CPU_TYPE_X86:
   1.321 +      register_names = DwarfCFIToModule::RegisterNames::I386();
   1.322 +      break;
   1.323 +    case CPU_TYPE_X86_64:
   1.324 +      register_names = DwarfCFIToModule::RegisterNames::X86_64();
   1.325 +      break;
   1.326 +    case CPU_TYPE_ARM:
   1.327 +      register_names = DwarfCFIToModule::RegisterNames::ARM();
   1.328 +      break;
   1.329 +    default: {
   1.330 +      const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
   1.331 +          macho_reader.cpu_type(), macho_reader.cpu_subtype());
   1.332 +      fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
   1.333 +              selected_object_name_.c_str());
   1.334 +      if (arch)
   1.335 +        fprintf(stderr, "architecture '%s'", arch->name);
   1.336 +      else
   1.337 +        fprintf(stderr, "architecture %d,%d",
   1.338 +                macho_reader.cpu_type(), macho_reader.cpu_subtype());
   1.339 +      fprintf(stderr, " to Breakpad symbol file: no register name table\n");
   1.340 +      return false;
   1.341 +    }
   1.342 +  }
   1.343 +
   1.344 +  // Find the call frame information and its size.
   1.345 +  const char *cfi = reinterpret_cast<const char *>(section.contents.start);
   1.346 +  size_t cfi_size = section.contents.Size();
   1.347 +
   1.348 +  // Plug together the parser, handler, and their entourages.
   1.349 +  DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
   1.350 +                                             section.section_name);
   1.351 +  DwarfCFIToModule handler(module, register_names, &module_reporter);
   1.352 +  dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
   1.353 +                                       dwarf2reader::ENDIANNESS_BIG :
   1.354 +                                       dwarf2reader::ENDIANNESS_LITTLE);
   1.355 +  byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
   1.356 +  // At the moment, according to folks at Apple and some cursory
   1.357 +  // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
   1.358 +  // this is the only base address the CFI parser will need.
   1.359 +  byte_reader.SetCFIDataBase(section.address, cfi);
   1.360 +
   1.361 +  dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
   1.362 +                                                       section.section_name);
   1.363 +  dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
   1.364 +                                     &byte_reader, &handler, &dwarf_reporter,
   1.365 +                                     eh_frame);
   1.366 +  parser.Start();
   1.367 +  return true;
   1.368 +}
   1.369 +
   1.370 +// A LoadCommandHandler that loads whatever debugging data it finds into a
   1.371 +// Module.
   1.372 +class DumpSymbols::LoadCommandDumper:
   1.373 +      public mach_o::Reader::LoadCommandHandler {
   1.374 + public:
   1.375 +  // Create a load command dumper handling load commands from READER's
   1.376 +  // file, and adding data to MODULE.
   1.377 +  LoadCommandDumper(const DumpSymbols &dumper,
   1.378 +                    google_breakpad::Module *module,
   1.379 +                    const mach_o::Reader &reader,
   1.380 +                    SymbolData symbol_data)
   1.381 +      : dumper_(dumper),
   1.382 +        module_(module),
   1.383 +        reader_(reader),
   1.384 +        symbol_data_(symbol_data) { }
   1.385 +
   1.386 +  bool SegmentCommand(const mach_o::Segment &segment);
   1.387 +  bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
   1.388 +
   1.389 + private:
   1.390 +  const DumpSymbols &dumper_;
   1.391 +  google_breakpad::Module *module_;  // WEAK
   1.392 +  const mach_o::Reader &reader_;
   1.393 +  const SymbolData symbol_data_;
   1.394 +};
   1.395 +
   1.396 +bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
   1.397 +  mach_o::SectionMap section_map;
   1.398 +  if (!reader_.MapSegmentSections(segment, &section_map))
   1.399 +    return false;
   1.400 +
   1.401 +  if (segment.name == "__TEXT" && symbol_data_ != NO_CFI) {
   1.402 +    module_->SetLoadAddress(segment.vmaddr);
   1.403 +    mach_o::SectionMap::const_iterator eh_frame =
   1.404 +        section_map.find("__eh_frame");
   1.405 +    if (eh_frame != section_map.end()) {
   1.406 +      // If there is a problem reading this, don't treat it as a fatal error.
   1.407 +      dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
   1.408 +    }
   1.409 +    return true;
   1.410 +  }
   1.411 +
   1.412 +  if (segment.name == "__DWARF") {
   1.413 +    if (symbol_data_ != ONLY_CFI) {
   1.414 +      if (!dumper_.ReadDwarf(module_, reader_, section_map))
   1.415 +        return false;
   1.416 +    }
   1.417 +    if (symbol_data_ != NO_CFI) {
   1.418 +      mach_o::SectionMap::const_iterator debug_frame
   1.419 +          = section_map.find("__debug_frame");
   1.420 +      if (debug_frame != section_map.end()) {
   1.421 +        // If there is a problem reading this, don't treat it as a fatal error.
   1.422 +        dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
   1.423 +      }
   1.424 +    }
   1.425 +  }
   1.426 +
   1.427 +  return true;
   1.428 +}
   1.429 +
   1.430 +bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
   1.431 +                                                   const ByteBuffer &strings) {
   1.432 +  StabsToModule stabs_to_module(module_);
   1.433 +  // Mac OS X STABS are never "unitized", and the size of the 'value' field
   1.434 +  // matches the address size of the executable.
   1.435 +  StabsReader stabs_reader(entries.start, entries.Size(),
   1.436 +                           strings.start, strings.Size(),
   1.437 +                           reader_.big_endian(),
   1.438 +                           reader_.bits_64() ? 8 : 4,
   1.439 +                           true,
   1.440 +                           &stabs_to_module);
   1.441 +  if (!stabs_reader.Process())
   1.442 +    return false;
   1.443 +  stabs_to_module.Finalize();
   1.444 +  return true;
   1.445 +}
   1.446 +
   1.447 +bool DumpSymbols::ReadSymbolData(Module** out_module) {
   1.448 +  // Select an object file, if SetArchitecture hasn't been called to set one
   1.449 +  // explicitly.
   1.450 +  if (!selected_object_file_) {
   1.451 +    // If there's only one architecture, that's the one.
   1.452 +    if (object_files_.size() == 1)
   1.453 +      selected_object_file_ = &object_files_[0];
   1.454 +    else {
   1.455 +      // Look for an object file whose architecture matches our own.
   1.456 +      const NXArchInfo *local_arch = NXGetLocalArchInfo();
   1.457 +      if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
   1.458 +        fprintf(stderr, "%s: object file contains more than one"
   1.459 +                " architecture, none of which match the current"
   1.460 +                " architecture; specify an architecture explicitly"
   1.461 +                " with '-a ARCH' to resolve the ambiguity\n",
   1.462 +                [object_filename_ fileSystemRepresentation]);
   1.463 +        return false;
   1.464 +      }
   1.465 +    }
   1.466 +  }
   1.467 +
   1.468 +  assert(selected_object_file_);
   1.469 +
   1.470 +  // Find the name of the selected file's architecture, to appear in
   1.471 +  // the MODULE record and in error messages.
   1.472 +  const NXArchInfo *selected_arch_info =
   1.473 +      google_breakpad::BreakpadGetArchInfoFromCpuType(
   1.474 +          selected_object_file_->cputype, selected_object_file_->cpusubtype);
   1.475 +
   1.476 +  const char *selected_arch_name = selected_arch_info->name;
   1.477 +  if (strcmp(selected_arch_name, "i386") == 0)
   1.478 +    selected_arch_name = "x86";
   1.479 +
   1.480 +  // Produce a name to use in error messages that includes the
   1.481 +  // filename, and the architecture, if there is more than one.
   1.482 +  selected_object_name_ = [object_filename_ UTF8String];
   1.483 +  if (object_files_.size() > 1) {
   1.484 +    selected_object_name_ += ", architecture ";
   1.485 +    selected_object_name_ + selected_arch_name;
   1.486 +  }
   1.487 +
   1.488 +  // Compute a module name, to appear in the MODULE record.
   1.489 +  NSString *module_name = [object_filename_ lastPathComponent];
   1.490 +
   1.491 +  // Choose an identifier string, to appear in the MODULE record.
   1.492 +  string identifier = Identifier();
   1.493 +  if (identifier.empty())
   1.494 +    return false;
   1.495 +  identifier += "0";
   1.496 +
   1.497 +  // Create a module to hold the debugging information.
   1.498 +  scoped_ptr<Module> module(new Module([module_name UTF8String],
   1.499 +                                       "mac",
   1.500 +                                       selected_arch_name,
   1.501 +                                       identifier));
   1.502 +
   1.503 +  // Parse the selected object file.
   1.504 +  mach_o::Reader::Reporter reporter(selected_object_name_);
   1.505 +  mach_o::Reader reader(&reporter);
   1.506 +  if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
   1.507 +                   + selected_object_file_->offset,
   1.508 +                   selected_object_file_->size,
   1.509 +                   selected_object_file_->cputype,
   1.510 +                   selected_object_file_->cpusubtype))
   1.511 +    return false;
   1.512 +
   1.513 +  // Walk its load commands, and deal with whatever is there.
   1.514 +  LoadCommandDumper load_command_dumper(*this, module.get(), reader,
   1.515 +                                        symbol_data_);
   1.516 +  if (!reader.WalkLoadCommands(&load_command_dumper))
   1.517 +    return false;
   1.518 +
   1.519 +  *out_module = module.release();
   1.520 +
   1.521 +  return true;
   1.522 +}
   1.523 +
   1.524 +bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
   1.525 +  Module* module = NULL;
   1.526 +
   1.527 +  if (ReadSymbolData(&module) && module) {
   1.528 +    bool res = module->Write(stream, symbol_data_);
   1.529 +    delete module;
   1.530 +    return res;
   1.531 +  }
   1.532 +
   1.533 +  return false;
   1.534 +}
   1.535 +
   1.536 +}  // namespace google_breakpad

mercurial