1 // -*- mode: c++ -*-
2 
3 // Copyright (c) 2011, Google Inc.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 
32 // Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
33 
34 // dump_syms.cc: Create a symbol file for use with minidumps
35 
36 #include "common/mac/dump_syms.h"
37 
38 #include <assert.h>
39 #include <dirent.h>
40 #include <errno.h>
41 #include <mach-o/arch.h>
42 #include <mach-o/fat.h>
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <unistd.h>
48 
49 #include <ostream>
50 #include <string>
51 #include <vector>
52 
53 #include "common/dwarf/bytereader-inl.h"
54 #include "common/dwarf/dwarf2reader.h"
55 #include "common/dwarf_cfi_to_module.h"
56 #include "common/dwarf_cu_to_module.h"
57 #include "common/dwarf_line_to_module.h"
58 #include "common/dwarf_range_list_handler.h"
59 #include "common/mac/file_id.h"
60 #include "common/mac/arch_utilities.h"
61 #include "common/mac/macho_reader.h"
62 #include "common/module.h"
63 #include "common/path_helper.h"
64 #include "common/scoped_ptr.h"
65 #include "common/stabs_reader.h"
66 #include "common/stabs_to_module.h"
67 #include "common/symbol_data.h"
68 
69 #ifndef CPU_TYPE_ARM
70 #define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
71 #endif //  CPU_TYPE_ARM
72 
73 #ifndef CPU_TYPE_ARM64
74 #define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228))
75 #endif  // CPU_TYPE_ARM64
76 
77 using dwarf2reader::ByteReader;
78 using google_breakpad::DwarfCUToModule;
79 using google_breakpad::DwarfLineToModule;
80 using google_breakpad::DwarfRangeListHandler;
81 using google_breakpad::FileID;
82 using google_breakpad::mach_o::FatReader;
83 using google_breakpad::mach_o::Section;
84 using google_breakpad::mach_o::Segment;
85 using google_breakpad::Module;
86 using google_breakpad::StabsReader;
87 using google_breakpad::StabsToModule;
88 using google_breakpad::scoped_ptr;
89 using std::make_pair;
90 using std::pair;
91 using std::string;
92 using std::vector;
93 
94 namespace {
95 // Return a vector<string> with absolute paths to all the entries
96 // in directory (excluding . and ..).
list_directory(const string & directory)97 vector<string> list_directory(const string& directory) {
98   vector<string> entries;
99   DIR* dir = opendir(directory.c_str());
100   if (!dir) {
101     return entries;
102   }
103 
104   string path = directory;
105   if (path[path.length() - 1] != '/') {
106     path += '/';
107   }
108 
109   struct dirent* entry = NULL;
110   while ((entry = readdir(dir))) {
111     if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
112       entries.push_back(path + entry->d_name);
113     }
114   }
115 
116   closedir(dir);
117   return entries;
118 }
119 }
120 
121 namespace google_breakpad {
122 
Read(const string & filename)123 bool DumpSymbols::Read(const string &filename) {
124   struct stat st;
125   if (stat(filename.c_str(), &st) == -1) {
126     fprintf(stderr, "Could not access object file %s: %s\n",
127             filename.c_str(), strerror(errno));
128     return false;
129   }
130 
131   input_pathname_ = filename;
132 
133   // Does this filename refer to a dSYM bundle?
134   string contents_path = input_pathname_ + "/Contents/Resources/DWARF";
135   if (S_ISDIR(st.st_mode) &&
136       access(contents_path.c_str(), F_OK) == 0) {
137     // If there's one file under Contents/Resources/DWARF then use that,
138     // otherwise bail out.
139     const vector<string> entries = list_directory(contents_path);
140     if (entries.size() == 0) {
141       fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
142               input_pathname_.c_str());
143       return false;
144     }
145     if (entries.size() > 1) {
146       fprintf(stderr, "Too many DWARF files in bundle: %s\n",
147               input_pathname_.c_str());
148       return false;
149     }
150 
151     object_filename_ = entries[0];
152   } else {
153     object_filename_ = input_pathname_;
154   }
155 
156   // Read the file's contents into memory.
157   bool read_ok = true;
158   string error;
159   if (stat(object_filename_.c_str(), &st) != -1) {
160     FILE* f = fopen(object_filename_.c_str(), "rb");
161     if (f) {
162       contents_.reset(new uint8_t[st.st_size]);
163       off_t total = 0;
164       while (total < st.st_size && !feof(f)) {
165         size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f);
166         if (read == 0) {
167           if (ferror(f)) {
168             read_ok = false;
169             error = strerror(errno);
170           }
171           break;
172         }
173         total += read;
174       }
175       fclose(f);
176     } else {
177       error = strerror(errno);
178     }
179   }
180 
181   if (!read_ok) {
182     fprintf(stderr, "Error reading object file: %s: %s\n",
183             object_filename_.c_str(),
184             error.c_str());
185     return false;
186   }
187 
188   // Get the list of object files present in the file.
189   FatReader::Reporter fat_reporter(object_filename_);
190   FatReader fat_reader(&fat_reporter);
191   if (!fat_reader.Read(&contents_[0],
192                        st.st_size)) {
193     return false;
194   }
195 
196   // Get our own copy of fat_reader's object file list.
197   size_t object_files_count;
198   const SuperFatArch *object_files =
199     fat_reader.object_files(&object_files_count);
200   if (object_files_count == 0) {
201     fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
202             object_filename_.c_str());
203     return false;
204   }
205   object_files_.resize(object_files_count);
206   memcpy(&object_files_[0], object_files,
207          sizeof(SuperFatArch) * object_files_count);
208 
209   return true;
210 }
211 
SetArchitecture(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype)212 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
213                                   cpu_subtype_t cpu_subtype) {
214   // Find the best match for the architecture the user requested.
215   const SuperFatArch *best_match = FindBestMatchForArchitecture(
216       cpu_type, cpu_subtype);
217   if (!best_match) return false;
218 
219   // Record the selected object file.
220   selected_object_file_ = best_match;
221   return true;
222 }
223 
SetArchitecture(const std::string & arch_name)224 bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
225   bool arch_set = false;
226   const NXArchInfo *arch_info =
227       google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
228   if (arch_info) {
229     arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
230   }
231   return arch_set;
232 }
233 
FindBestMatchForArchitecture(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype)234 SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
235     cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
236   // Check if all the object files can be converted to struct fat_arch.
237   bool can_convert_to_fat_arch = true;
238   vector<struct fat_arch> fat_arch_vector;
239   for (vector<SuperFatArch>::const_iterator it = object_files_.begin();
240        it != object_files_.end();
241        ++it) {
242     struct fat_arch arch;
243     bool success = it->ConvertToFatArch(&arch);
244     if (!success) {
245       can_convert_to_fat_arch = false;
246       break;
247     }
248     fat_arch_vector.push_back(arch);
249   }
250 
251   // If all the object files can be converted to struct fat_arch, use
252   // NXFindBestFatArch.
253   if (can_convert_to_fat_arch) {
254     const struct fat_arch *best_match
255       = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0],
256                           static_cast<uint32_t>(fat_arch_vector.size()));
257 
258     for (size_t i = 0; i < fat_arch_vector.size(); ++i) {
259       if (best_match == &fat_arch_vector[i])
260         return &object_files_[i];
261     }
262     assert(best_match == NULL);
263     return NULL;
264   }
265 
266   // Check for an exact match with cpu_type and cpu_subtype.
267   for (vector<SuperFatArch>::iterator it = object_files_.begin();
268        it != object_files_.end();
269        ++it) {
270     if (static_cast<cpu_type_t>(it->cputype) == cpu_type &&
271         static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype)
272       return &*it;
273   }
274 
275   // No exact match found.
276   // TODO(erikchen): If it becomes necessary, we can copy the implementation of
277   // NXFindBestFatArch, located at
278   // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
279   fprintf(stderr, "Failed to find an exact match for an object file with cpu "
280       "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
281       "larger than 2**32.\n", cpu_type, cpu_subtype);
282   return NULL;
283 }
284 
Identifier()285 string DumpSymbols::Identifier() {
286   FileID file_id(object_filename_.c_str());
287   unsigned char identifier_bytes[16];
288   cpu_type_t cpu_type = selected_object_file_->cputype;
289   cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype & ~CPU_SUBTYPE_MASK;
290   if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
291     fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
292             object_filename_.c_str());
293     return "";
294   }
295 
296   char identifier_string[40];
297   FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
298                                     sizeof(identifier_string));
299 
300   string compacted(identifier_string);
301   for(size_t i = compacted.find('-'); i != string::npos;
302       i = compacted.find('-', i))
303     compacted.erase(i, 1);
304 
305   return compacted;
306 }
307 
308 // A range handler that accepts rangelist data parsed by
309 // dwarf2reader::RangeListReader and populates a range vector (typically
310 // owned by a function) with the results.
311 class DumpSymbols::DumperRangesHandler:
312       public DwarfCUToModule::RangesHandler {
313  public:
DumperRangesHandler(const uint8_t * buffer,uint64 size,dwarf2reader::ByteReader * reader)314   DumperRangesHandler(const uint8_t *buffer, uint64 size,
315                       dwarf2reader::ByteReader* reader)
316       : buffer_(buffer), size_(size), reader_(reader) { }
317 
ReadRanges(uint64 offset,Module::Address base_address,vector<Module::Range> * ranges)318   bool ReadRanges(uint64 offset, Module::Address base_address,
319                   vector<Module::Range>* ranges) {
320     DwarfRangeListHandler handler(base_address, ranges);
321     dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
322                                                    &handler);
323 
324     return rangelist_reader.ReadRangeList(offset);
325   }
326 
327  private:
328   const uint8_t *buffer_;
329   uint64 size_;
330   dwarf2reader::ByteReader* reader_;
331 };
332 
333 // A line-to-module loader that accepts line number info parsed by
334 // dwarf2reader::LineInfo and populates a Module and a line vector
335 // with the results.
336 class DumpSymbols::DumperLineToModule:
337       public DwarfCUToModule::LineToModuleHandler {
338  public:
339   // Create a line-to-module converter using BYTE_READER.
DumperLineToModule(dwarf2reader::ByteReader * byte_reader)340   DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
341       : byte_reader_(byte_reader) { }
342 
StartCompilationUnit(const string & compilation_dir)343   void StartCompilationUnit(const string& compilation_dir) {
344     compilation_dir_ = compilation_dir;
345   }
346 
ReadProgram(const uint8_t * program,uint64 length,Module * module,vector<Module::Line> * lines)347   void ReadProgram(const uint8_t *program, uint64 length,
348                    Module *module, vector<Module::Line> *lines) {
349     DwarfLineToModule handler(module, compilation_dir_, lines);
350     dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
351     parser.Start();
352   }
353  private:
354   string compilation_dir_;
355   dwarf2reader::ByteReader *byte_reader_;  // WEAK
356 };
357 
CreateEmptyModule(scoped_ptr<Module> & module)358 bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
359   // Select an object file, if SetArchitecture hasn't been called to set one
360   // explicitly.
361   if (!selected_object_file_) {
362     // If there's only one architecture, that's the one.
363     if (object_files_.size() == 1)
364       selected_object_file_ = &object_files_[0];
365     else {
366       // Look for an object file whose architecture matches our own.
367       const NXArchInfo *local_arch = NXGetLocalArchInfo();
368       if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
369         fprintf(stderr, "%s: object file contains more than one"
370                 " architecture, none of which match the current"
371                 " architecture; specify an architecture explicitly"
372                 " with '-a ARCH' to resolve the ambiguity\n",
373                 object_filename_.c_str());
374         return false;
375       }
376     }
377   }
378 
379   assert(selected_object_file_);
380 
381   // Find the name of the selected file's architecture, to appear in
382   // the MODULE record and in error messages.
383   const NXArchInfo *selected_arch_info =
384       google_breakpad::BreakpadGetArchInfoFromCpuType(
385           selected_object_file_->cputype, selected_object_file_->cpusubtype);
386 
387   const char *selected_arch_name = selected_arch_info->name;
388   if (strcmp(selected_arch_name, "i386") == 0)
389     selected_arch_name = "x86";
390 
391   // Produce a name to use in error messages that includes the
392   // filename, and the architecture, if there is more than one.
393   selected_object_name_ = object_filename_;
394   if (object_files_.size() > 1) {
395     selected_object_name_ += ", architecture ";
396     selected_object_name_ + selected_arch_name;
397   }
398 
399   // Compute a module name, to appear in the MODULE record.
400   string module_name = google_breakpad::BaseName(object_filename_);
401 
402   // Choose an identifier string, to appear in the MODULE record.
403   string identifier = Identifier();
404   if (identifier.empty())
405     return false;
406   identifier += "0";
407 
408   // Create a module to hold the debugging information.
409   module.reset(new Module(module_name,
410                           "mac",
411                           selected_arch_name,
412                           identifier));
413   return true;
414 }
415 
ReadDwarf(google_breakpad::Module * module,const mach_o::Reader & macho_reader,const mach_o::SectionMap & dwarf_sections,bool handle_inter_cu_refs) const416 void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
417                             const mach_o::Reader &macho_reader,
418                             const mach_o::SectionMap &dwarf_sections,
419                             bool handle_inter_cu_refs) const {
420   // Build a byte reader of the appropriate endianness.
421   ByteReader byte_reader(macho_reader.big_endian()
422                          ? dwarf2reader::ENDIANNESS_BIG
423                          : dwarf2reader::ENDIANNESS_LITTLE);
424 
425   // Construct a context for this file.
426   DwarfCUToModule::FileContext file_context(selected_object_name_,
427                                             module,
428                                             handle_inter_cu_refs);
429 
430   // Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
431   for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
432        it != dwarf_sections.end(); ++it) {
433     file_context.AddSectionToSectionMap(
434         it->first,
435         it->second.contents.start,
436         it->second.contents.Size());
437   }
438 
439   // Find the __debug_info section.
440   dwarf2reader::SectionMap::const_iterator debug_info_entry =
441       file_context.section_map().find("__debug_info");
442   // There had better be a __debug_info section!
443   if (debug_info_entry == file_context.section_map().end()) {
444     fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
445             selected_object_name_.c_str());
446     return;
447   }
448   const std::pair<const uint8_t*, uint64>& debug_info_section =
449       debug_info_entry->second;
450 
451   // Build a line-to-module loader for the root handler to use.
452   DumperLineToModule line_to_module(&byte_reader);
453 
454   // Optional .debug_ranges reader
455   scoped_ptr<DumperRangesHandler> ranges_handler;
456   dwarf2reader::SectionMap::const_iterator ranges_entry =
457       file_context.section_map().find("__debug_ranges");
458   if (ranges_entry != file_context.section_map().end()) {
459     const std::pair<const uint8_t *, uint64>& ranges_section =
460       ranges_entry->second;
461     ranges_handler.reset(
462       new DumperRangesHandler(ranges_section.first, ranges_section.second,
463                               &byte_reader));
464   }
465 
466   // Walk the __debug_info section, one compilation unit at a time.
467   uint64 debug_info_length = debug_info_section.second;
468   for (uint64 offset = 0; offset < debug_info_length;) {
469     // Make a handler for the root DIE that populates MODULE with the
470     // debug info.
471     DwarfCUToModule::WarningReporter reporter(selected_object_name_,
472                                               offset);
473     DwarfCUToModule root_handler(&file_context, &line_to_module,
474                                  ranges_handler.get(), &reporter);
475     // Make a Dwarf2Handler that drives our DIEHandler.
476     dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
477     // Make a DWARF parser for the compilation unit at OFFSET.
478     dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_,
479                                                file_context.section_map(),
480                                                offset,
481                                                &byte_reader,
482                                                &die_dispatcher);
483     // Process the entire compilation unit; get the offset of the next.
484     offset += dwarf_reader.Start();
485   }
486 }
487 
ReadCFI(google_breakpad::Module * module,const mach_o::Reader & macho_reader,const mach_o::Section & section,bool eh_frame) const488 bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
489                           const mach_o::Reader &macho_reader,
490                           const mach_o::Section &section,
491                           bool eh_frame) const {
492   // Find the appropriate set of register names for this file's
493   // architecture.
494   vector<string> register_names;
495   switch (macho_reader.cpu_type()) {
496     case CPU_TYPE_X86:
497       register_names = DwarfCFIToModule::RegisterNames::I386();
498       break;
499     case CPU_TYPE_X86_64:
500       register_names = DwarfCFIToModule::RegisterNames::X86_64();
501       break;
502     case CPU_TYPE_ARM:
503       register_names = DwarfCFIToModule::RegisterNames::ARM();
504       break;
505     case CPU_TYPE_ARM64:
506       register_names = DwarfCFIToModule::RegisterNames::ARM64();
507       break;
508     default: {
509       const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
510           macho_reader.cpu_type(), macho_reader.cpu_subtype());
511       fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
512               selected_object_name_.c_str());
513       if (arch)
514         fprintf(stderr, "architecture '%s'", arch->name);
515       else
516         fprintf(stderr, "architecture %d,%d",
517                 macho_reader.cpu_type(), macho_reader.cpu_subtype());
518       fprintf(stderr, " to Breakpad symbol file: no register name table\n");
519       return false;
520     }
521   }
522 
523   // Find the call frame information and its size.
524   const uint8_t *cfi = section.contents.start;
525   size_t cfi_size = section.contents.Size();
526 
527   // Plug together the parser, handler, and their entourages.
528   DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
529                                              section.section_name);
530   DwarfCFIToModule handler(module, register_names, &module_reporter);
531   dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
532                                        dwarf2reader::ENDIANNESS_BIG :
533                                        dwarf2reader::ENDIANNESS_LITTLE);
534   byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
535   // At the moment, according to folks at Apple and some cursory
536   // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
537   // this is the only base address the CFI parser will need.
538   byte_reader.SetCFIDataBase(section.address, cfi);
539 
540   dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
541                                                        section.section_name);
542   dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
543                                      &byte_reader, &handler, &dwarf_reporter,
544                                      eh_frame);
545   parser.Start();
546   return true;
547 }
548 
549 // A LoadCommandHandler that loads whatever debugging data it finds into a
550 // Module.
551 class DumpSymbols::LoadCommandDumper:
552       public mach_o::Reader::LoadCommandHandler {
553  public:
554   // Create a load command dumper handling load commands from READER's
555   // file, and adding data to MODULE.
LoadCommandDumper(const DumpSymbols & dumper,google_breakpad::Module * module,const mach_o::Reader & reader,SymbolData symbol_data,bool handle_inter_cu_refs)556   LoadCommandDumper(const DumpSymbols &dumper,
557                     google_breakpad::Module *module,
558                     const mach_o::Reader &reader,
559                     SymbolData symbol_data,
560                     bool handle_inter_cu_refs)
561       : dumper_(dumper),
562         module_(module),
563         reader_(reader),
564         symbol_data_(symbol_data),
565         handle_inter_cu_refs_(handle_inter_cu_refs) { }
566 
567   bool SegmentCommand(const mach_o::Segment &segment);
568   bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
569 
570  private:
571   const DumpSymbols &dumper_;
572   google_breakpad::Module *module_;  // WEAK
573   const mach_o::Reader &reader_;
574   const SymbolData symbol_data_;
575   const bool handle_inter_cu_refs_;
576 };
577 
SegmentCommand(const Segment & segment)578 bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
579   mach_o::SectionMap section_map;
580   if (!reader_.MapSegmentSections(segment, &section_map))
581     return false;
582 
583   if (segment.name == "__TEXT") {
584     module_->SetLoadAddress(segment.vmaddr);
585     if (symbol_data_ != NO_CFI) {
586       mach_o::SectionMap::const_iterator eh_frame =
587           section_map.find("__eh_frame");
588       if (eh_frame != section_map.end()) {
589         // If there is a problem reading this, don't treat it as a fatal error.
590         dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
591       }
592     }
593     return true;
594   }
595 
596   if (segment.name == "__DWARF") {
597     if (symbol_data_ != ONLY_CFI) {
598       dumper_.ReadDwarf(module_, reader_, section_map, handle_inter_cu_refs_);
599     }
600     if (symbol_data_ != NO_CFI) {
601       mach_o::SectionMap::const_iterator debug_frame
602           = section_map.find("__debug_frame");
603       if (debug_frame != section_map.end()) {
604         // If there is a problem reading this, don't treat it as a fatal error.
605         dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
606       }
607     }
608   }
609 
610   return true;
611 }
612 
SymtabCommand(const ByteBuffer & entries,const ByteBuffer & strings)613 bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
614                                                    const ByteBuffer &strings) {
615   StabsToModule stabs_to_module(module_);
616   // Mac OS X STABS are never "unitized", and the size of the 'value' field
617   // matches the address size of the executable.
618   StabsReader stabs_reader(entries.start, entries.Size(),
619                            strings.start, strings.Size(),
620                            reader_.big_endian(),
621                            reader_.bits_64() ? 8 : 4,
622                            true,
623                            &stabs_to_module);
624   if (!stabs_reader.Process())
625     return false;
626   stabs_to_module.Finalize();
627   return true;
628 }
629 
ReadSymbolData(Module ** out_module)630 bool DumpSymbols::ReadSymbolData(Module** out_module) {
631   scoped_ptr<Module> module;
632   if (!CreateEmptyModule(module))
633     return false;
634 
635   // Parse the selected object file.
636   mach_o::Reader::Reporter reporter(selected_object_name_);
637   mach_o::Reader reader(&reporter);
638   if (!reader.Read(&contents_[0]
639                    + selected_object_file_->offset,
640                    selected_object_file_->size,
641                    selected_object_file_->cputype,
642                    selected_object_file_->cpusubtype))
643     return false;
644 
645   // Walk its load commands, and deal with whatever is there.
646   LoadCommandDumper load_command_dumper(*this, module.get(), reader,
647                                         symbol_data_, handle_inter_cu_refs_);
648   if (!reader.WalkLoadCommands(&load_command_dumper))
649     return false;
650 
651   *out_module = module.release();
652 
653   return true;
654 }
655 
WriteSymbolFile(std::ostream & stream)656 bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
657   Module* module = NULL;
658 
659   if (ReadSymbolData(&module) && module) {
660     bool res = module->Write(stream, symbol_data_);
661     delete module;
662     return res;
663   }
664 
665   return false;
666 }
667 
668 // Read the selected object file's debugging information, and write out the
669 // header only to |stream|. Return true on success; if an error occurs, report
670 // it and return false.
WriteSymbolFileHeader(std::ostream & stream)671 bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) {
672   scoped_ptr<Module> module;
673   if (!CreateEmptyModule(module))
674     return false;
675 
676   return module->Write(stream, symbol_data_);
677 }
678 
679 }  // namespace google_breakpad
680