bug 384034 - update to breakpad revision 189. r=mento

This commit is contained in:
ted.mielczarek@gmail.com 2007-07-24 18:06:10 -07:00
Родитель 7e309a6774
Коммит e85e6f18f8
38 изменённых файлов: 952 добавлений и 128 удалений

Просмотреть файл

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