From 872d4645006af69f7a322d5d30254c4bcec41bc2 Mon Sep 17 00:00:00 2001 From: "qsr@chromium.org" Date: Thu, 4 Oct 2012 13:26:47 +0000 Subject: [PATCH] Update dump_syms to correctly filter on cpu subtype. Right now, if an archive contain multiple executable for the same CPU but with different subtype, there is no way to dump any but the first one. Review URL: https://breakpad.appspot.com/476002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1061 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/mac/handler/minidump_generator.cc | 8 +++-- src/common/mac/arch_utilities.cc | 1 + src/common/mac/dump_syms.mm | 3 +- src/common/mac/file_id.cc | 8 +++-- src/common/mac/file_id.h | 17 +++++---- src/common/mac/macho_id.cc | 27 ++++++++------ src/common/mac/macho_id.h | 33 +++++++++++------ src/common/mac/macho_walker.cc | 37 +++++++++++--------- src/common/mac/macho_walker.h | 26 +++++++------- 9 files changed, 95 insertions(+), 65 deletions(-) diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index d5bce994..fac1a60b 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -1304,14 +1305,15 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, MacFileUtilities::MachoID macho(module_path, reinterpret_cast(module->base_of_image), static_cast(module->size_of_image)); - result = macho.UUIDCommand(cpu_type, identifier); + result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); if (!result) - result = macho.MD5(cpu_type, identifier); + result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); } if (!result) { FileID file_id(module_path); - result = file_id.MachoIdentifier(cpu_type, identifier); + result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE, + identifier); } if (result) { diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc index 6f7c494c..972a3dae 100644 --- a/src/common/mac/arch_utilities.cc +++ b/src/common/mac/arch_utilities.cc @@ -53,6 +53,7 @@ const NXArchInfo* ArchInfo_armv7s() { CPU_SUBTYPE_ARM_V7); armv7s->name = "armv7s"; armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S; + armv7s->description = "arm v7s"; return armv7s; } diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm index ad2afd01..d79afe26 100644 --- a/src/common/mac/dump_syms.mm +++ b/src/common/mac/dump_syms.mm @@ -204,7 +204,8 @@ string DumpSymbols::Identifier() { FileID file_id([object_filename_ fileSystemRepresentation]); unsigned char identifier_bytes[16]; cpu_type_t cpu_type = selected_object_file_->cputype; - if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) { + cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; + if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", [object_filename_ fileSystemRepresentation]); return ""; diff --git a/src/common/mac/file_id.cc b/src/common/mac/file_id.cc index b81cf834..a2ee320b 100644 --- a/src/common/mac/file_id.cc +++ b/src/common/mac/file_id.cc @@ -70,13 +70,15 @@ bool FileID::FileIdentifier(unsigned char identifier[16]) { return true; } -bool FileID::MachoIdentifier(int cpu_type, unsigned char identifier[16]) { +bool FileID::MachoIdentifier(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]) { MachoID macho(path_); - if (macho.UUIDCommand(cpu_type, identifier)) + if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier)) return true; - return macho.MD5(cpu_type, identifier); + return macho.MD5(cpu_type, cpu_subtype, identifier); } // static diff --git a/src/common/mac/file_id.h b/src/common/mac/file_id.h index eb06b0d6..1d6dfde1 100644 --- a/src/common/mac/file_id.h +++ b/src/common/mac/file_id.h @@ -35,6 +35,7 @@ #define COMMON_MAC_FILE_ID_H__ #include +#include namespace google_breakpad { @@ -50,15 +51,18 @@ class FileID { bool FileIdentifier(unsigned char identifier[16]); // Treat the file as a mach-o file that will contain one or more archicture. - // Accepted values for |cpu_type| (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC) - // are listed in /usr/include/mach/machine.h. - // If |cpu_type| is 0, then the native cpu type is used. - // Returns false if opening the file failed or if the |cpu_type| is not - // present in the file. + // Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or + // CPU_TYPE_POWERPC) are listed in /usr/include/mach/machine.h. + // If |cpu_type| is 0, then the native cpu type is used. If |cpu_subtype| is + // CPU_SUBTYPE_MULTIPLE, the match is only done on |cpu_type|. + // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype| + // is not present in the file. // Return the unique identifier in |identifier|. // The current implementation will look for the (in order of priority): // LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|. - bool MachoIdentifier(int cpu_type, unsigned char identifier[16]); + bool MachoIdentifier(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); // Convert the |identifier| data to a NULL terminated string. The string will // be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE). @@ -75,4 +79,3 @@ class FileID { } // namespace google_breakpad #endif // COMMON_MAC_FILE_ID_H__ - diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc index abe1fabd..aa2cfc83 100644 --- a/src/common/mac/macho_id.cc +++ b/src/common/mac/macho_id.cc @@ -153,10 +153,12 @@ void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) { } } -bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) { +bool MachoID::UUIDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char bytes[16]) { struct breakpad_uuid_command uuid_cmd; uuid_cmd.cmd = 0; - if (!WalkHeader(cpu_type, UUIDWalkerCB, &uuid_cmd)) + if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd)) return false; // If we found the command, we'll have initialized the uuid_command @@ -169,10 +171,12 @@ bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) { return false; } -bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) { +bool MachoID::IDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]) { struct dylib_command dylib_cmd; dylib_cmd.cmd = 0; - if (!WalkHeader(cpu_type, IDWalkerCB, &dylib_cmd)) + if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd)) return false; // If we found the command, we'll have initialized the dylib_command @@ -210,37 +214,38 @@ bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) { return false; } -uint32_t MachoID::Adler32(int cpu_type) { +uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { update_function_ = &MachoID::UpdateCRC; crc_ = 0; - if (!WalkHeader(cpu_type, WalkerCB, this)) + if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) return 0; return crc_; } -bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) { +bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) { update_function_ = &MachoID::UpdateMD5; MD5Init(&md5_context_); - if (!WalkHeader(cpu_type, WalkerCB, this)) + if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) return false; MD5Final(identifier, &md5_context_); return true; } -bool MachoID::WalkHeader(int cpu_type, +bool MachoID::WalkHeader(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, MachoWalker::LoadCommandCallback callback, void *context) { if (memory_) { MachoWalker walker(memory_, memory_size_, callback, context); - return walker.WalkHeader(cpu_type); + return walker.WalkHeader(cpu_type, cpu_subtype); } else { MachoWalker walker(path_, callback, context); - return walker.WalkHeader(cpu_type); + return walker.WalkHeader(cpu_type, cpu_subtype); } } diff --git a/src/common/mac/macho_id.h b/src/common/mac/macho_id.h index ccb126d4..10375491 100644 --- a/src/common/mac/macho_id.h +++ b/src/common/mac/macho_id.h @@ -35,6 +35,7 @@ #define COMMON_MAC_MACHO_ID_H__ #include +#include #include #include "common/mac/macho_walker.h" @@ -48,22 +49,32 @@ class MachoID { MachoID(const char *path, void *memory, size_t size); ~MachoID(); - // For the given |cpu_type|, return a UUID from the LC_UUID command. + // For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID + // command. // Return false if there isn't a LC_UUID command. - bool UUIDCommand(int cpu_type, unsigned char identifier[16]); + bool UUIDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); - // For the given |cpu_type|, return a UUID from the LC_ID_DYLIB command. + // For the given |cpu_type| and |cpu_subtype|, return a UUID from the + // LC_ID_DYLIB command. // Return false if there isn't a LC_ID_DYLIB command. - bool IDCommand(int cpu_type, unsigned char identifier[16]); + bool IDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); - // For the given |cpu_type|, return the Adler32 CRC for the mach-o data - // segment(s). + // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the + // mach-o data segment(s). // Return 0 on error (e.g., if the file is not a mach-o file) - uint32_t Adler32(int cpu_type); + uint32_t Adler32(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype); - // For the given |cpu_type|, return the MD5 for the mach-o data segment(s). + // For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o + // data segment(s). // Return true on success, false otherwise - bool MD5(int cpu_type, unsigned char identifier[16]); + bool MD5(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); private: // Signature of class member function to be called with data read from file @@ -81,8 +92,8 @@ class MachoID { void Update(MachoWalker *walker, off_t offset, size_t size); // Factory for the MachoWalker - bool WalkHeader(int cpu_type, MachoWalker::LoadCommandCallback callback, - void *context); + bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, + MachoWalker::LoadCommandCallback callback, void *context); // The callback from the MachoWalker for CRC and MD5 static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc index eb915c39..b2948b71 100644 --- a/src/common/mac/macho_walker.cc +++ b/src/common/mac/macho_walker.cc @@ -79,21 +79,18 @@ MachoWalker::~MachoWalker() { close(file_); } -int MachoWalker::ValidateCPUType(int cpu_type) { - // If the user didn't specify, use the local architecture. +bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + cpu_type_t valid_cpu_type = cpu_type; + 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); - cpu_type = arch->cputype; + valid_cpu_type = arch->cputype; + valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; } - - return cpu_type; -} - -bool MachoWalker::WalkHeader(int cpu_type) { - int valid_cpu_type = ValidateCPUType(cpu_type); off_t offset; - if (FindHeader(valid_cpu_type, offset)) { + if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) { if (cpu_type & CPU_ARCH_ABI64) return WalkHeader64AtOffset(offset); @@ -131,8 +128,9 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { return false; } -bool MachoWalker::FindHeader(int cpu_type, off_t &offset) { - int valid_cpu_type = ValidateCPUType(cpu_type); +bool MachoWalker::FindHeader(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + off_t &offset) { // Read the magic bytes that's common amongst all mach-o files uint32_t magic; if (!ReadBytes(&magic, sizeof(magic), 0)) @@ -153,15 +151,18 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) { if (!is_fat) { // If we don't have a fat header, check if the cpu type matches the single // header - cpu_type_t header_cpu_type; - if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset)) + struct mach_header header; + if (!ReadBytes(&header, sizeof(header), 0)) return false; if (magic == MH_CIGAM || magic == MH_CIGAM_64) - header_cpu_type = ByteSwap(header_cpu_type); + swap_mach_header(&header, NXHostByteOrder()); - if (valid_cpu_type != header_cpu_type) + if (cpu_type != header.cputype || + (cpu_subtype != CPU_SUBTYPE_MULTIPLE && + cpu_subtype != header.cpusubtype)) { return false; + } offset = 0; return true; @@ -186,7 +187,9 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) { if (NXHostByteOrder() != NX_BigEndian) swap_fat_arch(&arch, 1, NXHostByteOrder()); - if (arch.cputype == valid_cpu_type) { + if (arch.cputype == cpu_type && + (cpu_subtype == CPU_SUBTYPE_MULTIPLE || + arch.cpusubtype == cpu_subtype)) { offset = arch.offset; return true; } diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h index cee3eb8d..dd535814 100644 --- a/src/common/mac/macho_walker.h +++ b/src/common/mac/macho_walker.h @@ -34,6 +34,7 @@ #ifndef COMMON_MAC_MACHO_WALKER_H__ #define COMMON_MAC_MACHO_WALKER_H__ +#include #include #include @@ -56,16 +57,14 @@ class MachoWalker { void *context); ~MachoWalker(); - // Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the - // native cpu type is used. Otherwise, accepted values are listed in - // /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC). - // Returns false if opening the file failed or if the |cpu_type| is not - // present in the file. - bool WalkHeader(int cpu_type); - - // Locate (if any) the header offset for |cpu_type| and return in |offset|. - // Return true if found, false otherwise. - bool FindHeader(int cpu_type, off_t &offset); + // Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type| + // is 0, then the native cpu type is used. Otherwise, accepted values are + // listed in /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or + // CPU_TYPE_POWERPC). If |cpu_subtype| is CPU_SUBTYPE_MULTIPLE, the match is + // only done on |cpu_type|. + // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype| + // is not present in the file. + bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); // Read |size| bytes from the opened file at |offset| into |buffer| bool ReadBytes(void *buffer, size_t size, off_t offset); @@ -74,8 +73,11 @@ class MachoWalker { bool CurrentHeader(struct mach_header_64 *header, off_t *offset); private: - // Validate the |cpu_type| - int ValidateCPUType(int cpu_type); + // Locate (if any) the header offset for |cpu_type| and return in |offset|. + // Return true if found, false otherwise. + bool FindHeader(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + off_t &offset); // Process an individual header starting at |offset| from the start of the // file. Return true if successful, false otherwise.