зеркало из https://github.com/mozilla/pjs.git
bug 384034 - update to breakpad revision 189. r=mento
This commit is contained in:
Родитель
9b8eeb075e
Коммит
2fd3b4e036
|
@ -52,6 +52,7 @@ lib_LTLIBRARIES = src/libbreakpad.la
|
|||
src_libbreakpad_la_SOURCES = \
|
||||
src/google_breakpad/common/breakpad_types.h \
|
||||
src/google_breakpad/common/minidump_format.h \
|
||||
src/google_breakpad/common/minidump_size.h \
|
||||
src/google_breakpad/processor/basic_source_line_resolver.h \
|
||||
src/google_breakpad/processor/call_stack.h \
|
||||
src/google_breakpad/processor/code_module.h \
|
||||
|
|
|
@ -380,6 +380,7 @@ lib_LTLIBRARIES = src/libbreakpad.la
|
|||
src_libbreakpad_la_SOURCES = \
|
||||
src/google_breakpad/common/breakpad_types.h \
|
||||
src/google_breakpad/common/minidump_format.h \
|
||||
src/google_breakpad/common/minidump_size.h \
|
||||
src/google_breakpad/processor/basic_source_line_resolver.h \
|
||||
src/google_breakpad/processor/call_stack.h \
|
||||
src/google_breakpad/processor/code_module.h \
|
||||
|
|
|
@ -118,7 +118,7 @@ ExceptionHandler::~ExceptionHandler() {
|
|||
}
|
||||
|
||||
bool ExceptionHandler::WriteMinidump() {
|
||||
return InternalWriteMinidump(0, NULL);
|
||||
return InternalWriteMinidump(0, 0, NULL);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -127,7 +127,7 @@ bool ExceptionHandler::WriteMinidump(const string &dump_path,
|
|||
void *callback_context) {
|
||||
ExceptionHandler handler(dump_path, NULL, callback,
|
||||
callback_context, false);
|
||||
return handler.InternalWriteMinidump(0, NULL);
|
||||
return handler.InternalWriteMinidump(0, 0, NULL);
|
||||
}
|
||||
|
||||
void ExceptionHandler::SetupHandler() {
|
||||
|
@ -176,8 +176,15 @@ void ExceptionHandler::HandleException(int signo) {
|
|||
// the signal handler frame as value parameter. For some reasons, the
|
||||
// prototype of the handler doesn't declare this information as parameter, we
|
||||
// will do it by hand. It is the second parameter above the signal number.
|
||||
const struct sigcontext *sig_ctx =
|
||||
reinterpret_cast<const struct sigcontext *>(&signo + 1);
|
||||
// However, if we are being called by another signal handler passing the
|
||||
// signal up the chain, then we may not have this random extra parameter,
|
||||
// so we may have to walk the stack to find it. We do the actual work
|
||||
// on another thread, where it's a little safer, but we want the ebp
|
||||
// from this frame to find it.
|
||||
uintptr_t current_ebp = 0;
|
||||
asm volatile ("movl %%ebp, %0"
|
||||
:"=m"(current_ebp));
|
||||
|
||||
pthread_mutex_lock(&handler_stack_mutex_);
|
||||
ExceptionHandler *current_handler =
|
||||
handler_stack_->at(handler_stack_->size() - ++handler_stack_index_);
|
||||
|
@ -185,7 +192,9 @@ void ExceptionHandler::HandleException(int signo) {
|
|||
|
||||
// Restore original handler.
|
||||
current_handler->TeardownHandler(signo);
|
||||
if (current_handler->InternalWriteMinidump(signo, sig_ctx)) {
|
||||
|
||||
struct sigcontext *sig_ctx = NULL;
|
||||
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
|
||||
// Fully handled this exception, safe to exit.
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
|
@ -194,7 +203,7 @@ void ExceptionHandler::HandleException(int signo) {
|
|||
typedef void (*SignalHandler)(int signo, struct sigcontext);
|
||||
SignalHandler old_handler =
|
||||
reinterpret_cast<SignalHandler>(current_handler->old_handlers_[signo]);
|
||||
if (old_handler != NULL)
|
||||
if (old_handler != NULL && sig_ctx != NULL)
|
||||
old_handler(signo, *sig_ctx);
|
||||
}
|
||||
|
||||
|
@ -212,7 +221,8 @@ void ExceptionHandler::HandleException(int signo) {
|
|||
}
|
||||
|
||||
bool ExceptionHandler::InternalWriteMinidump(int signo,
|
||||
const struct sigcontext *sig_ctx) {
|
||||
uintptr_t sighandler_ebp,
|
||||
struct sigcontext **sig_ctx) {
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
|
||||
|
@ -239,7 +249,7 @@ bool ExceptionHandler::InternalWriteMinidump(int signo,
|
|||
}
|
||||
|
||||
success = minidump_generator_.WriteMinidumpToFile(
|
||||
minidump_path, signo, sig_ctx);
|
||||
minidump_path, signo, sighandler_ebp, sig_ctx);
|
||||
|
||||
// Unblock the signals.
|
||||
if (blocked) {
|
||||
|
|
|
@ -132,7 +132,7 @@ class ExceptionHandler {
|
|||
// execution state independently of a crash. Returns true on success.
|
||||
bool WriteMinidump();
|
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const string &dump_path,
|
||||
MinidumpCallback callback,
|
||||
|
@ -151,7 +151,14 @@ class ExceptionHandler {
|
|||
// Signal handler.
|
||||
static void HandleException(int signo);
|
||||
|
||||
bool InternalWriteMinidump(int signo, const struct sigcontext *sig_ctx);
|
||||
// If called from a signal handler, sighandler_ebp is the ebp of
|
||||
// that signal handler's frame, and sig_ctx is an out parameter
|
||||
// that will be set to point at the sigcontext that was placed
|
||||
// on the stack by the kernel. You can pass zero and NULL
|
||||
// for the second and third parameters if you are not calling
|
||||
// this from a signal handler.
|
||||
bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp,
|
||||
struct sigcontext **sig_ctx);
|
||||
|
||||
private:
|
||||
FilterCallback filter_;
|
||||
|
|
|
@ -381,4 +381,30 @@ bool LinuxThread::IsAddressMapped(uintptr_t address) const {
|
|||
return addr.is_mapped;
|
||||
}
|
||||
|
||||
bool LinuxThread::FindSigContext(uintptr_t sighandler_ebp,
|
||||
struct sigcontext **sig_ctx) {
|
||||
uintptr_t previous_ebp;
|
||||
const int MAX_STACK_DEPTH = 10;
|
||||
int depth_counter = 0;
|
||||
|
||||
do {
|
||||
// We're looking for a |struct sigcontext| as the second parameter
|
||||
// to a signal handler function call. Luckily, the sigcontext
|
||||
// has an ebp member which should match the ebp pointed to
|
||||
// by the ebp of the signal handler frame.
|
||||
previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
|
||||
reinterpret_cast<void**>(sighandler_ebp)));
|
||||
// The stack looks like this:
|
||||
// | previous ebp | previous eip | first param | second param |,
|
||||
// so we need to offset by 3 to get to the second parameter.
|
||||
*sig_ctx = reinterpret_cast<struct sigcontext*>(sighandler_ebp +
|
||||
3 * sizeof(uintptr_t));
|
||||
sighandler_ebp = previous_ebp;
|
||||
depth_counter++;
|
||||
} while(previous_ebp != (*sig_ctx)->ebp && sighandler_ebp != 0 &&
|
||||
IsAddressMapped(sighandler_ebp) && depth_counter < MAX_STACK_DEPTH);
|
||||
|
||||
return previous_ebp == (*sig_ctx)->ebp && previous_ebp != 0;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -171,7 +171,10 @@ class LinuxThread {
|
|||
int ListModules(CallbackParam<ModuleCallback> *callback_param) const;
|
||||
|
||||
// Get the bottom of the stack from ebp.
|
||||
uintptr_t GetThreadStackBottom(uintptr_t current_esp) const;
|
||||
uintptr_t GetThreadStackBottom(uintptr_t current_ebp) const;
|
||||
|
||||
// Finds a sigcontext on the stack given the ebp of our signal handler.
|
||||
bool FindSigContext(uintptr_t sighandler_ebp, struct sigcontext **sig_ctx);
|
||||
|
||||
private:
|
||||
// This callback will run when a new thread has been found.
|
||||
|
|
|
@ -78,8 +78,14 @@ struct WriterArgument {
|
|||
// Signal number when crash happed. Can be 0 if this is a requested dump.
|
||||
int signo;
|
||||
|
||||
// Signal contex when crash happed. Can be NULL if this is a requested dump.
|
||||
const struct sigcontext *sig_ctx;
|
||||
// The ebp of the signal handler frame. Can be zero if this
|
||||
// is a requested dump.
|
||||
uintptr_t sighandler_ebp;
|
||||
|
||||
// Signal context when crash happed. Can be NULL if this is a requested dump.
|
||||
// This is actually an out parameter, but it will be filled in at the start
|
||||
// of the writer thread.
|
||||
struct sigcontext *sig_ctx;
|
||||
|
||||
// Used to get information about the threads.
|
||||
LinuxThread *thread_lister;
|
||||
|
@ -272,10 +278,10 @@ bool WriteCrashedThreadStream(MinidumpFileWriter *minidump_writer,
|
|||
|
||||
UntypedMDRVA memory(minidump_writer);
|
||||
if (!WriteThreadStack(writer_args->sig_ctx->ebp,
|
||||
writer_args->sig_ctx->esp,
|
||||
writer_args->thread_lister,
|
||||
&memory,
|
||||
&thread->stack))
|
||||
writer_args->sig_ctx->esp,
|
||||
writer_args->thread_lister,
|
||||
&memory,
|
||||
&thread->stack))
|
||||
return false;
|
||||
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer);
|
||||
|
@ -328,6 +334,9 @@ bool WriteThreadStream(MinidumpFileWriter *minidump_writer,
|
|||
bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
||||
const char *proc_cpu_path = "/proc/cpuinfo";
|
||||
char line[128];
|
||||
char vendor_id[13];
|
||||
const char vendor_id_name[] = "vendor_id";
|
||||
const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
|
||||
|
||||
struct CpuInfoEntry {
|
||||
const char *info_name;
|
||||
|
@ -340,6 +349,8 @@ bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
|||
{ NULL, -1 },
|
||||
};
|
||||
|
||||
memset(vendor_id, 0, sizeof(vendor_id));
|
||||
|
||||
FILE *fp = fopen(proc_cpu_path, "r");
|
||||
if (fp != NULL) {
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
|
@ -353,6 +364,26 @@ bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
|||
}
|
||||
entry++;
|
||||
}
|
||||
|
||||
// special case for vendor_id
|
||||
if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
|
||||
char *value = strchr(line, ':');
|
||||
if (value == NULL)
|
||||
continue;
|
||||
|
||||
value++;
|
||||
while (*value && isspace(*value))
|
||||
value++;
|
||||
if (*value) {
|
||||
size_t length = strlen(value);
|
||||
// we don't want the trailing newline
|
||||
if (value[length - 1] == '\n')
|
||||
length--;
|
||||
// ensure we have space for the value
|
||||
if (length < sizeof(vendor_id))
|
||||
strncpy(vendor_id, value, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
@ -373,8 +404,12 @@ bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
|||
(strlen(uts.machine) == 4 &&
|
||||
uts.machine[0] == 'i' &&
|
||||
uts.machine[2] == '8' &&
|
||||
uts.machine[3] == '6'))
|
||||
uts.machine[3] == '6')) {
|
||||
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_X86;
|
||||
if (vendor_id[0] != '\0')
|
||||
memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
|
||||
sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -685,12 +720,15 @@ int Write(void *argument) {
|
|||
if (!writer_args->thread_lister->SuspendAllThreads())
|
||||
return -1;
|
||||
|
||||
if (writer_args->sig_ctx != NULL) {
|
||||
if (writer_args->sighandler_ebp != 0 &&
|
||||
writer_args->thread_lister->FindSigContext(writer_args->sighandler_ebp,
|
||||
&writer_args->sig_ctx)) {
|
||||
writer_args->crashed_stack_bottom =
|
||||
writer_args->thread_lister->GetThreadStackBottom(writer_args->sig_ctx->ebp);
|
||||
writer_args->thread_lister->GetThreadStackBottom(
|
||||
writer_args->sig_ctx->ebp);
|
||||
int crashed_pid = FindCrashingThread(writer_args->crashed_stack_bottom,
|
||||
writer_args->requester_pid,
|
||||
writer_args->thread_lister);
|
||||
writer_args->requester_pid,
|
||||
writer_args->thread_lister);
|
||||
if (crashed_pid > 0)
|
||||
writer_args->crashed_pid = crashed_pid;
|
||||
}
|
||||
|
@ -740,7 +778,8 @@ void MinidumpGenerator::AllocateStack() {
|
|||
|
||||
bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
|
||||
int signo,
|
||||
const struct sigcontext *sig_ctx) const {
|
||||
uintptr_t sighandler_ebp,
|
||||
struct sigcontext **sig_ctx) const {
|
||||
assert(file_pathname != NULL);
|
||||
assert(stack_ != NULL);
|
||||
|
||||
|
@ -757,12 +796,15 @@ bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
|
|||
argument.requester_pid = getpid();
|
||||
argument.crashed_pid = getpid();
|
||||
argument.signo = signo;
|
||||
argument.sig_ctx = sig_ctx;
|
||||
argument.sighandler_ebp = sighandler_ebp;
|
||||
argument.sig_ctx = NULL;
|
||||
|
||||
int cloned_pid = clone(Write, stack_.get() + kStackSize,
|
||||
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
|
||||
(void*)&argument);
|
||||
waitpid(cloned_pid, NULL, __WALL);
|
||||
if (sig_ctx != NULL)
|
||||
*sig_ctx = argument.sig_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#ifndef CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__
|
||||
#define CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
|
@ -54,7 +56,8 @@ class MinidumpGenerator {
|
|||
// Write minidump.
|
||||
bool WriteMinidumpToFile(const char *file_pathname,
|
||||
int signo,
|
||||
const struct sigcontext *sig_ctx) const;
|
||||
uintptr_t sighandler_ebp,
|
||||
struct sigcontext **sig_ctx) const;
|
||||
private:
|
||||
// Allocate memory for stack.
|
||||
void AllocateStack();
|
||||
|
|
|
@ -77,7 +77,7 @@ static void CreateThread(int num) {
|
|||
int main(int argc, char *argv[]) {
|
||||
CreateThread(10);
|
||||
google_breakpad::MinidumpGenerator mg;
|
||||
if (mg.WriteMinidumpToFile("minidump_test.out", -1, NULL))
|
||||
if (mg.WriteMinidumpToFile("minidump_test.out", -1, 0, NULL))
|
||||
printf("Succeeded written minidump\n");
|
||||
else
|
||||
printf("Failed to write minidump\n");
|
||||
|
|
|
@ -37,26 +37,27 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "client/minidump_file_writer.h"
|
||||
#include "google_breakpad/common/minidump_size.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
template<typename MDType>
|
||||
inline bool TypedMDRVA<MDType>::Allocate() {
|
||||
allocation_state_ = SINGLE_OBJECT;
|
||||
return UntypedMDRVA::Allocate(sizeof(MDType));
|
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size());
|
||||
}
|
||||
|
||||
template<typename MDType>
|
||||
inline bool TypedMDRVA<MDType>::Allocate(size_t additional) {
|
||||
allocation_state_ = SINGLE_OBJECT;
|
||||
return UntypedMDRVA::Allocate(sizeof(MDType) + additional);
|
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + additional);
|
||||
}
|
||||
|
||||
template<typename MDType>
|
||||
inline bool TypedMDRVA<MDType>::AllocateArray(size_t count) {
|
||||
assert(count);
|
||||
allocation_state_ = ARRAY;
|
||||
return UntypedMDRVA::Allocate(sizeof(MDType) * count);
|
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() * count);
|
||||
}
|
||||
|
||||
template<typename MDType>
|
||||
|
@ -64,14 +65,14 @@ inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(unsigned int count,
|
|||
size_t size) {
|
||||
assert(count && size);
|
||||
allocation_state_ = SINGLE_OBJECT_WITH_ARRAY;
|
||||
return UntypedMDRVA::Allocate(sizeof(MDType) + count * size);
|
||||
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + count * size);
|
||||
}
|
||||
|
||||
template<typename MDType>
|
||||
inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) {
|
||||
assert(allocation_state_ == ARRAY);
|
||||
return writer_->Copy(position_ + index * sizeof(MDType), item,
|
||||
sizeof(MDType));
|
||||
return writer_->Copy(position_ + index * minidump_size<MDType>::size(), item,
|
||||
minidump_size<MDType>::size());
|
||||
}
|
||||
|
||||
template<typename MDType>
|
||||
|
@ -79,12 +80,13 @@ inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index,
|
|||
const void *src,
|
||||
size_t size) {
|
||||
assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY);
|
||||
return writer_->Copy(position_ + sizeof(MDType) + index * size, src, size);
|
||||
return writer_->Copy(position_ + minidump_size<MDType>::size() + index * size,
|
||||
src, size);
|
||||
}
|
||||
|
||||
template<typename MDType>
|
||||
inline bool TypedMDRVA<MDType>::Flush() {
|
||||
return writer_->Copy(position_, &data_, sizeof(MDType));
|
||||
return writer_->Copy(position_, &data_, minidump_size<MDType>::size());
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -200,12 +200,12 @@ class TypedMDRVA : public UntypedMDRVA {
|
|||
// alter its contents.
|
||||
MDType *get() { return &data_; }
|
||||
|
||||
// Allocates sizeof(MDType) bytes.
|
||||
// Allocates minidump_size<MDType>::size() bytes.
|
||||
// Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool Allocate();
|
||||
|
||||
// Allocates sizeof(MDType) + |additional| bytes.
|
||||
// Allocates minidump_size<MDType>::size() + |additional| bytes.
|
||||
// Must not call more than once.
|
||||
// Return true on success, or false on failure
|
||||
bool Allocate(size_t additional);
|
||||
|
|
|
@ -64,7 +64,7 @@ const GUIDGenerator kGuidGenerator;
|
|||
|
||||
bool CreateGUID(GUID *guid) {
|
||||
return kGuidGenerator.CreateGUID(guid);
|
||||
};
|
||||
}
|
||||
|
||||
// Parse guid to string.
|
||||
bool GUIDToString(const GUID *guid, char *buf, int buf_len) {
|
||||
|
|
|
@ -275,7 +275,11 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
|||
if (swap)
|
||||
swap_section(&sec, 1, NXHostByteOrder());
|
||||
|
||||
macho_id->Update(walker, header_offset + sec.offset, sec.size);
|
||||
// sections of type S_ZEROFILL are "virtual" and contain no data
|
||||
// in the file itself
|
||||
if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
|
||||
macho_id->Update(walker, header_offset + sec.offset, sec.size);
|
||||
|
||||
offset += sizeof(struct section);
|
||||
}
|
||||
} else if (cmd->cmd == LC_SEGMENT_64) {
|
||||
|
@ -304,7 +308,11 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
|||
if (swap)
|
||||
breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
|
||||
|
||||
macho_id->Update(walker, header_offset + sec64.offset, sec64.size);
|
||||
// sections of type S_ZEROFILL are "virtual" and contain no data
|
||||
// in the file itself
|
||||
if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
|
||||
macho_id->Update(walker, header_offset + sec64.offset, sec64.size);
|
||||
|
||||
offset += sizeof(struct section_64);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,8 +140,10 @@ bool HTTPUpload::SendRequest(const wstring &url,
|
|||
-1, HTTP_ADDREQ_FLAG_ADD);
|
||||
|
||||
string request_body;
|
||||
GenerateRequestBody(parameters, upload_file,
|
||||
file_part_name, boundary, &request_body);
|
||||
if (!GenerateRequestBody(parameters, upload_file,
|
||||
file_part_name, boundary, &request_body)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HttpSendRequest(request.get(), NULL, 0,
|
||||
const_cast<char *>(request_body.data()),
|
||||
|
|
|
@ -44,6 +44,12 @@
|
|||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
|
@ -67,6 +73,7 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
|
@ -502,9 +509,11 @@ typedef enum {
|
|||
typedef struct {
|
||||
u_int32_t length; /* Length of buffer in bytes (not characters),
|
||||
* excluding 0-terminator */
|
||||
u_int16_t buffer[0]; /* UTF-16-encoded, 0-terminated */
|
||||
u_int16_t buffer[1]; /* UTF-16-encoded, 0-terminated */
|
||||
} MDString; /* MINIDUMP_STRING */
|
||||
|
||||
static const size_t MDString_minsize = offsetof(MDString, buffer[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_int32_t thread_id;
|
||||
|
@ -519,9 +528,12 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
u_int32_t number_of_threads;
|
||||
MDRawThread threads[0];
|
||||
MDRawThread threads[1];
|
||||
} MDRawThreadList; /* MINIDUMP_THREAD_LIST */
|
||||
|
||||
static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,
|
||||
threads[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_int64_t base_of_image;
|
||||
|
@ -576,19 +588,25 @@ typedef struct {
|
|||
MDCVHeader cv_header;
|
||||
u_int32_t signature; /* time_t debug information created */
|
||||
u_int32_t age; /* revision of PDB file */
|
||||
u_int8_t pdb_file_name[0]; /* Pathname or filename of PDB file */
|
||||
u_int8_t pdb_file_name[1]; /* Pathname or filename of PDB file */
|
||||
} MDCVInfoPDB20;
|
||||
|
||||
static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
|
||||
pdb_file_name[0]);
|
||||
|
||||
#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */
|
||||
|
||||
typedef struct {
|
||||
u_int32_t cv_signature;
|
||||
MDGUID signature; /* GUID, identifies PDB file */
|
||||
u_int32_t age; /* Identifies incremental changes to PDB file */
|
||||
u_int8_t pdb_file_name[0]; /* Pathname or filename of PDB file,
|
||||
u_int8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
|
||||
* 0-terminated 8-bit character data (UTF-8?) */
|
||||
} MDCVInfoPDB70;
|
||||
|
||||
static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70,
|
||||
pdb_file_name[0]);
|
||||
|
||||
#define MD_CVINFOPDB70_SIGNATURE 0x53445352 /* cvSignature = 'SDSR' */
|
||||
|
||||
/* In addition to the two CodeView record formats above, used for linking
|
||||
|
@ -618,27 +636,37 @@ typedef struct {
|
|||
u_int32_t length; /* Length of entire MDImageDebugMisc structure */
|
||||
u_int8_t unicode; /* True if data is multibyte */
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t data[0];
|
||||
u_int8_t data[1];
|
||||
} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */
|
||||
|
||||
static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
|
||||
data[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_int32_t number_of_modules;
|
||||
MDRawModule modules[0];
|
||||
MDRawModule modules[1];
|
||||
} MDRawModuleList; /* MINIDUMP_MODULE_LIST */
|
||||
|
||||
static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList,
|
||||
modules[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_int32_t number_of_memory_ranges;
|
||||
MDMemoryDescriptor memory_ranges[0];
|
||||
MDMemoryDescriptor memory_ranges[1];
|
||||
} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */
|
||||
|
||||
static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,
|
||||
memory_ranges[0]);
|
||||
|
||||
|
||||
#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15
|
||||
|
||||
typedef struct {
|
||||
u_int32_t exception_code; /* Windows: MDExceptionCodeWin,
|
||||
* Mac OS X: MDExceptionMac. */
|
||||
* Mac OS X: MDExceptionMac,
|
||||
* Linux: MDExceptionCodeLinux. */
|
||||
u_int32_t exception_flags; /* Windows: 1 if noncontinuable,
|
||||
Mac OS X: MDExceptionCodeMac. */
|
||||
u_int64_t exception_record; /* Address (in the minidump-producing host's
|
||||
|
@ -848,12 +876,49 @@ typedef enum {
|
|||
/* EXC_GPFLT */
|
||||
/* EXC_I386_PGFLT = 14: should not occur in user space */
|
||||
/* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17,
|
||||
MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17
|
||||
/* EXC_ALIGNFLT (for vector operations) */
|
||||
/* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */
|
||||
/* EXC_I386_ENDPERR = 33: should not occur */
|
||||
} MDExceptionCodeMac;
|
||||
|
||||
/* For (MDException).exception_code. These values come from bits/signum.h.
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGURG = 23,
|
||||
/* Urgent condition on socket (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25,
|
||||
/* File size limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSYS = 31 /* Bad system call */
|
||||
} MDExceptionCodeLinux;
|
||||
|
||||
typedef struct {
|
||||
u_int32_t thread_id; /* Thread in which the exception
|
||||
|
@ -885,13 +950,9 @@ typedef struct {
|
|||
u_int16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
|
||||
u_int16_t processor_revision; /* x86: 0xMMSS, where MM=model,
|
||||
* SS=stepping */
|
||||
union {
|
||||
u_int16_t reserved0;
|
||||
struct {
|
||||
u_int8_t number_of_processors;
|
||||
u_int8_t product_type; /* Windows: VER_NT_* from WinNT.h */
|
||||
};
|
||||
};
|
||||
|
||||
u_int8_t number_of_processors;
|
||||
u_int8_t product_type; /* Windows: VER_NT_* from WinNT.h */
|
||||
|
||||
/* The next 5 fields are from the OSVERSIONINFO structure as returned
|
||||
* by GetVersionEx */
|
||||
|
@ -907,13 +968,9 @@ typedef struct {
|
|||
* (sw_vers -buildVersion).
|
||||
* Linux: uname -srvmo */
|
||||
|
||||
union {
|
||||
u_int32_t reserved1;
|
||||
struct {
|
||||
u_int16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
|
||||
u_int16_t reserved2;
|
||||
};
|
||||
};
|
||||
u_int16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
|
||||
u_int16_t reserved2;
|
||||
|
||||
MDCPUInformation cpu;
|
||||
} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */
|
||||
|
||||
|
@ -947,7 +1004,7 @@ typedef enum {
|
|||
/* The following values are Breakpad-defined. */
|
||||
MD_OS_UNIX = 0x8000, /* Generic Unix-ish */
|
||||
MD_OS_MAC_OS_X = 0x8101, /* Mac OS X/Darwin */
|
||||
MD_OS_LINUX = 0x8201, /* Linux */
|
||||
MD_OS_LINUX = 0x8201 /* Linux */
|
||||
} MDOSPlatform;
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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. */
|
||||
|
||||
// minidump_size.h: Provides a C++ template for programmatic access to
|
||||
// the sizes of various types defined in minidump_format.h.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
template<typename T>
|
||||
class minidump_size {
|
||||
public:
|
||||
static size_t size() { return sizeof(T); }
|
||||
};
|
||||
|
||||
// Explicit specializations for variable-length types. The size returned
|
||||
// for these should be the size for an object without its variable-length
|
||||
// section.
|
||||
|
||||
template<>
|
||||
class minidump_size<MDString> {
|
||||
public:
|
||||
static size_t size() { return MDString_minsize; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class minidump_size<MDRawThreadList> {
|
||||
public:
|
||||
static size_t size() { return MDRawThreadList_minsize; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class minidump_size<MDCVInfoPDB20> {
|
||||
public:
|
||||
static size_t size() { return MDCVInfoPDB20_minsize; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class minidump_size<MDCVInfoPDB70> {
|
||||
public:
|
||||
static size_t size() { return MDCVInfoPDB70_minsize; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class minidump_size<MDImageDebugMisc> {
|
||||
public:
|
||||
static size_t size() { return MDImageDebugMisc_minsize; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class minidump_size<MDRawModuleList> {
|
||||
public:
|
||||
static size_t size() { return MDRawModuleList_minsize; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class minidump_size<MDRawMemoryList> {
|
||||
public:
|
||||
static size_t size() { return MDRawMemoryList_minsize; }
|
||||
};
|
||||
|
||||
// Explicit specialization for MDRawModule, for which sizeof may include
|
||||
// tail-padding on some architectures but not others.
|
||||
|
||||
template<>
|
||||
class minidump_size<MDRawModule> {
|
||||
public:
|
||||
static size_t size() { return MD_MODULE_SIZE; }
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__
|
|
@ -221,6 +221,9 @@ class MinidumpMemoryRegion : public MinidumpObject,
|
|||
public:
|
||||
virtual ~MinidumpMemoryRegion();
|
||||
|
||||
static void set_max_bytes(u_int32_t max_bytes) { max_bytes_ = max_bytes; }
|
||||
static u_int32_t max_bytes() { return max_bytes_; }
|
||||
|
||||
// Returns a pointer to the base of the memory region. Returns the
|
||||
// cached value if available, otherwise, reads the minidump file and
|
||||
// caches the memory region.
|
||||
|
@ -258,6 +261,10 @@ class MinidumpMemoryRegion : public MinidumpObject,
|
|||
template<typename T> bool GetMemoryAtAddressInternal(u_int64_t address,
|
||||
T* value);
|
||||
|
||||
// The largest memory region that will be read from a minidump. The
|
||||
// default is 1MB.
|
||||
static u_int32_t max_bytes_;
|
||||
|
||||
// Base address and size of the memory region, and its position in the
|
||||
// minidump file.
|
||||
MDMemoryDescriptor* descriptor_;
|
||||
|
@ -312,6 +319,11 @@ class MinidumpThreadList : public MinidumpStream {
|
|||
public:
|
||||
virtual ~MinidumpThreadList();
|
||||
|
||||
static void set_max_threads(u_int32_t max_threads) {
|
||||
max_threads_ = max_threads;
|
||||
}
|
||||
static u_int32_t max_threads() { return max_threads_; }
|
||||
|
||||
unsigned int thread_count() const { return valid_ ? thread_count_ : 0; }
|
||||
|
||||
// Sequential access to threads.
|
||||
|
@ -335,6 +347,10 @@ class MinidumpThreadList : public MinidumpStream {
|
|||
|
||||
bool Read(u_int32_t aExpectedSize);
|
||||
|
||||
// The largest number of threads that will be read from a minidump. The
|
||||
// default is 256.
|
||||
static u_int32_t max_threads_;
|
||||
|
||||
// Access to threads using the thread ID as the key.
|
||||
IDToThreadMap id_to_thread_map_;
|
||||
|
||||
|
@ -353,6 +369,16 @@ class MinidumpModule : public MinidumpObject,
|
|||
public:
|
||||
virtual ~MinidumpModule();
|
||||
|
||||
static void set_max_cv_bytes(u_int32_t max_cv_bytes) {
|
||||
max_cv_bytes_ = max_cv_bytes;
|
||||
}
|
||||
static u_int32_t max_cv_bytes() { return max_cv_bytes_; }
|
||||
|
||||
static void set_max_misc_bytes(u_int32_t max_misc_bytes) {
|
||||
max_misc_bytes_ = max_misc_bytes;
|
||||
}
|
||||
static u_int32_t max_misc_bytes() { return max_misc_bytes_; }
|
||||
|
||||
const MDRawModule* module() const { return valid_ ? &module_ : NULL; }
|
||||
|
||||
// CodeModule implementation
|
||||
|
@ -408,6 +434,12 @@ class MinidumpModule : public MinidumpObject,
|
|||
// allow the CodeModule getters to be const methods.
|
||||
bool ReadAuxiliaryData();
|
||||
|
||||
// The largest number of bytes that will be read from a minidump for a
|
||||
// CodeView record or miscellaneous debugging record, respectively. The
|
||||
// default for each is 1024.
|
||||
static u_int32_t max_cv_bytes_;
|
||||
static u_int32_t max_misc_bytes_;
|
||||
|
||||
// True after a successful Read. This is different from valid_, which is
|
||||
// not set true until ReadAuxiliaryData also completes successfully.
|
||||
// module_valid_ is only used by ReadAuxiliaryData and the functions it
|
||||
|
@ -447,6 +479,11 @@ class MinidumpModuleList : public MinidumpStream,
|
|||
public:
|
||||
virtual ~MinidumpModuleList();
|
||||
|
||||
static void set_max_modules(u_int32_t max_modules) {
|
||||
max_modules_ = max_modules;
|
||||
}
|
||||
static u_int32_t max_modules() { return max_modules_; }
|
||||
|
||||
// CodeModules implementation.
|
||||
virtual unsigned int module_count() const {
|
||||
return valid_ ? module_count_ : 0;
|
||||
|
@ -472,6 +509,10 @@ class MinidumpModuleList : public MinidumpStream,
|
|||
|
||||
bool Read(u_int32_t expected_size);
|
||||
|
||||
// The largest number of modules that will be read from a minidump. The
|
||||
// default is 1024.
|
||||
static u_int32_t max_modules_;
|
||||
|
||||
// Access to modules using addresses as the key.
|
||||
RangeMap<u_int64_t, unsigned int> *range_map_;
|
||||
|
||||
|
@ -493,6 +534,11 @@ class MinidumpMemoryList : public MinidumpStream {
|
|||
public:
|
||||
virtual ~MinidumpMemoryList();
|
||||
|
||||
static void set_max_regions(u_int32_t max_regions) {
|
||||
max_regions_ = max_regions;
|
||||
}
|
||||
static u_int32_t max_regions() { return max_regions_; }
|
||||
|
||||
unsigned int region_count() const { return valid_ ? region_count_ : 0; }
|
||||
|
||||
// Sequential access to memory regions.
|
||||
|
@ -517,6 +563,10 @@ class MinidumpMemoryList : public MinidumpStream {
|
|||
|
||||
bool Read(u_int32_t expected_size);
|
||||
|
||||
// The largest number of memory regions that will be read from a minidump.
|
||||
// The default is 256.
|
||||
static u_int32_t max_regions_;
|
||||
|
||||
// Access to memory regions using addresses as the key.
|
||||
RangeMap<u_int64_t, unsigned int> *range_map_;
|
||||
|
||||
|
@ -690,6 +740,16 @@ class Minidump {
|
|||
|
||||
~Minidump();
|
||||
|
||||
static void set_max_streams(u_int32_t max_streams) {
|
||||
max_streams_ = max_streams;
|
||||
}
|
||||
static u_int32_t max_streams() { return max_streams_; }
|
||||
|
||||
static void set_max_string_length(u_int32_t max_string_length) {
|
||||
max_string_length_ = max_string_length;
|
||||
}
|
||||
static u_int32_t max_string_length() { return max_string_length_; }
|
||||
|
||||
const MDRawHeader* header() const { return valid_ ? &header_ : NULL; }
|
||||
|
||||
// Reads the minidump file's header and top-level stream directory.
|
||||
|
@ -779,6 +839,17 @@ class Minidump {
|
|||
// Opens the minidump file, or if already open, seeks to the beginning.
|
||||
bool Open();
|
||||
|
||||
// The largest number of top-level streams that will be read from a minidump.
|
||||
// Note that streams are only read (and only consume memory) as needed,
|
||||
// when directed by the caller. The default is 128.
|
||||
static u_int32_t max_streams_;
|
||||
|
||||
// The maximum length of a UTF-16 string that will be read from a minidump
|
||||
// in 16-bit words. The default is 1024. UTF-16 strings are converted
|
||||
// to UTF-8 when stored in memory, and each UTF-16 word will be represented
|
||||
// by as many as 3 bytes in UTF-8.
|
||||
static unsigned int max_string_length_;
|
||||
|
||||
MDRawHeader header_;
|
||||
|
||||
// The list of streams.
|
||||
|
|
|
@ -46,9 +46,9 @@ class MinidumpProcessor {
|
|||
public:
|
||||
// Return type for Process()
|
||||
enum ProcessResult {
|
||||
PROCESS_OK, // the minidump was processed successfully
|
||||
PROCESS_ERROR, // there was an error processing the minidump
|
||||
PROCESS_INTERRUPTED, // processing was interrupted by the SymbolSupplier
|
||||
PROCESS_OK, // the minidump was processed successfully
|
||||
PROCESS_ERROR, // there was an error processing the minidump
|
||||
PROCESS_INTERRUPTED // processing was interrupted by the SymbolSupplier
|
||||
};
|
||||
|
||||
// Initializes this MinidumpProcessor. supplier should be an
|
||||
|
|
|
@ -52,7 +52,7 @@ class SymbolSupplier {
|
|||
FOUND,
|
||||
|
||||
// stops processing the minidump immediately
|
||||
INTERRUPT,
|
||||
INTERRUPT
|
||||
};
|
||||
|
||||
virtual ~SymbolSupplier() {}
|
||||
|
|
|
@ -43,6 +43,9 @@ using std::string;
|
|||
|
||||
struct SystemInfo {
|
||||
public:
|
||||
SystemInfo() : os(), os_short(), os_version(), cpu(), cpu_info(),
|
||||
cpu_count(0) {}
|
||||
|
||||
// Resets the SystemInfo object to its default values.
|
||||
void Clear() {
|
||||
os.clear();
|
||||
|
@ -50,6 +53,7 @@ struct SystemInfo {
|
|||
os_version.clear();
|
||||
cpu.clear();
|
||||
cpu_info.clear();
|
||||
cpu_count = 0;
|
||||
}
|
||||
|
||||
// A string identifying the operating system, such as "Windows NT",
|
||||
|
@ -82,6 +86,10 @@ struct SystemInfo {
|
|||
// present in the dump, or additional identifying information is not
|
||||
// defined for the CPU family, this field will be empty.
|
||||
string cpu_info;
|
||||
|
||||
// The number of processors in the system. Will be greater than one for
|
||||
// multi-core systems.
|
||||
int cpu_count;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "processor/address_map-inl.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
#define ASSERT_TRUE(condition) \
|
||||
if (!(condition)) { \
|
||||
|
@ -189,5 +190,7 @@ static bool RunTests() {
|
|||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
return RunTests() ? 0 : 1;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
#include "processor/stack_frame_info.h"
|
||||
|
||||
|
@ -202,6 +203,8 @@ static bool RunTests() {
|
|||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
if (!RunTests()) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
#include "processor/contained_range_map-inl.h"
|
||||
|
||||
#include "processor/logging.h"
|
||||
|
||||
|
||||
#define ASSERT_TRUE(condition) \
|
||||
if (!(condition)) { \
|
||||
|
@ -255,5 +257,7 @@ static bool RunTests() {
|
|||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
return RunTests() ? 0 : 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// logging.cc: Breakpad logging
|
||||
//
|
||||
// See logging.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "processor/logging.h"
|
||||
#include "processor/pathname_stripper.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
LogStream::LogStream(std::ostream &stream, Severity severity,
|
||||
const char *file, int line)
|
||||
: stream_(stream) {
|
||||
time_t clock;
|
||||
time(&clock);
|
||||
struct tm tm_struct;
|
||||
localtime_r(&clock, &tm_struct);
|
||||
char time_string[20];
|
||||
strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", &tm_struct);
|
||||
|
||||
const char *severity_string = "UNKNOWN_SEVERITY";
|
||||
switch (severity) {
|
||||
case SEVERITY_INFO:
|
||||
severity_string = "INFO";
|
||||
break;
|
||||
case SEVERITY_ERROR:
|
||||
severity_string = "ERROR";
|
||||
break;
|
||||
}
|
||||
|
||||
stream_ << time_string << ": " << PathnameStripper::File(file) << ":" <<
|
||||
line << ": " << severity_string << ": ";
|
||||
}
|
||||
|
||||
LogStream::~LogStream() {
|
||||
stream_ << std::endl;
|
||||
}
|
||||
|
||||
std::string HexString(u_int32_t number) {
|
||||
char buffer[11];
|
||||
snprintf(buffer, sizeof(buffer), "0x%x", number);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
std::string HexString(u_int64_t number) {
|
||||
char buffer[19];
|
||||
snprintf(buffer, sizeof(buffer), "0x%llx", number);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
std::string HexString(int number) {
|
||||
char buffer[19];
|
||||
snprintf(buffer, sizeof(buffer), "0x%x", number);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
int ErrnoString(std::string *error_string) {
|
||||
assert(error_string);
|
||||
|
||||
// strerror isn't necessarily thread-safe. strerror_r would be preferrable,
|
||||
// but GNU libc uses a nonstandard strerror_r by default, which returns a
|
||||
// char* (rather than an int success indicator) and doesn't necessarily
|
||||
// use the supplied buffer.
|
||||
error_string->assign(strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// logging.h: Breakpad logging
|
||||
//
|
||||
// Breakpad itself uses Breakpad logging with statements of the form:
|
||||
// BPLOG(severity) << "message";
|
||||
// severity may be INFO, ERROR, or other values defined in this file.
|
||||
//
|
||||
// BPLOG is an overridable macro so that users can customize Breakpad's
|
||||
// logging. Left at the default, logging messages are sent to stderr along
|
||||
// with a timestamp and the source code location that produced a message.
|
||||
// The streams may be changed by redefining BPLOG_*_STREAM, the logging
|
||||
// behavior may be changed by redefining BPLOG_*, and the entire logging
|
||||
// system may be overridden by redefining BPLOG(severity). These
|
||||
// redefinitions may be passed to the preprocessor as a command-line flag
|
||||
// (-D).
|
||||
//
|
||||
// If an additional header is required to override Breakpad logging, it can
|
||||
// be specified by the BP_LOGGING_INCLUDE macro. If defined, this header
|
||||
// will #include the header specified by that macro.
|
||||
//
|
||||
// If any initialization is needed before logging, it can be performed by
|
||||
// a function called through the BPLOG_INIT macro. Each main function of
|
||||
// an executable program in the Breakpad processor library calls
|
||||
// BPLOG_INIT(&argc, &argv); before any logging can be performed; define
|
||||
// BPLOG_INIT appropriately if initialization is required.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#ifndef PROCESSOR_LOGGING_H__
|
||||
#define PROCESSOR_LOGGING_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
#ifdef BP_LOGGING_INCLUDE
|
||||
#include BP_LOGGING_INCLUDE
|
||||
#endif // BP_LOGGING_INCLUDE
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class LogStream {
|
||||
public:
|
||||
enum Severity {
|
||||
SEVERITY_INFO,
|
||||
SEVERITY_ERROR
|
||||
};
|
||||
|
||||
// Begin logging a message to the stream identified by |stream|, at the
|
||||
// indicated severity. The file and line parameters should be set so as to
|
||||
// identify the line of source code that is producing a message.
|
||||
LogStream(std::ostream &stream, Severity severity,
|
||||
const char *file, int line);
|
||||
|
||||
// Finish logging by printing a newline and flushing the output stream.
|
||||
~LogStream();
|
||||
|
||||
template<typename T> std::ostream& operator<<(const T &t) {
|
||||
return stream_ << t;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream &stream_;
|
||||
|
||||
// Disallow copy constructor and assignment operator
|
||||
explicit LogStream(const LogStream &that);
|
||||
void operator=(const LogStream &that);
|
||||
};
|
||||
|
||||
// This class is used to explicitly ignore values in the conditional logging
|
||||
// macros. This avoids compiler warnings like "value computed is not used"
|
||||
// and "statement has no effect".
|
||||
class LogMessageVoidify {
|
||||
public:
|
||||
LogMessageVoidify() {}
|
||||
|
||||
// This has to be an operator with a precedence lower than << but higher
|
||||
// than ?:
|
||||
void operator&(std::ostream &) {}
|
||||
};
|
||||
|
||||
// Returns number formatted as a hexadecimal string, such as "0x7b".
|
||||
std::string HexString(u_int32_t number);
|
||||
std::string HexString(u_int64_t number);
|
||||
std::string HexString(int number);
|
||||
|
||||
// Returns the error code as set in the global errno variable, and sets
|
||||
// error_string, a required argument, to a string describing that error
|
||||
// code.
|
||||
int ErrnoString(std::string *error_string);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#ifndef BPLOG_INIT
|
||||
#define BPLOG_INIT(pargc, pargv)
|
||||
#endif // BPLOG_INIT
|
||||
|
||||
#ifndef BPLOG
|
||||
#define BPLOG(severity) BPLOG_ ## severity
|
||||
#endif // BPLOG
|
||||
|
||||
#ifndef BPLOG_INFO
|
||||
#ifndef BPLOG_INFO_STREAM
|
||||
#define BPLOG_INFO_STREAM std::clog
|
||||
#endif // BPLOG_INFO_STREAM
|
||||
#define BPLOG_INFO google_breakpad::LogStream(BPLOG_INFO_STREAM, \
|
||||
google_breakpad::LogStream::SEVERITY_INFO, \
|
||||
__FILE__, __LINE__)
|
||||
#endif // BPLOG_INFO
|
||||
|
||||
#ifndef BPLOG_ERROR
|
||||
#ifndef BPLOG_ERROR_STREAM
|
||||
#define BPLOG_ERROR_STREAM std::cerr
|
||||
#endif // BPLOG_ERROR_STREAM
|
||||
#define BPLOG_ERROR google_breakpad::LogStream(BPLOG_ERROR_STREAM, \
|
||||
google_breakpad::LogStream::SEVERITY_ERROR, \
|
||||
__FILE__, __LINE__)
|
||||
#endif // BPLOG_ERROR
|
||||
|
||||
#define BPLOG_IF(severity, condition) \
|
||||
!(condition) ? (void) 0 : \
|
||||
google_breakpad::LogMessageVoidify() & BPLOG(severity)
|
||||
|
||||
#endif // PROCESSOR_LOGGING_H__
|
|
@ -106,15 +106,13 @@ static inline void Swap(u_int32_t* value) {
|
|||
}
|
||||
|
||||
|
||||
static inline void Swap(u_int64_t* value) {
|
||||
*value = (*value >> 56) |
|
||||
((*value >> 40) & 0x000000000000ff00LL) |
|
||||
((*value >> 24) & 0x0000000000ff0000LL) |
|
||||
((*value >> 8) & 0x00000000ff000000LL) |
|
||||
((*value << 8) & 0x000000ff00000000LL) |
|
||||
((*value << 24) & 0x0000ff0000000000LL) |
|
||||
((*value << 40) & 0x00ff000000000000LL) |
|
||||
(*value << 56);
|
||||
static void Swap(u_int64_t* value) {
|
||||
u_int32_t* value32 = reinterpret_cast<u_int32_t*>(value);
|
||||
Swap(&value32[0]);
|
||||
Swap(&value32[1]);
|
||||
u_int32_t temp = value32[0];
|
||||
value32[0] = value32[1];
|
||||
value32[1] = temp;
|
||||
}
|
||||
|
||||
|
||||
|
@ -686,6 +684,9 @@ void MinidumpContext::Print() {
|
|||
//
|
||||
|
||||
|
||||
u_int32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024; // 1MB
|
||||
|
||||
|
||||
MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
|
||||
: MinidumpObject(minidump),
|
||||
descriptor_(NULL),
|
||||
|
@ -724,7 +725,13 @@ const u_int8_t* MinidumpMemoryRegion::GetMemory() {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (descriptor_->memory.data_size > max_bytes_) {
|
||||
BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
|
||||
descriptor_->memory.data_size << " exceeds maximum " <<
|
||||
max_bytes_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scoped_ptr< vector<u_int8_t> > memory(
|
||||
new vector<u_int8_t>(descriptor_->memory.data_size));
|
||||
|
||||
|
@ -1014,6 +1021,9 @@ void MinidumpThread::Print() {
|
|||
//
|
||||
|
||||
|
||||
u_int32_t MinidumpThreadList::max_threads_ = 256;
|
||||
|
||||
|
||||
MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
|
||||
: MinidumpStream(minidump),
|
||||
id_to_thread_map_(),
|
||||
|
@ -1064,8 +1074,13 @@ bool MinidumpThreadList::Read(u_int32_t expected_size) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (thread_count) {
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (thread_count > max_threads_) {
|
||||
BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
|
||||
" exceeds maximum " << max_threads_;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thread_count != 0) {
|
||||
scoped_ptr<MinidumpThreads> threads(
|
||||
new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
|
||||
|
||||
|
@ -1157,6 +1172,10 @@ void MinidumpThreadList::Print() {
|
|||
//
|
||||
|
||||
|
||||
u_int32_t MinidumpModule::max_cv_bytes_ = 1024;
|
||||
u_int32_t MinidumpModule::max_misc_bytes_ = 1024;
|
||||
|
||||
|
||||
MinidumpModule::MinidumpModule(Minidump* minidump)
|
||||
: MinidumpObject(minidump),
|
||||
module_valid_(false),
|
||||
|
@ -1308,7 +1327,8 @@ string MinidumpModule::code_identifier() const {
|
|||
break;
|
||||
}
|
||||
|
||||
case MD_OS_MAC_OS_X: {
|
||||
case MD_OS_MAC_OS_X:
|
||||
case MD_OS_LINUX: {
|
||||
// TODO(mmentovai): support uuid extension if present, otherwise fall
|
||||
// back to version (from LC_ID_DYLIB?), otherwise fall back to something
|
||||
// else.
|
||||
|
@ -1370,7 +1390,7 @@ string MinidumpModule::debug_file() const {
|
|||
// if misc_record->data is 0-terminated, so use an explicit size.
|
||||
file = string(
|
||||
reinterpret_cast<const char*>(misc_record->data),
|
||||
module_.misc_record.data_size - sizeof(MDImageDebugMisc));
|
||||
module_.misc_record.data_size - MDImageDebugMisc_minsize);
|
||||
} else {
|
||||
// There's a misc_record but it encodes the debug filename in UTF-16.
|
||||
// (Actually, because miscellaneous records are so old, it's probably
|
||||
|
@ -1379,7 +1399,7 @@ string MinidumpModule::debug_file() const {
|
|||
// return.
|
||||
|
||||
unsigned int bytes =
|
||||
module_.misc_record.data_size - sizeof(MDImageDebugMisc);
|
||||
module_.misc_record.data_size - MDImageDebugMisc_minsize;
|
||||
if (bytes % 2 == 0) {
|
||||
unsigned int utf16_words = bytes / 2;
|
||||
|
||||
|
@ -1525,14 +1545,19 @@ const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (module_.cv_record.data_size > max_cv_bytes_) {
|
||||
BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
|
||||
module_.cv_record.data_size << " exceeds maximum " <<
|
||||
max_cv_bytes_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocating something that will be accessed as MDCVInfoPDB70 or
|
||||
// MDCVInfoPDB20 but is allocated as u_int8_t[] can cause alignment
|
||||
// problems. x86 and ppc are able to cope, though. This allocation
|
||||
// style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
|
||||
// variable-sized due to their pdb_file_name fields; these structures
|
||||
// are not sizeof(MDCVInfoPDB70) or sizeof(MDCVInfoPDB20) and treating
|
||||
// are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
|
||||
// them as such would result in incomplete structures or overruns.
|
||||
scoped_ptr< vector<u_int8_t> > cv_record(
|
||||
new vector<u_int8_t>(module_.cv_record.data_size));
|
||||
|
@ -1553,9 +1578,9 @@ const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) {
|
|||
|
||||
if (signature == MD_CVINFOPDB70_SIGNATURE) {
|
||||
// Now that the structure type is known, recheck the size.
|
||||
if (sizeof(MDCVInfoPDB70) > module_.cv_record.data_size) {
|
||||
if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) {
|
||||
BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
|
||||
sizeof(MDCVInfoPDB70) << " > " <<
|
||||
MDCVInfoPDB70_minsize << " > " <<
|
||||
module_.cv_record.data_size;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1579,9 +1604,9 @@ const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) {
|
|||
}
|
||||
} else if (signature == MD_CVINFOPDB20_SIGNATURE) {
|
||||
// Now that the structure type is known, recheck the size.
|
||||
if (sizeof(MDCVInfoPDB20) > module_.cv_record.data_size) {
|
||||
if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) {
|
||||
BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
|
||||
sizeof(MDCVInfoPDB20) << " > " <<
|
||||
MDCVInfoPDB20_minsize << " > " <<
|
||||
module_.cv_record.data_size;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1635,9 +1660,9 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(u_int32_t* size) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (sizeof(MDImageDebugMisc) > module_.misc_record.data_size) {
|
||||
if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
|
||||
BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
|
||||
"size mismatch, " << sizeof(MDImageDebugMisc) << " > " <<
|
||||
"size mismatch, " << MDImageDebugMisc_minsize << " > " <<
|
||||
module_.misc_record.data_size;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1648,13 +1673,18 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(u_int32_t* size) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (module_.misc_record.data_size > max_misc_bytes_) {
|
||||
BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
|
||||
module_.misc_record.data_size << " exceeds maximum " <<
|
||||
max_misc_bytes_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocating something that will be accessed as MDImageDebugMisc but
|
||||
// is allocated as u_int8_t[] can cause alignment problems. x86 and
|
||||
// ppc are able to cope, though. This allocation style is needed
|
||||
// because the MDImageDebugMisc is variable-sized due to its data field;
|
||||
// this structure is not sizeof(MDImageDebugMisc) and treating it as such
|
||||
// this structure is not MDImageDebugMisc_minsize and treating it as such
|
||||
// would result in an incomplete structure or an overrun.
|
||||
scoped_ptr< vector<u_int8_t> > misc_record_mem(
|
||||
new vector<u_int8_t>(module_.misc_record.data_size));
|
||||
|
@ -1678,7 +1708,7 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(u_int32_t* size) {
|
|||
// in practice due to the layout of MDImageDebugMisc.
|
||||
u_int16_t* data16 = reinterpret_cast<u_int16_t*>(&(misc_record->data));
|
||||
unsigned int dataBytes = module_.misc_record.data_size -
|
||||
sizeof(MDImageDebugMisc);
|
||||
MDImageDebugMisc_minsize;
|
||||
unsigned int dataLength = dataBytes / 2;
|
||||
for (unsigned int characterIndex = 0;
|
||||
characterIndex < dataLength;
|
||||
|
@ -1846,6 +1876,9 @@ void MinidumpModule::Print() {
|
|||
//
|
||||
|
||||
|
||||
u_int32_t MinidumpModuleList::max_modules_ = 1024;
|
||||
|
||||
|
||||
MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
|
||||
: MinidumpStream(minidump),
|
||||
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
||||
|
@ -1897,8 +1930,13 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (module_count) {
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (module_count > max_modules_) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
|
||||
" exceeds maximum " << max_modules_;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (module_count != 0) {
|
||||
scoped_ptr<MinidumpModules> modules(
|
||||
new MinidumpModules(module_count, MinidumpModule(minidump_)));
|
||||
|
||||
|
@ -2064,6 +2102,9 @@ void MinidumpModuleList::Print() {
|
|||
//
|
||||
|
||||
|
||||
u_int32_t MinidumpMemoryList::max_regions_ = 256;
|
||||
|
||||
|
||||
MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
|
||||
: MinidumpStream(minidump),
|
||||
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
||||
|
@ -2119,8 +2160,13 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (region_count) {
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (region_count > max_regions_) {
|
||||
BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
|
||||
" exceeds maximum " << max_regions_;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (region_count != 0) {
|
||||
scoped_ptr<MemoryDescriptors> descriptors(
|
||||
new MemoryDescriptors(region_count));
|
||||
|
||||
|
@ -2820,6 +2866,10 @@ void MinidumpBreakpadInfo::Print() {
|
|||
//
|
||||
|
||||
|
||||
u_int32_t Minidump::max_streams_ = 128;
|
||||
unsigned int Minidump::max_string_length_ = 1024;
|
||||
|
||||
|
||||
Minidump::Minidump(const string& path)
|
||||
: header_(),
|
||||
directory_(NULL),
|
||||
|
@ -2933,8 +2983,13 @@ bool Minidump::Read() {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (header_.stream_count) {
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (header_.stream_count > max_streams_) {
|
||||
BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
|
||||
" exceeds maximum " << max_streams_;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header_.stream_count != 0) {
|
||||
scoped_ptr<MinidumpDirectoryEntries> directory(
|
||||
new MinidumpDirectoryEntries(header_.stream_count));
|
||||
|
||||
|
@ -3145,31 +3200,39 @@ string* Minidump::ReadString(off_t offset) {
|
|||
return NULL;
|
||||
}
|
||||
if (!SeekSet(offset)) {
|
||||
BPLOG(ERROR) << "ReadString could not seek to string";
|
||||
BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u_int32_t bytes;
|
||||
if (!ReadBytes(&bytes, sizeof(bytes))) {
|
||||
BPLOG(ERROR) << "ReadString could not read string size";
|
||||
BPLOG(ERROR) << "ReadString could not read string size at offset " <<
|
||||
offset;
|
||||
return NULL;
|
||||
}
|
||||
if (swap_)
|
||||
Swap(&bytes);
|
||||
|
||||
if (bytes % 2 != 0) {
|
||||
BPLOG(ERROR) << "ReadString found odd-sized string of " << bytes <<
|
||||
" bytes at offset " << offset;
|
||||
BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
|
||||
"-byte string at offset " << offset;
|
||||
return NULL;
|
||||
}
|
||||
unsigned int utf16_words = bytes / 2;
|
||||
|
||||
// TODO(mmentovai): verify rational size!
|
||||
if (utf16_words > max_string_length_) {
|
||||
BPLOG(ERROR) << "ReadString string length " << utf16_words <<
|
||||
" exceeds maximum " << max_string_length_ <<
|
||||
" at offset " << offset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector<u_int16_t> string_utf16(utf16_words);
|
||||
|
||||
if (utf16_words) {
|
||||
if (!ReadBytes(&string_utf16[0], bytes)) {
|
||||
BPLOG(ERROR) << "ReadString could not read string";
|
||||
BPLOG(ERROR) << "ReadString could not read " << bytes <<
|
||||
"-byte string at offset " << offset;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <cstdio>
|
||||
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -50,7 +51,7 @@ using google_breakpad::MinidumpBreakpadInfo;
|
|||
static bool PrintMinidumpDump(const char *minidump_file) {
|
||||
Minidump minidump(minidump_file);
|
||||
if (!minidump.Read()) {
|
||||
fprintf(stderr, "minidump.Read() failed\n");
|
||||
BPLOG(ERROR) << "minidump.Read() failed";
|
||||
return false;
|
||||
}
|
||||
minidump.Print();
|
||||
|
@ -60,7 +61,7 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
MinidumpThreadList *thread_list = minidump.GetThreadList();
|
||||
if (!thread_list) {
|
||||
++errors;
|
||||
printf("minidump.GetThreadList() failed\n");
|
||||
BPLOG(ERROR) << "minidump.GetThreadList() failed";
|
||||
} else {
|
||||
thread_list->Print();
|
||||
}
|
||||
|
@ -68,7 +69,7 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
MinidumpModuleList *module_list = minidump.GetModuleList();
|
||||
if (!module_list) {
|
||||
++errors;
|
||||
printf("minidump.GetModuleList() failed\n");
|
||||
BPLOG(ERROR) << "minidump.GetModuleList() failed";
|
||||
} else {
|
||||
module_list->Print();
|
||||
}
|
||||
|
@ -76,15 +77,14 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
MinidumpMemoryList *memory_list = minidump.GetMemoryList();
|
||||
if (!memory_list) {
|
||||
++errors;
|
||||
printf("minidump.GetMemoryList() failed\n");
|
||||
BPLOG(ERROR) << "minidump.GetMemoryList() failed";
|
||||
} else {
|
||||
memory_list->Print();
|
||||
}
|
||||
|
||||
MinidumpException *exception = minidump.GetException();
|
||||
if (!exception) {
|
||||
// Exception info is optional, so don't treat this as an error.
|
||||
printf("minidump.GetException() failed\n");
|
||||
BPLOG(INFO) << "minidump.GetException() failed";
|
||||
} else {
|
||||
exception->Print();
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
MinidumpSystemInfo *system_info = minidump.GetSystemInfo();
|
||||
if (!system_info) {
|
||||
++errors;
|
||||
printf("minidump.GetSystemInfo() failed\n");
|
||||
BPLOG(ERROR) << "minidump.GetSystemInfo() failed";
|
||||
} else {
|
||||
system_info->Print();
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
MinidumpMiscInfo *misc_info = minidump.GetMiscInfo();
|
||||
if (!misc_info) {
|
||||
++errors;
|
||||
printf("minidump.GetMiscInfo() failed\n");
|
||||
BPLOG(ERROR) << "minidump.GetMiscInfo() failed";
|
||||
} else {
|
||||
misc_info->Print();
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
MinidumpBreakpadInfo *breakpad_info = minidump.GetBreakpadInfo();
|
||||
if (!breakpad_info) {
|
||||
// Breakpad info is optional, so don't treat this as an error.
|
||||
printf("minidump.GetBreakpadInfo() failed\n");
|
||||
BPLOG(INFO) << "minidump.GetBreakpadInfo() failed";
|
||||
} else {
|
||||
breakpad_info->Print();
|
||||
}
|
||||
|
@ -119,6 +119,8 @@ static bool PrintMinidumpDump(const char *minidump_file) {
|
|||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
|
|
|
@ -112,6 +112,7 @@ MinidumpProcessor::ProcessResult MinidumpProcessor::Process(
|
|||
(has_dump_thread ? "" : "no ") << "dump thread, and " <<
|
||||
(has_requesting_thread ? "" : "no ") << "requesting thread";
|
||||
|
||||
bool interrupted = false;
|
||||
bool found_requesting_thread = false;
|
||||
unsigned int thread_count = threads->thread_count();
|
||||
for (unsigned int thread_index = 0;
|
||||
|
@ -203,13 +204,18 @@ MinidumpProcessor::ProcessResult MinidumpProcessor::Process(
|
|||
|
||||
scoped_ptr<CallStack> stack(new CallStack());
|
||||
if (!stackwalker->Walk(stack.get())) {
|
||||
BPLOG(INFO) << "Processing interrupted by stackwalker (missing " <<
|
||||
"symbols?) at " << thread_string;
|
||||
return PROCESS_INTERRUPTED;
|
||||
BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " <<
|
||||
thread_string;
|
||||
interrupted = true;
|
||||
}
|
||||
process_state->threads_.push_back(stack.release());
|
||||
}
|
||||
|
||||
if (interrupted) {
|
||||
BPLOG(INFO) << "Processing interrupted for " << minidump_file;
|
||||
return PROCESS_INTERRUPTED;
|
||||
}
|
||||
|
||||
// If a requesting thread was indicated, it must be present.
|
||||
if (has_requesting_thread && !found_requesting_thread) {
|
||||
// Don't mark as an error, but invalidate the requesting thread
|
||||
|
@ -284,6 +290,8 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
|
|||
}
|
||||
}
|
||||
|
||||
info->cpu_count = raw_system_info->number_of_processors;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -723,6 +731,107 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_t *address) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MD_OS_LINUX:
|
||||
switch (exception_code) {
|
||||
case MD_EXCEPTION_CODE_LIN_SIGHUP:
|
||||
reason = "SIGHUP";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGINT:
|
||||
reason = "SIGINT";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGQUIT:
|
||||
reason = "SIGQUIT";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGILL:
|
||||
reason = "SIGILL";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTRAP:
|
||||
reason = "SIGTRAP";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGABRT:
|
||||
reason = "SIGABRT";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGBUS:
|
||||
reason = "SIGBUS";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGFPE:
|
||||
reason = "SIGFPE";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGKILL:
|
||||
reason = "SIGKILL";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGUSR1:
|
||||
reason = "SIGUSR1";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSEGV:
|
||||
reason = "SIGSEGV";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGUSR2:
|
||||
reason = "SIGUSR2";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGPIPE:
|
||||
reason = "SIGPIPE";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGALRM:
|
||||
reason = "SIGALRM";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTERM:
|
||||
reason = "SIGTERM";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
|
||||
reason = "SIGSTKFLT";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGCHLD:
|
||||
reason = "SIGCHLD";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGCONT:
|
||||
reason = "SIGCONT";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSTOP:
|
||||
reason = "SIGSTOP";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTSTP:
|
||||
reason = "SIGTSTP";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTTIN:
|
||||
reason = "SIGTTIN";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGTTOU:
|
||||
reason = "SIGTTOU";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGURG:
|
||||
reason = "SIGURG";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGXCPU:
|
||||
reason = "SIGXCPU";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
|
||||
reason = "SIGXFSZ";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
|
||||
reason = "SIGVTALRM";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGPROF:
|
||||
reason = "SIGPROF";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGWINCH:
|
||||
reason = "SIGWINCH";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGIO:
|
||||
reason = "SIGIO";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGPWR:
|
||||
reason = "SIGPWR";
|
||||
break;
|
||||
case MD_EXCEPTION_CODE_LIN_SIGSYS:
|
||||
reason = "SIGSYS";
|
||||
break;
|
||||
default:
|
||||
BPLOG(INFO) << "Unknown exception reason " << reason;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "google_breakpad/processor/symbol_supplier.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
namespace {
|
||||
|
@ -204,6 +205,8 @@ static bool RunTests() {
|
|||
} // namespace
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
if (!RunTests()) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "google_breakpad/processor/minidump_processor.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/pathname_stripper.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
#include "processor/simple_symbol_supplier.h"
|
||||
|
@ -232,7 +233,7 @@ static void PrintModules(const CodeModules *modules) {
|
|||
printf("\n");
|
||||
printf("Loaded modules:\n");
|
||||
|
||||
u_int64_t main_address = 0xffffffffffffffffLL;
|
||||
u_int64_t main_address = 0;
|
||||
const CodeModule *main_module = modules->GetMainModule();
|
||||
if (main_module) {
|
||||
main_address = main_module->base_address();
|
||||
|
@ -248,7 +249,8 @@ static void PrintModules(const CodeModules *modules) {
|
|||
base_address, base_address + module->size() - 1,
|
||||
PathnameStripper::File(module->code_file()).c_str(),
|
||||
module->version().empty() ? "???" : module->version().c_str(),
|
||||
base_address == main_address ? " (main)" : "");
|
||||
main_module != NULL && base_address == main_address ?
|
||||
" (main)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +263,7 @@ static void PrintModulesMachineReadable(const CodeModules *modules) {
|
|||
if (!modules)
|
||||
return;
|
||||
|
||||
u_int64_t main_address = 0xffffffffffffffffLL;
|
||||
u_int64_t main_address = 0;
|
||||
const CodeModule *main_module = modules->GetMainModule();
|
||||
if (main_module) {
|
||||
main_address = main_module->base_address();
|
||||
|
@ -283,7 +285,8 @@ static void PrintModulesMachineReadable(const CodeModules *modules) {
|
|||
StripSeparator(module->debug_identifier()).c_str(),
|
||||
kOutputSeparator, base_address,
|
||||
kOutputSeparator, base_address + module->size() - 1,
|
||||
kOutputSeparator, base_address == main_address ? 1 : 0);
|
||||
kOutputSeparator,
|
||||
main_module != NULL && base_address == main_address ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,6 +302,9 @@ static void PrintProcessState(const ProcessState& process_state) {
|
|||
// This field is optional.
|
||||
printf(" %s\n", cpu_info.c_str());
|
||||
}
|
||||
printf(" %d CPU%s\n",
|
||||
process_state.system_info()->cpu_count,
|
||||
process_state.system_info()->cpu_count != 1 ? "s" : "");
|
||||
printf("\n");
|
||||
|
||||
// Print crash information.
|
||||
|
@ -338,16 +344,18 @@ static void PrintProcessStateMachineReadable(const ProcessState& process_state)
|
|||
{
|
||||
// Print OS and CPU information.
|
||||
// OS|{OS Name}|{OS Version}
|
||||
// CPU|{CPU Name}|{CPU Info}
|
||||
// CPU|{CPU Name}|{CPU Info}|{Number of CPUs}
|
||||
printf("OS%c%s%c%s\n", kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->os).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->os_version).c_str());
|
||||
printf("CPU%c%s%c%s\n", kOutputSeparator,
|
||||
printf("CPU%c%s%c%s%c%d\n", kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->cpu).c_str(),
|
||||
kOutputSeparator,
|
||||
// this may be empty
|
||||
StripSeparator(process_state.system_info()->cpu_info).c_str());
|
||||
StripSeparator(process_state.system_info()->cpu_info).c_str(),
|
||||
kOutputSeparator,
|
||||
process_state.system_info()->cpu_count);
|
||||
|
||||
int requesting_thread = process_state.requesting_thread();
|
||||
|
||||
|
@ -416,7 +424,7 @@ static bool PrintMinidumpProcess(const string &minidump_file,
|
|||
ProcessState process_state;
|
||||
if (minidump_processor.Process(minidump_file, &process_state) !=
|
||||
MinidumpProcessor::PROCESS_OK) {
|
||||
fprintf(stderr, "MinidumpProcessor::Process failed\n");
|
||||
BPLOG(ERROR) << "MinidumpProcessor::Process failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -438,6 +446,8 @@ static void usage(const char *program_name) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "processor/pathname_stripper.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
#define ASSERT_TRUE(condition) \
|
||||
if (!(condition)) { \
|
||||
|
@ -78,5 +79,7 @@ static bool RunTests() {
|
|||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
return RunTests() ? 0 : 1;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
#include "google_breakpad/processor/memory_region.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -296,5 +297,7 @@ static bool RunTests() {
|
|||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
return RunTests() ? 0 : 1;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#define PROCESSOR_RANGE_MAP_INL_H__
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "processor/range_map.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "processor/range_map-inl.h"
|
||||
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
|
||||
|
@ -487,5 +488,7 @@ static bool RunTests() {
|
|||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
return RunTests() ? 0 : 1;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "google_breakpad/processor/memory_region.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
|
@ -292,6 +293,8 @@ static bool Recursor(unsigned int depth, unsigned int parent_callers) {
|
|||
// be inlined anyway.
|
||||
int main(int argc, char** argv) __attribute__((noinline));
|
||||
int main(int argc, char** argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
return Recursor(RECURSION_DEPTH, CountCallerFrames()) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@ -302,8 +305,11 @@ int main(int argc, char** argv) {
|
|||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
// "make check" interprets an exit status of 77 to mean that the test is
|
||||
// not supported.
|
||||
BPLOG(ERROR) << "Selftest not supported here";
|
||||
return 77;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
OS|Windows NT|5.1.2600 Service Pack 2
|
||||
CPU|x86|GenuineIntel family 6 model 13 stepping 8
|
||||
CPU|x86|GenuineIntel family 6 model 13 stepping 8|1
|
||||
Crash|EXCEPTION_ACCESS_VIOLATION|0x45|0
|
||||
Module|test_app.exe||test_app.pdb|5A9832E5287241C1838ED98914E9B7FF1|0x00400000|0x0042cfff|1
|
||||
Module|dbghelp.dll|5.1.2600.2180|dbghelp.pdb|39559573E21B46F28E286923BE9E6A761|0x59a60000|0x59b00fff|0
|
||||
|
|
|
@ -2,6 +2,7 @@ Operating system: Windows NT
|
|||
5.1.2600 Service Pack 2
|
||||
CPU: x86
|
||||
GenuineIntel family 6 model 13 stepping 8
|
||||
1 CPU
|
||||
|
||||
Crash reason: EXCEPTION_ACCESS_VIOLATION
|
||||
Crash address: 0x45
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
/* Begin PBXBuildFile section */
|
||||
557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; };
|
||||
557800410BE1F28500EC23E0 /* macho_utilities.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5578003F0BE1F28500EC23E0 /* macho_utilities.h */; };
|
||||
8B40BDC00C0638E4009535AF /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B40BDBF0C0638E4009535AF /* logging.cc */; };
|
||||
8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; };
|
||||
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
|
||||
9B35FEE40B2675F9008DE8C7 /* code_module.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FEE20B2675F9008DE8C7 /* code_module.h */; };
|
||||
|
@ -78,6 +79,7 @@
|
|||
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; };
|
||||
5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; };
|
||||
8B40BDBF0C0638E4009535AF /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../../processor/logging.cc; sourceTree = SOURCE_ROOT; };
|
||||
8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; };
|
||||
9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -228,6 +230,7 @@
|
|||
9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */,
|
||||
9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */,
|
||||
9BDF172A0B1B8B2400F8391B /* call_stack.cc */,
|
||||
8B40BDBF0C0638E4009535AF /* logging.cc */,
|
||||
9BDF173F0B1B8B9A00F8391B /* minidump.cc */,
|
||||
9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */,
|
||||
9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */,
|
||||
|
@ -312,6 +315,7 @@
|
|||
9BE650B40B52FE3000611104 /* macho_id.cc in Sources */,
|
||||
9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */,
|
||||
557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */,
|
||||
8B40BDC00C0638E4009535AF /* logging.cc in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче