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
This commit is contained in:
qsr@chromium.org 2012-10-04 13:26:47 +00:00
parent a1da3a504b
commit 872d464500
9 changed files with 95 additions and 65 deletions

View file

@ -31,6 +31,7 @@
#include <cstdio>
#include <mach/host_info.h>
#include <mach/machine.h>
#include <mach/vm_statistics.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
@ -1304,14 +1305,15 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
MacFileUtilities::MachoID macho(module_path,
reinterpret_cast<void *>(module->base_of_image),
static_cast<size_t>(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) {

View file

@ -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;
}

View file

@ -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 "";

View file

@ -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

View file

@ -35,6 +35,7 @@
#define COMMON_MAC_FILE_ID_H__
#include <limits.h>
#include <mach/machine.h>
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__

View file

@ -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);
}
}

View file

@ -35,6 +35,7 @@
#define COMMON_MAC_MACHO_ID_H__
#include <limits.h>
#include <mach/machine.h>
#include <mach-o/loader.h>
#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,

View file

@ -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;
}

View file

@ -34,6 +34,7 @@
#ifndef COMMON_MAC_MACHO_WALKER_H__
#define COMMON_MAC_MACHO_WALKER_H__
#include <mach/machine.h>
#include <mach-o/loader.h>
#include <sys/types.h>
@ -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.