From 446616ee2276a4b9a30adf796c3a7bc692eb8239 Mon Sep 17 00:00:00 2001 From: "qsr@chromium.org" Date: Thu, 20 Oct 2011 15:22:48 +0000 Subject: [PATCH] Allow to retrieve id of a module from memory instead of going to disk for iOS. Allow macho_id and macho_walker to read data from memory. Wire up this when reading module on iOS. Review URL: http://breakpad.appspot.com/319001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@873 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/mac/handler/minidump_generator.cc | 28 ++++++++++--- src/client/mac/handler/minidump_generator.h | 4 +- src/common/mac/macho_id.cc | 41 +++++++++++++------- src/common/mac/macho_id.h | 15 +++++-- src/common/mac/macho_walker.cc | 28 ++++++++++++- src/common/mac/macho_walker.h | 17 +++++--- 6 files changed, 102 insertions(+), 31 deletions(-) diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index 05ee8312..f245f66d 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -54,6 +54,7 @@ #include "client/minidump_file_writer-inl.h" #include "common/mac/file_id.h" +#include "common/mac/macho_id.h" #include "common/mac/string_utilities.h" using MacStringUtils::ConvertToString; @@ -1160,7 +1161,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, module->version_info.file_version_lo |= (modVersion & 0xff); } - if (!WriteCVRecord(module, image->GetCPUType(), name.c_str())) { + if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) { return false; } } else { @@ -1206,7 +1207,11 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, module->size_of_image = static_cast(seg->vmsize); module->module_name_rva = string_location.rva; - if (!WriteCVRecord(module, cpu_type, name)) + bool in_memory = false; +#if TARGET_OS_IPHONE + in_memory = true; +#endif + if (!WriteCVRecord(module, cpu_type, name, in_memory)) return false; return true; @@ -1244,7 +1249,7 @@ int MinidumpGenerator::FindExecutableModule() { } bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, - const char *module_path) { + const char *module_path, bool in_memory) { TypedMDRVA cv(&writer_); // Only return the last path component of the full module path @@ -1270,10 +1275,23 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, cv_ptr->age = 0; // Get the module identifier - FileID file_id(module_path); unsigned char identifier[16]; + bool result = false; + if (in_memory) { + MacFileUtilities::MachoID macho(module_path, + reinterpret_cast(module->base_of_image), + static_cast(module->size_of_image)); + result = macho.UUIDCommand(cpu_type, identifier); + if (!result) + result = macho.MD5(cpu_type, identifier); + } - if (file_id.MachoIdentifier(cpu_type, identifier)) { + if (!result) { + FileID file_id(module_path); + result = file_id.MachoIdentifier(cpu_type, identifier); + } + + if (result) { cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 | (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 | (uint32_t)identifier[3]; diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h index 3ceb95be..7e932073 100644 --- a/src/client/mac/handler/minidump_generator.h +++ b/src/client/mac/handler/minidump_generator.h @@ -128,8 +128,8 @@ class MinidumpGenerator { bool WriteContext(breakpad_thread_state_data_t state, MDLocationDescriptor *register_location); bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); - bool WriteCVRecord(MDRawModule *module, int cpu_type, - const char *module_path); + bool WriteCVRecord(MDRawModule *module, int cpu_type, + const char *module_path, bool in_memory); bool WriteModuleStream(unsigned int index, MDRawModule *module); size_t CalculateStackSize(mach_vm_address_t start_addr); int FindExecutableModule(); diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc index 44e78205..ce0ecff3 100644 --- a/src/common/mac/macho_id.cc +++ b/src/common/mac/macho_id.cc @@ -52,17 +52,24 @@ extern "C" { // necessary for Leopard namespace MacFileUtilities { MachoID::MachoID(const char *path) - : file_(0), + : memory_(0), + memory_size_(0), + crc_(0), + md5_context_(), + update_function_(NULL) { + strlcpy(path_, path, sizeof(path_)); +} + +MachoID::MachoID(const char *path, void *memory, size_t size) + : memory_(memory), + memory_size_(size), crc_(0), md5_context_(), update_function_(NULL) { strlcpy(path_, path, sizeof(path_)); - file_ = open(path, O_RDONLY); } MachoID::~MachoID() { - if (file_ != -1) - close(file_); } // The CRC info is from http://en.wikipedia.org/wiki/Adler-32 @@ -144,10 +151,8 @@ void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) { bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) { struct breakpad_uuid_command uuid_cmd; - MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd); - uuid_cmd.cmd = 0; - if (!walker.WalkHeader(cpu_type)) + if (!WalkHeader(cpu_type, UUIDWalkerCB, &uuid_cmd)) return false; // If we found the command, we'll have initialized the uuid_command @@ -162,10 +167,8 @@ bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) { bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) { struct dylib_command dylib_cmd; - MachoWalker walker(path_, IDWalkerCB, &dylib_cmd); - dylib_cmd.cmd = 0; - if (!walker.WalkHeader(cpu_type)) + if (!WalkHeader(cpu_type, IDWalkerCB, &dylib_cmd)) return false; // If we found the command, we'll have initialized the dylib_command @@ -204,29 +207,39 @@ bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) { } uint32_t MachoID::Adler32(int cpu_type) { - MachoWalker walker(path_, WalkerCB, this); update_function_ = &MachoID::UpdateCRC; crc_ = 0; - if (!walker.WalkHeader(cpu_type)) + if (!WalkHeader(cpu_type, WalkerCB, this)) return 0; return crc_; } bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) { - MachoWalker walker(path_, WalkerCB, this); update_function_ = &MachoID::UpdateMD5; MD5Init(&md5_context_); - if (!walker.WalkHeader(cpu_type)) + if (!WalkHeader(cpu_type, WalkerCB, this)) return false; MD5Final(identifier, &md5_context_); return true; } +bool MachoID::WalkHeader(int cpu_type, + MachoWalker::LoadCommandCallback callback, + void *context) { + if (memory_) { + MachoWalker walker(memory_, memory_size_, callback, context); + return walker.WalkHeader(cpu_type); + } else { + MachoWalker walker(path_, callback, context); + return walker.WalkHeader(cpu_type); + } +} + // static bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, bool swap, void *context) { diff --git a/src/common/mac/macho_id.h b/src/common/mac/macho_id.h index 9bcefc56..a5338120 100644 --- a/src/common/mac/macho_id.h +++ b/src/common/mac/macho_id.h @@ -37,15 +37,15 @@ #include #include +#include "common/mac/macho_walker.h" #include "common/md5.h" namespace MacFileUtilities { -class MachoWalker; - class MachoID { public: MachoID(const char *path); + MachoID(const char *path, void *memory, size_t size); ~MachoID(); // For the given |cpu_type|, return a UUID from the LC_UUID command. @@ -80,6 +80,10 @@ class MachoID { // Bottleneck for update routines void Update(MachoWalker *walker, off_t offset, size_t size); + // Factory for the MachoWalker + bool WalkHeader(int cpu_type, 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, bool swap, void *context); @@ -95,8 +99,11 @@ class MachoID { // File path char path_[PATH_MAX]; - // File descriptor - int file_; + // Memory region to read from + void *memory_; + + // Size of the memory region + size_t memory_size_; // The current crc value uint32_t crc_; diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc index 3e8fe211..00fde03e 100644 --- a/src/common/mac/macho_walker.cc +++ b/src/common/mac/macho_walker.cc @@ -52,6 +52,8 @@ namespace MacFileUtilities { MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, void *context) : file_(0), + memory_(NULL), + memory_size_(0), callback_(callback), callback_context_(context), current_header_(NULL), @@ -60,6 +62,18 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, file_ = open(path, O_RDONLY); } +MachoWalker::MachoWalker(void *memory, size_t size, + LoadCommandCallback callback, void *context) + : file_(0), + memory_(memory), + memory_size_(size), + callback_(callback), + callback_context_(context), + current_header_(NULL), + current_header_size_(0), + current_header_offset_(0) { +} + MachoWalker::~MachoWalker() { if (file_ != -1) close(file_); @@ -90,7 +104,19 @@ bool MachoWalker::WalkHeader(int cpu_type) { } bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { - return pread(file_, buffer, size, offset) == (ssize_t)size; + if (memory_) { + bool result = true; + if (offset + size > memory_size_) { + size = memory_size_ - offset; + result = false; + } + if (size < 0) + return false; + memcpy(buffer, static_cast(memory_) + offset, size); + return result; + } else { + return pread(file_, buffer, size, offset) == (ssize_t)size; + } } bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h index 0d30b5c0..cee3eb8d 100644 --- a/src/common/mac/macho_walker.h +++ b/src/common/mac/macho_walker.h @@ -52,7 +52,8 @@ class MachoWalker { off_t offset, bool swap, void *context); MachoWalker(const char *path, LoadCommandCallback callback, void *context); - MachoWalker(int file_descriptor, LoadCommandCallback callback, void *context); + MachoWalker(void *memory, size_t size, LoadCommandCallback callback, + void *context); ~MachoWalker(); // Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the @@ -68,7 +69,7 @@ class MachoWalker { // Read |size| bytes from the opened file at |offset| into |buffer| bool ReadBytes(void *buffer, size_t size, off_t offset); - + // Return the current header and header offset bool CurrentHeader(struct mach_header_64 *header, off_t *offset); @@ -87,19 +88,25 @@ class MachoWalker { // File descriptor to the opened file int file_; + // Memory location to read from. + void *memory_; + + // Size of the memory segment we can read from. + size_t memory_size_; + // User specified callback & context LoadCommandCallback callback_; void *callback_context_; - + // Current header, size, and offset. The mach_header_64 is used for both // 32-bit and 64-bit headers because they only differ in their last field - // (reserved). By adding the |current_header_size_| and the + // (reserved). By adding the |current_header_size_| and the // |current_header_offset_|, you can determine the offset in the file just // after the header. struct mach_header_64 *current_header_; unsigned long current_header_size_; off_t current_header_offset_; - + private: MachoWalker(const MachoWalker &); MachoWalker &operator=(const MachoWalker &);