diff options
Diffstat (limited to 'src/common/mac/dump_syms.cc')
-rw-r--r-- | src/common/mac/dump_syms.cc | 201 |
1 files changed, 115 insertions, 86 deletions
diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc index 9658b2c6..c06945e4 100644 --- a/src/common/mac/dump_syms.cc +++ b/src/common/mac/dump_syms.cc @@ -32,6 +32,10 @@ // dump_syms.cc: Create a symbol file for use with minidumps +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/dump_syms.h" #include <assert.h> @@ -217,11 +221,10 @@ bool DumpSymbols::ReadData(uint8_t* contents, size_t size, return true; } -bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { +bool DumpSymbols::SetArchitecture(const ArchInfo& info) { // Find the best match for the architecture the user requested. - const SuperFatArch* best_match = FindBestMatchForArchitecture( - cpu_type, cpu_subtype); + const SuperFatArch* best_match = + FindBestMatchForArchitecture(info.cputype, info.cpusubtype); if (!best_match) return false; // Record the selected object file. @@ -229,70 +232,37 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, return true; } -bool DumpSymbols::SetArchitecture(const std::string& arch_name) { - bool arch_set = false; - const NXArchInfo* arch_info = - google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str()); - if (arch_info) { - arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype); - } - return arch_set; -} SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( - cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - // Check if all the object files can be converted to struct fat_arch. - bool can_convert_to_fat_arch = true; - vector<struct fat_arch> fat_arch_vector; - for (vector<SuperFatArch>::const_iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - struct fat_arch arch; - bool success = it->ConvertToFatArch(&arch); - if (!success) { - can_convert_to_fat_arch = false; - break; - } - fat_arch_vector.push_back(arch); - } - - // If all the object files can be converted to struct fat_arch, use - // NXFindBestFatArch. - if (can_convert_to_fat_arch) { - const struct fat_arch* best_match - = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0], - static_cast<uint32_t>(fat_arch_vector.size())); - - for (size_t i = 0; i < fat_arch_vector.size(); ++i) { - if (best_match == &fat_arch_vector[i]) - return &object_files_[i]; + cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype) { + SuperFatArch* closest_match = nullptr; + for (auto& object_file : object_files_) { + if (static_cast<cpu_type_t>(object_file.cputype) == cpu_type) { + // If there's an exact match, return it directly. + if ((static_cast<cpu_subtype_t>(object_file.cpusubtype) & + ~CPU_SUBTYPE_MASK) == (cpu_subtype & ~CPU_SUBTYPE_MASK)) { + return &object_file; + } + // Otherwise, hold on to this as the closest match since at least the CPU + // type matches. + if (!closest_match) { + closest_match = &object_file; + } } - assert(best_match == NULL); - // Fall through since NXFindBestFatArch can't find arm slices on x86_64 - // macOS 13. See FB11955188. } - - // Check for an exact match with cpu_type and cpu_subtype. - for (vector<SuperFatArch>::iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - if (static_cast<cpu_type_t>(it->cputype) == cpu_type && - (static_cast<cpu_subtype_t>(it->cpusubtype) & ~CPU_SUBTYPE_MASK) == - (cpu_subtype & ~CPU_SUBTYPE_MASK)) - return &*it; - } - // No exact match found. - // TODO(erikchen): If it becomes necessary, we can copy the implementation of - // NXFindBestFatArch, located at - // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. - fprintf(stderr, "Failed to find an exact match for an object file with cpu " - "type: %d and cpu subtype: %d.\n", cpu_type, cpu_subtype); - if (!can_convert_to_fat_arch) { - fprintf(stderr, "Furthermore, at least one object file is larger " - "than 2**32.\n"); + fprintf(stderr, + "Failed to find an exact match for an object file with cpu " + "type: %d and cpu subtype: %d.\n", + cpu_type, cpu_subtype); + if (closest_match) { + fprintf(stderr, "Using %s as the closest match.\n", + GetNameFromCPUType(closest_match->cputype, + closest_match->cpusubtype)); + return closest_match; } - return NULL; + return nullptr; } string DumpSymbols::Identifier() { @@ -398,8 +368,8 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { selected_object_file_ = &object_files_[0]; else { // Look for an object file whose architecture matches our own. - const NXArchInfo* local_arch = NXGetLocalArchInfo(); - if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { + ArchInfo local_arch = GetLocalArchInfo(); + if (!SetArchitecture(local_arch)) { fprintf(stderr, "%s: object file contains more than one" " architecture, none of which match the current" " architecture; specify an architecture explicitly" @@ -414,18 +384,16 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { // Find the name of the selected file's architecture, to appear in // the MODULE record and in error messages. - const NXArchInfo* selected_arch_info = - google_breakpad::BreakpadGetArchInfoFromCpuType( - selected_object_file_->cputype, selected_object_file_->cpusubtype); + const char* selected_arch_name = GetNameFromCPUType( + selected_object_file_->cputype, selected_object_file_->cpusubtype); // In certain cases, it is possible that architecture info can't be reliably // determined, e.g. new architectures that breakpad is unware of. In that // case, avoid crashing and return false instead. - if (selected_arch_info == NULL) { + if (selected_arch_name == kUnknownArchName) { return false; } - const char* selected_arch_name = selected_arch_info->name; if (strcmp(selected_arch_name, "i386") == 0) selected_arch_name = "x86"; @@ -438,7 +406,12 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { } // Compute a module name, to appear in the MODULE record. - string module_name = google_breakpad::BaseName(object_filename_); + string module_name; + if (!module_name_.empty()) { + module_name = module_name_; + } else { + module_name = google_breakpad::BaseName(object_filename_); + } // Choose an identifier string, to appear in the MODULE record. string identifier = Identifier(); @@ -447,18 +420,71 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { // Create a module to hold the debugging information. module.reset(new Module(module_name, "mac", selected_arch_name, identifier, - "", enable_multiple_)); + "", enable_multiple_, prefer_extern_name_)); return true; } +void DumpSymbols::StartProcessSplitDwarf( + google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + void DumpSymbols::ReadDwarf(google_breakpad::Module* module, const mach_o::Reader& macho_reader, const mach_o::SectionMap& dwarf_sections, bool handle_inter_cu_refs) const { // Build a byte reader of the appropriate endianness. - ByteReader byte_reader(macho_reader.big_endian() - ? ENDIANNESS_BIG - : ENDIANNESS_LITTLE); + google_breakpad::Endianness endianness = + macho_reader.big_endian() ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; + ByteReader byte_reader(endianness); // Construct a context for this file. DwarfCUToModule::FileContext file_context(selected_object_name_, @@ -494,14 +520,14 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, // Walk the __debug_info section, one compilation unit at a time. uint64_t debug_info_length = debug_info_section.second; + bool handle_inline = symbol_data_ & INLINES; for (uint64_t offset = 0; offset < debug_info_length;) { // Make a handler for the root DIE that populates MODULE with the // debug info. DwarfCUToModule::WarningReporter reporter(selected_object_name_, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - &ranges_handler, &reporter, - symbol_data_ & INLINES); + &ranges_handler, &reporter, handle_inline); // Make a Dwarf2Handler that drives our DIEHandler. DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. @@ -512,6 +538,11 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += dwarf_reader.Start(); + // Start to process split dwarf file. + if (dwarf_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&dwarf_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } } } @@ -536,16 +567,14 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module* module, register_names = DwarfCFIToModule::RegisterNames::ARM64(); break; default: { - const NXArchInfo* arch = google_breakpad::BreakpadGetArchInfoFromCpuType( - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, "%s: cannot convert DWARF call frame information for ", - selected_object_name_.c_str()); - if (arch) - fprintf(stderr, "architecture '%s'", arch->name); - else - fprintf(stderr, "architecture %d,%d", - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, " to Breakpad symbol file: no register name table\n"); + const char* arch_name = GetNameFromCPUType(macho_reader.cpu_type(), + macho_reader.cpu_subtype()); + fprintf( + stderr, + "%s: cannot convert DWARF call frame information for architecture " + "'%s' (%d, %d) to Breakpad symbol file: no register name table\n", + selected_object_name_.c_str(), arch_name, macho_reader.cpu_type(), + macho_reader.cpu_subtype()); return false; } } |