aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErwin Jansen <jansene@google.com>2023-04-24 11:22:12 -0700
committerErwin Jansen <jansene@google.com>2023-04-24 11:22:12 -0700
commitdbe52e2e00172fe95e1c3c0de2637d968bfda387 (patch)
tree6e63001ba5e7300844e1864fc8519c27c8db452c
parent9a8a410e97d310f449913df41ada7445420f9cc8 (diff)
parentf548d75c9fa8bc062a580dbe5edb2fae2106d5c9 (diff)
downloadgoogle-breakpad-emu-34-release.tar.gz
This merges the latest changes from breakpad. This might help with the upload failures we are seeing on MacOs. Bug: 279454764 Change-Id: I0cc4f1cf0f73a3a790dfb8e947bbd634fc09abc4
-rw-r--r--src/common/dwarf_cfi_to_module.cc23
-rw-r--r--src/common/dwarf_cfi_to_module.h3
-rw-r--r--src/common/dwarf_cfi_to_module_unittest.cc12
-rw-r--r--src/common/dwarf_cu_to_module.cc32
-rw-r--r--src/common/dwarf_cu_to_module_unittest.cc13
-rw-r--r--src/common/linux/dump_symbols.cc4
-rw-r--r--src/common/linux/memory_mapped_file.cc7
-rw-r--r--src/common/mac/arch_utilities.cc97
-rw-r--r--src/common/mac/arch_utilities.h26
-rw-r--r--src/common/mac/dump_syms.cc129
-rw-r--r--src/common/mac/dump_syms.h48
-rw-r--r--src/common/mac/macho_walker.cc9
-rw-r--r--src/common/module.cc15
-rw-r--r--src/common/module.h16
-rw-r--r--src/common/module_unittest.cc31
-rw-r--r--src/processor/minidump.cc9
-rw-r--r--src/processor/minidump_processor.cc10
-rw-r--r--src/processor/minidump_stackwalk.cc12
-rw-r--r--src/processor/stackwalk_common.cc73
-rw-r--r--src/processor/stackwalk_common.h1
-rw-r--r--src/tools/mac/dump_syms/dump_syms_tool.cc84
-rw-r--r--src/tools/mac/dump_syms/macho_dump.cc206
22 files changed, 400 insertions, 460 deletions
diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc
index 287c851e..7e04d3c5 100644
--- a/src/common/dwarf_cfi_to_module.cc
+++ b/src/common/dwarf_cfi_to_module.cc
@@ -147,6 +147,29 @@ vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
}
+vector<string> DwarfCFIToModule::RegisterNames::RISCV() {
+ static const char *const names[] = {
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+ "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+ };
+
+ return MakeVector(names, sizeof(names) / sizeof(names[0]));
+}
+
bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length,
uint8_t version, const string& augmentation,
unsigned return_address) {
diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h
index 42b618d5..19297db9 100644
--- a/src/common/dwarf_cfi_to_module.h
+++ b/src/common/dwarf_cfi_to_module.h
@@ -114,6 +114,9 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// MIPS.
static vector<string> MIPS();
+ // RISC-V.
+ static vector<string> RISCV();
+
private:
// Given STRINGS, an array of C strings with SIZE elements, return an
// equivalent vector<string>.
diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc
index 43b5e7c4..b407edd0 100644
--- a/src/common/dwarf_cfi_to_module_unittest.cc
+++ b/src/common/dwarf_cfi_to_module_unittest.cc
@@ -307,3 +307,15 @@ TEST(RegisterNames, X86_64) {
EXPECT_EQ("$rsp", names[7]);
EXPECT_EQ("$rip", names[16]);
}
+
+TEST(RegisterNames, RISCV) {
+ vector<string> names = DwarfCFIToModule::RegisterNames::RISCV();
+
+ EXPECT_EQ("x0", names[0]);
+ EXPECT_EQ("x31", names[31]);
+ EXPECT_EQ("f0", names[32]);
+ EXPECT_EQ("f31", names[63]);
+ EXPECT_EQ("v0", names[96]);
+ EXPECT_EQ("v31", names[127]);
+}
+
diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc
index 43b468c1..708ed143 100644
--- a/src/common/dwarf_cu_to_module.cc
+++ b/src/common/dwarf_cu_to_module.cc
@@ -330,7 +330,10 @@ class DwarfCUToModule::GenericDIEHandler: public DIEHandler {
// Use this from EndAttributes member functions, not ProcessAttribute*
// functions; only the former can be sure that all the DIE's attributes
// have been seen.
- StringView ComputeQualifiedName();
+ //
+ // On return, if has_qualified_name is non-NULL, *has_qualified_name is set to
+ // true if the DIE includes a fully-qualified name, false otherwise.
+ StringView ComputeQualifiedName(bool* has_qualified_name);
CUContext* cu_context_;
DIEContext* parent_context_;
@@ -466,7 +469,8 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
}
}
-StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
+StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName(
+ bool* has_qualified_name) {
// Use the demangled name, if one is available. Demangled names are
// preferable to those inferred from the DWARF structure because they
// include argument types.
@@ -482,6 +486,15 @@ StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
StringView* unqualified_name = nullptr;
StringView* enclosing_name = nullptr;
if (!qualified_name) {
+ if (has_qualified_name) {
+ // dSYMs built with -gmlt do not include the DW_AT_linkage_name
+ // with the unmangled symbol, but rather include it in the
+ // LC_SYMTAB STABS, which end up in the externs of the module.
+ //
+ // Remember this so the Module can copy over the extern name later.
+ *has_qualified_name = false;
+ }
+
// Find the unqualified name. If the DIE has its own DW_AT_name
// attribute, then use that; otherwise, check the specification.
if (!name_attribute_.empty()) {
@@ -500,6 +513,10 @@ StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
} else if (parent_context_) {
enclosing_name = &parent_context_->name;
}
+ } else {
+ if (has_qualified_name) {
+ *has_qualified_name = true;
+ }
}
// Prepare the return value before upcoming mutations possibly invalidate the
@@ -722,7 +739,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
ranges_form_(DW_FORM_sec_offset),
ranges_data_(0),
inline_(false),
- handle_inline_(handle_inline) {}
+ handle_inline_(handle_inline),
+ has_qualified_name_(false) {}
void ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form,
@@ -745,6 +763,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
bool inline_;
vector<unique_ptr<Module::Inline>> child_inlines_;
bool handle_inline_;
+ bool has_qualified_name_;
DIEContext child_context_; // A context for our children.
};
@@ -808,7 +827,7 @@ DIEHandler* DwarfCUToModule::FuncHandler::FindChildHandler(
bool DwarfCUToModule::FuncHandler::EndAttributes() {
// Compute our name, and record a specification, if appropriate.
- name_ = ComputeQualifiedName();
+ name_ = ComputeQualifiedName(&has_qualified_name_);
if (name_.empty() && abstract_origin_) {
name_ = abstract_origin_->name;
}
@@ -881,6 +900,9 @@ void DwarfCUToModule::FuncHandler::Finish() {
scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
func->ranges = ranges;
func->parameter_size = 0;
+ // If the name was unqualified, prefer the Extern name if there's a mismatch
+ // (the Extern name will be fully-qualified in that case).
+ func->prefer_extern_name = !has_qualified_name_;
if (func->address) {
// If the function address is zero this is a sign that this function
// description is just empty debug data and should just be discarded.
@@ -915,7 +937,7 @@ void DwarfCUToModule::FuncHandler::Finish() {
}
bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
- child_context_.name = ComputeQualifiedName();
+ child_context_.name = ComputeQualifiedName(NULL);
if (child_context_.name.empty() && no_specification) {
cu_context_->reporter->UnknownSpecification(offset_, specification_offset_);
}
diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc
index 7ab2f15c..134b2c24 100644
--- a/src/common/dwarf_cu_to_module_unittest.cc
+++ b/src/common/dwarf_cu_to_module_unittest.cc
@@ -267,6 +267,10 @@ class CUFixtureBase {
void TestFunction(int i, const string& name,
Module::Address address, Module::Address size);
+ // Test that the I'th function (ordered by address) in the module
+ // this.module_ has the given prefer_extern_name.
+ void TestFunctionPreferExternName(int i, bool prefer_extern_name);
+
// Test that the number of source lines owned by the I'th function
// in the module this.module_ is equal to EXPECTED.
void TestLineCount(int i, size_t expected);
@@ -615,6 +619,15 @@ void CUFixtureBase::TestFunction(int i, const string& name,
EXPECT_EQ(0U, function->parameter_size);
}
+void CUFixtureBase::TestFunctionPreferExternName(int i,
+ bool prefer_extern_name) {
+ FillFunctions();
+ ASSERT_LT((size_t)i, functions_.size());
+
+ Module::Function* function = functions_[i];
+ EXPECT_EQ(prefer_extern_name, function->prefer_extern_name);
+}
+
void CUFixtureBase::TestLineCount(int i, size_t expected) {
FillFunctions();
ASSERT_LT((size_t) i, functions_.size());
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index 48e4c926..8179663b 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -449,6 +449,9 @@ bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header,
case EM_X86_64:
*register_names = DwarfCFIToModule::RegisterNames::X86_64();
return true;
+ case EM_RISCV:
+ *register_names = DwarfCFIToModule::RegisterNames::RISCV();
+ return true;
default:
return false;
}
@@ -1022,6 +1025,7 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
case EM_SPARC: return "sparc";
case EM_SPARCV9: return "sparcv9";
case EM_X86_64: return "x86_64";
+ case EM_RISCV: return "riscv";
default: return NULL;
}
}
diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc
index 568312cf..a7b96eb5 100644
--- a/src/common/linux/memory_mapped_file.cc
+++ b/src/common/linux/memory_mapped_file.cc
@@ -61,8 +61,11 @@ MemoryMappedFile::~MemoryMappedFile() {
bool MemoryMappedFile::Map(const char* path, size_t offset) {
Unmap();
-
- int fd = sys_open(path, O_RDONLY, 0);
+ // Based on https://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html
+ // If O_NONBLOCK is set: The open() function will return without blocking
+ // for the device to be ready or available. Setting this value will provent
+ // hanging if file is not avilable.
+ int fd = sys_open(path, O_RDONLY | O_NONBLOCK, 0);
if (fd == -1) {
return false;
}
diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc
index 543c7c4a..febf8a22 100644
--- a/src/common/mac/arch_utilities.cc
+++ b/src/common/mac/arch_utilities.cc
@@ -53,86 +53,44 @@
#define CPU_SUBTYPE_ARM64_E (static_cast<cpu_subtype_t>(2))
#endif // CPU_SUBTYPE_ARM64_E
-namespace {
-
-const NXArchInfo* ArchInfo_arm64(cpu_subtype_t cpu_subtype) {
- const char* name = NULL;
- switch (cpu_subtype) {
- case CPU_SUBTYPE_ARM64_ALL:
- name = "arm64";
- break;
- case CPU_SUBTYPE_ARM64_E:
- name = "arm64e";
- break;
- default:
- return NULL;
- }
-
- NXArchInfo* arm64 = new NXArchInfo;
- *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
- CPU_SUBTYPE_ARM_V7);
- arm64->name = name;
- arm64->cputype = CPU_TYPE_ARM64;
- arm64->cpusubtype = cpu_subtype;
- arm64->description = "arm 64";
- return arm64;
-}
-
-const NXArchInfo* ArchInfo_armv7s() {
- NXArchInfo* armv7s = new NXArchInfo;
- *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
- CPU_SUBTYPE_ARM_V7);
- armv7s->name = "armv7s";
- armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S;
- armv7s->description = "arm v7s";
- return armv7s;
-}
-
-} // namespace
-
-namespace google_breakpad {
-
-const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) {
+std::optional<ArchInfo> GetArchInfoFromName(const char* arch_name) {
// TODO: Remove this when the OS knows about arm64.
if (!strcmp("arm64", arch_name))
- return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64,
- CPU_SUBTYPE_ARM64_ALL);
+ return ArchInfo{CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL};
if (!strcmp("arm64e", arch_name))
- return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64,
- CPU_SUBTYPE_ARM64_E);
-
+ return ArchInfo{CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_E};
// TODO: Remove this when the OS knows about armv7s.
if (!strcmp("armv7s", arch_name))
- return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S);
+ return ArchInfo{CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S};
- return NXGetArchInfoFromName(arch_name);
+ const NXArchInfo* info = NXGetArchInfoFromName(arch_name);
+ if (info)
+ return ArchInfo{info->cputype, info->cpusubtype};
+ return std::nullopt;
}
-const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype) {
+const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
// TODO: Remove this when the OS knows about arm64.
if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) {
- static const NXArchInfo* arm64 = ArchInfo_arm64(cpu_subtype);
- return arm64;
+ return "arm64";
}
if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_E) {
- static const NXArchInfo* arm64e = ArchInfo_arm64(cpu_subtype);
- return arm64e;
+ return "arm64e";
}
// TODO: Remove this when the OS knows about armv7s.
if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) {
- static const NXArchInfo* armv7s = ArchInfo_armv7s();
- return armv7s;
+ return "armv7s";
}
- return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
+ const NXArchInfo* info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
+ if (info)
+ return info->name;
+ return kUnknownArchName;
}
-} // namespace google_breakpad
-
// TODO(crbug.com/1242776): The "#ifndef __APPLE__" should be here, but the
// system version of NXGetLocalArchInfo returns incorrect information on
// x86_64 machines (treating them as just x86), so use the Breakpad version
@@ -207,7 +165,7 @@ const NXArchInfo kKnownArchitectures[] = {
} // namespace
-const NXArchInfo *NXGetLocalArchInfo(void) {
+ArchInfo GetLocalArchInfo(void) {
Architecture arch;
#if defined(__i386__)
arch = kArch_i386;
@@ -222,7 +180,8 @@ const NXArchInfo *NXGetLocalArchInfo(void) {
#else
#error "Unsupported CPU architecture"
#endif
- return &kKnownArchitectures[arch];
+ NXArchInfo info = kKnownArchitectures[arch];
+ return {info.cputype, info.cpusubtype};
}
#ifndef __APPLE__
@@ -251,22 +210,4 @@ const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype,
}
return candidate;
}
-
-struct fat_arch *NXFindBestFatArch(cpu_type_t cputype,
- cpu_subtype_t cpusubtype,
- struct fat_arch *fat_archs,
- uint32_t nfat_archs) {
- struct fat_arch *candidate = NULL;
- for (uint32_t f = 0; f < nfat_archs; ++f) {
- if (fat_archs[f].cputype == cputype) {
- if (fat_archs[f].cpusubtype == cpusubtype) {
- return &fat_archs[f];
- }
- if (!candidate) {
- candidate = &fat_archs[f];
- }
- }
- }
- return candidate;
-}
#endif // !__APPLE__
diff --git a/src/common/mac/arch_utilities.h b/src/common/mac/arch_utilities.h
index d267c43b..3b036738 100644
--- a/src/common/mac/arch_utilities.h
+++ b/src/common/mac/arch_utilities.h
@@ -31,16 +31,26 @@
#ifndef COMMON_MAC_ARCH_UTILITIES_H__
#define COMMON_MAC_ARCH_UTILITIES_H__
-#include <mach-o/arch.h>
+#include <mach/machine.h>
-namespace google_breakpad {
+#include <optional>
-// Custom implementation of |NXGetArchInfoFromName| and
-// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes.
-const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name);
-const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype);
+static constexpr const char* kUnknownArchName = "<Unknown architecture>";
-} // namespace google_breakpad
+struct ArchInfo {
+ cpu_type_t cputype;
+ cpu_subtype_t cpusubtype;
+};
+
+// Returns architecture info if `arch_name` corresponds to a valid, known
+// architecture, and std::nullopt otherwise.
+std::optional<ArchInfo> GetArchInfoFromName(const char* arch_name);
+
+// Returns the name of the architecture specified by `cpu_type` and
+// `cpu_subtype`, or `kUnknownArchName` if it's unknown or invalid.
+const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
+
+// Returns the architecture of the machine this code is running on.
+ArchInfo GetLocalArchInfo();
#endif // COMMON_MAC_ARCH_UTILITIES_H__
diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc
index e1025f79..dd91196a 100644
--- a/src/common/mac/dump_syms.cc
+++ b/src/common/mac/dump_syms.cc
@@ -221,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.
@@ -233,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() {
@@ -402,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"
@@ -418,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";
@@ -442,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();
@@ -451,7 +420,7 @@ 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;
}
@@ -540,16 +509,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;
}
}
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
index c2e1b40b..5bcb0b58 100644
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -43,6 +43,7 @@
#include <vector>
#include "common/byte_cursor.h"
+#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
#include "common/mac/super_fat_arch.h"
#include "common/module.h"
@@ -55,7 +56,9 @@ class DumpSymbols {
public:
DumpSymbols(SymbolData symbol_data,
bool handle_inter_cu_refs,
- bool enable_multiple = false)
+ bool enable_multiple = false,
+ const std::string& module_name = "",
+ bool prefer_extern_name = false)
: symbol_data_(symbol_data),
handle_inter_cu_refs_(handle_inter_cu_refs),
object_filename_(),
@@ -65,12 +68,19 @@ class DumpSymbols {
object_files_(),
selected_object_file_(),
selected_object_name_(),
- enable_multiple_(enable_multiple) {}
+ enable_multiple_(enable_multiple),
+ module_name_(module_name),
+ prefer_extern_name_(prefer_extern_name) {}
~DumpSymbols() = default;
// Prepare to read debugging information from |filename|. |filename| may be
// the name of a fat file, a Mach-O file, or a dSYM bundle containing either
- // of the above. On success, return true; if there is a problem reading
+ // of the above.
+ //
+ // If |module_name_| is empty, uses the basename of |filename| as the module
+ // name. Otherwise, uses |module_name_| as the module name.
+ //
+ // On success, return true; if there is a problem reading
// |filename|, report it and return false.
bool Read(const std::string& filename);
@@ -82,26 +92,15 @@ class DumpSymbols {
// problem reading |contents|, report it and return false.
bool ReadData(uint8_t* contents, size_t size, const std::string& filename);
- // If this dumper's file includes an object file for |cpu_type| and
- // |cpu_subtype|, then select that object file for dumping, and return
- // true. Otherwise, return false, and leave this dumper's selected
- // architecture unchanged.
+ // If this dumper's file includes an object file for `info`, then select that
+ // object file for dumping, and return true. Otherwise, return false, and
+ // leave this dumper's selected architecture unchanged.
//
// By default, if this dumper's file contains only one object file, then
// the dumper will dump those symbols; and if it contains more than one
// object file, then the dumper will dump the object file whose
// architecture matches that of this dumper program.
- bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
-
- // If this dumper's file includes an object file for |arch_name|, then select
- // that object file for dumping, and return true. Otherwise, return false,
- // and leave this dumper's selected architecture unchanged.
- //
- // By default, if this dumper's file contains only one object file, then
- // the dumper will dump those symbols; and if it contains more than one
- // object file, then the dumper will dump the object file whose
- // architecture matches that of this dumper program.
- bool SetArchitecture(const std::string& arch_name);
+ bool SetArchitecture(const ArchInfo& info);
// Return a pointer to an array of SuperFatArch structures describing the
// object files contained in this dumper's file. Set *|count| to the number
@@ -204,6 +203,19 @@ class DumpSymbols {
// See: https://crbug.com/google-breakpad/751 and docs at
// docs/symbol_files.md#records-3
bool enable_multiple_;
+
+ // If non-empty, used as the module name. Otherwise, the basename of
+ // |object_filename_| is used as the module name.
+ const std::string module_name_;
+
+ // If a Function and an Extern share the same address but have a different
+ // name, prefer the name of the Extern.
+ //
+ // Use this when dumping Mach-O .dSYMs built with -gmlt (Minimum Line Tables),
+ // as the Function's fully-qualified name will only be present in the STABS
+ // (which are placed in the Extern), not in the DWARF symbols (which are
+ // placed in the Function).
+ bool prefer_extern_name_;
};
} // namespace google_breakpad
diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc
index f9cd9327..4b9f56c2 100644
--- a/src/common/mac/macho_walker.cc
+++ b/src/common/mac/macho_walker.cc
@@ -38,15 +38,15 @@
#include <assert.h>
#include <fcntl.h>
-#include <mach-o/arch.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <string.h>
#include <unistd.h>
+#include "common/mac/arch_utilities.h"
#include "common/mac/byteswap.h"
-#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"
+#include "common/mac/macho_walker.h"
namespace MacFileUtilities {
@@ -85,9 +85,8 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
cpu_subtype_t valid_cpu_subtype = cpu_subtype;
// if |cpu_type| is 0, use the native cpu type.
if (cpu_type == 0) {
- const NXArchInfo* arch = NXGetLocalArchInfo();
- assert(arch);
- valid_cpu_type = arch->cputype;
+ ArchInfo arch = GetLocalArchInfo();
+ valid_cpu_type = arch.cputype;
valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
}
off_t offset;
diff --git a/src/common/module.cc b/src/common/module.cc
index a5c1b6ad..e61c3b7a 100644
--- a/src/common/module.cc
+++ b/src/common/module.cc
@@ -105,14 +105,16 @@ Module::Module(const string& name,
const string& architecture,
const string& id,
const string& code_id /* = "" */,
- bool enable_multiple_field /* = false*/)
+ bool enable_multiple_field /* = false*/,
+ bool prefer_extern_name /* = false*/)
: name_(name),
os_(os),
architecture_(architecture),
id_(id),
code_id_(code_id),
load_address_(0),
- enable_multiple_field_(enable_multiple_field) {}
+ enable_multiple_field_(enable_multiple_field),
+ prefer_extern_name_(prefer_extern_name) {}
Module::~Module() {
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
@@ -152,11 +154,14 @@ bool Module::AddFunction(Function* function) {
it_ext = externs_.find(&arm_thumb_ext);
}
if (it_ext != externs_.end()) {
+ Extern* found_ext = it_ext->get();
+ bool name_mismatch = found_ext->name != function->name;
if (enable_multiple_field_) {
- Extern* found_ext = it_ext->get();
// If the PUBLIC is for the same symbol as the FUNC, don't mark multiple.
- function->is_multiple |=
- found_ext->name != function->name || found_ext->is_multiple;
+ function->is_multiple |= name_mismatch || found_ext->is_multiple;
+ }
+ if (name_mismatch && prefer_extern_name_) {
+ function->name = AddStringToPool(it_ext->get()->name);
}
externs_.erase(it_ext);
}
diff --git a/src/common/module.h b/src/common/module.h
index c1fd9f59..d736701f 100644
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -131,6 +131,10 @@ class Module {
// If this symbol has been folded with other symbols in the linked binary.
bool is_multiple = false;
+
+ // If the function's name should be filled out from a matching Extern,
+ // should they not match.
+ bool prefer_extern_name = false;
};
struct InlineOrigin {
@@ -317,7 +321,8 @@ class Module {
const string& architecture,
const string& id,
const string& code_id = "",
- bool enable_multiple_field = false);
+ bool enable_multiple_field = false,
+ bool prefer_extern_name = false);
~Module();
// Set the module's load address to LOAD_ADDRESS; addresses given
@@ -502,6 +507,15 @@ class Module {
// at
// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md#records-3
bool enable_multiple_field_;
+
+ // If a Function and an Extern share the same address but have a different
+ // name, prefer the name of the Extern.
+ //
+ // Use this when dumping Mach-O .dSYMs built with -gmlt (Minimum Line Tables),
+ // as the Function's fully-qualified name will only be present in the STABS
+ // (which are placed in the Extern), not in the DWARF symbols (which are
+ // placed in the Function).
+ bool prefer_extern_name_;
};
} // namespace google_breakpad
diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
index 213b3154..6a6762e5 100644
--- a/src/common/module_unittest.cc
+++ b/src/common/module_unittest.cc
@@ -641,6 +641,37 @@ TEST(Module, ConstructFunctionsAndExternsWithSameAddress) {
}
// If there exists an extern and a function at the same address, only write
+// out the FUNC entry.
+TEST(Module, ConstructFunctionsAndExternsWithSameAddressPreferExternName) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", false, true);
+
+ // Two externs.
+ auto extern1 = std::make_unique<Module::Extern>(0xabc0);
+ extern1->name = "extern1";
+ auto extern2 = std::make_unique<Module::Extern>(0xfff0);
+ extern2->name = "extern2";
+
+ m.AddExtern(std::move(extern1));
+ m.AddExtern(std::move(extern2));
+
+ Module::Function* function = new Module::Function("function2", 0xfff0);
+ Module::Range range(0xfff0, 0x10);
+ function->ranges.push_back(range);
+ function->parameter_size = 0;
+ m.AddFunction(function);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME
+ "\n"
+ "FUNC fff0 10 0 extern2\n"
+ "PUBLIC abc0 0 extern1\n",
+ contents.c_str());
+}
+
+// If there exists an extern and a function at the same address, only write
// out the FUNC entry, and mark it with `m` if the multiple field is enabled.
TEST(Module, ConstructFunctionsAndExternsWithSameAddressMultiple) {
stringstream s;
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index 0f08271d..84a7f8c6 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -76,6 +76,11 @@ using std::vector;
namespace {
+// Limit arrived at by adding up possible states in Intel Ch. 13.5 X-SAVE
+// MANAGED STATE
+// (~ 3680 bytes) plus some extra for the future.
+const uint32_t kMaxXSaveAreaSize = 16384;
+
// Returns true iff |context_size| matches exactly one of the sizes of the
// various MDRawContext* types.
// TODO(blundell): This function can be removed once
@@ -507,6 +512,10 @@ bool MinidumpContext::Read(uint32_t expected_size) {
// sizeof(MDRawContextAMD64). For now we skip this extended data.
if (expected_size > sizeof(MDRawContextAMD64)) {
size_t bytes_left = expected_size - sizeof(MDRawContextAMD64);
+ if (bytes_left > kMaxXSaveAreaSize) {
+ BPLOG(ERROR) << "MinidumpContext oversized xstate area";
+ return false;
+ }
std::vector<uint8_t> xstate(bytes_left);
if (!minidump_->ReadBytes(xstate.data(),
bytes_left)) {
diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc
index d56a7d63..5ba6ff4f 100644
--- a/src/processor/minidump_processor.cc
+++ b/src/processor/minidump_processor.cc
@@ -633,6 +633,16 @@ bool MinidumpProcessor::GetCPUInfo(Minidump* dump, SystemInfo* info) {
break;
}
+ case MD_CPU_ARCHITECTURE_RISCV: {
+ info->cpu = "riscv";
+ break;
+ }
+
+ case MD_CPU_ARCHITECTURE_RISCV64: {
+ info->cpu = "riscv64";
+ break;
+ }
+
default: {
// Assign the numeric architecture ID into the CPU string.
char cpu_string[7];
diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc
index 4c7a94f4..d44ddf84 100644
--- a/src/processor/minidump_stackwalk.cc
+++ b/src/processor/minidump_stackwalk.cc
@@ -66,6 +66,7 @@ struct Options {
bool machine_readable;
bool output_stack_contents;
bool output_requesting_thread_only;
+ bool brief;
string minidump_file;
std::vector<string> symbol_paths;
@@ -119,6 +120,8 @@ bool PrintMinidumpProcess(const Options& options) {
if (options.machine_readable) {
PrintProcessStateMachineReadable(process_state);
+ } else if (options.brief) {
+ PrintRequestingThreadBrief(process_state);
} else {
PrintProcessState(process_state, options.output_stack_contents,
options.output_requesting_thread_only, &resolver);
@@ -139,7 +142,8 @@ static void Usage(int argc, const char *argv[], bool error) {
"\n"
" -m Output in machine-readable format\n"
" -s Output stack contents\n"
- " -c Output thread that causes crash or dump only\n",
+ " -c Output thread that causes crash or dump only\n"
+ " -b Brief of the thread that causes crash or dump\n",
google_breakpad::BaseName(argv[0]).c_str());
}
@@ -149,14 +153,18 @@ static void SetupOptions(int argc, const char *argv[], Options* options) {
options->machine_readable = false;
options->output_stack_contents = false;
options->output_requesting_thread_only = false;
+ options->brief = false;
- while ((ch = getopt(argc, (char * const*)argv, "chms")) != -1) {
+ while ((ch = getopt(argc, (char* const*)argv, "bchms")) != -1) {
switch (ch) {
case 'h':
Usage(argc, argv, false);
exit(0);
break;
+ case 'b':
+ options->brief = true;
+ break;
case 'c':
options->output_requesting_thread_only = true;
break;
diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc
index 253960f5..644ede79 100644
--- a/src/processor/stackwalk_common.cc
+++ b/src/processor/stackwalk_common.cc
@@ -281,7 +281,33 @@ static void PrintStackContents(const string& indent,
}
-// PrintStack prints the call stack in |stack| to PrintStream, in a reasonably
+static void PrintFrameHeader(const StackFrame* frame, int frame_index) {
+ fprintf(PrintStream, "%2d ", frame_index);
+
+ uint64_t instruction_address = frame->ReturnAddress();
+
+ if (frame->module) {
+ fprintf(PrintStream, "%s", PathnameStripper::File(frame->module->code_file()).c_str());
+ if (!frame->function_name.empty()) {
+ fprintf(PrintStream, "!%s", frame->function_name.c_str());
+ if (!frame->source_file_name.empty()) {
+ string source_file = PathnameStripper::File(frame->source_file_name);
+ fprintf(PrintStream, " [%s : %d + 0x%" PRIx64 "]", source_file.c_str(),
+ frame->source_line,
+ instruction_address - frame->source_line_base);
+ } else {
+ fprintf(PrintStream, " + 0x%" PRIx64, instruction_address - frame->function_base);
+ }
+ } else {
+ fprintf(PrintStream, " + 0x%" PRIx64,
+ instruction_address - frame->module->base_address());
+ }
+ } else {
+ fprintf(PrintStream, "0x%" PRIx64, instruction_address);
+ }
+}
+
+// PrintStack prints the call stack in |stack| to stdout, in a reasonably
// useful form. Module, function, and source file names are displayed if
// they are available. The code offset to the base code address of the
// source line, function, or module is printed, preferring them in that
@@ -302,30 +328,8 @@ static void PrintStack(const CallStack* stack,
}
for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
const StackFrame* frame = stack->frames()->at(frame_index);
- fprintf(PrintStream, "%2d ", frame_index);
-
- uint64_t instruction_address = frame->ReturnAddress();
-
- if (frame->module) {
- fprintf(PrintStream, "%s", PathnameStripper::File(frame->module->code_file()).c_str());
- if (!frame->function_name.empty()) {
- fprintf(PrintStream, "!%s", frame->function_name.c_str());
- if (!frame->source_file_name.empty()) {
- string source_file = PathnameStripper::File(frame->source_file_name);
- fprintf(PrintStream, " [%s : %d + 0x%" PRIx64 "]",
- source_file.c_str(),
- frame->source_line,
- instruction_address - frame->source_line_base);
- } else {
- fprintf(PrintStream, " + 0x%" PRIx64, instruction_address - frame->function_base);
- }
- } else {
- fprintf(PrintStream, " + 0x%" PRIx64,
- instruction_address - frame->module->base_address());
- }
- } else {
- fprintf(PrintStream, "0x%" PRIx64, instruction_address);
- }
+ PrintFrameHeader(frame, frame_index);
+ fprintf(PrintStream, "\n ");
fprintf(PrintStream, "\n ");
// Inlined frames don't have registers info.
@@ -996,7 +1000,7 @@ static void PrintStackMachineReadable(int thread_num, const CallStack* stack) {
instruction_address - frame->module->base_address());
}
} else {
- // the printf before this prints a trailing separator for module name
+ // the fprintf before this prints a trailing separator for module name
fprintf(PrintStream, "%c%c%c%c0x%" PRIx64,
kOutputSeparator, // empty function name
kOutputSeparator, // empty source file
@@ -1287,4 +1291,21 @@ void PrintProcessStateMachineReadable(const ProcessState& process_state) {
}
}
+void PrintRequestingThreadBrief(const ProcessState& process_state) {
+ int requesting_thread = process_state.requesting_thread();
+ if (requesting_thread == -1) {
+ fprintf(PrintStream, " <no crashing or requesting dump thread identified>\n");
+ return;
+ }
+
+ fprintf(PrintStream, "Thread %d (%s)\n", requesting_thread,
+ process_state.crashed() ? "crashed" : "requested dump, did not crash");
+ const CallStack* stack = process_state.threads()->at(requesting_thread);
+ int frame_count = stack->frames()->size();
+ for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
+ PrintFrameHeader(stack->frames()->at(frame_index), frame_index);
+ fprintf(PrintStream, "\n");
+ }
+}
+
} // namespace google_breakpad
diff --git a/src/processor/stackwalk_common.h b/src/processor/stackwalk_common.h
index 5a861bbd..b2266e4d 100644
--- a/src/processor/stackwalk_common.h
+++ b/src/processor/stackwalk_common.h
@@ -45,6 +45,7 @@ void PrintProcessState(const ProcessState& process_state,
bool output_stack_contents,
bool output_requesting_thread_only,
SourceLineResolverInterface* resolver);
+void PrintRequestingThreadBrief(const ProcessState& process_state);
} // namespace google_breakpad
diff --git a/src/tools/mac/dump_syms/dump_syms_tool.cc b/src/tools/mac/dump_syms/dump_syms_tool.cc
index 2f2815c5..9fb8d13f 100644
--- a/src/tools/mac/dump_syms/dump_syms_tool.cc
+++ b/src/tools/mac/dump_syms/dump_syms_tool.cc
@@ -63,16 +63,20 @@ struct Options {
cfi(true),
handle_inter_cu_refs(true),
handle_inlines(false),
- enable_multiple(false) {}
+ enable_multiple(false),
+ module_name(),
+ prefer_extern_name(false) {}
string srcPath;
string dsymPath;
- const NXArchInfo *arch;
+ std::optional<ArchInfo> arch;
bool header_only;
bool cfi;
bool handle_inter_cu_refs;
bool handle_inlines;
bool enable_multiple;
+ string module_name;
+ bool prefer_extern_name;
};
static bool StackFrameEntryComparator(const Module::StackFrameEntry* a,
@@ -121,11 +125,12 @@ static void CopyCFIDataBetweenModules(Module* to_module,
}
static bool SetArchitecture(DumpSymbols& dump_symbols,
- const NXArchInfo* arch,
+ const ArchInfo& arch,
const std::string& filename) {
- if (!dump_symbols.SetArchitecture(arch->cputype, arch->cpusubtype)) {
+ if (!dump_symbols.SetArchitecture(arch)) {
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
- filename.c_str(), arch->name);
+ filename.c_str(),
+ GetNameFromCPUType(arch.cputype, arch.cpusubtype));
size_t available_size;
const SuperFatArch* available =
dump_symbols.AvailableArchitectures(&available_size);
@@ -135,14 +140,8 @@ static bool SetArchitecture(DumpSymbols& dump_symbols,
fprintf(stderr, "architectures present in the file are:\n");
for (size_t i = 0; i < available_size; i++) {
const SuperFatArch* arch = &available[i];
- const NXArchInfo* arch_info =
- google_breakpad::BreakpadGetArchInfoFromCpuType(arch->cputype,
- arch->cpusubtype);
- if (arch_info)
- fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description);
- else
- fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n",
- arch->cputype, arch->cpusubtype);
+ fprintf(stderr, "%s\n",
+ GetNameFromCPUType(arch->cputype, arch->cpusubtype));
}
return false;
}
@@ -154,7 +153,8 @@ static bool Start(const Options& options) {
(options.handle_inlines ? INLINES : NO_DATA) |
(options.cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES;
DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs,
- options.enable_multiple);
+ options.enable_multiple, options.module_name,
+ options.prefer_extern_name);
// For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the
// Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI
@@ -173,7 +173,7 @@ static bool Start(const Options& options) {
return false;
if (options.arch &&
- !SetArchitecture(dump_symbols, options.arch, primary_file)) {
+ !SetArchitecture(dump_symbols, *options.arch, primary_file)) {
return false;
}
@@ -193,7 +193,7 @@ static bool Start(const Options& options) {
return false;
if (options.arch &&
- !SetArchitecture(dump_symbols, options.arch, options.srcPath)) {
+ !SetArchitecture(dump_symbols, *options.arch, options.srcPath)) {
return false;
}
Module* cfi_module = NULL;
@@ -201,13 +201,38 @@ static bool Start(const Options& options) {
return false;
scoped_ptr<Module> scoped_cfi_module(cfi_module);
+ bool name_matches;
+ if (!options.module_name.empty()) {
+ // Ignore the basename of the dSYM and binary and use the passed-in module
+ // name.
+ name_matches = true;
+ } else {
+ name_matches = cfi_module->name() == module->name();
+ }
+
// Ensure that the modules are for the same debug code file.
- if (cfi_module->name() != module->name() ||
- cfi_module->os() != module->os() ||
+ if (!name_matches || cfi_module->os() != module->os() ||
cfi_module->architecture() != module->architecture() ||
cfi_module->identifier() != module->identifier()) {
fprintf(stderr, "Cannot generate a symbol file from split sources that do"
" not match.\n");
+ if (!name_matches) {
+ fprintf(stderr, "Name mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->name().c_str(), module->name().c_str());
+ }
+ if (cfi_module->os() != module->os()) {
+ fprintf(stderr, "OS mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->os().c_str(), module->os().c_str());
+ }
+ if (cfi_module->architecture() != module->architecture()) {
+ fprintf(stderr, "Architecture mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->architecture().c_str(),
+ module->architecture().c_str());
+ }
+ if (cfi_module->identifier() != module->identifier()) {
+ fprintf(stderr, "Identifier mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->identifier().c_str(), module->identifier().c_str());
+ }
return false;
}
@@ -220,8 +245,10 @@ static bool Start(const Options& options) {
//=============================================================================
static void Usage(int argc, const char *argv[]) {
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
- fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] "
- "<Mach-o file>\n", argv[0]);
+ fprintf(stderr,
+ "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] "
+ "[-n MODULE] [-x] <Mach-o file>\n",
+ argv[0]);
fprintf(stderr, "\t-i: Output module header information only.\n");
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n");
fprintf(stderr, "\t in the file, if it contains only one architecture]\n");
@@ -233,6 +260,12 @@ static void Usage(int argc, const char *argv[]) {
fprintf(stderr,
"\t-m: Enable writing the optional 'm' field on FUNC "
"and PUBLIC, denoting multiple symbols for the address.\n");
+ fprintf(stderr,
+ "\t-n: Use MODULE as the name of the module rather than \n"
+ "the basename of the Mach-O file/dSYM.\n");
+ fprintf(stderr,
+ "\t-x: Prefer the PUBLIC (extern) name over the FUNC if\n"
+ "they do not match.\n");
fprintf(stderr, "\t-h: Usage\n");
fprintf(stderr, "\t-?: Usage\n");
}
@@ -242,14 +275,13 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
extern int optind;
signed char ch;
- while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?h")) != -1) {
+ while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?hn:x")) != -1) {
switch (ch) {
case 'i':
options->header_only = true;
break;
case 'a': {
- const NXArchInfo *arch_info =
- google_breakpad::BreakpadGetArchInfoFromName(optarg);
+ std::optional<ArchInfo> arch_info = GetArchInfoFromName(optarg);
if (!arch_info) {
fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg);
Usage(argc, argv);
@@ -273,6 +305,12 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
case 'm':
options->enable_multiple = true;
break;
+ case 'n':
+ options->module_name = optarg;
+ break;
+ case 'x':
+ options->prefer_extern_name = true;
+ break;
case '?':
case 'h':
Usage(argc, argv);
diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc
deleted file mode 100644
index 2610025c..00000000
--- a/src/tools/mac/dump_syms/macho_dump.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2010 Google LLC
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google LLC nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-
-// macho_dump.cc: Dump the contents of a Mach-O file. This is mostly
-// a test program for the Mach_O::FatReader and Mach_O::Reader classes.
-
-#ifdef HAVE_CONFIG_H
-#include <config.h> // Must come first
-#endif
-
-#include <errno.h>
-#include <fcntl.h>
-#include <mach-o/arch.h>
-#include <sys/mman.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "common/byte_cursor.h"
-#include "common/mac/arch_utilities.h"
-#include "common/mac/macho_reader.h"
-#include "common/path_helper.h"
-
-using google_breakpad::ByteBuffer;
-using std::ostringstream;
-using std::string;
-using std::vector;
-
-namespace {
-namespace mach_o = google_breakpad::mach_o;
-
-string program_name;
-
-int check_syscall(int result, const char* operation, const char* filename) {
- if (result < 0) {
- fprintf(stderr, "%s: %s '%s': %s\n",
- program_name.c_str(), operation,
- filename, strerror(errno));
- exit(1);
- }
- return result;
-}
-
-class DumpSection: public mach_o::Reader::SectionHandler {
- public:
- DumpSection() : index_(0) { }
- bool HandleSection(const mach_o::Section& section) {
- printf(" section %d '%s' in segment '%s'\n"
- " address: 0x%llx\n"
- " alignment: 1 << %d B\n"
- " flags: %d\n"
- " size: %ld\n",
- index_++, section.section_name.c_str(), section.segment_name.c_str(),
- section.address, section.align,
- mach_o::SectionFlags(section.flags),
- section.contents.Size());
- return true;
- }
-
- private:
- int index_;
-};
-
-class DumpCommand: public mach_o::Reader::LoadCommandHandler {
- public:
- DumpCommand(mach_o::Reader* reader) : reader_(reader), index_(0) { }
- bool UnknownCommand(mach_o::LoadCommandType type,
- const ByteBuffer& contents) {
- printf(" load command %d: %d", index_++, type);
- return true;
- }
- bool SegmentCommand(const mach_o::Segment& segment) {
- printf(" load command %d: %s-bit segment '%s'\n"
- " address: 0x%llx\n"
- " memory size: 0x%llx\n"
- " maximum protection: 0x%x\n"
- " initial protection: 0x%x\n"
- " flags: %d\n"
- " section_list size: %ld B\n",
- index_++, (segment.bits_64 ? "64" : "32"), segment.name.c_str(),
- segment.vmaddr, segment.vmsize, segment.maxprot,
- segment.initprot, mach_o::SegmentFlags(segment.flags),
- segment.section_list.Size());
-
- DumpSection dump_section;
- return reader_->WalkSegmentSections(segment, &dump_section);
- }
- private:
- mach_o::Reader* reader_;
- int index_;
-};
-
-void DumpFile(const char* filename) {
- int fd = check_syscall(open(filename, O_RDONLY), "opening", filename);
- struct stat attributes;
- check_syscall(fstat(fd, &attributes),
- "getting file attributes for", filename);
- void* mapping = mmap(NULL, attributes.st_size, PROT_READ,
- MAP_PRIVATE, fd, 0);
- close(fd);
- check_syscall(mapping == (void*)-1 ? -1 : 0,
- "mapping contents of", filename);
-
- mach_o::FatReader::Reporter fat_reporter(filename);
- mach_o::FatReader fat_reader(&fat_reporter);
- if (!fat_reader.Read(reinterpret_cast<uint8_t*>(mapping),
- attributes.st_size)) {
- exit(1);
- }
- printf("filename: %s\n", filename);
- size_t object_files_size;
- const SuperFatArch* super_fat_object_files =
- fat_reader.object_files(&object_files_size);
- struct fat_arch* object_files;
- if (!super_fat_object_files->ConvertToFatArch(object_files)) {
- exit(1);
- }
- printf(" object file count: %ld\n", object_files_size);
- for (size_t i = 0; i < object_files_size; i++) {
- const struct fat_arch& file = object_files[i];
- const NXArchInfo* fat_arch_info =
- google_breakpad::BreakpadGetArchInfoFromCpuType(
- file.cputype, file.cpusubtype);
- printf("\n object file %ld:\n"
- " fat header:\n:"
- " CPU type: %s (%s)\n"
- " size: %d B\n"
- " alignment: 1<<%d B\n",
- i, fat_arch_info->name, fat_arch_info->description,
- file.size, file.align);
-
- ostringstream name;
- name << filename;
- if (object_files_size > 1)
- name << ", object file #" << i;
- ByteBuffer file_contents(reinterpret_cast<uint8_t*>(mapping)
- + file.offset, file.size);
- mach_o::Reader::Reporter reporter(name.str());
- mach_o::Reader reader(&reporter);
- if (!reader.Read(file_contents, file.cputype, file.cpusubtype)) {
- exit(1);
- }
-
- const NXArchInfo* macho_arch_info =
- NXGetArchInfoFromCpuType(reader.cpu_type(),
- reader.cpu_subtype());
- printf(" Mach-O header:\n"
- " word size: %s\n"
- " CPU type: %s (%s)\n"
- " File type: %d\n"
- " flags: %x\n",
- (reader.bits_64() ? "64 bits" : "32 bits"),
- macho_arch_info->name, macho_arch_info->description,
- reader.file_type(), reader.flags());
-
- DumpCommand dump_command(&reader);
- reader.WalkLoadCommands(&dump_command);
- }
- munmap(mapping, attributes.st_size);
-}
-
-} // namespace
-
-int main(int argc, char** argv) {
- program_name = google_breakpad::BaseName(argv[0]);
- if (argc == 1) {
- fprintf(stderr, "Usage: %s FILE ...\n"
- "Dump the contents of the Mach-O or fat binary files "
- "'FILE ...'.\n", program_name.c_str());
- }
- for (int i = 1; i < argc; i++) {
- DumpFile(argv[i]);
- }
-}