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
This commit is contained in:
qsr@chromium.org 2011-10-20 15:22:48 +00:00
parent 05829315f0
commit 446616ee22
6 changed files with 102 additions and 31 deletions

View File

@ -54,6 +54,7 @@
#include "client/minidump_file_writer-inl.h" #include "client/minidump_file_writer-inl.h"
#include "common/mac/file_id.h" #include "common/mac/file_id.h"
#include "common/mac/macho_id.h"
#include "common/mac/string_utilities.h" #include "common/mac/string_utilities.h"
using MacStringUtils::ConvertToString; using MacStringUtils::ConvertToString;
@ -1160,7 +1161,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
module->version_info.file_version_lo |= (modVersion & 0xff); 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; return false;
} }
} else { } else {
@ -1206,7 +1207,11 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
module->size_of_image = static_cast<u_int32_t>(seg->vmsize); module->size_of_image = static_cast<u_int32_t>(seg->vmsize);
module->module_name_rva = string_location.rva; 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 false;
return true; return true;
@ -1244,7 +1249,7 @@ int MinidumpGenerator::FindExecutableModule() {
} }
bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
const char *module_path) { const char *module_path, bool in_memory) {
TypedMDRVA<MDCVInfoPDB70> cv(&writer_); TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
// Only return the last path component of the full module path // 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; cv_ptr->age = 0;
// Get the module identifier // Get the module identifier
FileID file_id(module_path);
unsigned char identifier[16]; unsigned char identifier[16];
bool result = false;
if (in_memory) {
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);
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 | cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
(uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 | (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
(uint32_t)identifier[3]; (uint32_t)identifier[3];

View File

@ -129,7 +129,7 @@ class MinidumpGenerator {
MDLocationDescriptor *register_location); MDLocationDescriptor *register_location);
bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
bool WriteCVRecord(MDRawModule *module, int cpu_type, bool WriteCVRecord(MDRawModule *module, int cpu_type,
const char *module_path); const char *module_path, bool in_memory);
bool WriteModuleStream(unsigned int index, MDRawModule *module); bool WriteModuleStream(unsigned int index, MDRawModule *module);
size_t CalculateStackSize(mach_vm_address_t start_addr); size_t CalculateStackSize(mach_vm_address_t start_addr);
int FindExecutableModule(); int FindExecutableModule();

View File

@ -52,17 +52,24 @@ extern "C" { // necessary for Leopard
namespace MacFileUtilities { namespace MacFileUtilities {
MachoID::MachoID(const char *path) 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), crc_(0),
md5_context_(), md5_context_(),
update_function_(NULL) { update_function_(NULL) {
strlcpy(path_, path, sizeof(path_)); strlcpy(path_, path, sizeof(path_));
file_ = open(path, O_RDONLY);
} }
MachoID::~MachoID() { MachoID::~MachoID() {
if (file_ != -1)
close(file_);
} }
// The CRC info is from http://en.wikipedia.org/wiki/Adler-32 // 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]) { bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
struct breakpad_uuid_command uuid_cmd; struct breakpad_uuid_command uuid_cmd;
MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd);
uuid_cmd.cmd = 0; uuid_cmd.cmd = 0;
if (!walker.WalkHeader(cpu_type)) if (!WalkHeader(cpu_type, UUIDWalkerCB, &uuid_cmd))
return false; return false;
// If we found the command, we'll have initialized the uuid_command // 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]) { bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
struct dylib_command dylib_cmd; struct dylib_command dylib_cmd;
MachoWalker walker(path_, IDWalkerCB, &dylib_cmd);
dylib_cmd.cmd = 0; dylib_cmd.cmd = 0;
if (!walker.WalkHeader(cpu_type)) if (!WalkHeader(cpu_type, IDWalkerCB, &dylib_cmd))
return false; return false;
// If we found the command, we'll have initialized the dylib_command // 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) { uint32_t MachoID::Adler32(int cpu_type) {
MachoWalker walker(path_, WalkerCB, this);
update_function_ = &MachoID::UpdateCRC; update_function_ = &MachoID::UpdateCRC;
crc_ = 0; crc_ = 0;
if (!walker.WalkHeader(cpu_type)) if (!WalkHeader(cpu_type, WalkerCB, this))
return 0; return 0;
return crc_; return crc_;
} }
bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) { bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
MachoWalker walker(path_, WalkerCB, this);
update_function_ = &MachoID::UpdateMD5; update_function_ = &MachoID::UpdateMD5;
MD5Init(&md5_context_); MD5Init(&md5_context_);
if (!walker.WalkHeader(cpu_type)) if (!WalkHeader(cpu_type, WalkerCB, this))
return false; return false;
MD5Final(identifier, &md5_context_); MD5Final(identifier, &md5_context_);
return true; 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 // static
bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context) { bool swap, void *context) {

View File

@ -37,15 +37,15 @@
#include <limits.h> #include <limits.h>
#include <mach-o/loader.h> #include <mach-o/loader.h>
#include "common/mac/macho_walker.h"
#include "common/md5.h" #include "common/md5.h"
namespace MacFileUtilities { namespace MacFileUtilities {
class MachoWalker;
class MachoID { class MachoID {
public: public:
MachoID(const char *path); MachoID(const char *path);
MachoID(const char *path, void *memory, size_t size);
~MachoID(); ~MachoID();
// For the given |cpu_type|, return a UUID from the LC_UUID command. // For the given |cpu_type|, return a UUID from the LC_UUID command.
@ -80,6 +80,10 @@ class MachoID {
// Bottleneck for update routines // Bottleneck for update routines
void Update(MachoWalker *walker, off_t offset, size_t size); 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 // The callback from the MachoWalker for CRC and MD5
static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context); bool swap, void *context);
@ -95,8 +99,11 @@ class MachoID {
// File path // File path
char path_[PATH_MAX]; char path_[PATH_MAX];
// File descriptor // Memory region to read from
int file_; void *memory_;
// Size of the memory region
size_t memory_size_;
// The current crc value // The current crc value
uint32_t crc_; uint32_t crc_;

View File

@ -52,6 +52,8 @@ namespace MacFileUtilities {
MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
void *context) void *context)
: file_(0), : file_(0),
memory_(NULL),
memory_size_(0),
callback_(callback), callback_(callback),
callback_context_(context), callback_context_(context),
current_header_(NULL), current_header_(NULL),
@ -60,6 +62,18 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
file_ = open(path, O_RDONLY); 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() { MachoWalker::~MachoWalker() {
if (file_ != -1) if (file_ != -1)
close(file_); close(file_);
@ -90,8 +104,20 @@ bool MachoWalker::WalkHeader(int cpu_type) {
} }
bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
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<char *>(memory_) + offset, size);
return result;
} else {
return pread(file_, buffer, size, offset) == (ssize_t)size; return pread(file_, buffer, size, offset) == (ssize_t)size;
} }
}
bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
if (current_header_) { if (current_header_) {

View File

@ -52,7 +52,8 @@ class MachoWalker {
off_t offset, bool swap, void *context); off_t offset, bool swap, void *context);
MachoWalker(const char *path, LoadCommandCallback callback, 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(); ~MachoWalker();
// Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the // Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the
@ -87,6 +88,12 @@ class MachoWalker {
// File descriptor to the opened file // File descriptor to the opened file
int 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 // User specified callback & context
LoadCommandCallback callback_; LoadCommandCallback callback_;
void *callback_context_; void *callback_context_;