Add google breakpad to 3rdparty, and gather crash reports

This commit is contained in:
David Sansome 2011-03-23 21:53:24 +00:00
parent d91aaa880c
commit d50cfaed46
51 changed files with 12775 additions and 12 deletions

20
3rdparty/google-breakpad/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 2.6)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(SOURCES
client/linux/crash_generation/crash_generation_client.cc
client/linux/handler/exception_handler.cc
client/linux/minidump_writer/linux_dumper.cc
client/linux/minidump_writer/minidump_writer.cc
client/minidump_file_writer.cc
common/convert_UTF.c
common/md5.c
common/string_conversion.cc
common/linux/file_id.cc
common/linux/guid_creator.cc
)
ADD_LIBRARY(breakpad STATIC
${SOURCES}
)

View File

@ -0,0 +1,44 @@
// Copyright (c) 2010, 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.
// The Android NDK doesn't have link.h. Fortunately, the only thing
// that Breakpad uses from it is the ElfW macro, so define it here.
#ifndef GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_LINK_H_
#define GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_LINK_H_
#include <sys/exec_elf.h>
#ifndef ElfW
#define ElfW(type) _ElfW (Elf, ELFSIZE, type)
#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
#define _ElfW_1(e,w,t) e##w##t
#endif
#endif // GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_LINK_H_

View File

@ -0,0 +1,77 @@
// Copyright (c) 2009, 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.
// Android runs a fairly new Linux kernel, so signal info is there,
// but the NDK doesn't have the structs defined, so define
// them here.
// Adapted from platform-linux.cc in V8
#ifndef GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
#define GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
#include <signal.h>
#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
struct sigcontext {
uint32_t trap_no;
uint32_t error_code;
uint32_t oldmask;
uint32_t arm_r0;
uint32_t arm_r1;
uint32_t arm_r2;
uint32_t arm_r3;
uint32_t arm_r4;
uint32_t arm_r5;
uint32_t arm_r6;
uint32_t arm_r7;
uint32_t arm_r8;
uint32_t arm_r9;
uint32_t arm_r10;
uint32_t arm_fp;
uint32_t arm_ip;
uint32_t arm_sp;
uint32_t arm_lr;
uint32_t arm_pc;
uint32_t arm_cpsr;
uint32_t fault_address;
};
typedef uint32_t __sigset_t;
typedef struct sigcontext mcontext_t;
typedef struct ucontext {
uint32_t uc_flags;
struct ucontext* uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
__sigset_t uc_sigmask;
} ucontext_t;
#endif
#endif // GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_

View File

@ -0,0 +1,89 @@
// Copyright (c) 2010 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.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <algorithm>
#include "client/linux/crash_generation/crash_generation_client.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
bool
CrashGenerationClient::RequestDump(const void* blob, size_t blob_size)
{
int fds[2];
sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int));
struct kernel_msghdr msg;
my_memset(&msg, 0, sizeof(struct kernel_msghdr));
struct kernel_iovec iov[1];
iov[0].iov_base = const_cast<void*>(blob);
iov[0].iov_len = blob_size;
msg.msg_iov = iov;
msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
char cmsg[kControlMsgSize];
my_memset(cmsg, 0, kControlMsgSize);
msg.msg_control = cmsg;
msg.msg_controllen = sizeof(cmsg);
struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg);
hdr->cmsg_level = SOL_SOCKET;
hdr->cmsg_type = SCM_RIGHTS;
hdr->cmsg_len = CMSG_LEN(sizeof(int));
int* p = reinterpret_cast<int*>(CMSG_DATA(hdr));
*p = fds[1];
HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0));
sys_close(fds[1]);
// wait for an ACK from the server
char b;
HANDLE_EINTR(sys_read(fds[0], &b, 1));
return true;
}
//static
CrashGenerationClient*
CrashGenerationClient::TryCreate(int server_fd)
{
if (0 > server_fd)
return NULL;
return new CrashGenerationClient(server_fd);
}
}

View File

@ -0,0 +1,69 @@
// Copyright (c) 2010 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.
#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#include <stddef.h>
namespace google_breakpad {
class CrashGenerationClient {
public:
~CrashGenerationClient()
{
}
// Request the crash server to generate a dump. |blob| is a hack,
// see exception_handler.h and minidump_writer.h
//
// Return true if the dump was successful; false otherwise.
bool RequestDump(const void* blob, size_t blob_size);
// Return a new CrashGenerationClient if |server_fd| is valid and
// connects to a CrashGenerationServer. Otherwise, return NULL.
// The returned CrashGenerationClient* is owned by the caller of
// this function.
static CrashGenerationClient* TryCreate(int server_fd);
private:
CrashGenerationClient(int server_fd) : server_fd_(server_fd)
{
}
int server_fd_;
// prevent copy construction and assignment
CrashGenerationClient(const CrashGenerationClient&);
CrashGenerationClient& operator=(const CrashGenerationClient&);
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_

View File

@ -0,0 +1,512 @@
// Copyright (c) 2010 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.
// The ExceptionHandler object installs signal handlers for a number of
// signals. We rely on the signal handler running on the thread which crashed
// in order to identify it. This is true of the synchronous signals (SEGV etc),
// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
// uses ExceptionHandler, you need to use tgkill to direct it to the current
// thread.
//
// The signal flow looks like this:
//
// SignalHandler (uses a global stack of ExceptionHandler objects to find
// | one to handle the signal. If the first rejects it, try
// | the second etc...)
// V
// HandleSignal ----------------------------| (clones a new process which
// | | shares an address space with
// (wait for cloned | the crashed process. This
// process) | allows us to ptrace the crashed
// | | process)
// V V
// (set signal handler to ThreadEntry (static function to bounce
// SIG_DFL and rethrow, | back into the object)
// killing the crashed |
// process) V
// DoDump (writes minidump)
// |
// V
// sys_exit
//
// This code is a little fragmented. Different functions of the ExceptionHandler
// class run in a number of different contexts. Some of them run in a normal
// context and are easy to code, others run in a compromised context and the
// restrictions at the top of minidump_writer.cc apply: no libc and use the
// alternative malloc. Each function should have comment above it detailing the
// context which it runs in.
#include "client/linux/handler/exception_handler.h"
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#if !defined(__ANDROID__)
#include <sys/signal.h>
#endif
#include <sys/syscall.h>
#if !defined(__ANDROID__)
#include <sys/ucontext.h>
#include <sys/user.h>
#endif
#include <sys/wait.h>
#if !defined(__ANDROID__)
#include <ucontext.h>
#endif
#include <unistd.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "common/linux/linux_libc_support.h"
#include "common/memory.h"
#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/guid_creator.h"
#include "common/linux/eintr_wrapper.h"
#include "third_party/lss/linux_syscall_support.h"
#ifndef PR_SET_PTRACER
#define PR_SET_PTRACER 0x59616d61
#endif
// A wrapper for the tgkill syscall: send a signal to a specific thread.
static int tgkill(pid_t tgid, pid_t tid, int sig) {
return syscall(__NR_tgkill, tgid, tid, sig);
return 0;
}
namespace google_breakpad {
// The list of signals which we consider to be crashes. The default action for
// all these signals must be Core (see man 7 signal) because we rethrow the
// signal after handling it and expect that it'll be fatal.
static const int kExceptionSignals[] = {
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1
};
// We can stack multiple exception handlers. In that case, this is the global
// which holds the stack.
std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
unsigned ExceptionHandler::handler_stack_index_ = 0;
pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
PTHREAD_MUTEX_INITIALIZER;
// Runs before crashing: normal context.
ExceptionHandler::ExceptionHandler(const std::string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
bool install_handler)
: filter_(filter),
callback_(callback),
callback_context_(callback_context),
handler_installed_(install_handler)
{
Init(dump_path, -1);
}
ExceptionHandler::ExceptionHandler(const std::string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
bool install_handler,
const int server_fd)
: filter_(filter),
callback_(callback),
callback_context_(callback_context),
handler_installed_(install_handler)
{
Init(dump_path, server_fd);
}
// Runs before crashing: normal context.
ExceptionHandler::~ExceptionHandler() {
UninstallHandlers();
}
void ExceptionHandler::Init(const std::string &dump_path,
const int server_fd)
{
crash_handler_ = NULL;
if (0 <= server_fd)
crash_generation_client_
.reset(CrashGenerationClient::TryCreate(server_fd));
if (handler_installed_)
InstallHandlers();
if (!IsOutOfProcess())
set_dump_path(dump_path);
pthread_mutex_lock(&handler_stack_mutex_);
if (handler_stack_ == NULL)
handler_stack_ = new std::vector<ExceptionHandler *>;
handler_stack_->push_back(this);
pthread_mutex_unlock(&handler_stack_mutex_);
}
// Runs before crashing: normal context.
bool ExceptionHandler::InstallHandlers() {
// We run the signal handlers on an alternative stack because we might have
// crashed because of a stack overflow.
// We use this value rather than SIGSTKSZ because we would end up overrunning
// such a small stack.
static const unsigned kSigStackSize = 8192;
signal_stack = malloc(kSigStackSize);
stack_t stack;
memset(&stack, 0, sizeof(stack));
stack.ss_sp = signal_stack;
stack.ss_size = kSigStackSize;
if (sys_sigaltstack(&stack, NULL) == -1)
return false;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
// mask all exception signals when we're handling one of them.
for (unsigned i = 0; kExceptionSignals[i] != -1; ++i)
sigaddset(&sa.sa_mask, kExceptionSignals[i]);
sa.sa_sigaction = SignalHandler;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) {
struct sigaction* old = new struct sigaction;
if (sigaction(kExceptionSignals[i], &sa, old) == -1)
return false;
old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old));
}
return true;
}
// Runs before crashing: normal context.
void ExceptionHandler::UninstallHandlers() {
for (unsigned i = 0; i < old_handlers_.size(); ++i) {
struct sigaction *action =
reinterpret_cast<struct sigaction*>(old_handlers_[i].second);
sigaction(old_handlers_[i].first, action, NULL);
delete action;
}
pthread_mutex_lock(&handler_stack_mutex_);
std::vector<ExceptionHandler*>::iterator handler =
std::find(handler_stack_->begin(), handler_stack_->end(), this);
handler_stack_->erase(handler);
pthread_mutex_unlock(&handler_stack_mutex_);
old_handlers_.clear();
}
// Runs before crashing: normal context.
void ExceptionHandler::UpdateNextID() {
GUID guid;
char guid_str[kGUIDStringLength + 1];
if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
next_minidump_id_ = guid_str;
next_minidump_id_c_ = next_minidump_id_.c_str();
char minidump_path[PATH_MAX];
snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp",
dump_path_c_,
guid_str);
next_minidump_path_ = minidump_path;
next_minidump_path_c_ = next_minidump_path_.c_str();
}
}
// void ExceptionHandler::set_crash_handler(HandlerCallback callback) {
// crash_handler_ = callback;
// }
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
// All the exception signals are blocked at this point.
pthread_mutex_lock(&handler_stack_mutex_);
if (!handler_stack_->size()) {
pthread_mutex_unlock(&handler_stack_mutex_);
return;
}
for (int i = handler_stack_->size() - 1; i >= 0; --i) {
if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) {
// successfully handled: We are in an invalid state since an exception
// signal has been delivered. We don't call the exit handlers because
// they could end up corrupting on-disk state.
break;
}
}
pthread_mutex_unlock(&handler_stack_mutex_);
if (info->si_pid) {
// This signal was triggered by somebody sending us the signal with kill().
// In order to retrigger it, we have to queue a new signal by calling
// kill() ourselves.
if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) {
// If we failed to kill ourselves (e.g. because a sandbox disallows us
// to do so), we instead resort to terminating our process. This will
// result in an incorrect exit code.
_exit(1);
}
} else {
// This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV).
// No need to reissue the signal. It will automatically trigger again,
// when we return from the signal handler.
}
// As soon as we return from the signal handler, our signal will become
// unmasked. At that time, we will get terminated with the same signal that
// was triggered originally. This allows our parent to know that we crashed.
// The default action for all the signals which we catch is Core, so
// this is the end of us.
signal(sig, SIG_DFL);
}
struct ThreadArgument {
pid_t pid; // the crashing process
ExceptionHandler* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
// This is the entry function for the cloned process. We are in a compromised
// context here: see the top of the file.
// static
int ExceptionHandler::ThreadEntry(void *arg) {
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
// Block here until the crashing process unblocks us when
// we're allowed to use ptrace
thread_arg->handler->WaitForContinueSignal();
return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
thread_arg->context_size) == false;
}
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
if (filter_ && !filter_(callback_context_))
return false;
// Allow ourselves to be dumped if the signal is trusted.
bool signal_trusted = info->si_code > 0;
bool signal_pid_trusted = info->si_code == SI_USER ||
info->si_code == SI_TKILL;
if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) {
sys_prctl(PR_SET_DUMPABLE, 1);
}
CrashContext context;
memcpy(&context.siginfo, info, sizeof(siginfo_t));
memcpy(&context.context, uc, sizeof(struct ucontext));
#if !defined(__ARM_EABI__)
// FP state is not part of user ABI on ARM Linux.
struct ucontext *uc_ptr = (struct ucontext*)uc;
if (uc_ptr->uc_mcontext.fpregs) {
memcpy(&context.float_state,
uc_ptr->uc_mcontext.fpregs,
sizeof(context.float_state));
}
#endif
context.tid = syscall(__NR_gettid);
if (crash_handler_ != NULL) {
if (crash_handler_(&context, sizeof(context),
callback_context_)) {
return true;
}
}
return GenerateDump(&context);
}
// This function may run in a compromised context: see the top of the file.
bool ExceptionHandler::GenerateDump(CrashContext *context) {
if (IsOutOfProcess())
return crash_generation_client_->RequestDump(context, sizeof(*context));
static const unsigned kChildStackSize = 8000;
PageAllocator allocator;
uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize);
if (!stack)
return false;
// clone() needs the top-most address. (scrub just to be safe)
stack += kChildStackSize;
my_memset(stack - 16, 0, 16);
ThreadArgument thread_arg;
thread_arg.handler = this;
thread_arg.pid = getpid();
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
// We need to explicitly enable ptrace of parent processes on some
// kernels, but we need to know the PID of the cloned process before we
// can do this. Create a pipe here which we can use to block the
// cloned process after creating it, until we have explicitly enabled ptrace
if(sys_pipe(fdes) == -1) {
// Creating the pipe failed. We'll log an error but carry on anyway,
// as we'll probably still get a useful crash report. All that will happen
// is the write() and read() calls will fail with EBADF
static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump \
sys_pipe failed:";
sys_write(2, no_pipe_msg, sizeof(no_pipe_msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
&thread_arg, NULL, NULL, NULL);
int r, status;
// Allow the child to ptrace us
prctl(PR_SET_PTRACER, child, 0, 0, 0);
SendContinueSignalToChild();
do {
r = sys_waitpid(child, &status, __WALL);
} while (r == -1 && errno == EINTR);
sys_close(fdes[0]);
sys_close(fdes[1]);
if (r == -1) {
static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:";
sys_write(2, msg, sizeof(msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
if (callback_)
success = callback_(dump_path_c_, next_minidump_id_c_,
callback_context_, success);
return success;
}
// This function runs in a compromised context: see the top of the file.
void ExceptionHandler::SendContinueSignalToChild() {
static const char okToContinueMessage = 'a';
int r;
r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char)));
if(r == -1) {
static const char msg[] = "ExceptionHandler::SendContinueSignalToChild \
sys_write failed:";
sys_write(2, msg, sizeof(msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
}
// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
void ExceptionHandler::WaitForContinueSignal() {
int r;
char receivedMessage;
r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char)));
if(r == -1) {
static const char msg[] = "ExceptionHandler::WaitForContinueSignal \
sys_read failed:";
sys_write(2, msg, sizeof(msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
}
// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
size_t context_size) {
return google_breakpad::WriteMinidump(next_minidump_path_c_,
crashing_process,
context,
context_size,
mapping_list_);
}
// static
bool ExceptionHandler::WriteMinidump(const std::string &dump_path,
MinidumpCallback callback,
void* callback_context) {
ExceptionHandler eh(dump_path, NULL, callback, callback_context, false);
return eh.WriteMinidump();
}
bool ExceptionHandler::WriteMinidump() {
#if !defined(__ARM_EABI__)
// Allow ourselves to be dumped.
sys_prctl(PR_SET_DUMPABLE, 1);
CrashContext context;
int getcontext_result = getcontext(&context.context);
if (getcontext_result)
return false;
memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
sizeof(context.float_state));
context.tid = sys_gettid();
bool success = GenerateDump(&context);
UpdateNextID();
return success;
#else
return false;
#endif // !defined(__ARM_EABI__)
}
void ExceptionHandler::AddMappingInfo(const std::string& name,
const u_int8_t identifier[sizeof(MDGUID)],
uintptr_t start_address,
size_t mapping_size,
size_t file_offset) {
MappingInfo info;
info.start_addr = start_address;
info.size = mapping_size;
info.offset = file_offset;
strncpy(info.name, name.c_str(), std::min(name.size(), sizeof(info)));
MappingEntry mapping;
mapping.first = info;
memcpy(mapping.second, identifier, sizeof(MDGUID));
mapping_list_.push_back(mapping);
}
} // namespace google_breakpad

View File

@ -0,0 +1,259 @@
// Copyright (c) 2010 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.
#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
#include <string>
#include <vector>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#if defined(__ANDROID__)
#include "client/linux/android_ucontext.h"
#endif
#include "client/linux/crash_generation/crash_generation_client.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "google_breakpad/common/minidump_format.h"
#include "processor/scoped_ptr.h"
struct sigaction;
namespace google_breakpad {
class ExceptionHandler;
// ExceptionHandler
//
// ExceptionHandler can write a minidump file when an exception occurs,
// or when WriteMinidump() is called explicitly by your program.
//
// To have the exception handler write minidumps when an uncaught exception
// (crash) occurs, you should create an instance early in the execution
// of your program, and keep it around for the entire time you want to
// have crash handling active (typically, until shutdown).
// (NOTE): There should be only be one this kind of exception handler
// object per process.
//
// If you want to write minidumps without installing the exception handler,
// you can create an ExceptionHandler with install_handler set to false,
// then call WriteMinidump. You can also use this technique if you want to
// use different minidump callbacks for different call sites.
//
// In either case, a callback function is called when a minidump is written,
// which receives the unqiue id of the minidump. The caller can use this
// id to collect and write additional application state, and to launch an
// external crash-reporting application.
//
// Caller should try to make the callbacks as crash-friendly as possible,
// it should avoid use heap memory allocation as much as possible.
class ExceptionHandler {
public:
// A callback function to run before Breakpad performs any substantial
// processing of an exception. A FilterCallback is called before writing
// a minidump. context is the parameter supplied by the user as
// callback_context when the handler was created.
//
// If a FilterCallback returns true, Breakpad will continue processing,
// attempting to write a minidump. If a FilterCallback returns false,
// Breakpad will immediately report the exception as unhandled without
// writing a minidump, allowing another handler the opportunity to handle it.
typedef bool (*FilterCallback)(void *context);
// A callback function to run after the minidump has been written.
// minidump_id is a unique id for the dump, so the minidump
// file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied
// by the user as callback_context when the handler was created. succeeded
// indicates whether a minidump file was successfully written.
//
// If an exception occurred and the callback returns true, Breakpad will
// treat the exception as fully-handled, suppressing any other handlers from
// being notified of the exception. If the callback returns false, Breakpad
// will treat the exception as unhandled, and allow another handler to handle
// it. If there are no other handlers, Breakpad will report the exception to
// the system as unhandled, allowing a debugger or native crash dialog the
// opportunity to handle the exception. Most callback implementations
// should normally return the value of |succeeded|, or when they wish to
// not report an exception of handled, false. Callbacks will rarely want to
// return true directly (unless |succeeded| is true).
typedef bool (*MinidumpCallback)(const char *dump_path,
const char *minidump_id,
void *context,
bool succeeded);
// In certain cases, a user may wish to handle the generation of the minidump
// themselves. In this case, they can install a handler callback which is
// called when a crash has occurred. If this function returns true, no other
// processing of occurs and the process will shortly be crashed. If this
// returns false, the normal processing continues.
typedef bool (*HandlerCallback)(const void* crash_context,
size_t crash_context_size,
void* context);
// Creates a new ExceptionHandler instance to handle writing minidumps.
// Before writing a minidump, the optional filter callback will be called.
// Its return value determines whether or not Breakpad should write a
// minidump. Minidump files will be written to dump_path, and the optional
// callback is called after writing the dump file, as described above.
// If install_handler is true, then a minidump will be written whenever
// an unhandled exception occurs. If it is false, minidumps will only
// be written when WriteMinidump is called.
ExceptionHandler(const std::string &dump_path,
FilterCallback filter, MinidumpCallback callback,
void *callback_context,
bool install_handler);
// Creates a new ExceptionHandler instance that can attempt to
// perform out-of-process dump generation if server_fd is valid. If
// server_fd is invalid, in-process dump generation will be
// used. See the above ctor for a description of the other
// parameters.
ExceptionHandler(const std::string& dump_path,
FilterCallback filter, MinidumpCallback callback,
void* callback_context,
bool install_handler,
const int server_fd);
~ExceptionHandler();
// Get and set the minidump path.
std::string dump_path() const { return dump_path_; }
void set_dump_path(const std::string &dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
UpdateNextID();
}
void set_crash_handler(HandlerCallback callback) {
crash_handler_ = callback;
}
// Writes a minidump immediately. This can be used to capture the
// execution state independently of a crash. Returns true on success.
bool WriteMinidump();
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const std::string &dump_path,
MinidumpCallback callback,
void *callback_context);
// This structure is passed to minidump_writer.h:WriteMinidump via an opaque
// blob. It shouldn't be needed in any user code.
struct CrashContext {
siginfo_t siginfo;
pid_t tid; // the crashing thread.
struct ucontext context;
#if !defined(__ARM_EABI__)
// #ifdef this out because FP state is not part of user ABI for Linux ARM.
struct _libc_fpstate float_state;
#endif
};
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const {
return crash_generation_client_.get() != NULL;
}
// Add information about a memory mapping. This can be used if
// a custom library loader is used that maps things in a way
// that the linux dumper can't handle by reading the maps file.
void AddMappingInfo(const std::string& name,
const u_int8_t identifier[sizeof(MDGUID)],
uintptr_t start_address,
size_t mapping_size,
size_t file_offset);
private:
void Init(const std::string &dump_path,
const int server_fd);
bool InstallHandlers();
void UninstallHandlers();
void PreresolveSymbols();
bool GenerateDump(CrashContext *context);
void SendContinueSignalToChild();
void WaitForContinueSignal();
void UpdateNextID();
static void SignalHandler(int sig, siginfo_t* info, void* uc);
bool HandleSignal(int sig, siginfo_t* info, void* uc);
static int ThreadEntry(void* arg);
bool DoDump(pid_t crashing_process, const void* context,
size_t context_size);
const FilterCallback filter_;
const MinidumpCallback callback_;
void* const callback_context_;
scoped_ptr<CrashGenerationClient> crash_generation_client_;
std::string dump_path_;
std::string next_minidump_path_;
std::string next_minidump_id_;
// Pointers to C-string representations of the above. These are set
// when the above are set so we can avoid calling c_str during
// an exception.
const char* dump_path_c_;
const char* next_minidump_path_c_;
const char* next_minidump_id_c_;
const bool handler_installed_;
void* signal_stack; // the handler stack.
HandlerCallback crash_handler_;
// The global exception handler stack. This is need becuase there may exist
// multiple ExceptionHandler instances in a process. Each will have itself
// registered in this stack.
static std::vector<ExceptionHandler*> *handler_stack_;
// The index of the handler that should handle the next exception.
static unsigned handler_stack_index_;
static pthread_mutex_t handler_stack_mutex_;
// A vector of the old signal handlers.
std::vector<std::pair<int, struct sigaction *> > old_handlers_;
// We need to explicitly enable ptrace of parent processes on some
// kernels, but we need to know the PID of the cloned process before we
// can do this. We create a pipe which we can use to block the
// cloned process after creating it, until we have explicitly enabled
// ptrace. This is used to store the file descriptors for the pipe
int fdes[2];
// Callers can add extra info about mappings for cases where the
// dumper code cannot extract enough information from /proc/<pid>/maps.
MappingList mapping_list_;
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_

View File

@ -0,0 +1,105 @@
// Copyright (c) 2009, 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.
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
#include <stdint.h>
#include <unistd.h>
#include <limits.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
// A class for enumerating a directory without using diropen/readdir or other
// functions which may allocate memory.
class DirectoryReader {
public:
DirectoryReader(int fd)
: fd_(fd),
buf_used_(0) {
}
// Return the next entry from the directory
// name: (output) the NUL terminated entry name
//
// Returns true iff successful (false on EOF).
//
// After calling this, one must call |PopEntry| otherwise you'll get the same
// entry over and over.
bool GetNextEntry(const char** name) {
struct kernel_dirent* const dent =
reinterpret_cast<kernel_dirent*>(buf_);
if (buf_used_ == 0) {
// need to read more entries.
const int n = sys_getdents(fd_, dent, sizeof(buf_));
if (n < 0) {
return false;
} else if (n == 0) {
hit_eof_ = true;
} else {
buf_used_ += n;
}
}
if (buf_used_ == 0 && hit_eof_)
return false;
assert(buf_used_ > 0);
*name = dent->d_name;
return true;
}
void PopEntry() {
if (!buf_used_)
return;
const struct kernel_dirent* const dent =
reinterpret_cast<kernel_dirent*>(buf_);
buf_used_ -= dent->d_reclen;
memmove(buf_, buf_ + dent->d_reclen, buf_used_);
}
private:
const int fd_;
bool hit_eof_;
unsigned buf_used_;
uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1];
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_

View File

@ -0,0 +1,130 @@
// Copyright (c) 2009, 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.
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
// A class for reading a file, line by line, without using fopen/fgets or other
// functions which may allocate memory.
class LineReader {
public:
LineReader(int fd)
: fd_(fd),
hit_eof_(false),
buf_used_(0) {
}
// The maximum length of a line.
static const size_t kMaxLineLen = 512;
// Return the next line from the file.
// line: (output) a pointer to the start of the line. The line is NUL
// terminated.
// len: (output) the length of the line (not inc the NUL byte)
//
// Returns true iff successful (false on EOF).
//
// One must call |PopLine| after this function, otherwise you'll continue to
// get the same line over and over.
bool GetNextLine(const char **line, unsigned *len) {
for (;;) {
if (buf_used_ == 0 && hit_eof_)
return false;
for (unsigned i = 0; i < buf_used_; ++i) {
if (buf_[i] == '\n' || buf_[i] == 0) {
buf_[i] = 0;
*len = i;
*line = buf_;
return true;
}
}
if (buf_used_ == sizeof(buf_)) {
// we scanned the whole buffer and didn't find an end-of-line marker.
// This line is too long to process.
return false;
}
// We didn't find any end-of-line terminators in the buffer. However, if
// this is the last line in the file it might not have one:
if (hit_eof_) {
assert(buf_used_);
// There's room for the NUL because of the buf_used_ == sizeof(buf_)
// check above.
buf_[buf_used_] = 0;
*len = buf_used_;
buf_used_ += 1; // since we appended the NUL.
*line = buf_;
return true;
}
// Otherwise, we should pull in more data from the file
const ssize_t n = sys_read(fd_, buf_ + buf_used_,
sizeof(buf_) - buf_used_);
if (n < 0) {
return false;
} else if (n == 0) {
hit_eof_ = true;
} else {
buf_used_ += n;
}
// At this point, we have either set the hit_eof_ flag, or we have more
// data to process...
}
}
void PopLine(unsigned len) {
// len doesn't include the NUL byte at the end.
assert(buf_used_ >= len + 1);
buf_used_ -= len + 1;
memmove(buf_, buf_ + len + 1, buf_used_);
}
private:
const int fd_;
bool hit_eof_;
unsigned buf_used_;
char buf_[kMaxLineLen];
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_

View File

@ -0,0 +1,555 @@
// Copyright (c) 2010, 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.
// This code deals with the mechanics of getting information about a crashed
// process. Since this code may run in a compromised address space, the same
// rules apply as detailed at the top of minidump_writer.h: no libc calls and
// use the alternative allocator.
#include "client/linux/minidump_writer/linux_dumper.h"
#include <asm/ptrace.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#if !defined(__ANDROID__)
#include <link.h>
#endif
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
#include "client/linux/minidump_writer/directory_reader.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
static const char kMappedFileUnsafePrefix[] = "/dev/";
static const char kDeletedSuffix[] = " (deleted)";
// Suspend a thread by attaching to it.
static bool SuspendThread(pid_t pid) {
// This may fail if the thread has just died or debugged.
errno = 0;
if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
errno != 0) {
return false;
}
while (sys_waitpid(pid, NULL, __WALL) < 0) {
if (errno != EINTR) {
sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
return false;
}
}
#if defined(__i386) || defined(__x86_64)
// On x86, the stack pointer is NULL or -1, when executing trusted code in
// the seccomp sandbox. Not only does this cause difficulties down the line
// when trying to dump the thread's stack, it also results in the minidumps
// containing information about the trusted threads. This information is
// generally completely meaningless and just pollutes the minidumps.
// We thus test the stack pointer and exclude any threads that are part of
// the seccomp sandbox's trusted code.
user_regs_struct regs;
if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
#if defined(__i386)
!regs.esp
#elif defined(__x86_64)
!regs.rsp
#endif
) {
sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
return false;
}
#endif
return true;
}
// Resume a thread by detaching from it.
static bool ResumeThread(pid_t pid) {
return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
}
inline static bool IsMappedFileOpenUnsafe(
const google_breakpad::MappingInfo& mapping) {
// It is unsafe to attempt to open a mapped file that lives under /dev,
// because the semantics of the open may be driver-specific so we'd risk
// hanging the crash dumper. And a file in /dev/ almost certainly has no
// ELF file identifier anyways.
return my_strncmp(mapping.name,
kMappedFileUnsafePrefix,
sizeof(kMappedFileUnsafePrefix) - 1) == 0;
}
namespace google_breakpad {
LinuxDumper::LinuxDumper(int pid)
: pid_(pid),
threads_suspended_(false),
threads_(&allocator_, 8),
mappings_(&allocator_) {
}
bool LinuxDumper::Init() {
return EnumerateThreads(&threads_) &&
EnumerateMappings(&mappings_);
}
bool LinuxDumper::ThreadsSuspend() {
if (threads_suspended_)
return true;
for (size_t i = 0; i < threads_.size(); ++i) {
if (!SuspendThread(threads_[i])) {
// If the thread either disappeared before we could attach to it, or if
// it was part of the seccomp sandbox's trusted code, it is OK to
// silently drop it from the minidump.
memmove(&threads_[i], &threads_[i+1],
(threads_.size() - i - 1) * sizeof(threads_[i]));
threads_.resize(threads_.size() - 1);
--i;
}
}
threads_suspended_ = true;
return threads_.size() > 0;
}
bool LinuxDumper::ThreadsResume() {
if (!threads_suspended_)
return false;
bool good = true;
for (size_t i = 0; i < threads_.size(); ++i)
good &= ResumeThread(threads_[i]);
threads_suspended_ = false;
return good;
}
void
LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
assert(path);
if (!path) {
return;
}
path[0] = '\0';
const unsigned pid_len = my_int_len(pid);
assert(node);
if (!node) {
return;
}
size_t node_len = my_strlen(node);
assert(node_len < NAME_MAX);
if (node_len >= NAME_MAX) {
return;
}
assert(node_len > 0);
if (node_len == 0) {
return;
}
assert(pid > 0);
if (pid <= 0) {
return;
}
const size_t total_length = 6 + pid_len + 1 + node_len;
assert(total_length < NAME_MAX);
if (total_length >= NAME_MAX) {
return;
}
memcpy(path, "/proc/", 6);
my_itos(path + 6, pid, pid_len);
memcpy(path + 6 + pid_len, "/", 1);
memcpy(path + 6 + pid_len + 1, node, node_len);
path[total_length] = '\0';
}
bool
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
int mapping_id,
uint8_t identifier[sizeof(MDGUID)])
{
assert(mapping_id == -1 || mapping_id < mappings_.size());
my_memset(identifier, 0, sizeof(MDGUID));
if (IsMappedFileOpenUnsafe(mapping))
return false;
char filename[NAME_MAX];
size_t filename_len = my_strlen(mapping.name);
assert(filename_len < NAME_MAX);
if (filename_len >= NAME_MAX)
return false;
memcpy(filename, mapping.name, filename_len);
filename[filename_len] = '\0';
bool filename_modified = HandleDeletedFileInMapping(filename);
int fd = sys_open(filename, O_RDONLY, 0);
if (fd < 0)
return false;
struct kernel_stat st;
if (sys_fstat(fd, &st) != 0) {
sys_close(fd);
return false;
}
#if defined(__x86_64)
#define sys_mmap2 sys_mmap
#endif
void* base = sys_mmap2(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
sys_close(fd);
if (base == MAP_FAILED)
return false;
bool success = FileID::ElfFileIdentifierFromMappedFile(base, identifier);
sys_munmap(base, st.st_size);
if (success && mapping_id != -1 && filename_modified) {
mappings_[mapping_id]->name[filename_len -
sizeof(kDeletedSuffix) + 1] = '\0';
}
return success;
}
void*
LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
char auxv_path[NAME_MAX];
BuildProcPath(auxv_path, pid, "auxv");
// If BuildProcPath errors out due to invalid input, we'll handle it when
// we try to sys_open the file.
// Find the AT_SYSINFO_EHDR entry for linux-gate.so
// See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
// information.
int fd = sys_open(auxv_path, O_RDONLY, 0);
if (fd < 0) {
return NULL;
}
elf_aux_entry one_aux_entry;
while (sys_read(fd,
&one_aux_entry,
sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
one_aux_entry.a_type != AT_NULL) {
if (one_aux_entry.a_type == AT_SYSINFO_EHDR) {
close(fd);
return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
}
}
close(fd);
return NULL;
}
bool
LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*>* result) const {
char maps_path[NAME_MAX];
BuildProcPath(maps_path, pid_, "maps");
// linux_gate_loc is the beginning of the kernel's mapping of
// linux-gate.so in the process. It doesn't actually show up in the
// maps list as a filename, so we use the aux vector to find it's
// load location and special case it's entry when creating the list
// of mappings.
const void* linux_gate_loc;
linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
const int fd = sys_open(maps_path, O_RDONLY, 0);
if (fd < 0)
return false;
LineReader* const line_reader = new(allocator_) LineReader(fd);
const char* line;
unsigned line_len;
while (line_reader->GetNextLine(&line, &line_len)) {
uintptr_t start_addr, end_addr, offset;
const char* i1 = my_read_hex_ptr(&start_addr, line);
if (*i1 == '-') {
const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
if (*i2 == ' ') {
const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
if (*i3 == ' ') {
const char* name = NULL;
// Only copy name if the name is a valid path name, or if
// it's the VDSO image.
if (((name = my_strchr(line, '/')) == NULL) &&
linux_gate_loc &&
reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
name = kLinuxGateLibraryName;
offset = 0;
}
// Merge adjacent mappings with the same name into one module,
// assuming they're a single library mapped by the dynamic linker
if (name && result->size()) {
MappingInfo* module = (*result)[result->size() - 1];
if ((start_addr == module->start_addr + module->size) &&
(my_strlen(name) == my_strlen(module->name)) &&
(my_strncmp(name, module->name, my_strlen(name)) == 0)) {
module->size = end_addr - module->start_addr;
line_reader->PopLine(line_len);
continue;
}
}
MappingInfo* const module = new(allocator_) MappingInfo;
memset(module, 0, sizeof(MappingInfo));
module->start_addr = start_addr;
module->size = end_addr - start_addr;
module->offset = offset;
if (name != NULL) {
const unsigned l = my_strlen(name);
if (l < sizeof(module->name))
memcpy(module->name, name, l);
}
result->push_back(module);
}
}
}
line_reader->PopLine(line_len);
}
sys_close(fd);
return result->size() > 0;
}
// Parse /proc/$pid/task to list all the threads of the process identified by
// pid.
bool LinuxDumper::EnumerateThreads(wasteful_vector<pid_t>* result) const {
char task_path[NAME_MAX];
BuildProcPath(task_path, pid_, "task");
const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
if (fd < 0)
return false;
DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
// The directory may contain duplicate entries which we filter by assuming
// that they are consecutive.
int last_tid = -1;
const char* dent_name;
while (dir_reader->GetNextEntry(&dent_name)) {
if (my_strcmp(dent_name, ".") &&
my_strcmp(dent_name, "..")) {
int tid = 0;
if (my_strtoui(&tid, dent_name) &&
last_tid != tid) {
last_tid = tid;
result->push_back(tid);
}
}
dir_reader->PopEntry();
}
sys_close(fd);
return true;
}
// Read thread info from /proc/$pid/status.
// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
// these members are set to -1. Returns true iff all three members are
// available.
bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) {
assert(info != NULL);
char status_path[NAME_MAX];
BuildProcPath(status_path, tid, "status");
const int fd = open(status_path, O_RDONLY);
if (fd < 0)
return false;
LineReader* const line_reader = new(allocator_) LineReader(fd);
const char* line;
unsigned line_len;
info->ppid = info->tgid = -1;
while (line_reader->GetNextLine(&line, &line_len)) {
if (my_strncmp("Tgid:\t", line, 6) == 0) {
my_strtoui(&info->tgid, line + 6);
} else if (my_strncmp("PPid:\t", line, 6) == 0) {
my_strtoui(&info->ppid, line + 6);
}
line_reader->PopLine(line_len);
}
if (info->ppid == -1 || info->tgid == -1)
return false;
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
return false;
}
#if !defined(__ANDROID__)
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
return false;
}
#endif
#if defined(__i386)
if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
return false;
#endif
#if defined(__i386) || defined(__x86_64)
for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
if (sys_ptrace(
PTRACE_PEEKUSER, tid,
reinterpret_cast<void*> (offsetof(struct user,
u_debugreg[0]) + i *
sizeof(debugreg_t)),
&info->dregs[i]) == -1) {
return false;
}
}
#endif
const uint8_t* stack_pointer;
#if defined(__i386)
memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
#elif defined(__x86_64)
memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
#elif defined(__ARM_EABI__)
memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
#else
#error "This code hasn't been ported to your platform yet."
#endif
return GetStackInfo(&info->stack, &info->stack_len,
(uintptr_t) stack_pointer);
}
// Get information about the stack, given the stack pointer. We don't try to
// walk the stack since we might not have all the information needed to do
// unwind. So we just grab, up to, 32k of stack.
bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
uintptr_t int_stack_pointer) {
// Move the stack pointer to the bottom of the page that it's in.
const uintptr_t page_size = getpagesize();
uint8_t* const stack_pointer =
reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
// The number of bytes of stack which we try to capture.
static const ptrdiff_t kStackToCapture = 32 * 1024;
const MappingInfo* mapping = FindMapping(stack_pointer);
if (!mapping)
return false;
const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
const ptrdiff_t distance_to_end =
static_cast<ptrdiff_t>(mapping->size) - offset;
*stack_len = distance_to_end > kStackToCapture ?
kStackToCapture : distance_to_end;
*stack = stack_pointer;
return true;
}
// static
void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length) {
unsigned long tmp = 55;
size_t done = 0;
static const size_t word_size = sizeof(tmp);
uint8_t* const local = (uint8_t*) dest;
uint8_t* const remote = (uint8_t*) src;
while (done < length) {
const size_t l = length - done > word_size ? word_size : length - done;
if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
tmp = 0;
}
memcpy(local + done, &tmp, l);
done += l;
}
}
// Find the mapping which the given memory address falls in.
const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
const uintptr_t addr = (uintptr_t) address;
for (size_t i = 0; i < mappings_.size(); ++i) {
const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
if (addr >= start && addr - start < mappings_[i]->size)
return mappings_[i];
}
return NULL;
}
bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
// Check for ' (deleted)' in |path|.
// |path| has to be at least as long as "/x (deleted)".
const size_t path_len = my_strlen(path);
if (path_len < kDeletedSuffixLen + 2)
return false;
if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
kDeletedSuffixLen) != 0) {
return false;
}
// Check |path| against the /proc/pid/exe 'symlink'.
char exe_link[NAME_MAX];
char new_path[NAME_MAX];
BuildProcPath(exe_link, pid_, "exe");
ssize_t new_path_len = sys_readlink(exe_link, new_path, NAME_MAX);
if (new_path_len <= 0 || new_path_len == NAME_MAX)
return false;
new_path[new_path_len] = '\0';
if (my_strcmp(path, new_path) != 0)
return false;
// Check to see if someone actually named their executable 'foo (deleted)'.
struct kernel_stat exe_stat;
struct kernel_stat new_path_stat;
if (sys_stat(exe_link, &exe_stat) == 0 &&
sys_stat(new_path, &new_path_stat) == 0 &&
exe_stat.st_dev == new_path_stat.st_dev &&
exe_stat.st_ino == new_path_stat.st_ino) {
return false;
}
memcpy(path, exe_link, NAME_MAX);
return true;
}
} // namespace google_breakpad

View File

@ -0,0 +1,192 @@
// Copyright (c) 2010, 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.
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
#include <elf.h>
#include <linux/limits.h>
#include <stdint.h>
#include <sys/types.h>
#if !defined(__ANDROID__)
#include <sys/user.h>
#endif
#include "common/memory.h"
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
#if defined(__i386) || defined(__x86_64)
typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
#endif
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
#if defined(__i386) || defined(__ARM_EABI__)
#if !defined(__ANDROID__)
typedef Elf32_auxv_t elf_aux_entry;
#else
// Android is missing this structure definition
typedef struct
{
uint32_t a_type; /* Entry type */
union
{
uint32_t a_val; /* Integer value */
} a_un;
} elf_aux_entry;
#if !defined(AT_SYSINFO_EHDR)
#define AT_SYSINFO_EHDR 33
#endif
#endif // __ANDROID__
#elif defined(__x86_64__)
typedef Elf64_auxv_t elf_aux_entry;
#endif
// When we find the VDSO mapping in the process's address space, this
// is the name we use for it when writing it to the minidump.
// This should always be less than NAME_MAX!
const char kLinuxGateLibraryName[] = "linux-gate.so";
// We produce one of these structures for each thread in the crashed process.
struct ThreadInfo {
pid_t tgid; // thread group id
pid_t ppid; // parent process
// Even on platforms where the stack grows down, the following will point to
// the smallest address in the stack.
const void* stack; // pointer to the stack area
size_t stack_len; // length of the stack to copy
#if defined(__i386) || defined(__x86_64)
user_regs_struct regs;
user_fpregs_struct fpregs;
static const unsigned kNumDebugRegisters = 8;
debugreg_t dregs[8];
#if defined(__i386)
user_fpxregs_struct fpxregs;
#endif // defined(__i386)
#elif defined(__ARM_EABI__)
// Mimicking how strace does this(see syscall.c, search for GETREGS)
#if defined(__ANDROID__)
struct pt_regs regs;
#else
struct user_regs regs;
struct user_fpregs fpregs;
#endif // __ANDROID__
#endif
};
// One of these is produced for each mapping in the process (i.e. line in
// /proc/$x/maps).
struct MappingInfo {
uintptr_t start_addr;
size_t size;
size_t offset; // offset into the backed file.
char name[NAME_MAX];
};
class LinuxDumper {
public:
explicit LinuxDumper(pid_t pid);
// Parse the data for |threads| and |mappings|.
bool Init();
// Suspend/resume all threads in the given process.
bool ThreadsSuspend();
bool ThreadsResume();
// Read information about the given thread. Returns true on success. One must
// have called |ThreadsSuspend| first.
bool ThreadInfoGet(pid_t tid, ThreadInfo* info);
// These are only valid after a call to |Init|.
const wasteful_vector<pid_t> &threads() { return threads_; }
const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
const MappingInfo* FindMapping(const void* address) const;
// Find a block of memory to take as the stack given the top of stack pointer.
// stack: (output) the lowest address in the memory area
// stack_len: (output) the length of the memory area
// stack_top: the current top of the stack
bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
PageAllocator* allocator() { return &allocator_; }
// memcpy from a remote process.
static void CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length);
// Builds a proc path for a certain pid for a node. path is a
// character array that is overwritten, and node is the final node
// without any slashes.
void BuildProcPath(char* path, pid_t pid, const char* node) const;
// Generate a File ID from the .text section of a mapped entry.
// mapping_id may be -1 if this is not a member of mappings_.
bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
int mapping_id,
uint8_t identifier[sizeof(MDGUID)]);
// Utility method to find the location of where the kernel has
// mapped linux-gate.so in memory(shows up in /proc/pid/maps as
// [vdso], but we can't guarantee that it's the only virtual dynamic
// shared object. Parsing the auxilary vector for AT_SYSINFO_EHDR
// is the safest way to go.)
void* FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const;
private:
bool EnumerateMappings(wasteful_vector<MappingInfo*>* result) const;
bool EnumerateThreads(wasteful_vector<pid_t>* result) const;
// For the case where a running program has been deleted, it'll show up in
// /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then
// see if '/path/to/program (deleted)' matches /proc/pid/exe and return
// /proc/pid/exe in |path| so ELF identifier generation works correctly. This
// also checks to see if '/path/to/program (deleted)' exists, so it does not
// get fooled by a poorly named binary.
// For programs that don't end with ' (deleted)', this is a no-op.
// This assumes |path| is a buffer with length NAME_MAX.
// Returns true if |path| is modified.
bool HandleDeletedFileInMapping(char* path) const;
const pid_t pid_;
mutable PageAllocator allocator_;
bool threads_suspended_;
wasteful_vector<pid_t> threads_; // the ids of all the threads
wasteful_vector<MappingInfo*> mappings_; // info from /proc/<pid>/maps
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_

View File

@ -0,0 +1,75 @@
/* Copyright (c) 2010, 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_extension_linux.h: A definition of exception codes for
* Linux
*
* (This is C99 source, please don't corrupt it with C++.)
*
* Author: Adam Langley
* Split into its own file: Markus Gutschke */
#ifndef SRC_CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_EXTENSION_LINUX_H_
#define SRC_CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_EXTENSION_LINUX_H_
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
#include "google_breakpad/common/minidump_format.h"
// These are additional minidump stream values which are specific to the linux
// breakpad implementation.
enum {
MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */
MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */
MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */
MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */
MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */
MD_LINUX_DSO_DEBUG = 0x4767000A /* DSO data */
};
typedef struct {
void* addr;
MDRVA name;
void* ld;
} MDRawLinkMap;
typedef struct {
u_int32_t version;
MDRVA map;
u_int32_t dso_count;
void* brk;
void* ldbase;
void* dynamic;
} MDRawDebug;
#endif // SRC_CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_EXTENSION_LINUX_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
// Copyright (c) 2009, 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.
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
#include <stdint.h>
#include <unistd.h>
#include <list>
#include <utility>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
// A list of <MappingInfo, GUID>
typedef std::pair<struct MappingInfo, u_int8_t[sizeof(MDGUID)]> MappingEntry;
typedef std::list<MappingEntry> MappingList;
// Write a minidump to the filesystem. This function does not malloc nor use
// libc functions which may. Thus, it can be used in contexts where the state
// of the heap may be corrupt.
// filename: the filename to write to. This is opened O_EXCL and fails if
// open fails.
// crashing_process: the pid of the crashing process. This must be trusted.
// blob: a blob of data from the crashing process. See exception_handler.h
// blob_size: the length of |blob|, in bytes
//
// Returns true iff successful.
bool WriteMinidump(const char* filename, pid_t crashing_process,
const void* blob, size_t blob_size);
// This overload also allows passing a list of known mappings.
bool WriteMinidump(const char* filename, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings);
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_

View File

@ -0,0 +1,97 @@
// Copyright (c) 2006, 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_file_writer-inl.h: Minidump file writer implementation.
//
// See minidump_file_writer.h for documentation.
#ifndef CLIENT_MINIDUMP_FILE_WRITER_INL_H__
#define CLIENT_MINIDUMP_FILE_WRITER_INL_H__
#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(minidump_size<MDType>::size());
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::Allocate(size_t additional) {
allocation_state_ = SINGLE_OBJECT;
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(minidump_size<MDType>::size() * count);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(size_t count,
size_t length) {
assert(count && length);
allocation_state_ = SINGLE_OBJECT_WITH_ARRAY;
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + count * length);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) {
assert(allocation_state_ == ARRAY);
return writer_->Copy(
static_cast<MDRVA>(position_ + index * minidump_size<MDType>::size()),
item, minidump_size<MDType>::size());
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index,
const void *src,
size_t length) {
assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY);
return writer_->Copy(
static_cast<MDRVA>(position_ + minidump_size<MDType>::size()
+ index * length),
src, length);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::Flush() {
return writer_->Copy(position_, &data_, minidump_size<MDType>::size());
}
} // namespace google_breakpad
#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__

View File

@ -0,0 +1,273 @@
// Copyright (c) 2006, 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_file_writer.cc: Minidump file writer implementation.
//
// See minidump_file_writer.h for documentation.
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "client/minidump_file_writer-inl.h"
#include "common/linux/linux_libc_support.h"
#include "common/string_conversion.h"
#if __linux__
#include "third_party/lss/linux_syscall_support.h"
#endif
namespace google_breakpad {
const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
MinidumpFileWriter::MinidumpFileWriter() : file_(-1), position_(0), size_(0) {
}
MinidumpFileWriter::~MinidumpFileWriter() {
Close();
}
bool MinidumpFileWriter::Open(const char *path) {
assert(file_ == -1);
#if __linux__
file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
#else
file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
#endif
return file_ != -1;
}
bool MinidumpFileWriter::Close() {
bool result = true;
if (file_ != -1) {
if (-1 == ftruncate(file_, position_)) {
return false;
}
#if __linux__
result = (sys_close(file_) == 0);
#else
result = (close(file_) == 0);
#endif
file_ = -1;
}
return result;
}
bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
unsigned int length,
TypedMDRVA<MDString> *mdstring) {
bool result = true;
if (sizeof(wchar_t) == sizeof(u_int16_t)) {
// Shortcut if wchar_t is the same size as MDString's buffer
result = mdstring->Copy(str, mdstring->get()->length);
} else {
u_int16_t out[2];
int out_idx = 0;
// Copy the string character by character
while (length && result) {
UTF32ToUTF16Char(*str, out);
if (!out[0])
return false;
// Process one character at a time
--length;
++str;
// Append the one or two UTF-16 characters. The first one will be non-
// zero, but the second one may be zero, depending on the conversion from
// UTF-32.
int out_count = out[1] ? 2 : 1;
size_t out_size = sizeof(u_int16_t) * out_count;
result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
out_idx += out_count;
}
}
return result;
}
bool MinidumpFileWriter::CopyStringToMDString(const char *str,
unsigned int length,
TypedMDRVA<MDString> *mdstring) {
bool result = true;
u_int16_t out[2];
int out_idx = 0;
// Copy the string character by character
while (length && result) {
int conversion_count = UTF8ToUTF16Char(str, length, out);
if (!conversion_count)
return false;
// Move the pointer along based on the nubmer of converted characters
length -= conversion_count;
str += conversion_count;
// Append the one or two UTF-16 characters
int out_count = out[1] ? 2 : 1;
size_t out_size = sizeof(u_int16_t) * out_count;
result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
out_idx += out_count;
}
return result;
}
template <typename CharType>
bool MinidumpFileWriter::WriteStringCore(const CharType *str,
unsigned int length,
MDLocationDescriptor *location) {
assert(str);
assert(location);
// Calculate the mdstring length by either limiting to |length| as passed in
// or by finding the location of the NULL character.
unsigned int mdstring_length = 0;
if (!length)
length = INT_MAX;
for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length)
;
// Allocate the string buffer
TypedMDRVA<MDString> mdstring(this);
if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(u_int16_t)))
return false;
// Set length excluding the NULL and copy the string
mdstring.get()->length =
static_cast<u_int32_t>(mdstring_length * sizeof(u_int16_t));
bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
// NULL terminate
if (result) {
u_int16_t ch = 0;
result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
if (result)
*location = mdstring.location();
}
return result;
}
bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
MDLocationDescriptor *location) {
return WriteStringCore(str, length, location);
}
bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
MDLocationDescriptor *location) {
return WriteStringCore(str, length, location);
}
bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
MDMemoryDescriptor *output) {
assert(src);
assert(output);
UntypedMDRVA mem(this);
if (!mem.Allocate(size))
return false;
if (!mem.Copy(src, mem.size()))
return false;
output->start_of_memory_range = reinterpret_cast<u_int64_t>(src);
output->memory = mem.location();
return true;
}
MDRVA MinidumpFileWriter::Allocate(size_t size) {
assert(size);
assert(file_ != -1);
size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
if (position_ + aligned_size > size_) {
size_t growth = aligned_size;
size_t minimal_growth = getpagesize();
// Ensure that the file grows by at least the size of a memory page
if (growth < minimal_growth)
growth = minimal_growth;
size_t new_size = size_ + growth;
if (ftruncate(file_, new_size) != 0)
return kInvalidMDRVA;
size_ = new_size;
}
MDRVA current_position = position_;
position_ += static_cast<MDRVA>(aligned_size);
return current_position;
}
bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
assert(src);
assert(size);
assert(file_ != -1);
// Ensure that the data will fit in the allocated space
if (static_cast<size_t>(size + position) > size_)
return false;
// Seek and write the data
#if __linux__
if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (sys_write(file_, src, size) == size) {
#else
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (write(file_, src, size) == size) {
#endif
return true;
}
}
return false;
}
bool UntypedMDRVA::Allocate(size_t size) {
assert(size_ == 0);
size_ = size;
position_ = writer_->Allocate(size_);
return position_ != MinidumpFileWriter::kInvalidMDRVA;
}
bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) {
assert(src);
assert(size);
assert(pos + size <= position_ + size_);
return writer_->Copy(pos, src, size);
}
} // namespace google_breakpad

View File

@ -0,0 +1,250 @@
// Copyright (c) 2006, 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_file_writer.h: Implements file-based minidump generation. It's
// intended to be used with the Google Breakpad open source crash handling
// project.
#ifndef CLIENT_MINIDUMP_FILE_WRITER_H__
#define CLIENT_MINIDUMP_FILE_WRITER_H__
#include <string>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
class UntypedMDRVA;
template<typename MDType> class TypedMDRVA;
// The user of this class can Open() a file and add minidump streams, data, and
// strings using the definitions in minidump_format.h. Since this class is
// expected to be used in a situation where the current process may be
// damaged, it will not allocate heap memory.
// Sample usage:
// MinidumpFileWriter writer;
// writer.Open("/tmp/minidump.dmp");
// TypedMDRVA<MDRawHeader> header(&writer_);
// header.Allocate();
// header->get()->signature = MD_HEADER_SIGNATURE;
// :
// writer.Close();
class MinidumpFileWriter {
public:
// Invalid MDRVA (Minidump Relative Virtual Address)
// returned on failed allocation
static const MDRVA kInvalidMDRVA;
MinidumpFileWriter();
~MinidumpFileWriter();
// Open |path| as the destination of the minidump data. Any existing file
// will be overwritten.
// Return true on success, or false on failure
bool Open(const char *path);
// Close the current file
// Return true on success, or false on failure
bool Close();
// Copy the contents of |str| to a MDString and write it to the file.
// |str| is expected to be either UTF-16 or UTF-32 depending on the size
// of wchar_t.
// Maximum |length| of characters to copy from |str|, or specify 0 to use the
// entire NULL terminated string. Copying will stop at the first NULL.
// |location| the allocated location
// Return true on success, or false on failure
bool WriteString(const wchar_t *str, unsigned int length,
MDLocationDescriptor *location);
// Same as above, except with |str| as a UTF-8 string
bool WriteString(const char *str, unsigned int length,
MDLocationDescriptor *location);
// Write |size| bytes starting at |src| into the current position.
// Return true on success and set |output| to position, or false on failure
bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output);
// Copies |size| bytes from |src| to |position|
// Return true on success, or false on failure
bool Copy(MDRVA position, const void *src, ssize_t size);
// Return the current position for writing to the minidump
inline MDRVA position() const { return position_; }
private:
friend class UntypedMDRVA;
// Allocates an area of |size| bytes.
// Returns the position of the allocation, or kInvalidMDRVA if it was
// unable to allocate the bytes.
MDRVA Allocate(size_t size);
// The file descriptor for the output file
int file_;
// Current position in buffer
MDRVA position_;
// Current allocated size
size_t size_;
// Copy |length| characters from |str| to |mdstring|. These are distinct
// because the underlying MDString is a UTF-16 based string. The wchar_t
// variant may need to create a MDString that has more characters than the
// source |str|, whereas the UTF-8 variant may coalesce characters to form
// a single UTF-16 character.
bool CopyStringToMDString(const wchar_t *str, unsigned int length,
TypedMDRVA<MDString> *mdstring);
bool CopyStringToMDString(const char *str, unsigned int length,
TypedMDRVA<MDString> *mdstring);
// The common templated code for writing a string
template <typename CharType>
bool WriteStringCore(const CharType *str, unsigned int length,
MDLocationDescriptor *location);
};
// Represents an untyped allocated chunk
class UntypedMDRVA {
public:
explicit UntypedMDRVA(MinidumpFileWriter *writer)
: writer_(writer),
position_(writer->position()),
size_(0) {}
// Allocates |size| bytes. Must not call more than once.
// Return true on success, or false on failure
bool Allocate(size_t size);
// Returns the current position or kInvalidMDRVA if allocation failed
inline MDRVA position() const { return position_; }
// Number of bytes allocated
inline size_t size() const { return size_; }
// Return size and position
inline MDLocationDescriptor location() const {
MDLocationDescriptor location = { static_cast<int>(size_), position_ };
return location;
}
// Copy |size| bytes starting at |src| into the minidump at |position|
// Return true on success, or false on failure
bool Copy(MDRVA position, const void *src, size_t size);
// Copy |size| bytes from |src| to the current position
inline bool Copy(const void *src, size_t size) {
return Copy(position_, src, size);
}
protected:
// Writer we associate with
MinidumpFileWriter *writer_;
// Position of the start of the data
MDRVA position_;
// Allocated size
size_t size_;
};
// Represents a Minidump object chunk. Additional memory can be allocated at
// the end of the object as a:
// - single allocation
// - Array of MDType objects
// - A MDType object followed by an array
template<typename MDType>
class TypedMDRVA : public UntypedMDRVA {
public:
// Constructs an unallocated MDRVA
explicit TypedMDRVA(MinidumpFileWriter *writer)
: UntypedMDRVA(writer),
data_(),
allocation_state_(UNALLOCATED) {}
inline ~TypedMDRVA() {
// Ensure that the data_ object is written out
if (allocation_state_ != ARRAY)
Flush();
}
// Address of object data_ of MDType. This is not declared const as the
// typical usage will be to access the underlying |data_| object as to
// alter its contents.
MDType *get() { return &data_; }
// Allocates minidump_size<MDType>::size() bytes.
// Must not call more than once.
// Return true on success, or false on failure
bool Allocate();
// 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);
// Allocate an array of |count| elements of MDType.
// Must not call more than once.
// Return true on success, or false on failure
bool AllocateArray(size_t count);
// Allocate an array of |count| elements of |size| after object of MDType
// Must not call more than once.
// Return true on success, or false on failure
bool AllocateObjectAndArray(size_t count, size_t size);
// Copy |item| to |index|
// Must have been allocated using AllocateArray().
// Return true on success, or false on failure
bool CopyIndex(unsigned int index, MDType *item);
// Copy |size| bytes starting at |str| to |index|
// Must have been allocated using AllocateObjectAndArray().
// Return true on success, or false on failure
bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size);
// Write data_
bool Flush();
private:
enum AllocationState {
UNALLOCATED = 0,
SINGLE_OBJECT,
ARRAY,
SINGLE_OBJECT_WITH_ARRAY
};
MDType data_;
AllocationState allocation_state_;
};
} // namespace google_breakpad
#endif // CLIENT_MINIDUMP_FILE_WRITER_H__

View File

@ -0,0 +1,533 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "convert_UTF.h"
#ifdef CVTUTF_DEBUG
#include <stdio.h>
#endif
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (UTF32)0xD800
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
#define false 0
#define true 1
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
if (target >= targetEnd) {
result = targetExhausted; break;
}
ch = *source++;
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_LEGAL_UTF32) {
if (flags == strictConversion) {
result = sourceIllegal;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
--source; /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF32* target = *targetStart;
UTF32 ch, ch2;
while (source < sourceEnd) {
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
if (target >= targetEnd) {
source = oldSource; /* Back up source pointer! */
result = targetExhausted; break;
}
*target++ = ch;
}
*sourceStart = source;
*targetStart = target;
#ifdef CVTUTF_DEBUG
if (result == sourceIllegal) {
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
fflush(stderr);
}
#endif
return result;
}
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if (target > targetEnd) {
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static Boolean isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xED: if (a > 0x9F) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
if (*source > 0xF4) return false;
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
return false;
}
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_UTF16) {
if (flags == strictConversion) {
result = sourceIllegal;
source -= (extraBytesToRead+1); /* return to the start */
break; /* Bail out; shouldn't continue */
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
ch = *source++;
if (flags == strictConversion ) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/*
* Figure out how many bytes the result will require. Turn any
* illegally large UTF32 things (> Plane 17) into replacement chars.
*/
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
target += bytesToWrite;
if (target > targetEnd) {
--source; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF32* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up the source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_LEGAL_UTF32) {
/*
* UTF-16 surrogate values are illegal in UTF-32, and anything
* over Plane 17 (> 0x10FFFF) is illegal.
*/
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = ch;
}
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
result = sourceIllegal;
*target++ = UNI_REPLACEMENT_CHAR;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */

View File

@ -0,0 +1,143 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
typedef unsigned long UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
#endif
/* --------------------------------------------------------------------- */

View File

@ -0,0 +1,47 @@
// Copyright (c) 2010 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.
#ifndef COMMON_LINUX_EINTR_WRAPPER_H_
#define COMMON_LINUX_EINTR_WRAPPER_H_
#include <errno.h>
// This provides a wrapper around system calls which may be interrupted by a
// signal and return EINTR. See man 7 signal.
//
#define HANDLE_EINTR(x) ({ \
typeof(x) __eintr_result__; \
do { \
__eintr_result__ = x; \
} while (__eintr_result__ == -1 && errno == EINTR); \
__eintr_result__;\
})
#endif // ifndef COMMON_LINUX_EINTR_WRAPPER_H_

View File

@ -0,0 +1,216 @@
// Copyright (c) 2006, 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.
//
// file_id.cc: Return a unique identifier for a file
//
// See file_id.h for documentation
//
#include "common/linux/file_id.h"
#include <arpa/inet.h>
#include <assert.h>
#include <elf.h>
#include <fcntl.h>
#if defined(__ANDROID__)
#include "client/linux/android_link.h"
#else
#include <link.h>
#endif
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
FileID::FileID(const char* path) {
strncpy(path_, path, sizeof(path_));
}
struct ElfClass32 {
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Shdr Shdr;
static const int kClass = ELFCLASS32;
};
struct ElfClass64 {
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Shdr Shdr;
static const int kClass = ELFCLASS64;
};
// These three functions are also used inside the crashed process, so be safe
// and use the syscall/libc wrappers instead of direct syscalls or libc.
template<typename ElfClass>
static void FindElfClassTextSection(const char *elf_base,
const void **text_start,
int *text_size) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
assert(elf_base);
assert(text_start);
assert(text_size);
assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
const char* text_section_name = ".text";
int name_len = my_strlen(text_section_name);
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
const Shdr* sections =
reinterpret_cast<const Shdr*>(elf_base + elf_header->e_shoff);
const Shdr* string_section = sections + elf_header->e_shstrndx;
const Shdr* text_section = NULL;
for (int i = 0; i < elf_header->e_shnum; ++i) {
if (sections[i].sh_type == SHT_PROGBITS) {
const char* section_name = (char*)(elf_base +
string_section->sh_offset +
sections[i].sh_name);
if (!my_strncmp(section_name, text_section_name, name_len)) {
text_section = &sections[i];
break;
}
}
}
if (text_section != NULL && text_section->sh_size > 0) {
*text_start = elf_base + text_section->sh_offset;
*text_size = text_section->sh_size;
}
}
static bool FindElfTextSection(const void *elf_mapped_base,
const void **text_start,
int *text_size) {
assert(elf_mapped_base);
assert(text_start);
assert(text_size);
const char* elf_base =
static_cast<const char*>(elf_mapped_base);
const ElfW(Ehdr)* elf_header =
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
return false;
if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) {
FindElfClassTextSection<ElfClass32>(elf_base, text_start, text_size);
} else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) {
FindElfClassTextSection<ElfClass64>(elf_base, text_start, text_size);
} else {
return false;
}
return true;
}
// static
bool FileID::ElfFileIdentifierFromMappedFile(void* base,
uint8_t identifier[kMDGUIDSize])
{
const void* text_section = NULL;
int text_size = 0;
bool success = false;
if (FindElfTextSection(base, &text_section, &text_size) && (text_size > 0)) {
my_memset(identifier, 0, kMDGUIDSize);
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section);
const uint8_t* ptr_end = ptr + std::min(text_size, 4096);
while (ptr < ptr_end) {
for (unsigned i = 0; i < kMDGUIDSize; i++)
identifier[i] ^= ptr[i];
ptr += kMDGUIDSize;
}
success = true;
}
return success;
}
bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
int fd = open(path_, O_RDONLY);
if (fd < 0)
return false;
struct stat st;
if (fstat(fd, &st) != 0) {
close(fd);
return false;
}
void* base = mmap(NULL, st.st_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
close(fd);
if (base == MAP_FAILED)
return false;
bool success = ElfFileIdentifierFromMappedFile(base, identifier);
munmap(base, st.st_size);
return success;
}
// static
void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
char* buffer, int buffer_length) {
uint8_t identifier_swapped[kMDGUIDSize];
// Endian-ness swap to match dump processor expectation.
memcpy(identifier_swapped, identifier, kMDGUIDSize);
uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
*data1 = htonl(*data1);
uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
*data2 = htons(*data2);
uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
*data3 = htons(*data3);
int buffer_idx = 0;
for (unsigned int idx = 0;
(buffer_idx < buffer_length) && (idx < kMDGUIDSize);
++idx) {
int hi = (identifier_swapped[idx] >> 4) & 0x0F;
int lo = (identifier_swapped[idx]) & 0x0F;
if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
buffer[buffer_idx++] = '-';
buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
}
// NULL terminate
buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
}
} // namespace google_breakpad

View File

@ -0,0 +1,76 @@
// Copyright (c) 2006, 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.
//
// file_id.h: Return a unique identifier for a file
//
#ifndef COMMON_LINUX_FILE_ID_H__
#define COMMON_LINUX_FILE_ID_H__
#include <limits.h>
#include "common/linux/guid_creator.h"
namespace google_breakpad {
static const size_t kMDGUIDSize = sizeof(MDGUID);
class FileID {
public:
explicit FileID(const char* path);
~FileID() {}
// Load the identifier for the elf file path specified in the constructor into
// |identifier|. Return false if the identifier could not be created for the
// file.
// The current implementation will XOR the first 4096 bytes of the
// .text section to generate an identifier.
bool ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]);
// Load the identifier for the elf file mapped into memory at |base| into
// |identifier|. Return false if the identifier could not be created for the
// file.
static bool ElfFileIdentifierFromMappedFile(void* base,
uint8_t identifier[kMDGUIDSize]);
// Convert the |identifier| data to a NULL terminated string. The string will
// be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
// The |buffer| should be at least 37 bytes long to receive all of the data
// and termination. Shorter buffers will contain truncated data.
static void ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
char* buffer, int buffer_length);
private:
// Storage for the path specified
char path_[PATH_MAX];
};
} // namespace google_breakpad
#endif // COMMON_LINUX_FILE_ID_H__

View File

@ -0,0 +1,96 @@
// Copyright (c) 2006, 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.
#include "common/linux/guid_creator.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
//
// GUIDGenerator
//
// This class is used to generate random GUID.
// Currently use random number to generate a GUID since Linux has
// no native GUID generator. This should be OK since we don't expect
// crash to happen very offen.
//
class GUIDGenerator {
public:
GUIDGenerator() {
srandom(time(NULL));
}
static u_int32_t BytesToUInt32(const u_int8_t bytes[]) {
return ((u_int32_t) bytes[0]
| ((u_int32_t) bytes[1] << 8)
| ((u_int32_t) bytes[2] << 16)
| ((u_int32_t) bytes[3] << 24));
}
static void UInt32ToBytes(u_int8_t bytes[], u_int32_t n) {
bytes[0] = n & 0xff;
bytes[1] = (n >> 8) & 0xff;
bytes[2] = (n >> 16) & 0xff;
bytes[3] = (n >> 24) & 0xff;
}
bool CreateGUID(GUID *guid) const {
guid->data1 = random();
guid->data2 = (u_int16_t)(random());
guid->data3 = (u_int16_t)(random());
UInt32ToBytes(&guid->data4[0], random());
UInt32ToBytes(&guid->data4[4], random());
return true;
}
};
// Guid generator.
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) {
// Should allow more space the the max length of GUID.
assert(buf_len > kGUIDStringLength);
int num = snprintf(buf, buf_len, kGUIDFormatString,
guid->data1, guid->data2, guid->data3,
GUIDGenerator::BytesToUInt32(&(guid->data4[0])),
GUIDGenerator::BytesToUInt32(&(guid->data4[4])));
if (num != kGUIDStringLength)
return false;
buf[num] = '\0';
return true;
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2006, 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.
#ifndef COMMON_LINUX_GUID_CREATOR_H__
#define COMMON_LINUX_GUID_CREATOR_H__
#include "google_breakpad/common/minidump_format.h"
typedef MDGUID GUID;
// Format string for parsing GUID.
#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x"
// Length of GUID string. Don't count the ending '\0'.
#define kGUIDStringLength 36
// Create a guid.
bool CreateGUID(GUID *guid);
// Get the string from guid.
bool GUIDToString(const GUID *guid, char *buf, int buf_len);
#endif

View File

@ -0,0 +1,178 @@
// Copyright (c) 2009, 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.
// This header provides replacements for libc functions that we need. We if
// call the libc functions directly we risk crashing in the dynamic linker as
// it tries to resolve uncached PLT entries.
#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
#include <stdint.h>
#include <limits.h>
#include <sys/types.h>
extern "C" {
static inline size_t
my_strlen(const char* s) {
size_t len = 0;
while (*s++) len++;
return len;
}
static inline int
my_strcmp(const char* a, const char* b) {
for (;;) {
if (*a < *b)
return -1;
else if (*a > *b)
return 1;
else if (*a == 0)
return 0;
a++;
b++;
}
}
static inline int
my_strncmp(const char* a, const char* b, size_t len) {
for (size_t i = 0; i < len; ++i) {
if (*a < *b)
return -1;
else if (*a > *b)
return 1;
else if (*a == 0)
return 0;
a++;
b++;
}
return 0;
}
// Parse a non-negative integer.
// result: (output) the resulting non-negative integer
// s: a NUL terminated string
// Return true iff successful.
static inline bool
my_strtoui(int* result, const char* s) {
if (*s == 0)
return false;
int r = 0;
for (;; s++) {
if (*s == 0)
break;
const int old_r = r;
r *= 10;
if (*s < '0' || *s > '9')
return false;
r += *s - '0';
if (r < old_r)
return false;
}
*result = r;
return true;
}
// Return the length of the given, non-negative integer when expressed in base
// 10.
static inline unsigned
my_int_len(int i) {
if (!i)
return 1;
int len = 0;
while (i) {
len++;
i /= 10;
}
return len;
}
// Convert a non-negative integer to a string
// output: (output) the resulting string is written here. This buffer must be
// large enough to hold the resulting string. Call |my_int_len| to get the
// required length.
// i: the non-negative integer to serialise.
// i_len: the length of the integer in base 10 (see |my_int_len|).
static inline void
my_itos(char* output, int i, unsigned i_len) {
for (unsigned index = i_len; index; --index, i /= 10)
output[index - 1] = '0' + (i % 10);
}
static inline const char*
my_strchr(const char* haystack, char needle) {
while (*haystack && *haystack != needle)
haystack++;
if (*haystack == needle)
return haystack;
return (const char*) 0;
}
// Read a hex value
// result: (output) the resulting value
// s: a string
// Returns a pointer to the first invalid charactor.
static inline const char*
my_read_hex_ptr(uintptr_t* result, const char* s) {
uintptr_t r = 0;
for (;; ++s) {
if (*s >= '0' && *s <= '9') {
r <<= 4;
r += *s - '0';
} else if (*s >= 'a' && *s <= 'f') {
r <<= 4;
r += (*s - 'a') + 10;
} else if (*s >= 'A' && *s <= 'F') {
r <<= 4;
r += (*s - 'A') + 10;
} else {
break;
}
}
*result = r;
return s;
}
static inline void
my_memset(void* ip, char c, size_t len) {
char* p = (char *) ip;
while (len--)
*p++ = c;
}
} // extern "C"
#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_

246
3rdparty/google-breakpad/common/md5.c vendored Normal file
View File

@ -0,0 +1,246 @@
/*
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include <string.h>
#include "common/md5.h"
#ifndef WORDS_BIGENDIAN
#define byteReverse(buf, len) /* Nothing */
#else
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
u32 t;
do {
t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(u32 *) buf = t;
buf += 4;
} while (--longs);
}
#endif
static void MD5Transform(u32 buf[4], u32 const in[16]);
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
u32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((u32 *) ctx->in)[14] = ctx->bits[0];
((u32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(u32 buf[4], u32 const in[16])
{
register u32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

31
3rdparty/google-breakpad/common/md5.h vendored Normal file
View File

@ -0,0 +1,31 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: liuli@google.com (Liu Li)
#ifndef COMMON_MD5_H__
#define COMMON_MD5_H__
#include <stdint.h>
typedef uint32_t u32;
typedef uint8_t u8;
struct MD5Context {
u32 buf[4];
u32 bits[2];
u8 in[64];
};
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void MD5Init(struct MD5Context *ctx);
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
#ifdef __cplusplus
}
#endif
#endif // COMMON_MD5_H__

206
3rdparty/google-breakpad/common/memory.h vendored Normal file
View File

@ -0,0 +1,206 @@
// Copyright (c) 2009, 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.
#ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_
#define GOOGLE_BREAKPAD_COMMON_MEMORY_H_
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#ifdef __APPLE__
#define sys_mmap mmap
#define sys_mmap2 mmap
#define sys_munmap munmap
#define MAP_ANONYMOUS MAP_ANON
#else
#include "third_party/lss/linux_syscall_support.h"
#endif
namespace google_breakpad {
// This is very simple allocator which fetches pages from the kernel directly.
// Thus, it can be used even when the heap may be corrupted.
//
// There is no free operation. The pages are only freed when the object is
// destroyed.
class PageAllocator {
public:
PageAllocator()
: page_size_(getpagesize()),
last_(NULL),
current_page_(NULL),
page_offset_(0) {
}
~PageAllocator() {
FreeAll();
}
void *Alloc(unsigned bytes) {
if (!bytes)
return NULL;
if (current_page_ && page_size_ - page_offset_ >= bytes) {
uint8_t *const ret = current_page_ + page_offset_;
page_offset_ += bytes;
if (page_offset_ == page_size_) {
page_offset_ = 0;
current_page_ = NULL;
}
return ret;
}
const unsigned pages =
(bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
uint8_t *const ret = GetNPages(pages);
if (!ret)
return NULL;
page_offset_ = (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % page_size_;
current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL;
return ret + sizeof(PageHeader);
}
private:
uint8_t *GetNPages(unsigned num_pages) {
#ifdef __x86_64
void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else
void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#endif
if (a == MAP_FAILED)
return NULL;
struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
header->next = last_;
header->num_pages = num_pages;
last_ = header;
return reinterpret_cast<uint8_t*>(a);
}
void FreeAll() {
PageHeader *next;
for (PageHeader *cur = last_; cur; cur = next) {
next = cur->next;
sys_munmap(cur, cur->num_pages * page_size_);
}
}
struct PageHeader {
PageHeader *next; // pointer to the start of the next set of pages.
unsigned num_pages; // the number of pages in this set.
};
const unsigned page_size_;
PageHeader *last_;
uint8_t *current_page_;
unsigned page_offset_;
};
// A wasteful vector is like a normal std::vector, except that it's very much
// simplier and it allocates memory from a PageAllocator. It's wasteful
// because, when resizing, it always allocates a whole new array since the
// PageAllocator doesn't support realloc.
template<class T>
class wasteful_vector {
public:
wasteful_vector(PageAllocator *allocator, unsigned size_hint = 16)
: allocator_(allocator),
a_((T*) allocator->Alloc(sizeof(T) * size_hint)),
allocated_(size_hint),
used_(0) {
}
void push_back(const T& new_element) {
if (used_ == allocated_)
Realloc(allocated_ * 2);
a_[used_++] = new_element;
}
size_t size() const {
return used_;
}
void resize(unsigned sz, T c = T()) {
// No need to test "sz >= 0", as "sz" is unsigned.
if (sz <= used_) {
used_ = sz;
} else {
unsigned a = allocated_;
if (sz > a) {
while (sz > a) {
a *= 2;
}
Realloc(a);
}
while (sz > used_) {
a_[used_++] = c;
}
}
}
T& operator[](size_t index) {
return a_[index];
}
const T& operator[](size_t index) const {
return a_[index];
}
private:
void Realloc(unsigned new_size) {
T *new_array =
reinterpret_cast<T*>(allocator_->Alloc(sizeof(T) * new_size));
memcpy(new_array, a_, used_ * sizeof(T));
a_ = new_array;
allocated_ = new_size;
}
PageAllocator *const allocator_;
T *a_; // pointer to an array of |allocated_| elements.
unsigned allocated_; // size of |a_|, in elements.
unsigned used_; // number of used slots in |a_|.
};
} // namespace google_breakpad
inline void* operator new(size_t nbytes,
google_breakpad::PageAllocator& allocator) {
return allocator.Alloc(nbytes);
}
#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_

View File

@ -0,0 +1,154 @@
// Copyright (c) 2006, 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.
#include "common/convert_UTF.h"
#include "processor/scoped_ptr.h"
#include "common/string_conversion.h"
#include <string.h>
namespace google_breakpad {
using std::string;
using std::vector;
void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
size_t source_length = strlen(in);
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
const UTF8 *source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->empty();
out->insert(out->begin(), source_length, 0);
u_int16_t *target_ptr = &(*out)[0];
u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
// Resize to be the size of the # of converted characters + NULL
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]) {
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
const UTF8 *source_end_ptr = source_ptr + sizeof(char);
u_int16_t *target_ptr = out;
u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
out[0] = out[1] = 0;
// Process one character at a time
while (1) {
ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result == conversionOK)
return static_cast<int>(source_ptr - reinterpret_cast<const UTF8 *>(in));
// Add another character to the input stream and try again
source_ptr = reinterpret_cast<const UTF8 *>(in);
++source_end_ptr;
if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length)
break;
}
return 0;
}
void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out) {
size_t source_length = wcslen(in);
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
const UTF32 *source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->empty();
out->insert(out->begin(), source_length, 0);
u_int16_t *target_ptr = &(*out)[0];
u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
// Resize to be the size of the # of converted characters + NULL
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]) {
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in);
const UTF32 *source_end_ptr = source_ptr + 1;
u_int16_t *target_ptr = out;
u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
out[0] = out[1] = 0;
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result != conversionOK) {
out[0] = out[1] = 0;
}
}
static inline u_int16_t Swap(u_int16_t value) {
return (value >> 8) | (value << 8);
}
string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap) {
const UTF16 *source_ptr = &in[0];
scoped_ptr<u_int16_t> source_buffer;
// If we're to swap, we need to make a local copy and swap each byte pair
if (swap) {
int idx = 0;
source_buffer.reset(new u_int16_t[in.size()]);
UTF16 *source_buffer_ptr = source_buffer.get();
for (vector<u_int16_t>::const_iterator it = in.begin();
it != in.end(); ++it, ++idx)
source_buffer_ptr[idx] = Swap(*it);
source_ptr = source_buffer.get();
}
// The maximum expansion would be 4x the size of the input string.
const UTF16 *source_end_ptr = source_ptr + in.size();
size_t target_capacity = in.size() * 4;
scoped_array<UTF8> target_buffer(new UTF8[target_capacity]);
UTF8 *target_ptr = target_buffer.get();
UTF8 *target_end_ptr = target_ptr + target_capacity;
ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result == conversionOK) {
const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get());
return targetPtr;
}
return "";
}
} // namespace google_breakpad

View File

@ -0,0 +1,66 @@
// Copyright (c) 2006, 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.
// string_conversion.h: Conversion between different UTF-8/16/32 encodings.
#ifndef COMMON_STRING_CONVERSION_H__
#define COMMON_STRING_CONVERSION_H__
#include <string>
#include <vector>
#include "google_breakpad/common/breakpad_types.h"
namespace google_breakpad {
using std::vector;
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
void UTF8ToUTF16(const char *in, vector<u_int16_t> *out);
// Convert at least one character (up to a maximum of |in_length|) from |in|
// to UTF-16 into |out|. Return the number of characters consumed from |in|.
// Any unused characters in |out| will be initialized to 0. No memory will
// be allocated by this routine.
int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]);
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out);
// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be
// initialized to 0. No memory will be allocated by this routine.
void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]);
// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting.
std::string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap);
} // namespace google_breakpad
#endif // COMMON_STRING_CONVERSION_H__

View File

@ -0,0 +1,83 @@
/* Copyright (c) 2006, 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. */
/* breakpad_types.h: Precise-width types
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file ensures that types u_intN_t are defined for N = 8, 16, 32, and
* 64. Types of precise widths are crucial to the task of writing data
* structures on one platform and reading them on another.
*
* Author: Mark Mentovai */
#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
#ifndef _WIN32
#include <sys/types.h>
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif /* __STDC_FORMAT_MACROS */
#include <inttypes.h>
#if defined(__SUNPRO_CC) || (defined(__GNUC__) && defined(__sun__))
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
typedef uint32_t u_int32_t;
typedef uint64_t u_int64_t;
#endif
#else /* !_WIN32 */
#include <WTypes.h>
typedef unsigned __int8 u_int8_t;
typedef unsigned __int16 u_int16_t;
typedef unsigned __int32 u_int32_t;
typedef unsigned __int64 u_int64_t;
#endif /* !_WIN32 */
typedef struct {
u_int64_t high;
u_int64_t low;
} u_int128_t;
typedef u_int64_t breakpad_time_t;
/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to
* llx, which is the format string for "long long" - this is a 64-bit
* integral type on many systems. */
#ifndef PRIx64
#define PRIx64 "llx"
#endif /* !PRIx64 */
#endif /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */

View File

@ -0,0 +1,231 @@
/* Copyright (c) 2006, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file contains the necessary definitions to read minidump files
* produced on amd64. These files may be read on any platform provided
* that the alignments of these structures on the processing system are
* identical to the alignments of these structures on the producing system.
* For this reason, precise-sized types are used. The structures defined
* by this file have been laid out to minimize alignment problems by ensuring
* ensuring that all members are aligned on their natural boundaries. In
* In some cases, tail-padding may be significant when different ABIs specify
* different tail-padding behaviors. To avoid problems when reading or
* 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
* for other CPUs and other operating systems.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably in terms of interoperability with minidumps
* produced by DbgHelp on Windows, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file. DbgHelp
* on Windows is assumed to be the reference implementation; this file
* seeks to provide a cross-platform compatible implementation. To avoid
* collisions with the types and values defined and used by DbgHelp in the
* event that this implementation is used on Windows, each type and value
* defined here is given a new name, beginning with "MD". Names of the
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
* Author: Mark Mentovai
* Change to split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
/*
* AMD64 support, see WINNT.H
*/
typedef struct {
u_int16_t control_word;
u_int16_t status_word;
u_int8_t tag_word;
u_int8_t reserved1;
u_int16_t error_opcode;
u_int32_t error_offset;
u_int16_t error_selector;
u_int16_t reserved2;
u_int32_t data_offset;
u_int16_t data_selector;
u_int16_t reserved3;
u_int32_t mx_csr;
u_int32_t mx_csr_mask;
u_int128_t float_registers[8];
u_int128_t xmm_registers[16];
u_int8_t reserved4[96];
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
#define MD_CONTEXT_AMD64_VR_COUNT 26
typedef struct {
/*
* Register parameter home addresses.
*/
u_int64_t p1_home;
u_int64_t p2_home;
u_int64_t p3_home;
u_int64_t p4_home;
u_int64_t p5_home;
u_int64_t p6_home;
/* The next field determines the layout of the structure, and which parts
* of it are populated */
u_int32_t context_flags;
u_int32_t mx_csr;
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
u_int16_t cs;
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
u_int16_t ds;
u_int16_t es;
u_int16_t fs;
u_int16_t gs;
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
u_int16_t ss;
u_int32_t eflags;
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
u_int64_t dr0;
u_int64_t dr1;
u_int64_t dr2;
u_int64_t dr3;
u_int64_t dr6;
u_int64_t dr7;
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
u_int64_t rax;
u_int64_t rcx;
u_int64_t rdx;
u_int64_t rbx;
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
u_int64_t rsp;
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
u_int64_t rbp;
u_int64_t rsi;
u_int64_t rdi;
u_int64_t r8;
u_int64_t r9;
u_int64_t r10;
u_int64_t r11;
u_int64_t r12;
u_int64_t r13;
u_int64_t r14;
u_int64_t r15;
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
u_int64_t rip;
/* The next set of registers are included with
* MD_CONTEXT_AMD64_FLOATING_POINT
*/
union {
MDXmmSaveArea32AMD64 flt_save;
struct {
u_int128_t header[2];
u_int128_t legacy[8];
u_int128_t xmm0;
u_int128_t xmm1;
u_int128_t xmm2;
u_int128_t xmm3;
u_int128_t xmm4;
u_int128_t xmm5;
u_int128_t xmm6;
u_int128_t xmm7;
u_int128_t xmm8;
u_int128_t xmm9;
u_int128_t xmm10;
u_int128_t xmm11;
u_int128_t xmm12;
u_int128_t xmm13;
u_int128_t xmm14;
u_int128_t xmm15;
} sse_registers;
};
u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
u_int64_t vector_control;
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
u_int64_t debug_control;
u_int64_t last_branch_to_rip;
u_int64_t last_branch_from_rip;
u_int64_t last_exception_to_rip;
u_int64_t last_exception_from_rip;
} MDRawContextAMD64; /* CONTEXT */
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
* context stored in the structure. The high 26 bits identify the CPU, the
* low 6 bits identify the type of context saved. */
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001)
/* CONTEXT_CONTROL */
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002)
/* CONTEXT_INTEGER */
#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004)
/* CONTEXT_SEGMENTS */
#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008)
/* CONTEXT_FLOATING_POINT */
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
/* CONTEXT_DEBUG_REGISTERS */
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
* I think it really means CONTEXT_FLOATING_POINT.
*/
#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \
MD_CONTEXT_AMD64_INTEGER | \
MD_CONTEXT_AMD64_FLOATING_POINT)
/* CONTEXT_FULL */
#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \
MD_CONTEXT_AMD64_SEGMENTS | \
MD_CONTEXT_X86_DEBUG_REGISTERS)
/* CONTEXT_ALL */
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */

View File

@ -0,0 +1,140 @@
/* Copyright (c) 2009, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file contains the necessary definitions to read minidump files
* produced on ARM. These files may be read on any platform provided
* that the alignments of these structures on the processing system are
* identical to the alignments of these structures on the producing system.
* For this reason, precise-sized types are used. The structures defined
* by this file have been laid out to minimize alignment problems by
* ensuring that all members are aligned on their natural boundaries.
* In some cases, tail-padding may be significant when different ABIs specify
* different tail-padding behaviors. To avoid problems when reading or
* 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.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file.
*
* Author: Julian Seward
*/
/*
* ARM support
*/
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__
#define MD_FLOATINGSAVEAREA_ARM_FPR_COUNT 32
#define MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT 8
/*
* Note that these structures *do not* map directly to the CONTEXT
* structure defined in WinNT.h in the Windows Mobile SDK. That structure
* does not accomodate VFPv3, and I'm unsure if it was ever used in the
* wild anyway, as Windows CE only seems to produce "cedumps" which
* are not exactly minidumps.
*/
typedef struct {
u_int64_t fpscr; /* FPU status register */
/* 32 64-bit floating point registers, d0 .. d31. */
u_int64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT];
/* Miscellaneous control words */
u_int32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT];
} MDFloatingSaveAreaARM;
#define MD_CONTEXT_ARM_GPR_COUNT 16
typedef struct {
/* The next field determines the layout of the structure, and which parts
* of it are populated
*/
u_int32_t context_flags;
/* 16 32-bit integer registers, r0 .. r15
* Note the following fixed uses:
* r13 is the stack pointer
* r14 is the link register
* r15 is the program counter
*/
u_int32_t iregs[MD_CONTEXT_ARM_GPR_COUNT];
/* CPSR (flags, basically): 32 bits:
bit 31 - N (negative)
bit 30 - Z (zero)
bit 29 - C (carry)
bit 28 - V (overflow)
bit 27 - Q (saturation flag, sticky)
All other fields -- ignore */
u_int32_t cpsr;
/* The next field is included with MD_CONTEXT_ARM_FLOATING_POINT */
MDFloatingSaveAreaARM float_save;
} MDRawContextARM;
/* Indices into iregs for registers with a dedicated or conventional
* purpose.
*/
enum MDARMRegisterNumbers {
MD_CONTEXT_ARM_REG_FP = 11,
MD_CONTEXT_ARM_REG_SP = 13,
MD_CONTEXT_ARM_REG_LR = 14,
MD_CONTEXT_ARM_REG_PC = 15
};
/* For (MDRawContextARM).context_flags. These values indicate the type of
* context stored in the structure. */
#define MD_CONTEXT_ARM_INTEGER (MD_CONTEXT_ARM | 0x00000002)
#define MD_CONTEXT_ARM_FLOATING_POINT (MD_CONTEXT_ARM | 0x00000004)
#define MD_CONTEXT_ARM_FULL (MD_CONTEXT_ARM_INTEGER | \
MD_CONTEXT_ARM_FLOATING_POINT)
#define MD_CONTEXT_ARM_ALL (MD_CONTEXT_ARM_INTEGER | \
MD_CONTEXT_ARM_FLOATING_POINT)
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ */

View File

@ -0,0 +1,163 @@
/* Copyright (c) 2006, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file contains the necessary definitions to read minidump files
* produced on ppc. These files may be read on any platform provided
* that the alignments of these structures on the processing system are
* identical to the alignments of these structures on the producing system.
* For this reason, precise-sized types are used. The structures defined
* by this file have been laid out to minimize alignment problems by ensuring
* ensuring that all members are aligned on their natural boundaries. In
* In some cases, tail-padding may be significant when different ABIs specify
* different tail-padding behaviors. To avoid problems when reading or
* 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
* for other CPUs and other operating systems.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably in terms of interoperability with minidumps
* produced by DbgHelp on Windows, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file. DbgHelp
* on Windows is assumed to be the reference implementation; this file
* seeks to provide a cross-platform compatible implementation. To avoid
* collisions with the types and values defined and used by DbgHelp in the
* event that this implementation is used on Windows, each type and value
* defined here is given a new name, beginning with "MD". Names of the
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
* Author: Mark Mentovai
* Change to split into its own file: Neal Sidhwaney */
/*
* Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X'
* mach/ppc/_types.h
*/
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32
typedef struct {
/* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used
* here for precise sizing. */
u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
u_int32_t fpscr_pad;
u_int32_t fpscr; /* Status/control */
} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */
#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32
typedef struct {
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
* exposes them as four 32-bit quantities. */
u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
u_int128_t save_vscr; /* Status/control */
u_int32_t save_pad5[4];
u_int32_t save_vrvalid; /* Identifies which vector registers are saved */
u_int32_t save_pad6[7];
} MDVectorSaveAreaPPC; /* ppc_vector_state */
#define MD_CONTEXT_PPC_GPR_COUNT 32
/* Use the same 32-bit alignment when accessing this structure from 64-bit code
* as is used natively in 32-bit code. #pragma pack is a MSVC extension
* supported by gcc. */
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#pragma pack(4)
#else
#pragma pack(push, 4)
#endif
typedef struct {
/* context_flags is not present in ppc_thread_state, but it aids
* identification of MDRawContextPPC among other raw context types,
* and it guarantees alignment when we get to float_save. */
u_int32_t context_flags;
u_int32_t srr0; /* Machine status save/restore: stores pc
* (instruction) */
u_int32_t srr1; /* Machine status save/restore: stores msr
* (ps, program/machine state) */
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
* used for brevity. */
u_int32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
u_int32_t cr; /* Condition */
u_int32_t xer; /* Integer (fiXed-point) exception */
u_int32_t lr; /* Link */
u_int32_t ctr; /* Count */
u_int32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
u_int32_t vrsave; /* Vector save */
/* float_save and vector_save aren't present in ppc_thread_state, but
* are represented in separate structures that still define a thread's
* context. */
MDFloatingSaveAreaPPC float_save;
MDVectorSaveAreaPPC vector_save;
} MDRawContextPPC; /* Based on ppc_thread_state */
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#pragma pack(0)
#else
#pragma pack(pop)
#endif
/* For (MDRawContextPPC).context_flags. These values indicate the type of
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
* CPUs. */
#define MD_CONTEXT_PPC 0x20000000
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
MD_CONTEXT_PPC_FLOATING_POINT | \
MD_CONTEXT_PPC_VECTOR)
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */

View File

@ -0,0 +1,129 @@
/* Copyright (c) 2008, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file contains the necessary definitions to read minidump files
* produced on ppc64. These files may be read on any platform provided
* that the alignments of these structures on the processing system are
* identical to the alignments of these structures on the producing system.
* For this reason, precise-sized types are used. The structures defined
* by this file have been laid out to minimize alignment problems by ensuring
* ensuring that all members are aligned on their natural boundaries. In
* In some cases, tail-padding may be significant when different ABIs specify
* different tail-padding behaviors. To avoid problems when reading or
* 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
* for other CPUs and other operating systems.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably in terms of interoperability with minidumps
* produced by DbgHelp on Windows, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file. DbgHelp
* on Windows is assumed to be the reference implementation; this file
* seeks to provide a cross-platform compatible implementation. To avoid
* collisions with the types and values defined and used by DbgHelp in the
* event that this implementation is used on Windows, each type and value
* defined here is given a new name, beginning with "MD". Names of the
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
* Author: Neal Sidhwaney */
/*
* Breakpad minidump extension for PPC64 support. Based on Darwin/Mac OS X'
* mach/ppc/_types.h
*/
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
#include "minidump_cpu_ppc.h"
// these types are the same in ppc64 & ppc
typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64;
typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64;
#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT
typedef struct {
/* context_flags is not present in ppc_thread_state, but it aids
* identification of MDRawContextPPC among other raw context types,
* and it guarantees alignment when we get to float_save. */
u_int64_t context_flags;
u_int64_t srr0; /* Machine status save/restore: stores pc
* (instruction) */
u_int64_t srr1; /* Machine status save/restore: stores msr
* (ps, program/machine state) */
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
* used for brevity. */
u_int64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
u_int64_t cr; /* Condition */
u_int64_t xer; /* Integer (fiXed-point) exception */
u_int64_t lr; /* Link */
u_int64_t ctr; /* Count */
u_int64_t vrsave; /* Vector save */
/* float_save and vector_save aren't present in ppc_thread_state, but
* are represented in separate structures that still define a thread's
* context. */
MDFloatingSaveAreaPPC float_save;
MDVectorSaveAreaPPC vector_save;
} MDRawContextPPC64; /* Based on ppc_thread_state */
/* For (MDRawContextPPC).context_flags. These values indicate the type of
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
* CPUs. */
#define MD_CONTEXT_PPC 0x20000000
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
MD_CONTEXT_PPC_FLOATING_POINT | \
MD_CONTEXT_PPC_VECTOR)
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */

View File

@ -0,0 +1,158 @@
/* Copyright (c) 2006, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file contains the necessary definitions to read minidump files
* produced on sparc. These files may be read on any platform provided
* that the alignments of these structures on the processing system are
* identical to the alignments of these structures on the producing system.
* For this reason, precise-sized types are used. The structures defined
* by this file have been laid out to minimize alignment problems by ensuring
* ensuring that all members are aligned on their natural boundaries. In
* In some cases, tail-padding may be significant when different ABIs specify
* different tail-padding behaviors. To avoid problems when reading or
* 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
* for other CPUs and other operating systems.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably in terms of interoperability with minidumps
* produced by DbgHelp on Windows, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file. DbgHelp
* on Windows is assumed to be the reference implementation; this file
* seeks to provide a cross-platform compatible implementation. To avoid
* collisions with the types and values defined and used by DbgHelp in the
* event that this implementation is used on Windows, each type and value
* defined here is given a new name, beginning with "MD". Names of the
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
* Author: Mark Mentovai
* Change to split into its own file: Neal Sidhwaney */
/*
* SPARC support, see (solaris)sys/procfs_isa.h also
*/
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32
typedef struct {
/* FPU floating point regs */
u_int64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
u_int64_t filler;
u_int64_t fsr; /* FPU status register */
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
#define MD_CONTEXT_SPARC_GPR_COUNT 32
typedef struct {
/* The next field determines the layout of the structure, and which parts
* of it are populated
*/
u_int32_t context_flags;
u_int32_t flag_pad;
/*
* General register access (SPARC).
* Don't confuse definitions here with definitions in <sys/regset.h>.
* Registers are 32 bits for ILP32, 64 bits for LP64.
* SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit
*/
/* 32 Integer working registers */
/* g_r[0-7] global registers(g0-g7)
* g_r[8-15] out registers(o0-o7)
* g_r[16-23] local registers(l0-l7)
* g_r[24-31] in registers(i0-i7)
*/
u_int64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
/* several control registers */
/* Processor State register(PSR) for SPARC V7/V8
* Condition Code register (CCR) for SPARC V9
*/
u_int64_t ccr;
u_int64_t pc; /* Program Counter register (PC) */
u_int64_t npc; /* Next Program Counter register (nPC) */
u_int64_t y; /* Y register (Y) */
/* Address Space Identifier register (ASI) for SPARC V9
* WIM for SPARC V7/V8
*/
u_int64_t asi;
/* Floating-Point Registers State register (FPRS) for SPARC V9
* TBR for for SPARC V7/V8
*/
u_int64_t fprs;
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
MDFloatingSaveAreaSPARC float_save;
} MDRawContextSPARC; /* CONTEXT_SPARC */
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
* CPUs. */
#define MD_CONTEXT_SPARC 0x10000000
#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001)
#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002)
#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)
#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008)
#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \
MD_CONTEXT_SPARC_INTEGER)
#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \
MD_CONTEXT_SAPARC_FLOATING_POINT | \
MD_CONTEXT_SAPARC_EXTRA)
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */

View File

@ -0,0 +1,172 @@
/* Copyright (c) 2006, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* This file contains the necessary definitions to read minidump files
* produced on x86. These files may be read on any platform provided
* that the alignments of these structures on the processing system are
* identical to the alignments of these structures on the producing system.
* For this reason, precise-sized types are used. The structures defined
* by this file have been laid out to minimize alignment problems by ensuring
* ensuring that all members are aligned on their natural boundaries. In
* In some cases, tail-padding may be significant when different ABIs specify
* different tail-padding behaviors. To avoid problems when reading or
* 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
* for other CPUs and other operating systems.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably in terms of interoperability with minidumps
* produced by DbgHelp on Windows, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file. DbgHelp
* on Windows is assumed to be the reference implementation; this file
* seeks to provide a cross-platform compatible implementation. To avoid
* collisions with the types and values defined and used by DbgHelp in the
* event that this implementation is used on Windows, each type and value
* defined here is given a new name, beginning with "MD". Names of the
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
* Author: Mark Mentovai */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80
/* SIZE_OF_80387_REGISTERS */
typedef struct {
u_int32_t control_word;
u_int32_t status_word;
u_int32_t tag_word;
u_int32_t error_offset;
u_int32_t error_selector;
u_int32_t data_offset;
u_int32_t data_selector;
/* register_area contains eight 80-bit (x87 "long double") quantities for
* floating-point registers %st0 (%mm0) through %st7 (%mm7). */
u_int8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
u_int32_t cr0_npx_state;
} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */
#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512
/* MAXIMUM_SUPPORTED_EXTENSION */
typedef struct {
/* The next field determines the layout of the structure, and which parts
* of it are populated */
u_int32_t context_flags;
/* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */
u_int32_t dr0;
u_int32_t dr1;
u_int32_t dr2;
u_int32_t dr3;
u_int32_t dr6;
u_int32_t dr7;
/* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */
MDFloatingSaveAreaX86 float_save;
/* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */
u_int32_t gs;
u_int32_t fs;
u_int32_t es;
u_int32_t ds;
/* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */
u_int32_t edi;
u_int32_t esi;
u_int32_t ebx;
u_int32_t edx;
u_int32_t ecx;
u_int32_t eax;
/* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */
u_int32_t ebp;
u_int32_t eip;
u_int32_t cs; /* WinNT.h says "must be sanitized" */
u_int32_t eflags; /* WinNT.h says "must be sanitized" */
u_int32_t esp;
u_int32_t ss;
/* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
* It contains vector (MMX/SSE) registers. It it laid out in the
* format used by the fxsave and fsrstor instructions, so it includes
* a copy of the x87 floating-point registers as well. See FXSAVE in
* "Intel Architecture Software Developer's Manual, Volume 2." */
u_int8_t extended_registers[
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];
} MDRawContextX86; /* CONTEXT */
/* For (MDRawContextX86).context_flags. These values indicate the type of
* context stored in the structure. The high 26 bits identify the CPU, the
* low 6 bits identify the type of context saved. */
#define MD_CONTEXT_X86 0x00010000
/* CONTEXT_i386, CONTEXT_i486: identifies CPU */
#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001)
/* CONTEXT_CONTROL */
#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002)
/* CONTEXT_INTEGER */
#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004)
/* CONTEXT_SEGMENTS */
#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008)
/* CONTEXT_FLOATING_POINT */
#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010)
/* CONTEXT_DEBUG_REGISTERS */
#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)
/* CONTEXT_EXTENDED_REGISTERS */
#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \
MD_CONTEXT_X86_INTEGER | \
MD_CONTEXT_X86_SEGMENTS)
/* CONTEXT_FULL */
#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \
MD_CONTEXT_X86_FLOATING_POINT | \
MD_CONTEXT_X86_DEBUG_REGISTERS | \
MD_CONTEXT_X86_EXTENDED_REGISTERS)
/* CONTEXT_ALL */
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */

View File

@ -0,0 +1,85 @@
/* Copyright (c) 2006, 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_exception_linux.h: A definition of exception codes for
* Linux
*
* (This is C99 source, please don't corrupt it with C++.)
*
* Author: Mark Mentovai
* Split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
/* 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;
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */

View File

@ -0,0 +1,193 @@
/* Copyright (c) 2006, 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_exception_mac.h: A definition of exception codes for Mac
* OS X
*
* (This is C99 source, please don't corrupt it with C++.)
*
* Author: Mark Mentovai
* Split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X
* support. Based on Darwin/Mac OS X' mach/exception_types.h. This is
* what Mac OS X calls an "exception", not a "code". */
typedef enum {
/* Exception code. The high 16 bits of exception_code contains one of
* these values. */
MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */
/* EXC_BAD_ACCESS */
MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */
/* EXC_BAD_INSTRUCTION */
MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */
/* EXC_ARITHMETIC */
MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */
/* EXC_EMULATION */
MD_EXCEPTION_MAC_SOFTWARE = 5,
/* EXC_SOFTWARE */
MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */
/* EXC_BREAKPOINT */
MD_EXCEPTION_MAC_SYSCALL = 7,
/* EXC_SYSCALL */
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
/* EXC_MACH_SYSCALL */
MD_EXCEPTION_MAC_RPC_ALERT = 9
/* EXC_RPC_ALERT */
} MDExceptionMac;
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
* support. Based on Darwin/Mac OS X' mach/ppc/exception.h and
* mach/i386/exception.h. This is what Mac OS X calls a "code". */
typedef enum {
/* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values
* from mach/kern_return.h. */
MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1,
/* KERN_INVALID_ADDRESS */
MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2,
/* KERN_PROTECTION_FAILURE */
MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8,
/* KERN_NO_ACCESS */
MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9,
/* KERN_MEMORY_FAILURE */
MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10,
/* KERN_MEMORY_ERROR */
/* With MD_EXCEPTION_SOFTWARE */
MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */
MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */
MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
/* EXC_PPC_VM_PROT_READ */
MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102,
/* EXC_PPC_BADSPACE */
MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103,
/* EXC_PPC_UNALIGNED */
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */
MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1,
/* EXC_PPC_INVALID_SYSCALL */
MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2,
/* EXC_PPC_UNIPL_INST */
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3,
/* EXC_PPC_PRIVINST */
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4,
/* EXC_PPC_PRIVREG */
MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5,
/* EXC_PPC_TRACE */
MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6,
/* EXC_PPC_PERFMON */
/* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */
MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1,
/* EXC_PPC_OVERFLOW */
MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2,
/* EXC_PPC_ZERO_DIVIDE */
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3,
/* EXC_FLT_INEXACT */
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4,
/* EXC_PPC_FLT_ZERO_DIVIDE */
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5,
/* EXC_PPC_FLT_UNDERFLOW */
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6,
/* EXC_PPC_FLT_OVERFLOW */
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7,
/* EXC_PPC_FLT_NOT_A_NUMBER */
/* With MD_EXCEPTION_MAC_EMULATION on ppc */
MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8,
/* EXC_PPC_NOEMULATION */
MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9,
/* EXC_PPC_ALTIVECASSIST */
/* With MD_EXCEPTION_MAC_SOFTWARE on ppc */
MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */
MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */
/* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */
MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt
* values below. */
MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */
/* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */
MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */
MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */
MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */
MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */
MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */
MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */
MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */
MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */
/* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */
MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */
MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw
* x86 interrupt codes. Most of these are mapped to other Mach
* exceptions and codes, are handled, or should not occur in user space.
* A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */
/* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */
/* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */
/* EXC_I386_NMIFLT = 2: should not occur in user space */
/* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */
/* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */
/* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */
/* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */
/* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */
/* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */
/* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */
MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10,
/* EXC_INVTSSFLT */
MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11,
/* EXC_SEGNPFLT */
MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12,
/* EXC_STKFLT */
MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13,
/* 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
/* EXC_ALIGNFLT (for vector operations) */
/* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */
/* EXC_I386_ENDPERR = 33: should not occur */
} MDExceptionCodeMac;
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */

View File

@ -0,0 +1,94 @@
/* Copyright (c) 2006, 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_exception_solaris.h: A definition of exception codes for
* Solaris
*
* (This is C99 source, please don't corrupt it with C++.)
*
* Author: Mark Mentovai
* Split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h
*/
typedef enum {
MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */
MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */
MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */
MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */
MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */
MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */
MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */
MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */
MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */
MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */
MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */
MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */
MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */
MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */
MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */
MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */
MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */
MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */
MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */
MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */
MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */
MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */
MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */
MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occurred */
MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */
MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */
MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */
MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */
MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */
MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */
MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */
MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */
MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */
MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */
MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */
MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */
MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */
MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */
MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */
MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */
MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */
MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */
MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */
} MDExceptionCodeSolaris;
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */

View File

@ -0,0 +1,116 @@
/* Copyright (c) 2006, 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_exception_win32.h: Definitions of exception codes for
* Win32 platform
*
* (This is C99 source, please don't corrupt it with C++.)
*
* Author: Mark Mentovai
* Split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
/* For (MDException).exception_code. These values come from WinBase.h
* and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h,
* they are STATUS_ in WinNT.h). */
typedef enum {
MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005,
/* DBG_CONTROL_C */
MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001,
/* EXCEPTION_GUARD_PAGE */
MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002,
/* EXCEPTION_DATATYPE_MISALIGNMENT */
MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003,
/* EXCEPTION_BREAKPOINT */
MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004,
/* EXCEPTION_SINGLE_STEP */
MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005,
/* EXCEPTION_ACCESS_VIOLATION */
MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006,
/* EXCEPTION_IN_PAGE_ERROR */
MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008,
/* EXCEPTION_INVALID_HANDLE */
MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d,
/* EXCEPTION_ILLEGAL_INSTRUCTION */
MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025,
/* EXCEPTION_NONCONTINUABLE_EXCEPTION */
MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026,
/* EXCEPTION_INVALID_DISPOSITION */
MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c,
/* EXCEPTION_BOUNDS_EXCEEDED */
MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d,
/* EXCEPTION_FLT_DENORMAL_OPERAND */
MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e,
/* EXCEPTION_FLT_DIVIDE_BY_ZERO */
MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f,
/* EXCEPTION_FLT_INEXACT_RESULT */
MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090,
/* EXCEPTION_FLT_INVALID_OPERATION */
MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091,
/* EXCEPTION_FLT_OVERFLOW */
MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092,
/* EXCEPTION_FLT_STACK_CHECK */
MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093,
/* EXCEPTION_FLT_UNDERFLOW */
MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094,
/* EXCEPTION_INT_DIVIDE_BY_ZERO */
MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095,
/* EXCEPTION_INT_OVERFLOW */
MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096,
/* EXCEPTION_PRIV_INSTRUCTION */
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd,
/* EXCEPTION_STACK_OVERFLOW */
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194,
/* EXCEPTION_POSSIBLE_DEADLOCK */
MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409,
/* STATUS_STACK_BUFFER_OVERRUN */
MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374,
/* STATUS_HEAP_CORRUPTION */
MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363
/* Per http://support.microsoft.com/kb/185294,
generated by Visual C++ compiler */
} MDExceptionCodeWin;
// These constants are defined in the MSDN documentation of
// the EXCEPTION_RECORD structure.
typedef enum {
MD_ACCESS_VIOLATION_WIN_READ = 0,
MD_ACCESS_VIOLATION_WIN_WRITE = 1,
MD_ACCESS_VIOLATION_WIN_EXEC = 8
} MDAccessViolationTypeWin;
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */

View File

@ -0,0 +1,792 @@
/* Copyright (c) 2006, 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_format.h: A cross-platform reimplementation of minidump-related
* portions of DbgHelp.h from the Windows Platform SDK.
*
* (This is C99 source, please don't corrupt it with C++.)
*
* 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
* for other CPUs and other operating systems.
*
* Because precise data type sizes are crucial for this implementation to
* function properly and portably in terms of interoperability with minidumps
* produced by DbgHelp on Windows, a set of primitive types with known sizes
* are used as the basis of each structure defined by this file. DbgHelp
* on Windows is assumed to be the reference implementation; this file
* seeks to provide a cross-platform compatible implementation. To avoid
* collisions with the types and values defined and used by DbgHelp in the
* event that this implementation is used on Windows, each type and value
* defined here is given a new name, beginning with "MD". Names of the
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
* Author: Mark Mentovai */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
#if defined(_MSC_VER)
/* Disable "zero-sized array in struct/union" warnings when compiling in
* MSVC. DbgHelp.h does this too. */
#pragma warning(push)
#pragma warning(disable:4200)
#endif /* _MSC_VER */
/*
* guiddef.h
*/
typedef struct {
u_int32_t data1;
u_int16_t data2;
u_int16_t data3;
u_int8_t data4[8];
} MDGUID; /* GUID */
/*
* WinNT.h
*/
/* Non-x86 CPU identifiers found in the high 26 bits of
* (MDRawContext*).context_flags. These aren't used by Breakpad, but are
* defined here for reference, to avoid assigning values that conflict
* (although some values already conflict). */
#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */
#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */
/* Additional values from winnt.h in the Windows CE 5.0 SDK: */
#define MD_CONTEXT_SHX 0x000000c0 /* CONTEXT_SH4 (Super-H, includes SH3) */
#define MD_CONTEXT_ARM 0x00000040 /* CONTEXT_ARM (0x40 bit set in SHx?) */
#define MD_CONTEXT_MIPS 0x00010000 /* CONTEXT_R4000 (same value as x86?) */
#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */
#define MD_CONTEXT_CPU_MASK 0xffffffc0
/* This is a base type for MDRawContextX86 and MDRawContextPPC. This
* structure should never be allocated directly. The actual structure type
* can be determined by examining the context_flags field. */
typedef struct {
u_int32_t context_flags;
} MDRawContextBase;
#include "minidump_cpu_amd64.h"
#include "minidump_cpu_arm.h"
#include "minidump_cpu_ppc.h"
#include "minidump_cpu_ppc64.h"
#include "minidump_cpu_sparc.h"
#include "minidump_cpu_x86.h"
/*
* WinVer.h
*/
typedef struct {
u_int32_t signature;
u_int32_t struct_version;
u_int32_t file_version_hi;
u_int32_t file_version_lo;
u_int32_t product_version_hi;
u_int32_t product_version_lo;
u_int32_t file_flags_mask; /* Identifies valid bits in fileFlags */
u_int32_t file_flags;
u_int32_t file_os;
u_int32_t file_type;
u_int32_t file_subtype;
u_int32_t file_date_hi;
u_int32_t file_date_lo;
} MDVSFixedFileInfo; /* VS_FIXEDFILEINFO */
/* For (MDVSFixedFileInfo).signature */
#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd
/* VS_FFI_SIGNATURE */
/* For (MDVSFixedFileInfo).version */
#define MD_VSFIXEDFILEINFO_VERSION 0x00010000
/* VS_FFI_STRUCVERSION */
/* For (MDVSFixedFileInfo).file_flags_mask and
* (MDVSFixedFileInfo).file_flags */
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG 0x00000001
/* VS_FF_DEBUG */
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE 0x00000002
/* VS_FF_PRERELEASE */
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED 0x00000004
/* VS_FF_PATCHED */
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008
/* VS_FF_PRIVATEBUILD */
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010
/* VS_FF_INFOINFERRED */
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020
/* VS_FF_SPECIALBUILD */
/* For (MDVSFixedFileInfo).file_os: high 16 bits */
#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN 0 /* VOS_UNKNOWN */
#define MD_VSFIXEDFILEINFO_FILE_OS_DOS (1 << 16) /* VOS_DOS */
#define MD_VSFIXEDFILEINFO_FILE_OS_OS216 (2 << 16) /* VOS_OS216 */
#define MD_VSFIXEDFILEINFO_FILE_OS_OS232 (3 << 16) /* VOS_OS232 */
#define MD_VSFIXEDFILEINFO_FILE_OS_NT (4 << 16) /* VOS_NT */
#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE (5 << 16) /* VOS_WINCE */
/* Low 16 bits */
#define MD_VSFIXEDFILEINFO_FILE_OS__BASE 0 /* VOS__BASE */
#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1 /* VOS__WINDOWS16 */
#define MD_VSFIXEDFILEINFO_FILE_OS__PM16 2 /* VOS__PM16 */
#define MD_VSFIXEDFILEINFO_FILE_OS__PM32 3 /* VOS__PM32 */
#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4 /* VOS__WINDOWS32 */
/* For (MDVSFixedFileInfo).file_type */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN 0 /* VFT_UNKNOWN */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP 1 /* VFT_APP */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL 2 /* VFT_DLL */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV 3 /* VFT_DLL */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT 4 /* VFT_FONT */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD 5 /* VFT_VXD */
#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7 /* VFT_STATIC_LIB */
/* For (MDVSFixedFileInfo).file_subtype */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN 0
/* VFT2_UNKNOWN */
/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER 1
/* VFT2_DRV_PRINTER */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD 2
/* VFT2_DRV_KEYBOARD */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE 3
/* VFT2_DRV_LANGUAGE */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY 4
/* VFT2_DRV_DISPLAY */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE 5
/* VFT2_DRV_MOUSE */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK 6
/* VFT2_DRV_NETWORK */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM 7
/* VFT2_DRV_SYSTEM */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE 8
/* VFT2_DRV_INSTALLABLE */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND 9
/* VFT2_DRV_SOUND */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM 10
/* VFT2_DRV_COMM */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD 11
/* VFT2_DRV_INPUTMETHOD */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12
/* VFT2_DRV_VERSIONED_PRINTER */
/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER 1
/* VFT2_FONT_RASTER */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR 2
/* VFT2_FONT_VECTOR */
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE 3
/* VFT2_FONT_TRUETYPE */
/*
* DbgHelp.h
*/
/* An MDRVA is an offset into the minidump file. The beginning of the
* MDRawHeader is at offset 0. */
typedef u_int32_t MDRVA; /* RVA */
typedef struct {
u_int32_t data_size;
MDRVA rva;
} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */
typedef struct {
/* The base address of the memory range on the host that produced the
* minidump. */
u_int64_t start_of_memory_range;
MDLocationDescriptor memory;
} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */
typedef struct {
u_int32_t signature;
u_int32_t version;
u_int32_t stream_count;
MDRVA stream_directory_rva; /* A |stream_count|-sized array of
* MDRawDirectory structures. */
u_int32_t checksum; /* Can be 0. In fact, that's all that's
* been found in minidump files. */
u_int32_t time_date_stamp; /* time_t */
u_int64_t flags;
} MDRawHeader; /* MINIDUMP_HEADER */
/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the
* low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION. Per the
* documentation, the high 16 bits are implementation-specific. */
#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */
/* MINIDUMP_SIGNATURE */
#define MD_HEADER_VERSION 0x0000a793 /* 42899 */
/* MINIDUMP_VERSION */
/* For (MDRawHeader).flags: */
typedef enum {
/* MD_NORMAL is the standard type of minidump. It includes full
* streams for the thread list, module list, exception, system info,
* and miscellaneous info. A memory list stream is also present,
* pointing to the same stack memory contained in the thread list,
* as well as a 256-byte region around the instruction address that
* was executing when the exception occurred. Stack memory is from
* 4 bytes below a thread's stack pointer up to the top of the
* memory region encompassing the stack. */
MD_NORMAL = 0x00000000,
MD_WITH_DATA_SEGS = 0x00000001,
MD_WITH_FULL_MEMORY = 0x00000002,
MD_WITH_HANDLE_DATA = 0x00000004,
MD_FILTER_MEMORY = 0x00000008,
MD_SCAN_MEMORY = 0x00000010,
MD_WITH_UNLOADED_MODULES = 0x00000020,
MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040,
MD_FILTER_MODULE_PATHS = 0x00000080,
MD_WITH_PROCESS_THREAD_DATA = 0x00000100,
MD_WITH_PRIVATE_READ_WRITE_MEMORY = 0x00000200,
MD_WITHOUT_OPTIONAL_DATA = 0x00000400,
MD_WITH_FULL_MEMORY_INFO = 0x00000800,
MD_WITH_THREAD_INFO = 0x00001000,
MD_WITH_CODE_SEGS = 0x00002000,
MD_WITHOUT_AUXILLIARY_SEGS = 0x00004000,
MD_WITH_FULL_AUXILLIARY_STATE = 0x00008000,
MD_WITH_PRIVATE_WRITE_COPY_MEMORY = 0x00010000,
MD_IGNORE_INACCESSIBLE_MEMORY = 0x00020000,
MD_WITH_TOKEN_INFORMATION = 0x00040000
} MDType; /* MINIDUMP_TYPE */
typedef struct {
u_int32_t stream_type;
MDLocationDescriptor location;
} MDRawDirectory; /* MINIDUMP_DIRECTORY */
/* For (MDRawDirectory).stream_type */
typedef enum {
MD_UNUSED_STREAM = 0,
MD_RESERVED_STREAM_0 = 1,
MD_RESERVED_STREAM_1 = 2,
MD_THREAD_LIST_STREAM = 3, /* MDRawThreadList */
MD_MODULE_LIST_STREAM = 4, /* MDRawModuleList */
MD_MEMORY_LIST_STREAM = 5, /* MDRawMemoryList */
MD_EXCEPTION_STREAM = 6, /* MDRawExceptionStream */
MD_SYSTEM_INFO_STREAM = 7, /* MDRawSystemInfo */
MD_THREAD_EX_LIST_STREAM = 8,
MD_MEMORY_64_LIST_STREAM = 9,
MD_COMMENT_STREAM_A = 10,
MD_COMMENT_STREAM_W = 11,
MD_HANDLE_DATA_STREAM = 12,
MD_FUNCTION_TABLE_STREAM = 13,
MD_UNLOADED_MODULE_LIST_STREAM = 14,
MD_MISC_INFO_STREAM = 15, /* MDRawMiscInfo */
MD_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */
MD_THREAD_INFO_LIST_STREAM = 17,
MD_HANDLE_OPERATION_LIST_STREAM = 18,
MD_LAST_RESERVED_STREAM = 0x0000ffff,
/* Breakpad extension types. 0x4767 = "Gg" */
MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */
MD_ASSERTION_INFO_STREAM = 0x47670002 /* MDRawAssertionInfo */
} MDStreamType; /* MINIDUMP_STREAM_TYPE */
typedef struct {
u_int32_t length; /* Length of buffer in bytes (not characters),
* excluding 0-terminator */
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;
u_int32_t suspend_count;
u_int32_t priority_class;
u_int32_t priority;
u_int64_t teb; /* Thread environment block */
MDMemoryDescriptor stack;
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
} MDRawThread; /* MINIDUMP_THREAD */
typedef struct {
u_int32_t number_of_threads;
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;
u_int32_t size_of_image;
u_int32_t checksum; /* 0 if unknown */
u_int32_t time_date_stamp; /* time_t */
MDRVA module_name_rva; /* MDString, pathname or filename */
MDVSFixedFileInfo version_info;
/* The next field stores a CodeView record and is populated when a module's
* debug information resides in a PDB file. It identifies the PDB file. */
MDLocationDescriptor cv_record;
/* The next field is populated when a module's debug information resides
* in a DBG file. It identifies the DBG file. This field is effectively
* obsolete with modules built by recent toolchains. */
MDLocationDescriptor misc_record;
/* Alignment problem: reserved0 and reserved1 are defined by the platform
* SDK as 64-bit quantities. However, that results in a structure whose
* alignment is unpredictable on different CPUs and ABIs. If the ABI
* specifies full alignment of 64-bit quantities in structures (as ppc
* does), there will be padding between miscRecord and reserved0. If
* 64-bit quantities can be aligned on 32-bit boundaries (as on x86),
* this padding will not exist. (Note that the structure up to this point
* contains 1 64-bit member followed by 21 32-bit members.)
* As a workaround, reserved0 and reserved1 are instead defined here as
* four 32-bit quantities. This should be harmless, as there are
* currently no known uses for these fields. */
u_int32_t reserved0[2];
u_int32_t reserved1[2];
} MDRawModule; /* MINIDUMP_MODULE */
/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to
* be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC).
* This doesn't occur on systems that don't tail-pad in this manner. Define
* this macro to be the usable size of the MDRawModule struct, and use it in
* place of sizeof(MDRawModule). */
#define MD_MODULE_SIZE 108
/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70.
* Ref.: http://www.debuginfo.com/articles/debuginfomatch.html
* MDCVInfoPDB70 is the expected structure type with recent toolchains. */
typedef struct {
u_int32_t signature;
u_int32_t offset; /* Offset to debug data (expect 0 in minidump) */
} MDCVHeader;
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[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[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' */
typedef struct {
u_int32_t data1[2];
u_int32_t data2;
u_int32_t data3;
u_int32_t data4;
u_int32_t data5[3];
u_int8_t extra[2];
} MDCVInfoELF;
/* In addition to the two CodeView record formats above, used for linking
* to external pdb files, it is possible for debugging data to be carried
* directly in the CodeView record itself. These signature values will
* be found in the first 4 bytes of the CodeView record. Additional values
* not commonly experienced in the wild are given by "Microsoft Symbol and
* Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section
* 7.2. An in-depth description of the CodeView 4.1 format is given by
* "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/
* Microsoft Symbol File Internals/CodeView Subsections,
* http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf
*/
#define MD_CVINFOCV41_SIGNATURE 0x3930424e /* '90BN', CodeView 4.10. */
#define MD_CVINFOCV50_SIGNATURE 0x3131424e /* '11BN', CodeView 5.0,
* MS C7-format (/Z7). */
#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff /* An unlikely value. */
/* (MDRawModule).miscRecord can reference MDImageDebugMisc. The Windows
* structure is actually defined in WinNT.h. This structure is effectively
* obsolete with modules built by recent toolchains. */
typedef struct {
u_int32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
* this debug record type is mostly obsolete. */
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[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[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[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,
* 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
* memory) of another MDException, for
* nested exceptions. */
u_int64_t exception_address; /* The address that caused the exception.
* Mac OS X: exception subcode (which is
* typically the address). */
u_int32_t number_parameters; /* Number of valid elements in
* exception_information. */
u_int32_t __align;
u_int64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
} MDException; /* MINIDUMP_EXCEPTION */
#include "minidump_exception_win32.h"
#include "minidump_exception_mac.h"
#include "minidump_exception_linux.h"
#include "minidump_exception_solaris.h"
typedef struct {
u_int32_t thread_id; /* Thread in which the exception
* occurred. Corresponds to
* (MDRawThread).thread_id. */
u_int32_t __align;
MDException exception_record;
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */
typedef union {
struct {
u_int32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */
u_int32_t version_information; /* cpuid 1: eax */
u_int32_t feature_information; /* cpuid 1: edx */
u_int32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
} x86_cpu_info;
struct {
u_int64_t processor_features[2];
} other_cpu_info;
} MDCPUInformation; /* CPU_INFORMATION */
typedef struct {
/* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO
* structure as returned by GetSystemInfo */
u_int16_t processor_architecture;
u_int16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
u_int16_t processor_revision; /* x86: 0xMMSS, where MM=model,
* SS=stepping */
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 */
u_int32_t major_version;
u_int32_t minor_version;
u_int32_t build_number;
u_int32_t platform_id;
MDRVA csd_version_rva; /* MDString further identifying the
* host OS.
* Windows: name of the installed OS
* service pack.
* Mac OS X: the Apple OS build number
* (sw_vers -buildVersion).
* Linux: uname -srvmo */
u_int16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
u_int16_t reserved2;
MDCPUInformation cpu;
} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */
/* For (MDRawSystemInfo).processor_architecture: */
typedef enum {
MD_CPU_ARCHITECTURE_X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */
MD_CPU_ARCHITECTURE_MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */
MD_CPU_ARCHITECTURE_ALPHA = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */
MD_CPU_ARCHITECTURE_PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */
MD_CPU_ARCHITECTURE_SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX
* (Super-H) */
MD_CPU_ARCHITECTURE_ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */
MD_CPU_ARCHITECTURE_IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */
MD_CPU_ARCHITECTURE_ALPHA64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */
MD_CPU_ARCHITECTURE_MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL
* (Microsoft Intermediate Language) */
MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */
MD_CPU_ARCHITECTURE_X86_WIN64 = 10,
/* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */
MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
} MDCPUArchitecture;
/* For (MDRawSystemInfo).platform_id: */
typedef enum {
MD_OS_WIN32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */
MD_OS_WIN32_WINDOWS = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
MD_OS_WIN32_NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
MD_OS_WIN32_CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
* (Windows CE, Windows Mobile, "Handheld") */
/* 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_SOLARIS = 0x8202 /* Solaris */
} MDOSPlatform;
typedef struct {
u_int32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */
u_int32_t flags1;
/* The next field is only valid if flags1 contains
* MD_MISCINFO_FLAGS1_PROCESS_ID. */
u_int32_t process_id;
/* The next 3 fields are only valid if flags1 contains
* MD_MISCINFO_FLAGS1_PROCESS_TIMES. */
u_int32_t process_create_time; /* time_t process started */
u_int32_t process_user_time; /* seconds of user CPU time */
u_int32_t process_kernel_time; /* seconds of kernel CPU time */
/* The following fields are not present in MINIDUMP_MISC_INFO but are
* in MINIDUMP_MISC_INFO_2. When this struct is populated, these values
* may not be set. Use flags1 or sizeOfInfo to determine whether these
* values are present. These are only valid when flags1 contains
* MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */
u_int32_t processor_max_mhz;
u_int32_t processor_current_mhz;
u_int32_t processor_mhz_limit;
u_int32_t processor_max_idle_state;
u_int32_t processor_current_idle_state;
} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2 */
#define MD_MISCINFO_SIZE 24
#define MD_MISCINFO2_SIZE 44
/* For (MDRawMiscInfo).flags1. These values indicate which fields in the
* MDRawMiscInfoStructure are valid. */
typedef enum {
MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001,
/* MINIDUMP_MISC1_PROCESS_ID */
MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002,
/* MINIDUMP_MISC1_PROCESS_TIMES */
MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004
/* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */
} MDMiscInfoFlags1;
/*
* Around DbgHelp version 6.0, the style of new LIST structures changed
* from including an array of length 1 at the end of the struct to
* represent the variable-length data to including explicit
* "size of header", "size of entry" and "number of entries" fields
* in the header, presumably to allow backwards-compatibly-extending
* the structures in the future. The actual list entries follow the
* header data directly in this case.
*/
typedef struct {
u_int32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */
u_int32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */
u_int64_t number_of_entries;
} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */
typedef struct {
u_int64_t base_address; /* Base address of a region of pages */
u_int64_t allocation_base; /* Base address of a range of pages
* within this region. */
u_int32_t allocation_protection; /* Memory protection when this region
* was originally allocated:
* MDMemoryProtection */
u_int32_t __alignment1;
u_int64_t region_size;
u_int32_t state; /* MDMemoryState */
u_int32_t protection; /* MDMemoryProtection */
u_int32_t type; /* MDMemoryType */
u_int32_t __alignment2;
} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */
/* For (MDRawMemoryInfo).state */
typedef enum {
MD_MEMORY_STATE_COMMIT = 0x1000, /* physical storage has been allocated */
MD_MEMORY_STATE_RESERVE = 0x2000, /* reserved, but no physical storage */
MD_MEMORY_STATE_FREE = 0x10000 /* available to be allocated */
} MDMemoryState;
/* For (MDRawMemoryInfo).allocation_protection and .protection */
typedef enum {
MD_MEMORY_PROTECT_NOACCESS = 0x01, /* PAGE_NOACCESS */
MD_MEMORY_PROTECT_READONLY = 0x02, /* PAGE_READONLY */
MD_MEMORY_PROTECT_READWRITE = 0x04, /* PAGE_READWRITE */
MD_MEMORY_PROTECT_WRITECOPY = 0x08, /* PAGE_WRITECOPY */
MD_MEMORY_PROTECT_EXECUTE = 0x10, /* PAGE_EXECUTE */
MD_MEMORY_PROTECT_EXECUTE_READ = 0x20, /* PAGE_EXECUTE_READ */
MD_MEMORY_PROTECT_EXECUTE_READWRITE = 0x40, /* PAGE_EXECUTE_READWRITE */
MD_MEMORY_PROTECT_EXECUTE_WRITECOPY = 0x80, /* PAGE_EXECUTE_WRITECOPY */
/* These options can be combined with the previous flags. */
MD_MEMORY_PROTECT_GUARD = 0x100, /* PAGE_GUARD */
MD_MEMORY_PROTECT_NOCACHE = 0x200, /* PAGE_NOCACHE */
MD_MEMORY_PROTECT_WRITECOMBINE = 0x400, /* PAGE_WRITECOMBINE */
} MDMemoryProtection;
/* Used to mask the mutually exclusive options from the combinable flags. */
const u_int32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF;
/* For (MDRawMemoryInfo).type */
typedef enum {
MD_MEMORY_TYPE_PRIVATE = 0x20000, /* not shared by other processes */
MD_MEMORY_TYPE_MAPPED = 0x40000, /* mapped into the view of a section */
MD_MEMORY_TYPE_IMAGE = 0x1000000 /* mapped into the view of an image */
} MDMemoryType;
/*
* Breakpad extension types
*/
typedef struct {
/* validity is a bitmask with values from MDBreakpadInfoValidity, indicating
* which of the other fields in the structure are valid. */
u_int32_t validity;
/* Thread ID of the handler thread. dump_thread_id should correspond to
* the thread_id of an MDRawThread in the minidump's MDRawThreadList if
* a dedicated thread in that list was used to produce the minidump. If
* the MDRawThreadList does not contain a dedicated thread used to produce
* the minidump, this field should be set to 0 and the validity field
* must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */
u_int32_t dump_thread_id;
/* Thread ID of the thread that requested the minidump be produced. As
* with dump_thread_id, requesting_thread_id should correspond to the
* thread_id of an MDRawThread in the minidump's MDRawThreadList. For
* minidumps produced as a result of an exception, requesting_thread_id
* will be the same as the MDRawExceptionStream's thread_id field. For
* minidumps produced "manually" at the program's request,
* requesting_thread_id will indicate which thread caused the dump to be
* written. If the minidump was produced at the request of something
* other than a thread in the MDRawThreadList, this field should be set
* to 0 and the validity field must not contain
* MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */
u_int32_t requesting_thread_id;
} MDRawBreakpadInfo;
/* For (MDRawBreakpadInfo).validity: */
typedef enum {
/* When set, the dump_thread_id field is valid. */
MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID = 1 << 0,
/* When set, the requesting_thread_id field is valid. */
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1
} MDBreakpadInfoValidity;
typedef struct {
/* expression, function, and file are 0-terminated UTF-16 strings. They
* may be truncated if necessary, but should always be 0-terminated when
* written to a file.
* Fixed-length strings are used because MiniDumpWriteDump doesn't offer
* a way for user streams to point to arbitrary RVAs for strings. */
u_int16_t expression[128]; /* Assertion that failed... */
u_int16_t function[128]; /* ...within this function... */
u_int16_t file[128]; /* ...in this file... */
u_int32_t line; /* ...at this line. */
u_int32_t type;
} MDRawAssertionInfo;
/* For (MDRawAssertionInfo).type: */
typedef enum {
MD_ASSERTION_INFO_TYPE_UNKNOWN = 0,
/* Used for assertions that would be raised by the MSVC CRT but are
* directed to an invalid parameter handler instead. */
MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER,
/* Used for assertions that would be raised by the MSVC CRT but are
* directed to a pure virtual call handler instead. */
MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL
} MDAssertionInfoData;
#if defined(_MSC_VER)
#pragma warning(pop)
#endif /* _MSC_VER */
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */

View File

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

View File

@ -0,0 +1,335 @@
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
// Copyright (c) 2001, 2002 Peter Dimov
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
//
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
// of the object pointed to, either on destruction of the scoped_ptr or via
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
// use shared_ptr or std::auto_ptr if your needs are more complex.
// *** NOTE ***
// If your scoped_ptr is a class member of class FOO pointing to a
// forward declared type BAR (as shown below), then you MUST use a non-inlined
// version of the destructor. The destructor of a scoped_ptr (called from
// FOO's destructor) must have a complete definition of BAR in order to
// destroy it. Example:
//
// -- foo.h --
// class BAR;
//
// class FOO {
// public:
// FOO();
// ~FOO(); // Required for sources that instantiate class FOO to compile!
//
// private:
// scoped_ptr<BAR> bar_;
// };
//
// -- foo.cc --
// #include "foo.h"
// FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.
// scoped_ptr_malloc added by Google
// When one of these goes out of scope, instead of doing a delete or
// delete[], it calls free(). scoped_ptr_malloc<char> is likely to see
// much more use than any other specializations.
// release() added by Google
// Use this to conditionally transfer ownership of a heap-allocated object
// to the caller, usually on method success.
#ifndef PROCESSOR_SCOPED_PTR_H__
#define PROCESSOR_SCOPED_PTR_H__
#include <cstddef> // for std::ptrdiff_t
#include <assert.h> // for assert
#include <stdlib.h> // for free() decl
namespace google_breakpad {
template <typename T>
class scoped_ptr {
private:
T* ptr;
scoped_ptr(scoped_ptr const &);
scoped_ptr & operator=(scoped_ptr const &);
public:
typedef T element_type;
explicit scoped_ptr(T* p = 0): ptr(p) {}
~scoped_ptr() {
typedef char type_must_be_complete[sizeof(T)];
delete ptr;
}
void reset(T* p = 0) {
typedef char type_must_be_complete[sizeof(T)];
if (ptr != p) {
delete ptr;
ptr = p;
}
}
T& operator*() const {
assert(ptr != 0);
return *ptr;
}
T* operator->() const {
assert(ptr != 0);
return ptr;
}
bool operator==(T* p) const {
return ptr == p;
}
bool operator!=(T* p) const {
return ptr != p;
}
T* get() const {
return ptr;
}
void swap(scoped_ptr & b) {
T* tmp = b.ptr;
b.ptr = ptr;
ptr = tmp;
}
T* release() {
T* tmp = ptr;
ptr = 0;
return tmp;
}
private:
// no reason to use these: each scoped_ptr should have its own object
template <typename U> bool operator==(scoped_ptr<U> const& p) const;
template <typename U> bool operator!=(scoped_ptr<U> const& p) const;
};
template<typename T> inline
void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
a.swap(b);
}
template<typename T> inline
bool operator==(T* p, const scoped_ptr<T>& b) {
return p == b.get();
}
template<typename T> inline
bool operator!=(T* p, const scoped_ptr<T>& b) {
return p != b.get();
}
// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
// is guaranteed, either on destruction of the scoped_array or via an explicit
// reset(). Use shared_array or std::vector if your needs are more complex.
template<typename T>
class scoped_array {
private:
T* ptr;
scoped_array(scoped_array const &);
scoped_array & operator=(scoped_array const &);
public:
typedef T element_type;
explicit scoped_array(T* p = 0) : ptr(p) {}
~scoped_array() {
typedef char type_must_be_complete[sizeof(T)];
delete[] ptr;
}
void reset(T* p = 0) {
typedef char type_must_be_complete[sizeof(T)];
if (ptr != p) {
delete [] ptr;
ptr = p;
}
}
T& operator[](std::ptrdiff_t i) const {
assert(ptr != 0);
assert(i >= 0);
return ptr[i];
}
bool operator==(T* p) const {
return ptr == p;
}
bool operator!=(T* p) const {
return ptr != p;
}
T* get() const {
return ptr;
}
void swap(scoped_array & b) {
T* tmp = b.ptr;
b.ptr = ptr;
ptr = tmp;
}
T* release() {
T* tmp = ptr;
ptr = 0;
return tmp;
}
private:
// no reason to use these: each scoped_array should have its own object
template <typename U> bool operator==(scoped_array<U> const& p) const;
template <typename U> bool operator!=(scoped_array<U> const& p) const;
};
template<class T> inline
void swap(scoped_array<T>& a, scoped_array<T>& b) {
a.swap(b);
}
template<typename T> inline
bool operator==(T* p, const scoped_array<T>& b) {
return p == b.get();
}
template<typename T> inline
bool operator!=(T* p, const scoped_array<T>& b) {
return p != b.get();
}
// This class wraps the c library function free() in a class that can be
// passed as a template argument to scoped_ptr_malloc below.
class ScopedPtrMallocFree {
public:
inline void operator()(void* x) const {
free(x);
}
};
// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
// second template argument, the functor used to free the object.
template<typename T, typename FreeProc = ScopedPtrMallocFree>
class scoped_ptr_malloc {
private:
T* ptr;
scoped_ptr_malloc(scoped_ptr_malloc const &);
scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
public:
typedef T element_type;
explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
~scoped_ptr_malloc() {
typedef char type_must_be_complete[sizeof(T)];
free_((void*) ptr);
}
void reset(T* p = 0) {
typedef char type_must_be_complete[sizeof(T)];
if (ptr != p) {
free_((void*) ptr);
ptr = p;
}
}
T& operator*() const {
assert(ptr != 0);
return *ptr;
}
T* operator->() const {
assert(ptr != 0);
return ptr;
}
bool operator==(T* p) const {
return ptr == p;
}
bool operator!=(T* p) const {
return ptr != p;
}
T* get() const {
return ptr;
}
void swap(scoped_ptr_malloc & b) {
T* tmp = b.ptr;
b.ptr = ptr;
ptr = tmp;
}
T* release() {
T* tmp = ptr;
ptr = 0;
return tmp;
}
private:
// no reason to use these: each scoped_ptr_malloc should have its own object
template <typename U, typename GP>
bool operator==(scoped_ptr_malloc<U, GP> const& p) const;
template <typename U, typename GP>
bool operator!=(scoped_ptr_malloc<U, GP> const& p) const;
static FreeProc const free_;
};
template<typename T, typename FP>
FP const scoped_ptr_malloc<T,FP>::free_ = FP();
template<typename T, typename FP> inline
void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) {
a.swap(b);
}
template<typename T, typename FP> inline
bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) {
return p == b.get();
}
template<typename T, typename FP> inline
bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) {
return p != b.get();
}
} // namespace google_breakpad
#endif // PROCESSOR_SCOPED_PTR_H__

File diff suppressed because it is too large Load Diff

View File

@ -176,6 +176,7 @@ option(ENABLE_LIBLASTFM "Use liblastfm for fetching song info, scrobbling and ra
option(ENABLE_SCRIPTING_ARCHIVES "Enable support for loading scripts from archives (.clem or .tar.gz files)" OFF)
option(ENABLE_SCRIPTING_PYTHON "Enable python scripting" OFF)
option(ENABLE_REMOTE "Enable support for using remote controls with Clementine" OFF)
option(ENABLE_BREAKPAD "Enable crash reporting" ON)
if(ENABLE_LIBGPOD AND LIBGPOD_FOUND)
set(HAVE_LIBGPOD ON)
@ -213,6 +214,11 @@ if(ENABLE_WIIMOTEDEV AND HAVE_DBUS)
set(HAVE_WIIMOTEDEV ON)
endif(ENABLE_WIIMOTEDEV AND HAVE_DBUS)
# TODO: Remove the LINUX later
if(ENABLE_BREAKPAD AND LINUX)
set(HAVE_BREAKPAD ON)
endif(ENABLE_BREAKPAD AND LINUX)
if(ENABLE_VISUALISATIONS)
# When/if upstream accepts our patches then these options can be used to link
# to system installed projectM instead.
@ -328,6 +334,10 @@ if(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
add_subdirectory(gstafcsrc)
endif(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
if(HAVE_BREAKPAD)
add_subdirectory(3rdparty/google-breakpad)
endif(HAVE_BREAKPAD)
# Uninstall support
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
@ -348,6 +358,7 @@ summary_add("Gnome sound menu integration" HAVE_LIBINDICATE)
summary_add("Wiimote support" HAVE_WIIMOTEDEV)
summary_add("Visualisations" ENABLE_VISUALISATIONS)
summary_add("Last.fm support" HAVE_LIBLASTFM)
summary_add("Crash reporting" HAVE_BREAKPAD)
summary_add("(Mac OS X) Sparkle integration" HAVE_SPARKLE)
summary_add("(unstable) Scripting support: loading archives" HAVE_LIBARCHIVE)
summary_add("(unstable) Scripting support: Python" HAVE_SCRIPTING_PYTHON)

View File

@ -35,6 +35,10 @@ if(HAVE_SCRIPTING_PYTHON)
include_directories(${PYTHON_INCLUDE_DIRS})
endif(HAVE_SCRIPTING_PYTHON)
if(HAVE_BREAKPAD)
include_directories(../3rdparty/google-breakpad)
endif(HAVE_BREAKPAD)
cmake_policy(SET CMP0011 NEW)
include(../cmake/ParseArguments.cmake)
include(../cmake/Translations.cmake)
@ -53,6 +57,7 @@ set(SOURCES
core/backgroundstreams.cpp
core/backgroundthread.cpp
core/commandlineoptions.cpp
core/crashreporting.cpp
core/database.cpp
core/deletefiles.cpp
core/encoding.cpp
@ -263,6 +268,7 @@ set(HEADERS
core/artloader.h
core/backgroundstreams.h
core/backgroundthread.h
core/crashreporting.h
core/database.h
core/deletefiles.h
core/globalshortcuts.h
@ -945,6 +951,10 @@ if(HAVE_REMOTE)
link_directories(${GLOOX_LIBRARY_DIRS})
endif(HAVE_REMOTE)
if(HAVE_BREAKPAD)
target_link_libraries(clementine_lib breakpad)
endif(HAVE_BREAKPAD)
if (APPLE)
target_link_libraries(clementine_lib
${GROWL}

View File

@ -20,14 +20,7 @@
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#cmakedefine ENABLE_VISUALISATIONS
#cmakedefine USE_INSTALL_PREFIX
#cmakedefine USE_SYSTEM_PROJECTM
#cmakedefine SNOW_LEOPARD
#cmakedefine LEOPARD
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_STATIC_SQLITE
#cmakedefine HAVE_BREAKPAD
#cmakedefine HAVE_DBUS
#cmakedefine HAVE_GIO
#cmakedefine HAVE_IMOBILEDEVICE
@ -36,10 +29,14 @@
#cmakedefine HAVE_LIBINDICATE
#cmakedefine HAVE_LIBLASTFM
#cmakedefine HAVE_LIBMTP
#cmakedefine HAVE_WIIMOTEDEV
#cmakedefine HAVE_SCRIPTING_PYTHON
#cmakedefine HAVE_REMOTE
#cmakedefine HAVE_SCRIPTING_PYTHON
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_STATIC_SQLITE
#cmakedefine HAVE_WIIMOTEDEV
#cmakedefine LEOPARD
#cmakedefine SNOW_LEOPARD
#cmakedefine USE_INSTALL_PREFIX
#cmakedefine USE_SYSTEM_PROJECTM
#endif // CONFIG_H_IN

208
src/core/crashreporting.cpp Normal file
View File

@ -0,0 +1,208 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "crashreporting.h"
#include <QApplication>
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QProgressDialog>
#include <QUrl>
#include <QtDebug>
#ifdef HAVE_BREAKPAD
# include "client/linux/handler/exception_handler.h"
# include "third_party/lss/linux_syscall_support.h"
#endif
const char* CrashSender::kUploadURL = "http://crashes.clementine-player.org/getuploadurl";
const char* CrashReporting::kSendCrashReportOption = "--send-crash-report";
char* CrashReporting::sPath = NULL;
#ifdef HAVE_BREAKPAD
CrashReporting::CrashReporting()
: handler_(new google_breakpad::ExceptionHandler(
QDir::tempPath().toLocal8Bit().constData(), NULL,
CrashReporting::Handler, this, true)) {
}
CrashReporting::~CrashReporting() {
}
bool CrashReporting::SendCrashReport(int argc, char** argv) {
if (argc != 4 || strcmp(argv[1], kSendCrashReportOption) != 0) {
return false;
}
QApplication a(argc, argv);
CrashSender sender(QString("%1/%2.dmp").arg(argv[2], argv[3]));
if (sender.Start()) {
a.exec();
}
return true;
}
void CrashReporting::SetApplicationPath(const QString& path) {
sPath = strdup(path.toLocal8Bit().constData());
}
void CrashReporting::Print(const char* message) {
if (message) {
sys_write(1, message, strlen(message));
}
}
bool CrashReporting::Handler(const char* dump_path,
const char* minidump_id,
void* context,
bool succeeded) {
Print("Clementine has crashed! A crash report has been saved to:\n ");
Print(dump_path);
Print("/");
Print(minidump_id);
Print("\n\nPlease send this to the developers so they can fix the problem:\n"
" http://code.google.com/p/clementine-player/issues/entry\n\n");
if (sPath) {
// We know the path to clementine, so exec it again to prompt the user to
// upload the report.
const char* argv[] = {sPath, kSendCrashReportOption, dump_path, minidump_id, NULL};
sys_execv(sPath, argv);
}
return true;
}
CrashSender::CrashSender(const QString& path)
: network_(new QNetworkAccessManager(this)),
path_(path),
file_(new QFile(path_, this)),
progress_(NULL) {
}
bool CrashSender::Start() {
if (!file_->open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open crash report" << path_;
return false;
}
// No tr() here.
QMessageBox prompt(QMessageBox::Critical, "Clementine has crashed!", QString(
"A crash report has been created and saved to '%1'. With your permission "
"it can be automatically sent to our server so the developers can find "
"out what happened.").arg(path_));
prompt.addButton("Don't send", QMessageBox::RejectRole);
prompt.addButton("Send crash report", QMessageBox::AcceptRole);
if (prompt.exec() == QDialog::Rejected) {
return false;
}
progress_ = new QProgressDialog("Uploading crash report", "Cancel", 0, 0);
progress_->show();
// We'll get a redirect first, so don't start POSTing data yet.
QNetworkReply* reply = network_->get(QNetworkRequest(QUrl(kUploadURL)));
connect(reply, SIGNAL(finished()), SLOT(RedirectFinished()));
return true;
}
void CrashSender::RedirectFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) {
progress_->close();
return;
}
reply->deleteLater();
QUrl url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (!url.isValid()) {
progress_->close();
return;
}
// Read the file's data
QByteArray file_data = file_->readAll();
// Find a boundary that doesn't exist in the file
QByteArray boundary;
forever {
boundary = "--------------" + QString::number(qrand(), 16).toAscii();
if (!file_data.contains(boundary)) {
break;
}
}
QNetworkRequest req(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
// Construct the multipart/form-data
QByteArray form_data;
form_data.reserve(file_data.size() + 1024);
form_data.append("--");
form_data.append(boundary);
form_data.append("\nContent-Disposition: form-data; name=\"data\"; filename=\"data.dmp\"\n");
form_data.append("Content-Type: application/octet-stream\n\n");
form_data.append(file_data);
form_data.append("\n--");
form_data.append(boundary);
form_data.append("--");
progress_->setMaximum(form_data.size());
// Upload the data
reply = network_->post(req, form_data);
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SLOT(UploadProgress(qint64)));
connect(reply, SIGNAL(finished()), progress_, SLOT(close()));
}
void CrashSender::UploadProgress(qint64 bytes) {
progress_->setValue(bytes);
}
#else // HAVE_BREAKPAD
namespace google_breakpad {
class ExceptionHandler {};
}
CrashReporting::CrashReporting() {
}
CrashReporting::~CrashReporting() {
}
bool CrashReporting::SendCrashReport(int, char**) {
return false;
}
void CrashReporting::SetApplicationPath(const QString&) {
}
#endif // HAVE_BREAKPAD

97
src/core/crashreporting.h Normal file
View File

@ -0,0 +1,97 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CRASHREPORTING_H
#define CRASHREPORTING_H
#include <QObject>
#include <boost/scoped_ptr.hpp>
class QFile;
class QNetworkAccessManager;
class QProgressDialog;
namespace google_breakpad {
class ExceptionHandler;
}
// Wraps google_breakpad::ExceptionHandler - while an instance of this class
// is alive crashes will be handled.
class CrashReporting {
public:
CrashReporting();
~CrashReporting();
// If the commandline contains the --send-crash-report option, the user will
// be prompted to send the crash report and the function will return true
// (in which case the caller should exit the program). Otherwise the function
// returns false.
static bool SendCrashReport(int argc, char** argv);
// If this is set then the application is exec'd again with
// --send-crash-report when a crash happens.
static void SetApplicationPath(const QString& path);
private:
// Prints the message to stdout without using libc.
static void Print(const char* message);
// Breakpad callback.
static bool Handler(const char* dump_path,
const char* minidump_id,
void* context,
bool succeeded);
private:
Q_DISABLE_COPY(CrashReporting);
static const char* kSendCrashReportOption;
static char* sPath;
boost::scoped_ptr<google_breakpad::ExceptionHandler> handler_;
};
// Asks the user if he wants to send a crash report, and displays a progress
// dialog while uploading it if he does.
class CrashSender : public QObject {
Q_OBJECT
public:
CrashSender(const QString& path);
// Returns false if the user doesn't want to send the crash report (caller
// should exit), or true if he does (caller should start the Qt event loop).
bool Start();
private slots:
void RedirectFinished();
void UploadProgress(qint64 bytes);
private:
static const char* kUploadURL;
QNetworkAccessManager* network_;
QString path_;
QFile* file_;
QProgressDialog* progress_;
};
#endif // CRASHREPORTING_H

View File

@ -26,6 +26,7 @@
#include "config.h"
#include "core/artloader.h"
#include "core/commandlineoptions.h"
#include "core/crashreporting.h"
#include "core/database.h"
#include "core/encoding.h"
#include "core/mac_startup.h"
@ -129,6 +130,12 @@ void GLog(const gchar* domain,
}
int main(int argc, char *argv[]) {
if (CrashReporting::SendCrashReport(argc, argv)) {
return 0;
}
CrashReporting crash_reporting;
#ifdef Q_OS_DARWIN
// Do Mac specific startup to get media keys working.
// This must go before QApplication initialisation.
@ -218,6 +225,7 @@ int main(int argc, char *argv[]) {
// This MUST be done before parsing the commandline options so QTextCodec
// gets the right system locale for filenames.
QtSingleCoreApplication a(argc, argv);
crash_reporting.SetApplicationPath(a.applicationFilePath());
// Parse commandline options - need to do this before starting the
// full QApplication so it works without an X server