bug 465329 - sync to breakpad revision 299 (just the breakpad changes). r=bsmedberg

This commit is contained in:
Ted Mielczarek 2008-11-25 09:19:44 -05:00
Родитель 88e5a0fcd3
Коммит 4102dc999b
147 изменённых файлов: 40954 добавлений и 28382 удалений

0
toolkit/crashreporter/google-breakpad/AUTHORS Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/COPYING Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/ChangeLog Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/INSTALL Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/Makefile.am Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/Makefile.in Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/NEWS Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/README Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/aclocal.m4 поставляемый Executable file → Normal file
Просмотреть файл

0
toolkit/crashreporter/google-breakpad/configure.ac Executable file → Normal file
Просмотреть файл

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

@ -118,7 +118,9 @@ ExceptionHandler::~ExceptionHandler() {
}
bool ExceptionHandler::WriteMinidump() {
return InternalWriteMinidump(0, 0, NULL);
bool success = InternalWriteMinidump(0, 0, NULL);
UpdateNextID();
return success;
}
// static
@ -226,41 +228,49 @@ bool ExceptionHandler::InternalWriteMinidump(int signo,
if (filter_ && !filter_(callback_context_))
return false;
bool success = false;
// Block all the signals we want to process when writting minidump.
// We don't want it to be interrupted.
sigset_t sig_blocked, sig_old;
bool blocked = true;
sigfillset(&sig_blocked);
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i)
sigdelset(&sig_blocked, SigTable[i]);
if (sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old) != 0) {
blocked = false;
fprintf(stderr, "google_breakpad::ExceptionHandler::HandleException: "
"failed to block signals.\n");
}
success = minidump_generator_.WriteMinidumpToFile(
next_minidump_path_c_, signo, sighandler_ebp, sig_ctx);
// Unblock the signals.
if (blocked) {
sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
}
if (callback_)
success = callback_(dump_path_c_, next_minidump_id_c_,
callback_context_, success);
return success;
}
void ExceptionHandler::UpdateNextID() {
GUID guid;
bool success = false;;
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);
// Block all the signals we want to process when writting minidump.
// We don't want it to be interrupted.
sigset_t sig_blocked, sig_old;
bool blocked = true;
sigfillset(&sig_blocked);
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i)
sigdelset(&sig_blocked, SigTable[i]);
if (sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old) != 0) {
blocked = false;
fprintf(stderr, "google_breakpad::ExceptionHandler::HandleException: "
"failed to block signals.\n");
}
success = minidump_generator_.WriteMinidumpToFile(
minidump_path, signo, sighandler_ebp, sig_ctx);
// Unblock the signals.
if (blocked) {
sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
}
if (callback_)
success = callback_(dump_path_c_, guid_str,
callback_context_, success);
next_minidump_path_ = minidump_path;
next_minidump_path_c_ = next_minidump_path_.c_str();
}
return success;
}
} // namespace google_breakpad

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

@ -126,6 +126,7 @@ class ExceptionHandler {
void set_dump_path(const string &dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
UpdateNextID();
}
// Writes a minidump immediately. This can be used to capture the
@ -160,6 +161,10 @@ class ExceptionHandler {
bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp,
struct sigcontext **sig_ctx);
// Generates a new ID and stores it in next_minidump_id, and stores the
// path of the next minidump to be written in next_minidump_path_.
void UpdateNextID();
private:
FilterCallback filter_;
MinidumpCallback callback_;
@ -168,9 +173,20 @@ class ExceptionHandler {
// The directory in which a minidump will be written, set by the dump_path
// argument to the constructor, or set_dump_path.
string dump_path_;
// C style dump path. Keep this when setting dump path, since calling
// c_str() of std::string when crashing may not be safe.
// The basename of the next minidump to be written, without the extension
string next_minidump_id_;
// The full pathname of the next minidump to be written, including the file
// extension
string next_minidump_path_;
// 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_id_c_;
const char *next_minidump_path_c_;
// True if the ExceptionHandler installed an unhandled exception filter
// when created (with an install_handler parameter set to true).

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,258 @@
#ifndef _exc_user_
#define _exc_user_
/* Module exc */
#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>
#ifdef AUTOTEST
#ifndef FUNCTION_PTR_T
#define FUNCTION_PTR_T
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
typedef struct {
char *name;
function_ptr_t function;
} function_table_entry;
typedef function_table_entry *function_table_t;
#endif /* FUNCTION_PTR_T */
#endif /* AUTOTEST */
#ifndef exc_MSG_COUNT
#define exc_MSG_COUNT 3
#endif /* exc_MSG_COUNT */
#include <mach/std_types.h>
#include <mach/mig.h>
#include <mach/mig.h>
#include <mach/mach_types.h>
#ifdef __BeforeMigUserHeader
__BeforeMigUserHeader
#endif /* __BeforeMigUserHeader */
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Routine exception_raise */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt
);
/* Routine exception_raise_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
/* Routine exception_raise_state_identity */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
__END_DECLS
/********************** Caution **************************/
/* The following data types should be used to calculate */
/* maximum message sizes only. The actual message may be */
/* smaller, and the position of the arguments within the */
/* message layout may vary from what is presented here. */
/* For example, if any of the arguments are variable- */
/* sized, and less than the maximum is sent, the data */
/* will be packed tight in the actual message to reduce */
/* the presence of holes. */
/********************** Caution **************************/
/* typedefs for all requests */
#ifndef __Request__exc_subsystem__defined
#define __Request__exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
} __Request__exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} __Request__exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} __Request__exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__exc_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__exc_subsystem__defined
#define __RequestUnion__exc_subsystem__defined
union __RequestUnion__exc_subsystem {
__Request__exception_raise_t Request_exception_raise;
__Request__exception_raise_state_t Request_exception_raise_state;
__Request__exception_raise_state_identity_t Request_exception_raise_state_identity;
};
#endif /* !__RequestUnion__exc_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__exc_subsystem__defined
#define __Reply__exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[144];
} __Reply__exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[144];
} __Reply__exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Reply__exc_subsystem__defined */
/* union of all replies */
#ifndef __ReplyUnion__exc_subsystem__defined
#define __ReplyUnion__exc_subsystem__defined
union __ReplyUnion__exc_subsystem {
__Reply__exception_raise_t Reply_exception_raise;
__Reply__exception_raise_state_t Reply_exception_raise_state;
__Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity;
};
#endif /* !__RequestUnion__exc_subsystem__defined */
#ifndef subsystem_to_name_map_exc
#define subsystem_to_name_map_exc \
{ "exception_raise", 2401 },\
{ "exception_raise_state", 2402 },\
{ "exception_raise_state_identity", 2403 }
#endif
#ifdef __AfterMigUserHeader
__AfterMigUserHeader
#endif /* __AfterMigUserHeader */
#endif /* _exc_user_ */

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

@ -0,0 +1,381 @@
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*/
/* nealsid:
* This file was copied from libc/gen/nlist.c from Darwin's source code
* The version of nlist used as a base is from 10.5.2, libc-498
* http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c
*
* The full tarball is at:
* http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz
*
* I've modified it to be compatible with 64-bit images. However,
* 32-bit compatibility has not been retained.
*/
#ifdef __LP64__
#include <mach-o/nlist.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include "breakpad_nlist_64.h"
#include <TargetConditionals.h>
#include <stdio.h>
#include <mach/mach.h>
/* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */
/*
* Header prepended to each a.out file.
*/
struct exec {
unsigned short a_machtype; /* machine type */
unsigned short a_magic; /* magic number */
unsigned long a_text; /* size of text segment */
unsigned long a_data; /* size of initialized data */
unsigned long a_bss; /* size of uninitialized data */
unsigned long a_syms; /* size of symbol table */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* size of text relocation */
unsigned long a_drsize; /* size of data relocation */
};
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
#define N_BADMAG(x) \
(((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
#define N_TXTOFF(x) \
((x).a_magic==ZMAGIC ? 0 : sizeof (struct exec))
#define N_SYMOFF(x) \
(N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize)
int
__breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames);
/*
* nlist - retreive attributes from name list (string table version)
*/
int
breakpad_nlist_64(const char *name,
breakpad_nlist *list,
const char **symbolNames) {
int fd, n;
fd = open(name, O_RDONLY, 0);
if (fd < 0)
return (-1);
n = __breakpad_fdnlist_64(fd, list, symbolNames);
(void)close(fd);
return (n);
}
/* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */
int
__breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames) {
register breakpad_nlist *p, *q;
breakpad_nlist space[BUFSIZ/sizeof (breakpad_nlist)];
const register char *s1, *s2;
register int n, m;
int maxlen, nreq;
off_t sa; /* symbol address */
off_t ss; /* start of strings */
struct exec buf;
unsigned arch_offset = 0;
maxlen = 500;
for (q = list, nreq = 0;
symbolNames[q-list] && symbolNames[q-list][0];
q++, nreq++) {
q->n_type = 0;
q->n_value = 0;
q->n_desc = 0;
q->n_sect = 0;
q->n_un.n_strx = 0;
}
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) ||
(N_BADMAG(buf) && *((long *)&buf) != MH_MAGIC &&
NXSwapBigLongToHost(*((long *)&buf)) != FAT_MAGIC) &&
/* nealsid: The following is the big-endian ppc64 check */
(*((uint32_t*)&buf)) != FAT_MAGIC) {
return (-1);
}
/* Deal with fat file if necessary */
if (NXSwapBigLongToHost(*((long *)&buf)) == FAT_MAGIC ||
/* nealsid: The following is the big-endian ppc64 check */
*((int*)&buf) == FAT_MAGIC) {
struct host_basic_info hbi;
struct fat_header fh;
struct fat_arch *fat_archs, *fap;
unsigned i;
host_t host;
/* Get our host info */
host = mach_host_self();
i = HOST_BASIC_INFO_COUNT;
kern_return_t kr;
if ((kr=host_info(host, HOST_BASIC_INFO,
(host_info_t)(&hbi), &i)) != KERN_SUCCESS) {
return (-1);
}
mach_port_deallocate(mach_task_self(), host);
/* Read in the fat header */
lseek(fd, 0, SEEK_SET);
if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) {
return (-1);
}
/* Convert fat_narchs to host byte order */
fh.nfat_arch = NXSwapBigLongToHost(fh.nfat_arch);
/* Read in the fat archs */
fat_archs = (struct fat_arch *)malloc(fh.nfat_arch *
sizeof(struct fat_arch));
if (fat_archs == NULL) {
return (-1);
}
if (read(fd, (char *)fat_archs,
sizeof(struct fat_arch) * fh.nfat_arch) !=
sizeof(struct fat_arch) * fh.nfat_arch) {
free(fat_archs);
return (-1);
}
/*
* Convert archs to host byte ordering (a constraint of
* cpusubtype_getbestarch()
*/
for (i = 0; i < fh.nfat_arch; i++) {
fat_archs[i].cputype =
NXSwapBigLongToHost(fat_archs[i].cputype);
fat_archs[i].cpusubtype =
NXSwapBigLongToHost(fat_archs[i].cpusubtype);
fat_archs[i].offset =
NXSwapBigLongToHost(fat_archs[i].offset);
fat_archs[i].size =
NXSwapBigLongToHost(fat_archs[i].size);
fat_archs[i].align =
NXSwapBigLongToHost(fat_archs[i].align);
}
fap = NULL;
for (i = 0; i < fh.nfat_arch; i++) {
/* nealsid: Although the original Apple code uses host_info */
/* to retrieve the CPU type, the host_info will still return */
/* CPU_TYPE_X86 even if running as an x86_64 binary. Given that */
/* this code isn't necessary on i386, I've decided to hardcode */
/* looking for a 64-bit binary */
#if TARGET_CPU_X86_64
if (fat_archs[i].cputype == CPU_TYPE_X86_64) {
#elif TARGET_CPU_PPC64
if (fat_archs[i].cputype == CPU_TYPE_POWERPC64) {
#else
#error undefined cpu!
{
#endif
fap = &fat_archs[i];
break;
}
}
if (!fap) {
free(fat_archs);
return (-1);
}
arch_offset = fap->offset;
free(fat_archs);
/* Read in the beginning of the architecture-specific file */
lseek(fd, arch_offset, SEEK_SET);
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) {
return (-1);
}
}
if (*((int *)&buf) == MH_MAGIC_64) {
struct mach_header_64 mh;
struct load_command *load_commands, *lcp;
struct symtab_command *stp;
long i;
lseek(fd, arch_offset, SEEK_SET);
if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) {
return (-1);
}
load_commands = (struct load_command *)malloc(mh.sizeofcmds);
if (load_commands == NULL) {
return (-1);
}
if (read(fd, (char *)load_commands, mh.sizeofcmds) !=
mh.sizeofcmds) {
free(load_commands);
return (-1);
}
stp = NULL;
lcp = load_commands;
// nealsid:iterate through all load commands, looking for
// LC_SYMTAB load command
for (i = 0; i < mh.ncmds; i++) {
if (lcp->cmdsize % sizeof(long) != 0 ||
lcp->cmdsize <= 0 ||
(char *)lcp + lcp->cmdsize >
(char *)load_commands + mh.sizeofcmds) {
free(load_commands);
return (-1);
}
if (lcp->cmd == LC_SYMTAB) {
if (lcp->cmdsize !=
sizeof(struct symtab_command)) {
free(load_commands);
return (-1);
}
stp = (struct symtab_command *)lcp;
break;
}
lcp = (struct load_command *)
((char *)lcp + lcp->cmdsize);
}
if (stp == NULL) {
free(load_commands);
return (-1);
}
// sa points to the beginning of the symbol table
sa = stp->symoff + arch_offset;
// ss points to the beginning of the string table
ss = stp->stroff + arch_offset;
// n is the number of bytes in the symbol table
// each symbol table entry is an nlist structure
n = stp->nsyms * sizeof(breakpad_nlist);
free(load_commands);
}
else {
sa = N_SYMOFF(buf) + arch_offset;
ss = sa + buf.a_syms + arch_offset;
n = buf.a_syms;
}
lseek(fd, sa, SEEK_SET);
// the algorithm here is to read the nlist entries in m-sized
// chunks into q. q is then iterated over. for each entry in q,
// use the string table index(q->n_un.n_strx) to read the symbol
// name, then scan the nlist entries passed in by the user(via p),
// and look for a match
while (n) {
long savpos;
m = sizeof (space);
if (n < m)
m = n;
if (read(fd, (char *)space, m) != m)
break;
n -= m;
savpos = lseek(fd, 0, SEEK_CUR);
for (q = space; (m -= sizeof(breakpad_nlist)) >= 0; q++) {
char nambuf[BUFSIZ];
if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
continue;
// seek to the location in the binary where the symbol
// name is stored & read it into memory
lseek(fd, ss+q->n_un.n_strx, SEEK_SET);
read(fd, nambuf, maxlen+1);
s2 = nambuf;
for (p = list;
symbolNames[p-list] &&
symbolNames[p-list][0];
p++) {
// get the symbol name the user has passed in that
// corresponds to the nlist entry that we're looking at
s1 = symbolNames[p - list];
while (*s1) {
if (*s1++ != *s2++)
goto cont;
}
if (*s2)
goto cont;
p->n_value = q->n_value;
p->n_type = q->n_type;
p->n_desc = q->n_desc;
p->n_sect = q->n_sect;
p->n_un.n_strx = q->n_un.n_strx;
if (--nreq == 0)
return (nreq);
break;
cont: ;
}
}
lseek(fd, savpos, SEEK_SET);
}
return (nreq);
}
#endif /* __LP64__ */

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

@ -0,0 +1,43 @@
// 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.
// breakpad_nlist.h
//
// This file is meant to provide a header for clients of the modified
// nlist function implemented to work on 64-bit.
#ifndef CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__
typedef struct nlist_64 breakpad_nlist;
int
breakpad_nlist_64(const char *name,
breakpad_nlist *list,
const char **symbolNames);
#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */

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

@ -33,11 +33,14 @@ extern "C" { // needed to compile on Leopard
#include <stdio.h>
}
#include "breakpad_nlist_64.h"
#include <dlfcn.h>
#include <mach/mach_vm.h>
#include <algorithm>
#include "client/mac/handler/dynamic_images.h"
namespace google_breakpad {
//==============================================================================
// Returns the size of the memory region containing |address| and the
// number of bytes from |address| to the end of the region.
@ -46,27 +49,30 @@ namespace google_breakpad {
// first in order to handle cases when we're reading strings and they
// straddle two vm regions.
//
static vm_size_t GetMemoryRegionSize(task_port_t target_task,
const void* address,
vm_size_t *size_to_end) {
vm_address_t region_base = (vm_address_t)address;
vm_size_t region_size;
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task,
const void* address,
mach_vm_size_t *size_to_end) {
mach_vm_address_t region_base = (mach_vm_address_t)address;
mach_vm_size_t region_size;
natural_t nesting_level = 0;
vm_region_submap_info submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT;
vm_region_submap_info_64 submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
// Get information about the vm region containing |address|
kern_return_t result =
vm_region_recurse(target_task,
&region_base,
&region_size,
&nesting_level,
reinterpret_cast<vm_region_recurse_info_t>(&submap_info),
&info_count);
vm_region_recurse_info_t region_info;
region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);
kern_return_t result =
mach_vm_region_recurse(target_task,
&region_base,
&region_size,
&nesting_level,
region_info,
&info_count);
if (result == KERN_SUCCESS) {
// Get distance from |address| to the end of this region
*size_to_end = region_base + region_size -(vm_address_t)address;
*size_to_end = region_base + region_size -(mach_vm_address_t)address;
// If we want to handle strings as long as 4096 characters we may need
// to check if there's a vm region immediately following the first one.
@ -74,20 +80,19 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task,
// of the second region.
if (*size_to_end < 4096) {
// Second region starts where the first one ends
vm_address_t region_base2 =
(vm_address_t)(region_base + region_size);
vm_size_t region_size2;
mach_vm_address_t region_base2 =
(mach_vm_address_t)(region_base + region_size);
mach_vm_size_t region_size2;
// Get information about the following vm region
result =
vm_region_recurse(
target_task,
&region_base2,
&region_size2,
&nesting_level,
reinterpret_cast<vm_region_recurse_info_t>(&submap_info),
&info_count);
result =
mach_vm_region_recurse(target_task,
&region_base2,
&region_size2,
&nesting_level,
region_info,
&info_count);
// Extend region_size to go all the way to the end of the 2nd region
if (result == KERN_SUCCESS
&& region_base2 == region_base + region_size) {
@ -95,13 +100,13 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task,
}
}
*size_to_end = region_base + region_size -(vm_address_t)address;
*size_to_end = region_base + region_size -(mach_vm_address_t)address;
} else {
region_size = 0;
*size_to_end = 0;
}
return region_size;
return region_size;
}
#define kMaxStringLength 8192
@ -115,17 +120,18 @@ static void* ReadTaskString(task_port_t target_task,
// The problem is we don't know how much to read until we know how long
// the string is. And we don't know how long the string is, until we've read
// the memory! So, we'll try to read kMaxStringLength bytes
// (or as many bytes as we can until we reach the end of the vm region).
vm_size_t size_to_end;
// (or as many bytes as we can until we reach the end of the vm region).
mach_vm_size_t size_to_end;
GetMemoryRegionSize(target_task, address, &size_to_end);
if (size_to_end > 0) {
vm_size_t size_to_read =
mach_vm_size_t size_to_read =
size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end;
return ReadTaskMemory(target_task, address, size_to_read);
kern_return_t kr;
return ReadTaskMemory(target_task, address, size_to_read, &kr);
}
return NULL;
}
@ -134,29 +140,46 @@ static void* ReadTaskString(task_port_t target_task,
// and should be freed by the caller.
void* ReadTaskMemory(task_port_t target_task,
const void* address,
size_t length) {
size_t length,
kern_return_t *kr) {
void* result = NULL;
vm_address_t page_address = reinterpret_cast<vm_address_t>(address) & (-4096);
vm_address_t last_page_address =
(reinterpret_cast<vm_address_t>(address) + length + 4095) & (-4096);
vm_size_t page_size = last_page_address - page_address;
int systemPageSize = getpagesize();
// use the negative of the page size for the mask to find the page address
mach_vm_address_t page_address =
reinterpret_cast<mach_vm_address_t>(address) & (-systemPageSize);
mach_vm_address_t last_page_address =
(reinterpret_cast<mach_vm_address_t>(address) + length +
(systemPageSize - 1)) & (-systemPageSize);
mach_vm_size_t page_size = last_page_address - page_address;
uint8_t* local_start;
uint32_t local_length;
kern_return_t r = vm_read(target_task,
page_address,
page_size,
reinterpret_cast<vm_offset_t*>(&local_start),
&local_length);
kern_return_t r;
r = mach_vm_read(target_task,
page_address,
page_size,
reinterpret_cast<vm_offset_t*>(&local_start),
&local_length);
if (kr != NULL) {
*kr = r;
}
if (r == KERN_SUCCESS) {
result = malloc(length);
if (result != NULL) {
memcpy(result, &local_start[(uint32_t)address - page_address], length);
memcpy(result,
&local_start[(mach_vm_address_t)address - page_address],
length);
}
vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
}
return result;
}
@ -164,37 +187,75 @@ void* ReadTaskMemory(task_port_t target_task,
//==============================================================================
// Initializes vmaddr_, vmsize_, and slide_
void DynamicImage::CalculateMemoryInfo() {
mach_header *header = GetMachHeader();
void DynamicImage::CalculateMemoryAndVersionInfo() {
breakpad_mach_header *header = GetMachHeader();
// unless we can process the header, ensure that calls to
// IsValid() will return false
vmaddr_ = 0;
vmsize_ = 0;
slide_ = 0;
version_ = 0;
bool foundTextSection = false;
bool foundDylibIDCommand = false;
#if __LP64__
if(header->magic != MH_MAGIC_64) {
return;
}
#else
if(header->magic != MH_MAGIC) {
return;
}
#endif
#ifdef __LP64__
const uint32_t segmentLoadCommand = LC_SEGMENT_64;
#else
const uint32_t segmentLoadCommand = LC_SEGMENT;
#endif
const struct load_command *cmd =
reinterpret_cast<const struct load_command *>(header + 1);
for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
if (cmd->cmd == LC_SEGMENT) {
const struct segment_command *seg =
reinterpret_cast<const struct segment_command *>(cmd);
if (!foundTextSection) {
if (cmd->cmd == segmentLoadCommand) {
const breakpad_mach_segment_command *seg =
reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
vmaddr_ = seg->vmaddr;
vmsize_ = seg->vmsize;
slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
if (!strcmp(seg->segname, "__TEXT")) {
vmaddr_ = seg->vmaddr;
vmsize_ = seg->vmsize;
slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
}
foundTextSection = true;
}
return;
}
}
if (!foundDylibIDCommand) {
if (cmd->cmd == LC_ID_DYLIB) {
const struct dylib_command *dc =
reinterpret_cast<const struct dylib_command *>(cmd);
version_ = dc->dylib.current_version;
foundDylibIDCommand = true;
}
}
if (foundDylibIDCommand && foundTextSection) {
return;
}
cmd = reinterpret_cast<const struct load_command *>
(reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
}
// we failed - a call to IsValid() will return false
vmaddr_ = 0;
vmsize_ = 0;
slide_ = 0;
}
void DynamicImage::Print() {
@ -203,11 +264,11 @@ void DynamicImage::Print() {
path = "(unknown)";
}
printf("%p: %s\n", GetLoadAddress(), path);
mach_header *header = GetMachHeader();
breakpad_mach_header *header = GetMachHeader();
MachHeader(*header).Print();
printf("vmaddr\t\t: %p\n", reinterpret_cast<void*>(GetVMAddr()));
printf("vmsize\t\t: %d\n", GetVMSize());
printf("slide\t\t: %d\n", GetVMAddrSlide());
printf("vmsize\t\t: %llu\n", GetVMSize());
printf("slide\t\t: %td\n", GetVMAddrSlide());
}
#pragma mark -
@ -219,9 +280,12 @@ DynamicImages::DynamicImages(mach_port_t task)
ReadImageInfoForTask();
}
//==============================================================================
// This code was written using dyld_debug.c (from Darwin) as a guide.
void DynamicImages::ReadImageInfoForTask() {
void* DynamicImages::GetDyldAllImageInfosPointer()
{
const char *imageSymbolName = "_dyld_all_image_infos";
const char *dyldPath = "/usr/lib/dyld";
#ifndef __LP64__
struct nlist l[8];
memset(l, 0, sizeof(l) );
@ -229,10 +293,38 @@ void DynamicImages::ReadImageInfoForTask() {
// which lives in "dyld". This structure contains information about all
// of the loaded dynamic images.
struct nlist &list = l[0];
list.n_un.n_name = const_cast<char *>("_dyld_all_image_infos");
nlist("/usr/lib/dyld", &list);
if (list.n_value) {
list.n_un.n_name = const_cast<char *>(imageSymbolName);
nlist(dyldPath,&list);
if(list.n_value) {
return reinterpret_cast<void*>(list.n_value);
}
return NULL;
#else
struct nlist_64 l[8];
struct nlist_64 &list = l[0];
memset(l, 0, sizeof(l) );
const char *symbolNames[2] = { imageSymbolName, "\0" };
int invalidEntriesCount = breakpad_nlist_64(dyldPath,&list,symbolNames);
if(invalidEntriesCount != 0) {
return NULL;
}
assert(list.n_value);
return reinterpret_cast<void*>(list.n_value);
#endif
}
//==============================================================================
// This code was written using dyld_debug.c (from Darwin) as a guide.
void DynamicImages::ReadImageInfoForTask() {
void *imageList = GetDyldAllImageInfosPointer();
if (imageList) {
kern_return_t kr;
// Read the structure inside of dyld that contains information about
// loaded images. We're reading from the desired task's address space.
@ -241,8 +333,8 @@ void DynamicImages::ReadImageInfoForTask() {
// "dyld_debug.c" and is said to be nearly always valid.
dyld_all_image_infos *dyldInfo = reinterpret_cast<dyld_all_image_infos*>
(ReadTaskMemory(task_,
reinterpret_cast<void*>(list.n_value),
sizeof(dyld_all_image_infos)));
reinterpret_cast<void*>(imageList),
sizeof(dyld_all_image_infos), &kr));
if (dyldInfo) {
// number of loaded images
@ -253,7 +345,7 @@ void DynamicImages::ReadImageInfoForTask() {
dyld_image_info *infoArray = reinterpret_cast<dyld_image_info*>
(ReadTaskMemory(task_,
dyldInfo->infoArray,
count*sizeof(dyld_image_info)));
count*sizeof(dyld_image_info), &kr));
image_list_.reserve(count);
@ -261,20 +353,24 @@ void DynamicImages::ReadImageInfoForTask() {
dyld_image_info &info = infoArray[i];
// First read just the mach_header from the image in the task.
mach_header *header = reinterpret_cast<mach_header*>
(ReadTaskMemory(task_, info.load_address_, sizeof(mach_header)));
breakpad_mach_header *header = reinterpret_cast<breakpad_mach_header*>
(ReadTaskMemory(task_,
info.load_address_,
sizeof(breakpad_mach_header), &kr));
if (!header)
break; // bail on this dynamic image
// Now determine the total amount we really want to read based on the
// size of the load commands. We need the header plus all of the
// size of the load commands. We need the header plus all of the
// load commands.
unsigned int header_size = sizeof(mach_header) + header->sizeofcmds;
unsigned int header_size =
sizeof(breakpad_mach_header) + header->sizeofcmds;
free(header);
header = reinterpret_cast<mach_header*>
(ReadTaskMemory(task_, info.load_address_, header_size));
header = reinterpret_cast<breakpad_mach_header*>
(ReadTaskMemory(task_, info.load_address_, header_size, &kr));
// Read the file name from the task's memory space.
char *file_path = NULL;
@ -285,43 +381,52 @@ void DynamicImages::ReadImageInfoForTask() {
file_path = reinterpret_cast<char*>
(ReadTaskString(task_, info.file_path_));
}
// Create an object representing this image and add it to our list.
DynamicImage *new_image = new DynamicImage(header,
header_size,
info.load_address_,
file_path,
info.file_mod_date_,
task_);
DynamicImage *new_image;
new_image = new DynamicImage(header,
header_size,
(breakpad_mach_header*)info.load_address_,
file_path,
info.file_mod_date_,
task_);
if (new_image->IsValid()) {
image_list_.push_back(DynamicImageRef(new_image));
} else {
delete new_image;
}
if (file_path) {
free(file_path);
}
}
free(dyldInfo);
free(infoArray);
// sorts based on loading address
sort(image_list_.begin(), image_list_.end() );
// remove duplicates - this happens in certain strange cases
// You can see it in DashboardClient when Google Gadgets plugin
// is installed. Apple's crash reporter log and gdb "info shared"
// both show the same library multiple times at the same address
vector<DynamicImageRef>::iterator it = unique(image_list_.begin(),
image_list_.end() );
image_list_.erase(it, image_list_.end());
}
}
}
}
//==============================================================================
DynamicImage *DynamicImages::GetExecutableImage() {
int executable_index = GetExecutableImageIndex();
if (executable_index >= 0) {
return GetImage(executable_index);
}
return NULL;
}

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

@ -68,13 +68,22 @@ typedef struct dyld_all_image_infos {
bool processDetachedFromSharedRegion;
} dyld_all_image_infos;
// some typedefs to isolate 64/32 bit differences
#ifdef __LP64__
typedef mach_header_64 breakpad_mach_header;
typedef segment_command_64 breakpad_mach_segment_command;
#else
typedef mach_header breakpad_mach_header;
typedef segment_command breakpad_mach_segment_command;
#endif
//==============================================================================
// A simple wrapper for a mach_header
//
// This could be fleshed out with some more interesting methods.
class MachHeader {
public:
explicit MachHeader(const mach_header &header) : header_(header) {}
explicit MachHeader(const breakpad_mach_header &header) : header_(header) {}
void Print() {
printf("magic\t\t: %4x\n", header_.magic);
@ -86,16 +95,16 @@ class MachHeader {
printf("flags\t\t: %d\n", header_.flags);
}
mach_header header_;
breakpad_mach_header header_;
};
//==============================================================================
// Represents a single dynamically loaded mach-o image
class DynamicImage {
public:
DynamicImage(mach_header *header, // we take ownership
int header_size, // includes load commands
mach_header *load_address,
DynamicImage(breakpad_mach_header *header, // we take ownership
int header_size, // includes load commands
breakpad_mach_header *load_address,
char *inFilePath,
uintptr_t image_mod_date,
mach_port_t task)
@ -105,7 +114,7 @@ class DynamicImage {
file_mod_date_(image_mod_date),
task_(task) {
InitializeFilePath(inFilePath);
CalculateMemoryInfo();
CalculateMemoryAndVersionInfo();
}
~DynamicImage() {
@ -116,7 +125,7 @@ class DynamicImage {
}
// Returns pointer to a local copy of the mach_header plus load commands
mach_header *GetMachHeader() {return header_;}
breakpad_mach_header *GetMachHeader() {return header_;}
// Size of mach_header plus load commands
int GetHeaderSize() const {return header_size_;}
@ -127,20 +136,21 @@ class DynamicImage {
uintptr_t GetModDate() const {return file_mod_date_;}
// Actual address where the image was loaded
mach_header *GetLoadAddress() const {return load_address_;}
breakpad_mach_header *GetLoadAddress() const {return load_address_;}
// Address where the image should be loaded
uint32_t GetVMAddr() const {return vmaddr_;}
mach_vm_address_t GetVMAddr() const {return vmaddr_;}
// Difference between GetLoadAddress() and GetVMAddr()
ptrdiff_t GetVMAddrSlide() const {return slide_;}
// Size of the image
uint32_t GetVMSize() const {return vmsize_;}
mach_vm_size_t GetVMSize() const {return vmsize_;}
// Task owning this loaded image
mach_port_t GetTask() {return task_;}
uint32_t GetVersion() {return version_;}
// For sorting
bool operator<(const DynamicImage &inInfo) {
return GetLoadAddress() < inInfo.GetLoadAddress();
@ -167,39 +177,19 @@ class DynamicImage {
}
// Initializes vmaddr_, vmsize_, and slide_
void CalculateMemoryInfo();
void CalculateMemoryAndVersionInfo();
#if 0 // currently not needed
// Copy constructor: we don't want this to be invoked,
// but here's the code in case we need to make it public some day.
DynamicImage(DynamicImage &inInfo)
: load_address_(inInfo.load_address_),
vmaddr_(inInfo.vmaddr_),
vmsize_(inInfo.vmsize_),
slide_(inInfo.slide_),
file_mod_date_(inInfo.file_mod_date_),
task_(inInfo.task_) {
// copy file path string
InitializeFilePath(inInfo.GetFilePath());
breakpad_mach_header *header_; // our local copy of the header
int header_size_; // mach_header plus load commands
breakpad_mach_header *load_address_; // base address image is mapped into
mach_vm_address_t vmaddr_;
mach_vm_size_t vmsize_;
ptrdiff_t slide_;
uint32_t version_; // Dylib version
char *file_path_; // path dyld used to load the image
uintptr_t file_mod_date_; // time_t of image file
// copy mach_header and load commands
header_ = reinterpret_cast<mach_header*>(malloc(inInfo.header_size_));
memcpy(header_, inInfo.header_, inInfo.header_size_);
header_size_ = inInfo.header_size_;
}
#endif
mach_header *header_; // our local copy of the header
int header_size_; // mach_header plus load commands
mach_header *load_address_; // base address image is mapped into
uint32_t vmaddr_;
uint32_t vmsize_;
ptrdiff_t slide_;
char *file_path_; // path dyld used to load the image
uintptr_t file_mod_date_; // time_t of image file
mach_port_t task_;
mach_port_t task_;
};
//==============================================================================
@ -211,13 +201,19 @@ class DynamicImage {
class DynamicImageRef {
public:
explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} // STL required
// The copy constructor is required by STL
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}
bool operator<(const DynamicImageRef &inRef) const {
return (*const_cast<DynamicImageRef*>(this)->p)
< (*const_cast<DynamicImageRef&>(inRef).p);
}
bool operator==(const DynamicImageRef &inInfo) const {
return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() ==
(*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress();
}
// Be just like DynamicImage*
DynamicImage *operator->() {return p;}
operator DynamicImage*() {return p;}
@ -266,10 +262,14 @@ class DynamicImages {
}
void TestPrint() {
const breakpad_mach_header *header;
for (int i = 0; i < (int)image_list_.size(); ++i) {
printf("dyld: %p: name = %s\n", _dyld_get_image_header(i),
_dyld_get_image_name(i) );
const mach_header *header = _dyld_get_image_header(i);
_dyld_get_image_name(i) );
const void *imageHeader = _dyld_get_image_header(i);
header = reinterpret_cast<const breakpad_mach_header*>(imageHeader);
MachHeader(*header).Print();
}
}
@ -279,6 +279,7 @@ class DynamicImages {
// Initialization
void ReadImageInfoForTask();
void* GetDyldAllImageInfosPointer();
mach_port_t task_;
vector<DynamicImageRef> image_list_;
@ -286,7 +287,10 @@ class DynamicImages {
// Returns a malloced block containing the contents of memory at a particular
// location in another task.
void* ReadTaskMemory(task_port_t target_task, const void* address, size_t len);
void* ReadTaskMemory(task_port_t target_task,
const void* address,
size_t len,
kern_return_t *kr);
} // namespace google_breakpad

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

@ -83,7 +83,7 @@ struct ExceptionReplyMessage {
// Only catch these three exceptions. The other ones are nebulously defined
// and may result in treating a non-fatal exception as fatal.
exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
extern "C"
@ -137,8 +137,83 @@ extern "C"
mach_msg_type_number_t thread_state_count,
thread_state_t thread_state,
mach_msg_type_number_t *thread_state_count);
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count);
}
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
return KERN_SUCCESS;
}
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
return KERN_SUCCESS;
}
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count) {
if (task != mach_task_self()) {
return KERN_FAILURE;
}
return ForwardException(task, failed_thread, exception, code, code_count);
}
ExceptionHandler::ExceptionHandler(const string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
@ -150,7 +225,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
callback_context_(callback_context),
directCallback_(NULL),
handler_thread_(NULL),
handler_port_(0),
handler_port_(MACH_PORT_NULL),
previous_(NULL),
installed_exception_handler_(false),
is_in_teardown_(false),
@ -173,7 +248,7 @@ ExceptionHandler::ExceptionHandler(DirectCallback callback,
callback_context_(callback_context),
directCallback_(callback),
handler_thread_(NULL),
handler_port_(0),
handler_port_(MACH_PORT_NULL),
previous_(NULL),
installed_exception_handler_(false),
is_in_teardown_(false),
@ -205,7 +280,7 @@ bool ExceptionHandler::WriteMinidump() {
// the mutex when completed
pthread_mutex_lock(&minidump_write_mutex_);
}
use_minidump_write_mutex_ = false;
UpdateNextID();
return last_minidump_write_result_;
@ -256,14 +331,14 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
// If the user callback returned true and we're handling an exception
// (rather than just writing out the file), then we should exit without
// forwarding the exception to the next handler.
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
result)) {
if (exception_type && exception_code)
_exit(exception_type);
}
}
}
return result;
}
@ -272,20 +347,20 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
exception_data_t code,
mach_msg_type_number_t code_count) {
// At this time, we should have called Uninstall() on the exception handler
// so that the current exception ports are the ones that we should be
// so that the current exception ports are the ones that we should be
// forwarding to.
ExceptionParameters current;
current.count = EXC_TYPES_COUNT;
mach_port_t current_task = mach_task_self();
kern_return_t result = task_get_exception_ports(current_task,
kern_return_t result = task_get_exception_ports(current_task,
s_exception_mask,
current.masks,
&current.count,
current.ports,
current.behaviors,
current.flavors);
// Find the first exception handler that matches the exception
unsigned int found;
for (found = 0; found < current.count; ++found) {
@ -375,12 +450,12 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
sizeof(receive), self->handler_port_,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (result == KERN_SUCCESS) {
// Uninstall our handler so that we don't get in a loop if the process of
// writing out a minidump causes an exception. However, if the exception
// was caused by a fork'd process, don't uninstall things
if (receive.task.name == mach_task_self())
// If the actual exception code is zero, then we're calling this handler
// in a way that indicates that we want to either exit this thread or
// generate a minidump
@ -418,12 +493,15 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// When forking a child process with the exception handler installed,
// if the child crashes, it will send the exception back to the parent
// process. The check for task == self_task() ensures that only
// exceptions that occur in the parent process are caught and
// processed.
// process. The check for task == self_task() ensures that only
// exceptions that occur in the parent process are caught and
// processed. If the exception was not caused by this task, we
// still need to call into the exception server and have it return
// KERN_FAILURE (see breakpad_exception_raise) in order for the kernel
// to move onto the host exception handler for the child task
if (receive.task.name == mach_task_self()) {
self->SuspendThreads();
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
@ -432,28 +510,25 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Generate the minidump with the exception data.
self->WriteMinidumpWithException(receive.exception, receive.code[0],
receive.thread.name);
self->UninstallHandler(true);
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
gBreakpadAllocator->Protect();
#endif
// Pass along the exception to the server, which will setup the
// message and call catch_exception_raise() and put the KERN_SUCCESS
// into the reply.
ExceptionReplyMessage reply;
if (!exc_server(&receive.header, &reply.header))
exit(1);
// Send a reply and exit
result = mach_msg(&(reply.header), MACH_SEND_MSG,
reply.header.msgh_size, 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
} else {
// An exception occurred in a child process
}
// Pass along the exception to the server, which will setup the
// message and call breakpad_exception_raise() and put the return
// code into the reply.
ExceptionReplyMessage reply;
if (!exc_server(&receive.header, &reply.header))
exit(1);
// Send a reply and exit
result = mach_msg(&(reply.header), MACH_SEND_MSG,
reply.header.msgh_size, 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
}
}
}
@ -465,11 +540,11 @@ bool ExceptionHandler::InstallHandler() {
try {
#if USE_PROTECTED_ALLOCATIONS
previous_ = new (gBreakpadAllocator->Allocate(sizeof(ExceptionParameters)) )
ExceptionParameters();
ExceptionParameters();
#else
previous_ = new ExceptionParameters();
#endif
}
catch (std::bad_alloc) {
return false;
@ -478,14 +553,14 @@ bool ExceptionHandler::InstallHandler() {
// Save the current exception ports so that we can forward to them
previous_->count = EXC_TYPES_COUNT;
mach_port_t current_task = mach_task_self();
kern_return_t result = task_get_exception_ports(current_task,
kern_return_t result = task_get_exception_ports(current_task,
s_exception_mask,
previous_->masks,
&previous_->count,
previous_->ports,
previous_->behaviors,
previous_->flavors);
// Setup the exception ports on this task
if (result == KERN_SUCCESS)
result = task_set_exception_ports(current_task, s_exception_mask,
@ -499,10 +574,10 @@ bool ExceptionHandler::InstallHandler() {
bool ExceptionHandler::UninstallHandler(bool in_exception) {
kern_return_t result = KERN_SUCCESS;
if (installed_exception_handler_) {
mach_port_t current_task = mach_task_self();
// Restore the previous ports
for (unsigned int i = 0; i < previous_->count; ++i) {
result = task_set_exception_ports(current_task, previous_->masks[i],
@ -512,20 +587,20 @@ bool ExceptionHandler::UninstallHandler(bool in_exception) {
if (result != KERN_SUCCESS)
return false;
}
// this delete should NOT happen if an exception just occurred!
if (!in_exception) {
#if USE_PROTECTED_ALLOCATIONS
previous_->~ExceptionParameters();
#else
delete previous_;
delete previous_;
#endif
}
previous_ = NULL;
installed_exception_handler_ = false;
}
return result == KERN_SUCCESS;
}
@ -552,7 +627,7 @@ bool ExceptionHandler::Setup(bool install_handler) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int thread_create_result = pthread_create(&handler_thread_, &attr,
int thread_create_result = pthread_create(&handler_thread_, &attr,
&WaitForMessage, this);
pthread_attr_destroy(&attr);
result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;
@ -567,7 +642,7 @@ bool ExceptionHandler::Teardown() {
if (!UninstallHandler(false))
return false;
// Send an empty message so that the handler_thread exits
if (SendEmptyMachMessage()) {
mach_port_t current_task = mach_task_self();
@ -577,7 +652,7 @@ bool ExceptionHandler::Teardown() {
} else {
return false;
}
handler_thread_ = NULL;
handler_port_ = NULL;
pthread_mutex_destroy(&minidump_write_mutex_);
@ -622,7 +697,7 @@ bool ExceptionHandler::SuspendThreads() {
return false;
}
}
return true;
}
@ -640,7 +715,7 @@ bool ExceptionHandler::ResumeThreads() {
return false;
}
}
return true;
}

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

@ -58,14 +58,14 @@ class ExceptionHandler {
// 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_dir>/<minidump_id>.dmp.
// |context| is the value passed into the constructor.
// |context| is the value passed into the constructor.
// |succeeded| indicates whether a minidump file was successfully written.
// Return true if the exception was fully handled and breakpad should exit.
// Return false to allow any other exception handlers to process the
// Return false to allow any other exception handlers to process the
// exception.
typedef bool (*MinidumpCallback)(const char *dump_dir,
const char *minidump_id,
@ -85,7 +85,7 @@ class ExceptionHandler {
// 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 string &dump_path,
ExceptionHandler(const string &dump_path,
FilterCallback filter, MinidumpCallback callback,
void *callback_context, bool install_handler);
@ -104,7 +104,7 @@ class ExceptionHandler {
dump_path_c_ = dump_path_.c_str();
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
}
// Writes a minidump immediately. This can be used to capture the
// execution state independently of a crash. Returns true on success.
bool WriteMinidump();
@ -120,11 +120,11 @@ class ExceptionHandler {
// Uninstall the mach exception handler (if any)
bool UninstallHandler(bool in_exception);
// Setup the handler thread, and if |install_handler| is true, install the
// mach exception port handler
bool Setup(bool install_handler);
// Uninstall the mach exception handler (if any) and terminate the helper
// thread
bool Teardown();
@ -149,20 +149,20 @@ class ExceptionHandler {
// path of the next minidump to be written in next_minidump_path_.
void UpdateNextID();
// These functions will suspend/resume all threads except for the
// These functions will suspend/resume all threads except for the
// reporting thread
bool SuspendThreads();
bool ResumeThreads();
// The destination directory for the minidump
string dump_path_;
// The basename of the next minidump w/o extension
string next_minidump_id_;
// The full path to the next minidump to be written, including extension
string next_minidump_path_;
// Pointers to the UTF-8 versions of above
const char *dump_path_c_;
const char *next_minidump_id_c_;
@ -191,18 +191,18 @@ class ExceptionHandler {
// True, if we've installed the exception handler
bool installed_exception_handler_;
// True, if we're in the process of uninstalling the exception handler and
// the thread.
bool is_in_teardown_;
// Save the last result of the last minidump
bool last_minidump_write_result_;
// A mutex for use when writing out a minidump that was requested on a
// A mutex for use when writing out a minidump that was requested on a
// thread other than the exception handler.
pthread_mutex_t minidump_write_mutex_;
// True, if we're using the mutext to indicate when mindump writing occurs
bool use_minidump_write_mutex_;
};

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

@ -30,11 +30,13 @@
#include <cstdio>
#include <mach/host_info.h>
#include <mach/mach_vm.h>
#include <mach/vm_statistics.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
#include <mach/mach_vm.h>
#include <CoreFoundation/CoreFoundation.h>
@ -48,7 +50,7 @@ using MacStringUtils::IntegerValueAtIndex;
namespace google_breakpad {
// constructor when generating from within the crashed process
// constructor when generating from within the crashed process
MinidumpGenerator::MinidumpGenerator()
: exception_type_(0),
exception_code_(0),
@ -59,8 +61,10 @@ MinidumpGenerator::MinidumpGenerator()
GatherSystemInformation();
}
// constructor when generating from a different process than the crashed process
MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread)
// constructor when generating from a different process than the
// crashed process
MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
mach_port_t handler_thread)
: exception_type_(0),
exception_code_(0),
exception_thread_(0),
@ -71,7 +75,7 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, mach_port_t hand
} else {
dynamic_images_ = NULL;
}
GatherSystemInformation();
}
@ -89,26 +93,29 @@ void MinidumpGenerator::GatherSystemInformation() {
// If this is non-zero, then we've already gathered the information
if (os_major_version_)
return;
// This code extracts the version and build information from the OS
CFStringRef vers_path =
CFSTR("/System/Library/CoreServices/SystemVersion.plist");
CFURLRef sys_vers =
CFURLCreateWithFileSystemPath(NULL, vers_path, kCFURLPOSIXPathStyle, false);
CFURLCreateWithFileSystemPath(NULL,
vers_path,
kCFURLPOSIXPathStyle,
false);
CFDataRef data;
SInt32 error;
CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
&error);
if (!data)
return;
CFDictionaryRef list = static_cast<CFDictionaryRef>
(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
NULL));
if (!list)
return;
CFStringRef build_version = static_cast<CFStringRef>
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
CFStringRef product_version = static_cast<CFStringRef>
@ -203,102 +210,161 @@ bool MinidumpGenerator::Write(const char *path) {
dir.CopyIndex(i, &local_dir);
}
}
return result;
}
size_t MinidumpGenerator::CalculateStackSize(vm_address_t start_addr) {
vm_address_t stack_region_base = start_addr;
vm_size_t stack_region_size;
size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
mach_vm_address_t stack_region_base = start_addr;
mach_vm_size_t stack_region_size;
natural_t nesting_level = 0;
vm_region_submap_info submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT;
kern_return_t result =
vm_region_recurse(crashing_task_, &stack_region_base, &stack_region_size,
&nesting_level,
reinterpret_cast<vm_region_recurse_info_t>(&submap_info),
&info_count);
vm_region_submap_info_64 submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
if ((stack_region_base + stack_region_size) == 0xbffff000) {
// The stack for thread 0 needs to extend all the way to 0xc0000000
// For many processes the stack is first created in one page
// from 0xbffff000 - 0xc0000000 and is then later extended to
// a much larger size by creating a new VM region immediately below
// the initial page
vm_region_recurse_info_t region_info;
region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);
// include the original stack frame page (0xbffff000 - 0xc0000000)
stack_region_size += 0x1000;
if (start_addr == 0) {
return 0;
}
return result == KERN_SUCCESS ?
kern_return_t result =
mach_vm_region_recurse(crashing_task_, &stack_region_base,
&stack_region_size, &nesting_level,
region_info,
&info_count);
if (start_addr < stack_region_base) {
// probably stack corruption, since mach_vm_region had to go
// higher in the process address space to find a valid region.
return 0;
}
if ((stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK) {
// The stack for thread 0 needs to extend all the way to
// 0xc0000000 on 32 bit and 00007fff5fc00000 on 64bit. HOWEVER,
// for many processes, the stack is first created in one page
// below this, and is then later extended to a much larger size by
// creating a new VM region immediately below the initial page.
// You can see this for yourself by running vmmap on a "hello,
// world" program
// Because of the above, we'll add 4k to include the original
// stack frame page.
// This method of finding the stack region needs to be done in
// a better way; the breakpad issue 247 is tracking this.
stack_region_size += 0x1000;
}
return result == KERN_SUCCESS ?
stack_region_base + stack_region_size - start_addr : 0;
}
bool MinidumpGenerator::WriteStackFromStartAddress(
vm_address_t start_addr,
mach_vm_address_t start_addr,
MDMemoryDescriptor *stack_location) {
UntypedMDRVA memory(&writer_);
bool result = false;
size_t size = CalculateStackSize(start_addr);
// If there's an error in the calculation, return at least the current
// stack information
if (size == 0)
size = 16;
if (size == 0) {
// In some situations the stack address for the thread can come back 0.
// In these cases we skip over the threads in question and stuff the
// stack with a clearly borked value.
start_addr = 0xDEADBEEF;
size = 16;
if (!memory.Allocate(size))
return false;
if (!memory.Allocate(size))
return false;
unsigned long long dummy_stack[2]; // Fill dummy stack with 16 bytes of
// junk.
dummy_stack[0] = 0xDEADBEEF;
dummy_stack[1] = 0xDEADBEEF;
bool result;
if (dynamic_images_) {
void *stack_memory = ReadTaskMemory(crashing_task_, (void*)start_addr, size);
result = memory.Copy(stack_memory, size);
free(stack_memory);
result = memory.Copy(dummy_stack, size);
} else {
result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
if (!memory.Allocate(size))
return false;
if (dynamic_images_) {
kern_return_t kr;
void *stack_memory = ReadTaskMemory(crashing_task_,
(void*)start_addr,
size,
&kr);
if (stack_memory == NULL) {
return false;
}
result = memory.Copy(stack_memory, size);
free(stack_memory);
} else {
result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
}
}
stack_location->start_of_memory_range = start_addr;
stack_location->memory = memory.location();
return result;
}
#if TARGET_CPU_PPC
#if TARGET_CPU_PPC || TARGET_CPU_PPC64
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location) {
ppc_thread_state_t *machine_state =
reinterpret_cast<ppc_thread_state_t *>(state);
vm_address_t start_addr = machine_state->r1;
breakpad_thread_state_t *machine_state =
reinterpret_cast<breakpad_thread_state_t *>(state);
#if TARGET_CPU_PPC
mach_vm_address_t start_addr = machine_state->r1;
#else
mach_vm_address_t start_addr = machine_state->__r1;
#endif
return WriteStackFromStartAddress(start_addr, stack_location);
}
u_int64_t MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
ppc_thread_state_t *machine_state =
reinterpret_cast<ppc_thread_state_t *>(state);
u_int64_t
MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
breakpad_thread_state_t *machine_state =
reinterpret_cast<breakpad_thread_state_t *>(state);
#if TARGET_CPU_PPC
return machine_state->srr0;
#else
return machine_state->__srr0;
#endif
}
bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location) {
TypedMDRVA<MDRawContextPPC> context(&writer_);
ppc_thread_state_t *machine_state =
reinterpret_cast<ppc_thread_state_t *>(state);
TypedMDRVA<MinidumpContext> context(&writer_);
breakpad_thread_state_t *machine_state =
reinterpret_cast<breakpad_thread_state_t *>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
MDRawContextPPC *context_ptr = context.get();
MinidumpContext *context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
#if TARGET_CPU_PPC64
#define AddReg(a) context_ptr->a = machine_state->__ ## a
#define AddGPR(a) context_ptr->gpr[a] = machine_state->__r ## a
#else
#define AddReg(a) context_ptr->a = machine_state->a
#define AddGPR(a) context_ptr->gpr[a] = machine_state->r ## a
#endif
AddReg(srr0);
AddReg(cr);
AddReg(xer);
AddReg(ctr);
AddReg(mq);
AddReg(lr);
AddReg(vrsave);
@ -334,38 +400,68 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
AddGPR(29);
AddGPR(30);
AddGPR(31);
#if TARGET_CPU_PPC
/* The mq register is only for PPC */
AddReg(mq);
#endif
return true;
}
#elif TARGET_CPU_X86
#elif TARGET_CPU_X86 || TARGET_CPU_X86_64
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location) {
i386_thread_state_t *machine_state =
reinterpret_cast<i386_thread_state_t *>(state);
vm_address_t start_addr = machine_state->esp;
breakpad_thread_state_t *machine_state =
reinterpret_cast<breakpad_thread_state_t *>(state);
#if TARGET_CPU_X86_64
mach_vm_address_t start_addr = machine_state->__rsp;
#else
mach_vm_address_t start_addr = machine_state->esp;
#endif
return WriteStackFromStartAddress(start_addr, stack_location);
}
u_int64_t MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
i386_thread_state_t *machine_state =
reinterpret_cast<i386_thread_state_t *>(state);
u_int64_t
MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
breakpad_thread_state_t *machine_state =
reinterpret_cast<breakpad_thread_state_t *>(state);
#if TARGET_CPU_X86_64
return machine_state->__rip;
#else
return machine_state->eip;
#endif
}
bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location) {
TypedMDRVA<MDRawContextX86> context(&writer_);
i386_thread_state_t *machine_state =
reinterpret_cast<i386_thread_state_t *>(state);
TypedMDRVA<MinidumpContext> context(&writer_);
breakpad_thread_state_t *machine_state =
reinterpret_cast<breakpad_thread_state_t *>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
MDRawContextX86 *context_ptr = context.get();
MinidumpContext *context_ptr = context.get();
#if TARGET_CPU_X86
context_ptr->context_flags = MD_CONTEXT_X86;
#define AddReg(a) context_ptr->a = machine_state->a
AddReg(eax);
AddReg(ebx);
AddReg(ecx);
AddReg(edx);
AddReg(esi);
AddReg(edi);
AddReg(ebp);
AddReg(esp);
AddReg(cs);
AddReg(ds);
AddReg(ss);
@ -375,14 +471,37 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
AddReg(eflags);
AddReg(eip);
AddReg(eax);
AddReg(ebx);
AddReg(ecx);
AddReg(edx);
AddReg(esi);
AddReg(edi);
AddReg(ebp);
AddReg(esp);
#else
#define AddReg(a) context_ptr->a = machine_state->__ ## a
context_ptr->context_flags = MD_CONTEXT_AMD64;
AddReg(rax);
AddReg(rbx);
AddReg(rcx);
AddReg(rdx);
AddReg(rdi);
AddReg(rsi);
AddReg(rbp);
AddReg(rsp);
AddReg(r8);
AddReg(r9);
AddReg(r10);
AddReg(r11);
AddReg(r12);
AddReg(r13);
AddReg(r14);
AddReg(r15);
AddReg(rip);
// according to AMD's software developer guide, bits above 18 are
// not used in the flags register. Since the minidump format
// specifies 32 bits for the flags register, we can truncate safely
// with no loss.
context_ptr->eflags = machine_state->__rflags;
AddReg(cs);
AddReg(fs);
AddReg(gs);
#endif
return true;
}
#endif
@ -447,7 +566,8 @@ bool MinidumpGenerator::WriteThreadListStream(
return true;
}
bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
bool
MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
TypedMDRVA<MDRawExceptionStream> exception(&writer_);
if (!exception.Allocate())
@ -466,7 +586,9 @@ bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
breakpad_thread_state_data_t state;
mach_msg_type_number_t stateCount = sizeof(state);
if (thread_get_state(exception_thread_, BREAKPAD_MACHINE_THREAD_STATE, state,
if (thread_get_state(exception_thread_,
BREAKPAD_MACHINE_THREAD_STATE,
state,
&stateCount) != KERN_SUCCESS)
return false;
@ -508,13 +630,13 @@ bool MinidumpGenerator::WriteSystemInfoStream(
// to preserve it.
#define cpuid(op,eax,ebx,ecx,edx) \
asm ("pushl %%ebx \n\t" \
"cpuid \n\t" \
"movl %%ebx,%1 \n\t" \
"popl %%ebx" \
: "=a" (eax), \
"=g" (ebx), \
"=c" (ecx), \
"=d" (edx) \
"cpuid \n\t" \
"movl %%ebx,%1 \n\t" \
"popl %%ebx" \
: "=a" (eax), \
"=g" (ebx), \
"=c" (ecx), \
"=d" (edx) \
: "0" (op))
int unused, unused2;
// get vendor id
@ -564,7 +686,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
if (!image)
return false;
const mach_header *header = image->GetMachHeader();
const breakpad_mach_header *header = image->GetMachHeader();
if (!header)
return false;
@ -583,16 +705,49 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
module->size_of_image = image->GetVMSize();
module->module_name_rva = string_location.rva;
// We'll skip the executable module, because they don't have
// LC_ID_DYLIB load commands, and the crash processing server gets
// version information from the Plist file, anyway.
if (index != (uint32_t)FindExecutableModule()) {
module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
// Convert MAC dylib version format, which is a 32 bit number, to the
// format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits>
// so it fits nicely into the windows version with some massaging
// The mapping is:
// 1) upper 16 bits of MAC version go to lower 16 bits of product HI
// 2) Next most significant 8 bits go to upper 16 bits of product LO
// 3) Least significant 8 bits go to lower 16 bits of product LO
uint32_t modVersion = image->GetVersion();
module->version_info.file_version_hi = 0;
module->version_info.file_version_hi = modVersion >> 16;
module->version_info.file_version_lo |= (modVersion & 0xff00) << 8;
module->version_info.file_version_lo |= (modVersion & 0xff);
}
if (!WriteCVRecord(module, cpu_type, name)) {
return false;
}
} else {
// we're getting module info in the crashed process
const struct mach_header *header = _dyld_get_image_header(index);
const breakpad_mach_header *header;
header = (breakpad_mach_header*)_dyld_get_image_header(index);
if (!header)
return false;
#ifdef __LP64__
assert(header->magic == MH_MAGIC_64);
if(header->magic != MH_MAGIC_64)
return false;
#else
assert(header->magic == MH_MAGIC);
if(header->magic != MH_MAGIC)
return false;
#endif
int cpu_type = header->cputype;
unsigned long slide = _dyld_get_image_vmaddr_slide(index);
const char* name = _dyld_get_image_name(index);
@ -603,8 +758,10 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
if (cmd->cmd == LC_SEGMENT) {
const struct segment_command *seg =
reinterpret_cast<const struct segment_command *>(cmd);
const breakpad_mach_segment_command *seg =
reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
MDLocationDescriptor string_location;
@ -622,10 +779,10 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
}
}
cmd = reinterpret_cast<struct load_command *>((char *)cmd + cmd->cmdsize);
cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize);
}
}
return true;
}
@ -647,7 +804,7 @@ int MinidumpGenerator::FindExecutableModule() {
return index;
}
}
// failed - just use the first image
return 0;
}
@ -681,9 +838,9 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
// Get the module identifier
FileID file_id(module_path);
unsigned char identifier[16];
if (file_id.MachoIdentifier(cpu_type, identifier)) {
cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
(uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
(uint32_t)identifier[3];
cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5];
@ -705,9 +862,6 @@ bool MinidumpGenerator::WriteModuleListStream(
MDRawDirectory *module_list_stream) {
TypedMDRVA<MDRawModuleList> list(&writer_);
if (!_dyld_present())
return false;
int image_count = dynamic_images_ ?
dynamic_images_->GetImageCount() : _dyld_image_count();
@ -770,12 +924,15 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, info_ptr->process_id };
size_t size;
if (!sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &size, NULL, 0)) {
vm_address_t addr;
if (vm_allocate(mach_task_self(), &addr, size, true) == KERN_SUCCESS) {
mach_vm_address_t addr;
if (mach_vm_allocate(mach_task_self(),
&addr,
size,
true) == KERN_SUCCESS) {
struct kinfo_proc *proc = (struct kinfo_proc *)addr;
if (!sysctl(mib, sizeof(mib) / sizeof(mib[0]), proc, &size, NULL, 0))
info_ptr->process_create_time = proc->kp_proc.p_starttime.tv_sec;
vm_deallocate(mach_task_self(), addr, size);
mach_vm_deallocate(mach_task_self(), addr, size);
}
}

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

@ -46,6 +46,26 @@ namespace google_breakpad {
using std::string;
#if TARGET_CPU_X86_64 || TARGET_CPU_PPC64
#define TOP_OF_THREAD0_STACK 0x00007fff5fbff000
#else
#define TOP_OF_THREAD0_STACK 0xbffff000
#endif
#if TARGET_CPU_X86_64
typedef x86_thread_state64_t breakpad_thread_state_t;
typedef MDRawContextAMD64 MinidumpContext;
#elif TARGET_CPU_X86
typedef i386_thread_state_t breakpad_thread_state_t;
typedef MDRawContextX86 MinidumpContext;
#elif TARGET_CPU_PPC64
typedef ppc_thread_state64_t breakpad_thread_state_t;
typedef MDRawContextPPC64 MinidumpContext;
#elif TARGET_CPU_PPC
typedef ppc_thread_state_t breakpad_thread_state_t;
typedef MDRawContextPPC MinidumpContext;
#endif
// Creates a minidump file of the current process. If there is exception data,
// use SetExceptionInformation() to add this to the minidump. The minidump
// file is generated by the Write() function.
@ -93,7 +113,7 @@ class MinidumpGenerator {
// Helpers
u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state);
bool WriteStackFromStartAddress(vm_address_t start_addr,
bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
MDMemoryDescriptor *stack_location);
bool WriteStack(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
@ -103,7 +123,9 @@ class MinidumpGenerator {
bool WriteCVRecord(MDRawModule *module, int cpu_type,
const char *module_path);
bool WriteModuleStream(unsigned int index, MDRawModule *module);
size_t CalculateStackSize(vm_address_t start_addr);
size_t CalculateStackSize(mach_vm_address_t start_addr);
int FindExecutableModule();
// disallow copy ctor and operator=

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

@ -48,9 +48,13 @@ static void *Reporter(void *) {
struct passwd *user = getpwuid(getuid());
// Write it to the desktop
snprintf(buffer, sizeof(buffer), "/Users/%s/Desktop/test.dmp", user->pw_name);
snprintf(buffer,
sizeof(buffer),
"/Users/%s/Desktop/test.dmp",
user->pw_name);
fprintf(stdout, "Writing %s\n", buffer);
unlink(buffer);
md.Write(buffer);
doneWritingReport = true;

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

@ -49,6 +49,24 @@
D2F6511E0BEF973600920385 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; };
D2F6511F0BEF973900920385 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; };
D2F651210BEF975400920385 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; };
F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; };
F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; };
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; };
F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; };
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F310E8B07E800D7E813 /* dwarftests.mm */; };
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.mm */; };
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F760E8B0DC700D7E813 /* bytereader.cc */; };
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */; };
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F780E8B0DC700D7E813 /* functioninfo.cc */; };
F93A888B0E8B4C9A0026AF89 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = F9721FA80E8B0E4800D7E813 /* md5.c */; };
F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */; };
F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */; };
F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */; };
F98208A30DB32CAE0017AECA /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; };
F9AE5B390DBFDBDB00505983 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; };
F9AE5B3A0DBFDBDB00505983 /* DynamicImagesTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */; };
F9B34E870DBC1E1600306484 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; };
F9C5A4220DB82DD800209C76 /* DynamicImagesTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -106,6 +124,30 @@
D2F651080BEF949A00920385 /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dynamic_images.h; sourceTree = "<group>"; };
D2F6510C0BEF94EB00920385 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; };
D2F6510D0BEF94EB00920385 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; };
F917C4F70E03265A00F86017 /* breakpad_exc_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = breakpad_exc_server.c; sourceTree = "<group>"; };
F917C4F80E03265A00F86017 /* breakpad_exc_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_exc_server.h; sourceTree = "<group>"; };
F93A88750E8B4C700026AF89 /* octestcases.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = octestcases.octest; sourceTree = BUILT_PRODUCTS_DIR; };
F93A88760E8B4C700026AF89 /* obj-cTestCases-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "obj-cTestCases-Info.plist"; sourceTree = "<group>"; };
F9721F300E8B07E800D7E813 /* dwarftests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dwarftests.h; sourceTree = "<group>"; };
F9721F310E8B07E800D7E813 /* dwarftests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dwarftests.mm; sourceTree = "<group>"; };
F9721F380E8B0CFC00D7E813 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; };
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.mm; path = ../../../common/mac/dump_syms.mm; sourceTree = SOURCE_ROOT; };
F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
F9721F760E8B0DC700D7E813 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/mac/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/mac/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
F9721F780E8B0DC700D7E813 /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/mac/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; };
F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = /System/Library/Frameworks/SenTestingKit.framework; sourceTree = "<absolute>"; };
F9721FA80E8B0E4800D7E813 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../../../common/md5.c; sourceTree = SOURCE_ROOT; };
F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_test.h; sourceTree = "<group>"; };
F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_test.cc; sourceTree = "<group>"; };
F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = "<group>"; };
F98208A20DB32CAE0017AECA /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_64.h; sourceTree = "<group>"; };
F9AE19B50DB040E300C98454 /* minidump_tests32-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "minidump_tests32-Info.plist"; sourceTree = "<group>"; };
F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = minidump_tests64.cptest; sourceTree = BUILT_PRODUCTS_DIR; };
F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = minidump_tests32.cptest; sourceTree = BUILT_PRODUCTS_DIR; };
F9AE5B340DBFDBA300505983 /* minidump_tests64-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "minidump_tests64-Info.plist"; sourceTree = "<group>"; };
F9C5A4200DB82DD800209C76 /* DynamicImagesTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicImagesTests.h; sourceTree = "<group>"; };
F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicImagesTests.cc; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -132,12 +174,45 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F93A88720E8B4C700026AF89 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE19C00DB04A9500C98454 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE5B300DBFDBA300505983 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */,
F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* MinidumpWriter */ = {
isa = PBXGroup;
children = (
F9721FA80E8B0E4800D7E813 /* md5.c */,
F9721F760E8B0DC700D7E813 /* bytereader.cc */,
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */,
F9721F780E8B0DC700D7E813 /* functioninfo.cc */,
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */,
F9721F380E8B0CFC00D7E813 /* dump_syms.h */,
F917C4F70E03265A00F86017 /* breakpad_exc_server.c */,
F917C4F80E03265A00F86017 /* breakpad_exc_server.h */,
F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */,
F98208A20DB32CAE0017AECA /* breakpad_nlist_64.h */,
D2F6510C0BEF94EB00920385 /* macho_walker.cc */,
D2F6510D0BEF94EB00920385 /* macho_walker.h */,
D2F651070BEF949A00920385 /* dynamic_images.cc */,
@ -148,10 +223,14 @@
D2F650FD0BEF947200920385 /* macho_id.h */,
D2F650FE0BEF947200920385 /* macho_utilities.cc */,
D2F650FF0BEF947200920385 /* macho_utilities.h */,
F9C5A41F0DB82DB000209C76 /* testcases */,
9BD82C040B0133420055103E /* Breakpad */,
08FB7795FE84155DC02AAC07 /* Source */,
9B37CEEA0AF98EB600FA4BD4 /* Frameworks */,
1AB674ADFE9D54B511CA2CBB /* Products */,
F9AE19B50DB040E300C98454 /* minidump_tests32-Info.plist */,
F9AE5B340DBFDBA300505983 /* minidump_tests64-Info.plist */,
F93A88760E8B4C700026AF89 /* obj-cTestCases-Info.plist */,
);
name = MinidumpWriter;
sourceTree = "<group>";
@ -172,6 +251,9 @@
8DD76F6C0486A84900D96B5E /* generator_test */,
9BD82A9B0B00267E0055103E /* handler_test */,
9B7CA84E0B1297F200CD3A1D /* unit_test */,
F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */,
F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */,
F93A88750E8B4C700026AF89 /* octestcases.octest */,
);
name = Products;
sourceTree = "<group>";
@ -179,6 +261,8 @@
9B37CEEA0AF98EB600FA4BD4 /* Frameworks */ = {
isa = PBXGroup;
children = (
F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */,
F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */,
9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */,
);
name = Frameworks;
@ -204,6 +288,19 @@
name = Breakpad;
sourceTree = "<group>";
};
F9C5A41F0DB82DB000209C76 /* testcases */ = {
isa = PBXGroup;
children = (
F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */,
F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */,
F9C5A4200DB82DD800209C76 /* DynamicImagesTests.h */,
F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */,
F9721F300E8B07E800D7E813 /* dwarftests.h */,
F9721F310E8B07E800D7E813 /* dwarftests.mm */,
);
path = testcases;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -257,23 +354,148 @@
productReference = 9BD82A9B0B00267E0055103E /* handler_test */;
productType = "com.apple.product-type.tool";
};
F93A88740E8B4C700026AF89 /* obj-c_TestCases */ = {
isa = PBXNativeTarget;
buildConfigurationList = F93A88790E8B4C700026AF89 /* Build configuration list for PBXNativeTarget "obj-c_TestCases" */;
buildPhases = (
F93A88700E8B4C700026AF89 /* Resources */,
F93A88710E8B4C700026AF89 /* Sources */,
F93A88720E8B4C700026AF89 /* Frameworks */,
F93A88730E8B4C700026AF89 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = "obj-c_TestCases";
productName = octestcases;
productReference = F93A88750E8B4C700026AF89 /* octestcases.octest */;
productType = "com.apple.product-type.bundle";
};
F9AE19C20DB04A9500C98454 /* minidump_tests64 */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9AE19C70DB04AA200C98454 /* Build configuration list for PBXNativeTarget "minidump_tests64" */;
buildPhases = (
F9AE19BE0DB04A9500C98454 /* Resources */,
F9AE19BF0DB04A9500C98454 /* Sources */,
F9AE19C00DB04A9500C98454 /* Frameworks */,
F9AE19C10DB04A9500C98454 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = minidump_tests64;
productName = minidump_tests;
productReference = F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */;
productType = "com.apple.product-type.bundle";
};
F9AE5B320DBFDBA300505983 /* minidump_tests32 */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9AE5B380DBFDBA300505983 /* Build configuration list for PBXNativeTarget "minidump_tests32" */;
buildPhases = (
F9AE5B2E0DBFDBA300505983 /* Resources */,
F9AE5B2F0DBFDBA300505983 /* Sources */,
F9AE5B300DBFDBA300505983 /* Frameworks */,
F9AE5B310DBFDBA300505983 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = minidump_tests32;
productName = Untitled;
productReference = F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "minidump_test" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* MinidumpWriter */;
projectDirPath = "";
projectRoot = "";
targets = (
8DD76F620486A84900D96B5E /* generator_test */,
9BD82A9A0B00267E0055103E /* handler_test */,
9B7CA84D0B1297F200CD3A1D /* unit_test */,
F9AE19C20DB04A9500C98454 /* minidump_tests64 */,
F9AE5B320DBFDBA300505983 /* minidump_tests32 */,
F93A88740E8B4C700026AF89 /* obj-c_TestCases */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
F93A88700E8B4C700026AF89 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE19BE0DB04A9500C98454 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE5B2E0DBFDBA300505983 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
F93A88730E8B4C700026AF89 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n";
};
F9AE19C10DB04A9500C98454 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n# Run gcov on the framework getting tested\nif [ \"${CONFIGURATION}\" = 'Coverage' ];\nthen\n FRAMEWORK_NAME=minidump_tests64\n FRAMEWORK_OBJ_DIR=${OBJROOT}/${PROJECT_NAME}.build/${CONFIGURATION}/${FRAMEWORK_NAME}.build/Objects-normal/${NATIVE_ARCH_ACTUAL}\n mkdir -p coverage\n pushd coverage\n echo find ${OBJROOT} -name *.gcda -exec gcov -o ${FRAMEWORK_OBJ_DIR} {} \\;\n find ${OBJROOT} -name *.gcda -exec gcov -o ${FRAMEWORK_OBJ_DIR} {} \\;\n popd\nfi ";
};
F9AE5B310DBFDBA300505983 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8DD76F640486A84900D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -324,6 +546,43 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F93A88710E8B4C700026AF89 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */,
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */,
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */,
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */,
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */,
F93A888B0E8B4C9A0026AF89 /* md5.c in Sources */,
F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */,
F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */,
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */,
F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE19BF0DB04A9500C98454 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F9B34E870DBC1E1600306484 /* dynamic_images.cc in Sources */,
F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */,
F98208A30DB32CAE0017AECA /* breakpad_nlist_64.cc in Sources */,
F9C5A4220DB82DD800209C76 /* DynamicImagesTests.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE5B2F0DBFDBA300505983 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F9AE5B390DBFDBDB00505983 /* dynamic_images.cc in Sources */,
F9AE5B3A0DBFDBDB00505983 /* DynamicImagesTests.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
@ -456,6 +715,182 @@
};
name = Release;
};
F93A88770E8B4C700026AF89 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
GCC_CHAR_IS_UNSIGNED_CHAR = YES;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
INFOPLIST_FILE = "obj-cTestCases-Info.plist";
INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles";
OTHER_LDFLAGS = (
"-lcrypto",
"-framework",
Cocoa,
"-framework",
SenTestingKit,
);
PREBINDING = NO;
PRODUCT_NAME = octestcases;
USER_HEADER_SEARCH_PATHS = "../../../..//**";
WRAPPER_EXTENSION = octest;
};
name = Debug;
};
F93A88780E8B4C700026AF89 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
GCC_CHAR_IS_UNSIGNED_CHAR = YES;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_MODEL_TUNING = G5;
INFOPLIST_FILE = "obj-cTestCases-Info.plist";
INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles";
OTHER_LDFLAGS = (
"-lcrypto",
"-framework",
Cocoa,
"-framework",
SenTestingKit,
);
PREBINDING = NO;
PRODUCT_NAME = octestcases;
USER_HEADER_SEARCH_PATHS = "../../../..//**";
WRAPPER_EXTENSION = octest;
ZERO_LINK = NO;
};
name = Release;
};
F9AE19C40DB04A9500C98454 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
"$(NATIVE_ARCH_64_BIT)",
ppc64,
);
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Headers/Carbon.h";
INFOPLIST_FILE = "minidump_tests64-Info.plist";
INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles";
MACOSX_DEPLOYMENT_TARGET = 10.5;
OTHER_LDFLAGS = (
"-framework",
Carbon,
"-framework",
CPlusTest,
);
PREBINDING = NO;
PRODUCT_NAME = minidump_tests64;
SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
};
name = Debug;
};
F9AE19C50DB04A9500C98454 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
"$(NATIVE_ARCH_64_BIT)",
ppc64,
);
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Headers/Carbon.h";
INFOPLIST_FILE = "minidump_tests64-Info.plist";
INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles";
MACOSX_DEPLOYMENT_TARGET = 10.5;
OTHER_LDFLAGS = (
"-framework",
Carbon,
"-framework",
CPlusTest,
);
PREBINDING = NO;
PRODUCT_NAME = minidump_tests64;
SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
ZERO_LINK = NO;
};
name = Release;
};
F9AE5B350DBFDBA300505983 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH)";
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Headers/Carbon.h";
INFOPLIST_FILE = "minidump_tests32-Info.plist";
INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles";
OTHER_LDFLAGS = (
"-framework",
Carbon,
"-framework",
CPlusTest,
"-lcrypto",
);
PREBINDING = NO;
PRODUCT_NAME = minidump_tests32;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
};
name = Debug;
};
F9AE5B370DBFDBA300505983 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH)";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Headers/Carbon.h";
INFOPLIST_FILE = "minidump_tests32-Info.plist";
INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles";
OTHER_LDFLAGS = (
"-lcrypto",
"-framework",
Carbon,
"-framework",
CPlusTest,
);
PREBINDING = NO;
PRODUCT_NAME = minidump_tests32;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
ZERO_LINK = NO;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -495,6 +930,33 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F93A88790E8B4C700026AF89 /* Build configuration list for PBXNativeTarget "obj-c_TestCases" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F93A88770E8B4C700026AF89 /* Debug */,
F93A88780E8B4C700026AF89 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F9AE19C70DB04AA200C98454 /* Build configuration list for PBXNativeTarget "minidump_tests64" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9AE19C40DB04A9500C98454 /* Debug */,
F9AE19C50DB04A9500C98454 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F9AE5B380DBFDBA300505983 /* Build configuration list for PBXNativeTarget "minidump_tests32" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9AE5B350DBFDBA300505983 /* Debug */,
F9AE5B370DBFDBA300505983 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;

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

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.google.breakpad.minidump_tests32</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

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

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.google.breakpad.minidump_tests64</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>
<string>yes</string>
</dict>
</plist>

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

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

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

@ -0,0 +1,85 @@
// 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.
//
// DynamicImagesTests.cpp
// minidump_test
//
// Created by Neal Sidhwaney on 4/17/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#include "client/mac/handler/testcases/DynamicImagesTests.h"
#include "client/mac/handler/dynamic_images.h"
DynamicImagesTests test2(TEST_INVOCATION(DynamicImagesTests,
ReadTaskMemoryTest));
DynamicImagesTests test3(TEST_INVOCATION(DynamicImagesTests,
ReadLibrariesFromLocalTaskTest));
DynamicImagesTests::DynamicImagesTests(TestInvocation *invocation)
: TestCase(invocation) {
}
DynamicImagesTests::~DynamicImagesTests() {
}
void DynamicImagesTests::ReadTaskMemoryTest() {
kern_return_t kr;
// pick test2 as a symbol we know to be valid to read
// anything will work, really
void *addr = reinterpret_cast<void*>(&test2);
void *buf;
fprintf(stderr, "reading 0x%p\n", addr);
buf = google_breakpad::ReadTaskMemory(mach_task_self(),
addr,
getpagesize(),
&kr);
CPTAssert(kr == KERN_SUCCESS);
CPTAssert(buf != NULL);
CPTAssert(0 == memcmp(buf, (const void*)addr, getpagesize()));
free(buf);
}
void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() {
mach_port_t me = mach_task_self();
google_breakpad::DynamicImages *d = new google_breakpad::DynamicImages(me);
fprintf(stderr,"Local task image count: %d\n", d->GetImageCount());
d->TestPrint();
CPTAssert(d->GetImageCount() > 0);
}

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

@ -0,0 +1,52 @@
// 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.
//
// DynamicImagesTests.h
// minidump_test
//
// Created by Neal Sidhwaney on 4/17/08.
// Copyright 2008 Google Inc. All rights reserved.
//
//
#ifndef _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__
#define _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__
#include <CPlusTest/CPlusTest.h>
class DynamicImagesTests : public TestCase {
public:
explicit DynamicImagesTests(TestInvocation* invocation);
virtual ~DynamicImagesTests();
void ReadTaskMemoryTest();
void ReadLibrariesFromLocalTaskTest();
};
#endif /* _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__ */

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

@ -0,0 +1,106 @@
// 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.
//
// breakpad_nlist_test.cc
// minidump_test
//
// Created by Neal Sidhwaney on 4/13/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#include "client/mac/handler/testcases/breakpad_nlist_test.h"
#include <mach-o/nlist.h>
#include "client/mac/handler/breakpad_nlist_64.h"
BreakpadNlistTest test1(TEST_INVOCATION(BreakpadNlistTest, CompareToNM));
BreakpadNlistTest::BreakpadNlistTest(TestInvocation *invocation)
: TestCase(invocation) {
}
BreakpadNlistTest::~BreakpadNlistTest() {
}
void BreakpadNlistTest::CompareToNM() {
#if TARGET_CPU_X86_64
system("/usr/bin/nm -arch x86_64 /usr/lib/dyld > /tmp/dyld-namelist.txt");
#elif TARGET_CPU_PPC64
system("/usr/bin/nm -arch ppc64 /usr/lib/dyld > /tmp/dyld-namelist.txt");
#endif
FILE *fd = fopen("/tmp/dyld-namelist.txt", "rt");
char oneNMAddr[30];
char symbolType;
char symbolName[500];
while (!feof(fd)) {
fscanf(fd, "%s %c %s", oneNMAddr, &symbolType, symbolName);
breakpad_nlist symbolList[2];
breakpad_nlist &list = symbolList[0];
memset(symbolList, 0, sizeof(breakpad_nlist)*2);
const char *symbolNames[2];
symbolNames[0] = (const char*)symbolName;
symbolNames[1] = "\0";
breakpad_nlist_64("/usr/lib/dyld", &list, symbolNames);
uint64_t nmAddr = strtol(oneNMAddr, NULL, 16);
if (!IsSymbolMoreThanOnceInDyld(symbolName)) {
CPTAssert(nmAddr == symbolList[0].n_value);
}
}
fclose(fd);
}
bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char *symbolName) {
// These are the symbols that occur more than once when nm dumps
// the symbol table of /usr/lib/dyld. Our nlist program returns
// the first address because it's doing a search so we need to exclude
// these from causing the test to fail
const char *multipleSymbols[] = {
"__Z41__static_initialization_and_destruction_0ii",
"___tcf_0",
"___tcf_1",
"_read_encoded_value_with_base",
"_read_sleb128",
"_read_uleb128",
"\0"};
bool found = false;
for (int i = 0; multipleSymbols[i][0]; i++) {
if (!strcmp(multipleSymbols[i], symbolName)) {
found = true;
break;
}
}
return found;
}

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

@ -0,0 +1,62 @@
// 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.
//
// breakpad_nlist_test.h
// minidump_test
//
// Created by Neal Sidhwaney on 4/13/08.
// Copyright 2008 Google Inc. All rights reserved.
//
//
#ifndef CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__
#define CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__
#include <CPlusTest/CPlusTest.h>
class BreakpadNlistTest : public TestCase {
private:
// nm dumps multiple addresses for the same symbol in
// /usr/lib/dyld. So we track those so we don't report failures
// in mismatches between what our nlist returns and what nm has
// for the duplicate symbols.
bool IsSymbolMoreThanOnceInDyld(const char *symbolName);
public:
explicit BreakpadNlistTest(TestInvocation* invocation);
virtual ~BreakpadNlistTest();
/* This test case runs nm on /usr/lib/dyld and then compares the
output of every symbol to what our nlist implementation returns */
void CompareToNM();
};
#endif /* CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__*/

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

@ -0,0 +1,46 @@
// 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.
//
// dwarftests.h
// minidump_test
//
// Created by Neal Sidhwaney on 9/24/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#import <SenTestingKit/SenTestingKit.h>
@interface dwarftests : SenTestCase {
}
- (void) testDWARFSymbolFileGeneration;
@end

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

@ -0,0 +1,60 @@
// 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.
//
// dwarftests.m
// minidump_test
//
// Created by Neal Sidhwaney on 9/24/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#import "dwarftests.h"
#import "dump_syms.h"
@implementation dwarftests
- (void) testDWARFSymbolFileGeneration {
NSString *inputBreakpadSymbolFile = @"testcases/testdata/dump_syms_i386_breakpad.sym";
NSString *outputBreakpadSymbolFile = @"/tmp/dump_syms_i386.breakpad";
DumpSymbols *dump = [[DumpSymbols alloc] initWithContentsOfFile:@"testcases/testdata/dump_syms_dwarf_data"];
STAssertNotNil(dump, @"DumpSymbols is nil");
[dump setArchitecture:@"i386"];
[dump writeSymbolFile:outputBreakpadSymbolFile];
NSData *d = [[NSData alloc] initWithContentsOfFile:inputBreakpadSymbolFile];
STAssertNotNil(d, @"Input breakpad symbol file not found");
NSData *d1 = [[NSData alloc] initWithContentsOfFile:outputBreakpadSymbolFile];
STAssertNotNil(d1, @"Output breakpad symbol file not found");
STAssertTrue([d isEqualToData:d1],
@"Symbol files were not equal!",nil);
}
@end

Двоичные данные
toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/testdata/dump_syms_dwarf_data поставляемый Normal file

Двоичный файл не отображается.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

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

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

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

@ -145,6 +145,18 @@ static bool CompareFile(const char *path) {
ASSERT_NE(fd, -1);
ASSERT_TRUE(buffer);
ASSERT_EQ(read(fd, buffer, expected_byte_count), expected_byte_count);
char *b1, *b2;
b1 = (char*)buffer;
b2 = (char*)expected;
while (*b1 == *b2) {
b1++;
b2++;
}
printf("%d\n",b1 - (char*)buffer);
ASSERT_EQ(memcmp(buffer, expected, expected_byte_count), 0);
return true;
}

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

@ -1,49 +1,49 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler", "handler\exception_handler.vcproj", "{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
ProjectSection(ProjectDependencies) = postProject
{A820AF62-6239-4693-8430-4F516C1838F4} = {A820AF62-6239-4693-8430-4F516C1838F4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_report_sender", "sender\crash_report_sender.vcproj", "{9946A048-043B-4F8F-9E07-9297B204714C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation", "crash_generation\crash_generation.vcproj", "{A820AF62-6239-4693-8430-4F516C1838F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugStaticCRT|Win32 = DebugStaticCRT|Win32
Release|Win32 = Release|Win32
ReleaseStaticCRT|Win32 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.ActiveCfg = Debug|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.Build.0 = Debug|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.ActiveCfg = Release|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.Build.0 = Release|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Debug|Win32.ActiveCfg = Debug|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Debug|Win32.Build.0 = Debug|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.ActiveCfg = Release|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.Build.0 = Release|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.ActiveCfg = Debug|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.Build.0 = Debug|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.ActiveCfg = Release|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.Build.0 = Release|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler", "handler\exception_handler.vcproj", "{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
ProjectSection(ProjectDependencies) = postProject
{A820AF62-6239-4693-8430-4F516C1838F4} = {A820AF62-6239-4693-8430-4F516C1838F4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_report_sender", "sender\crash_report_sender.vcproj", "{9946A048-043B-4F8F-9E07-9297B204714C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation", "crash_generation\crash_generation.vcproj", "{A820AF62-6239-4693-8430-4F516C1838F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugStaticCRT|Win32 = DebugStaticCRT|Win32
Release|Win32 = Release|Win32
ReleaseStaticCRT|Win32 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.ActiveCfg = Debug|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.Build.0 = Debug|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.ActiveCfg = Release|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.Build.0 = Release|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Debug|Win32.ActiveCfg = Debug|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Debug|Win32.Build.0 = Debug|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.ActiveCfg = Release|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.Build.0 = Release|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.ActiveCfg = Debug|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.Build.0 = Debug|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.ActiveCfg = Release|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.Build.0 = Release|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

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

@ -1,63 +1,63 @@
// 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.
#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
#include <Windows.h>
namespace google_breakpad {
// Automatically enters the critical section in the constructor and leaves
// the critical section in the destructor.
class AutoCriticalSection {
public:
// Creates a new instance with the given critical section object
// and enters the critical section immediately.
explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs) {
assert(cs_);
EnterCriticalSection(cs_);
}
// Destructor: leaves the critical section.
~AutoCriticalSection() {
LeaveCriticalSection(cs_);
}
private:
// Disable copy ctor and operator=.
AutoCriticalSection(const AutoCriticalSection&);
AutoCriticalSection& operator=(const AutoCriticalSection&);
CRITICAL_SECTION* cs_;
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
// 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.
#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
#include <Windows.h>
namespace google_breakpad {
// Automatically enters the critical section in the constructor and leaves
// the critical section in the destructor.
class AutoCriticalSection {
public:
// Creates a new instance with the given critical section object
// and enters the critical section immediately.
explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs) {
assert(cs_);
EnterCriticalSection(cs_);
}
// Destructor: leaves the critical section.
~AutoCriticalSection() {
LeaveCriticalSection(cs_);
}
private:
// Disable copy ctor and operator=.
AutoCriticalSection(const AutoCriticalSection&);
AutoCriticalSection& operator=(const AutoCriticalSection&);
CRITICAL_SECTION* cs_;
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__

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

@ -1,122 +1,179 @@
// 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.
#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
#include <Windows.h>
#include <DbgHelp.h>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
// Constants for the protocol between client and the server.
// Tags sent with each message indicating the purpose of
// the message.
enum MessageTag {
MESSAGE_TAG_NONE = 0,
MESSAGE_TAG_REGISTRATION_REQUEST = 1,
MESSAGE_TAG_REGISTRATION_RESPONSE = 2,
MESSAGE_TAG_REGISTRATION_ACK = 3
};
// Message structure for IPC between crash client and crash server.
struct ProtocolMessage {
ProtocolMessage()
: tag(MESSAGE_TAG_NONE),
pid(0),
dump_type(MiniDumpNormal),
thread_id(0),
exception_pointers(NULL),
assert_info(NULL),
dump_request_handle(NULL),
dump_generated_handle(NULL),
server_alive_handle(NULL) {
}
// Creates an instance with the given parameters.
ProtocolMessage(MessageTag arg_tag,
DWORD arg_pid,
MINIDUMP_TYPE arg_dump_type,
DWORD* arg_thread_id,
EXCEPTION_POINTERS** arg_exception_pointers,
MDRawAssertionInfo* arg_assert_info,
HANDLE arg_dump_request_handle,
HANDLE arg_dump_generated_handle,
HANDLE arg_server_alive)
: tag(arg_tag),
pid(arg_pid),
dump_type(arg_dump_type),
thread_id(arg_thread_id),
exception_pointers(arg_exception_pointers),
assert_info(arg_assert_info),
dump_request_handle(arg_dump_request_handle),
dump_generated_handle(arg_dump_generated_handle),
server_alive_handle(arg_server_alive) {
}
// Tag in the message.
MessageTag tag;
// Process id.
DWORD pid;
// Dump type requested.
MINIDUMP_TYPE dump_type;
// Client thread id pointer.
DWORD* thread_id;
// Exception information.
EXCEPTION_POINTERS** exception_pointers;
// Assert information in case of an invalid parameter or
// pure call failure.
MDRawAssertionInfo* assert_info;
// Handle to signal the crash event.
HANDLE dump_request_handle;
// Handle to check if server is done generating crash.
HANDLE dump_generated_handle;
// Handle to a mutex that becomes signaled (WAIT_ABANDONED)
// if server process goes down.
HANDLE server_alive_handle;
private:
// Disable copy ctor and operator=.
ProtocolMessage(const ProtocolMessage& msg);
ProtocolMessage& operator=(const ProtocolMessage& msg);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
// 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.
#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
#include <Windows.h>
#include <DbgHelp.h>
#include <string>
#include <utility>
#include "common/windows/string_utils-inl.h"
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
// Name/value pair for custom client information.
struct CustomInfoEntry {
// Maximum length for name and value for client custom info.
static const int kNameMaxLength = 64;
static const int kValueMaxLength = 64;
CustomInfoEntry() {
// Putting name and value in initializer list makes VC++ show warning 4351.
set_name(NULL);
set_value(NULL);
}
CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) {
set_name(name_arg);
set_value(value_arg);
}
void set_name(const wchar_t* name_arg) {
if (!name_arg) {
name[0] = L'\0';
return;
}
WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg);
}
void set_value(const wchar_t* value_arg) {
if (!value_arg) {
value[0] = L'\0';
return;
}
WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg);
}
void set(const wchar_t* name_arg, const wchar_t* value_arg) {
set_name(name_arg);
set_value(value_arg);
}
wchar_t name[kNameMaxLength];
wchar_t value[kValueMaxLength];
};
// Constants for the protocol between client and the server.
// Tags sent with each message indicating the purpose of
// the message.
enum MessageTag {
MESSAGE_TAG_NONE = 0,
MESSAGE_TAG_REGISTRATION_REQUEST = 1,
MESSAGE_TAG_REGISTRATION_RESPONSE = 2,
MESSAGE_TAG_REGISTRATION_ACK = 3
};
struct CustomClientInfo {
const CustomInfoEntry* entries;
int count;
};
// Message structure for IPC between crash client and crash server.
struct ProtocolMessage {
ProtocolMessage()
: tag(MESSAGE_TAG_NONE),
pid(0),
dump_type(MiniDumpNormal),
thread_id(0),
exception_pointers(NULL),
assert_info(NULL),
custom_client_info(),
dump_request_handle(NULL),
dump_generated_handle(NULL),
server_alive_handle(NULL) {
}
// Creates an instance with the given parameters.
ProtocolMessage(MessageTag arg_tag,
DWORD arg_pid,
MINIDUMP_TYPE arg_dump_type,
DWORD* arg_thread_id,
EXCEPTION_POINTERS** arg_exception_pointers,
MDRawAssertionInfo* arg_assert_info,
const CustomClientInfo& custom_info,
HANDLE arg_dump_request_handle,
HANDLE arg_dump_generated_handle,
HANDLE arg_server_alive)
: tag(arg_tag),
pid(arg_pid),
dump_type(arg_dump_type),
thread_id(arg_thread_id),
exception_pointers(arg_exception_pointers),
assert_info(arg_assert_info),
custom_client_info(custom_info),
dump_request_handle(arg_dump_request_handle),
dump_generated_handle(arg_dump_generated_handle),
server_alive_handle(arg_server_alive) {
}
// Tag in the message.
MessageTag tag;
// Process id.
DWORD pid;
// Dump type requested.
MINIDUMP_TYPE dump_type;
// Client thread id pointer.
DWORD* thread_id;
// Exception information.
EXCEPTION_POINTERS** exception_pointers;
// Assert information in case of an invalid parameter or
// pure call failure.
MDRawAssertionInfo* assert_info;
// Custom client information.
CustomClientInfo custom_client_info;
// Handle to signal the crash event.
HANDLE dump_request_handle;
// Handle to check if server is done generating crash.
HANDLE dump_generated_handle;
// Handle to a mutex that becomes signaled (WAIT_ABANDONED)
// if server process goes down.
HANDLE server_alive_handle;
private:
// Disable copy ctor and operator=.
ProtocolMessage(const ProtocolMessage& msg);
ProtocolMessage& operator=(const ProtocolMessage& msg);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__

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

@ -1,58 +1,58 @@
=========================================================================
State machine transitions for the Crash Generation Server
=========================================================================
=========================================================================
|
STATE | ACTIONS
|
=========================================================================
ERROR | Clean up resources used to serve clients.
| Always remain in ERROR state.
-------------------------------------------------------------------------
INITIAL | Connect to the pipe asynchronously.
| If connection is successfully queued up asynchronously,
| go into CONNECTING state.
| If connection is done synchronously, go into CONNECTED
| state.
| For any unexpected problems, go into ERROR state.
-------------------------------------------------------------------------
CONNECTING | Get the result of async connection request.
| If I/O is still incomplete, remain in the CONNECTING
| state.
| If connection is complete, go into CONNECTED state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
CONNECTED | Read from the pipe asynchronously.
| If read request is successfully queued up asynchronously,
| go into READING state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
READING | Get the result of async read request.
| If read is done, go into READ_DONE state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
READ_DONE | Register the client, prepare the reply and write the
| reply to the pipe asynchronously.
| If write request is successfully queued up asynchronously,
| go into WRITING state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
WRITING | Get the result of the async write request.
| If write is done, go into WRITE_DONE state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
WRITE_DONE | Read from the pipe asynchronously (for an ACK).
| If read request is successfully queued up asynchonously,
| go into READING_ACK state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
READING_ACK | Get the result of the async read request.
| If read is done, perform action for successful client
| connection.
| Go into DISCONNECTING state.
-------------------------------------------------------------------------
DISCONNECTING | Disconnect from the pipe, reset the event and go into
| INITIAL state and signal the event again. If anything
| fails, go into ERROR state.
=========================================================================
=========================================================================
State machine transitions for the Crash Generation Server
=========================================================================
=========================================================================
|
STATE | ACTIONS
|
=========================================================================
ERROR | Clean up resources used to serve clients.
| Always remain in ERROR state.
-------------------------------------------------------------------------
INITIAL | Connect to the pipe asynchronously.
| If connection is successfully queued up asynchronously,
| go into CONNECTING state.
| If connection is done synchronously, go into CONNECTED
| state.
| For any unexpected problems, go into ERROR state.
-------------------------------------------------------------------------
CONNECTING | Get the result of async connection request.
| If I/O is still incomplete, remain in the CONNECTING
| state.
| If connection is complete, go into CONNECTED state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
CONNECTED | Read from the pipe asynchronously.
| If read request is successfully queued up asynchronously,
| go into READING state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
READING | Get the result of async read request.
| If read is done, go into READ_DONE state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
READ_DONE | Register the client, prepare the reply and write the
| reply to the pipe asynchronously.
| If write request is successfully queued up asynchronously,
| go into WRITING state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
WRITING | Get the result of the async write request.
| If write is done, go into WRITE_DONE state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
WRITE_DONE | Read from the pipe asynchronously (for an ACK).
| If read request is successfully queued up asynchonously,
| go into READING_ACK state.
| For any unexpected problems, go into DISCONNECTING state.
-------------------------------------------------------------------------
READING_ACK | Get the result of the async read request.
| If read is done, perform action for successful client
| connection.
| Go into DISCONNECTING state.
-------------------------------------------------------------------------
DISCONNECTING | Disconnect from the pipe, reset the event and go into
| INITIAL state and signal the event again. If anything
| fails, go into ERROR state.
=========================================================================

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

@ -1,147 +1,210 @@
// 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.
#include "client/windows/crash_generation/client_info.h"
namespace google_breakpad {
ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
DWORD pid,
MINIDUMP_TYPE dump_type,
DWORD* thread_id,
EXCEPTION_POINTERS** ex_info,
MDRawAssertionInfo* assert_info)
: crash_server_(crash_server),
pid_(pid),
dump_type_(dump_type),
ex_info_(ex_info),
assert_info_(assert_info),
thread_id_(thread_id),
process_handle_(NULL),
dump_requested_handle_(NULL),
dump_generated_handle_(NULL),
dump_request_wait_handle_(NULL),
process_exit_wait_handle_(NULL) {
}
bool ClientInfo::Initialize() {
process_handle_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid_);
if (!process_handle_) {
return false;
}
dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
TRUE, // Manual reset.
FALSE, // Initial state.
NULL); // Name.
if (!dump_requested_handle_) {
return false;
}
dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
TRUE, // Manual reset.
FALSE, // Initial state.
NULL); // Name.
return dump_generated_handle_ != NULL;
}
ClientInfo::~ClientInfo() {
if (process_handle_) {
CloseHandle(process_handle_);
}
if (dump_requested_handle_) {
CloseHandle(dump_requested_handle_);
}
if (dump_generated_handle_) {
CloseHandle(dump_generated_handle_);
}
if (dump_request_wait_handle_) {
// Wait for callbacks that might already be running to finish.
UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
}
if (process_exit_wait_handle_) {
// Wait for the callback that might already be running to finish.
UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
}
}
bool ClientInfo::UnregisterWaits() {
bool success = true;
if (dump_request_wait_handle_) {
if (!UnregisterWait(dump_request_wait_handle_)) {
success = false;
} else {
dump_request_wait_handle_ = NULL;
}
}
if (process_exit_wait_handle_) {
if (!UnregisterWait(process_exit_wait_handle_)) {
success = false;
} else {
process_exit_wait_handle_ = NULL;
}
}
return success;
}
bool ClientInfo::GetClientExceptionInfo(
EXCEPTION_POINTERS** ex_info) const {
SIZE_T bytes_count = 0;
if (!ReadProcessMemory(process_handle_,
ex_info_,
ex_info,
sizeof(*ex_info),
&bytes_count)) {
return false;
}
return bytes_count == sizeof(*ex_info);
}
bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
SIZE_T bytes_count = 0;
if (!ReadProcessMemory(process_handle_,
thread_id_,
thread_id,
sizeof(*thread_id),
&bytes_count)) {
return false;
}
return bytes_count == sizeof(*thread_id);
}
} // namespace google_breakpad
// 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.
#include "client/windows/crash_generation/client_info.h"
#include "client/windows/common/ipc_protocol.h"
static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
namespace google_breakpad {
ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
DWORD pid,
MINIDUMP_TYPE dump_type,
DWORD* thread_id,
EXCEPTION_POINTERS** ex_info,
MDRawAssertionInfo* assert_info,
const CustomClientInfo& custom_client_info)
: crash_server_(crash_server),
pid_(pid),
dump_type_(dump_type),
ex_info_(ex_info),
assert_info_(assert_info),
custom_client_info_(custom_client_info),
thread_id_(thread_id),
process_handle_(NULL),
dump_requested_handle_(NULL),
dump_generated_handle_(NULL),
dump_request_wait_handle_(NULL),
process_exit_wait_handle_(NULL) {
GetSystemTimeAsFileTime(&start_time_);
}
bool ClientInfo::Initialize() {
process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_);
if (!process_handle_) {
return false;
}
dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
TRUE, // Manual reset.
FALSE, // Initial state.
NULL); // Name.
if (!dump_requested_handle_) {
return false;
}
dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
TRUE, // Manual reset.
FALSE, // Initial state.
NULL); // Name.
return dump_generated_handle_ != NULL;
}
ClientInfo::~ClientInfo() {
if (dump_request_wait_handle_) {
// Wait for callbacks that might already be running to finish.
UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
}
if (process_exit_wait_handle_) {
// Wait for the callback that might already be running to finish.
UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
}
if (process_handle_) {
CloseHandle(process_handle_);
}
if (dump_requested_handle_) {
CloseHandle(dump_requested_handle_);
}
if (dump_generated_handle_) {
CloseHandle(dump_generated_handle_);
}
}
bool ClientInfo::UnregisterWaits() {
bool success = true;
if (dump_request_wait_handle_) {
if (!UnregisterWait(dump_request_wait_handle_)) {
success = false;
} else {
dump_request_wait_handle_ = NULL;
}
}
if (process_exit_wait_handle_) {
if (!UnregisterWait(process_exit_wait_handle_)) {
success = false;
} else {
process_exit_wait_handle_ = NULL;
}
}
return success;
}
bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
SIZE_T bytes_count = 0;
if (!ReadProcessMemory(process_handle_,
ex_info_,
ex_info,
sizeof(*ex_info),
&bytes_count)) {
return false;
}
return bytes_count == sizeof(*ex_info);
}
bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
SIZE_T bytes_count = 0;
if (!ReadProcessMemory(process_handle_,
thread_id_,
thread_id,
sizeof(*thread_id),
&bytes_count)) {
return false;
}
return bytes_count == sizeof(*thread_id);
}
void ClientInfo::SetProcessUptime() {
FILETIME now = {0};
GetSystemTimeAsFileTime(&now);
ULARGE_INTEGER time_start;
time_start.HighPart = start_time_.dwHighDateTime;
time_start.LowPart = start_time_.dwLowDateTime;
ULARGE_INTEGER time_now;
time_now.HighPart = now.dwHighDateTime;
time_now.LowPart = now.dwLowDateTime;
// Calculate the delay and convert it from 100-nanoseconds to milliseconds.
__int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000;
// Convert it to a string.
wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value;
_i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10);
}
bool ClientInfo::PopulateCustomInfo() {
SIZE_T bytes_count = 0;
SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;
// If the scoped array for custom info already has an array, it will be
// the same size as what we need. This is because the number of custom info
// entries is always the same. So allocate memory only if scoped array has
// a NULL pointer.
if (!custom_info_entries_.get()) {
// Allocate an extra entry for reporting uptime for the client process.
custom_info_entries_.reset(
new CustomInfoEntry[custom_client_info_.count + 1]);
// Use the last element in the array for uptime.
custom_info_entries_.get()[custom_client_info_.count].set_name(
kCustomInfoProcessUptimeName);
}
if (!ReadProcessMemory(process_handle_,
custom_client_info_.entries,
custom_info_entries_.get(),
read_count,
&bytes_count)) {
return false;
}
SetProcessUptime();
return (bytes_count != read_count);
}
CustomClientInfo ClientInfo::GetCustomInfo() const {
CustomClientInfo custom_info;
custom_info.entries = custom_info_entries_.get();
// Add 1 to the count from the client process to account for extra entry for
// process uptime.
custom_info.count = custom_client_info_.count + 1;
return custom_info;
}
} // namespace google_breakpad

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

@ -1,145 +1,170 @@
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
#include <Windows.h>
#include <DbgHelp.h>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
class CrashGenerationServer;
// Abstraction for a crash client process.
class ClientInfo {
public:
// Creates an instance with the given values. Gets the process
// handle for the given process id and creates necessary event
// objects.
ClientInfo(CrashGenerationServer* crash_server,
DWORD pid,
MINIDUMP_TYPE dump_type,
DWORD* thread_id,
EXCEPTION_POINTERS** ex_info,
MDRawAssertionInfo* assert_info);
~ClientInfo();
CrashGenerationServer* crash_server() const { return crash_server_; }
DWORD pid() const { return pid_; }
MINIDUMP_TYPE dump_type() const { return dump_type_; }
EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
MDRawAssertionInfo* assert_info() const { return assert_info_; }
DWORD* thread_id() const { return thread_id_; }
HANDLE process_handle() const { return process_handle_; }
HANDLE dump_requested_handle() const { return dump_requested_handle_; }
HANDLE dump_generated_handle() const { return dump_generated_handle_; }
HANDLE dump_request_wait_handle() const {
return dump_request_wait_handle_;
}
void set_dump_request_wait_handle(HANDLE value) {
dump_request_wait_handle_ = value;
}
HANDLE process_exit_wait_handle() const {
return process_exit_wait_handle_;
}
void set_process_exit_wait_handle(HANDLE value) {
process_exit_wait_handle_ = value;
}
// Unregister all waits for the client.
bool UnregisterWaits();
bool Initialize();
bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
bool GetClientThreadId(DWORD* thread_id) const;
private:
// Crash generation server.
CrashGenerationServer* crash_server_;
// Client process ID.
DWORD pid_;
// Dump type requested by the client.
MINIDUMP_TYPE dump_type_;
// Address of an EXCEPTION_POINTERS* variable in the client
// process address space that will point to an instance of
// EXCEPTION_POINTERS containing information about crash.
//
// WARNING: Do not dereference these pointers as they are pointers
// in the address space of another process.
EXCEPTION_POINTERS** ex_info_;
// Address of an instance of MDRawAssertionInfo in the client
// process address space that will contain information about
// non-exception related crashes like invalid parameter assertion
// failures and pure calls.
//
// WARNING: Do not dereference these pointers as they are pointers
// in the address space of another process.
MDRawAssertionInfo* assert_info_;
// Address of a variable in the client process address space that
// will contain the thread id of the crashing client thread.
//
// WARNING: Do not dereference these pointers as they are pointers
// in the address space of another process.
DWORD* thread_id_;
// Client process handle.
HANDLE process_handle_;
// Dump request event handle.
HANDLE dump_requested_handle_;
// Dump generated event handle.
HANDLE dump_generated_handle_;
// Wait handle for dump request event.
HANDLE dump_request_wait_handle_;
// Wait handle for process exit event.
HANDLE process_exit_wait_handle_;
// Disallow copy ctor and operator=.
ClientInfo(const ClientInfo& client_info);
ClientInfo& operator=(const ClientInfo& client_info);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
#include <Windows.h>
#include <DbgHelp.h>
#include "client/windows/common/ipc_protocol.h"
#include "google_breakpad/common/minidump_format.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
class CrashGenerationServer;
// Abstraction for a crash client process.
class ClientInfo {
public:
// Creates an instance with the given values. Gets the process
// handle for the given process id and creates necessary event
// objects.
ClientInfo(CrashGenerationServer* crash_server,
DWORD pid,
MINIDUMP_TYPE dump_type,
DWORD* thread_id,
EXCEPTION_POINTERS** ex_info,
MDRawAssertionInfo* assert_info,
const CustomClientInfo& custom_client_info);
~ClientInfo();
CrashGenerationServer* crash_server() const { return crash_server_; }
DWORD pid() const { return pid_; }
MINIDUMP_TYPE dump_type() const { return dump_type_; }
EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
MDRawAssertionInfo* assert_info() const { return assert_info_; }
DWORD* thread_id() const { return thread_id_; }
HANDLE process_handle() const { return process_handle_; }
HANDLE dump_requested_handle() const { return dump_requested_handle_; }
HANDLE dump_generated_handle() const { return dump_generated_handle_; }
HANDLE dump_request_wait_handle() const {
return dump_request_wait_handle_;
}
void set_dump_request_wait_handle(HANDLE value) {
dump_request_wait_handle_ = value;
}
HANDLE process_exit_wait_handle() const {
return process_exit_wait_handle_;
}
void set_process_exit_wait_handle(HANDLE value) {
process_exit_wait_handle_ = value;
}
// Unregister all waits for the client.
bool UnregisterWaits();
bool Initialize();
bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
bool GetClientThreadId(DWORD* thread_id) const;
// Reads the custom information from the client process address space.
bool PopulateCustomInfo();
// Returns the client custom information.
CustomClientInfo GetCustomInfo() const;
private:
// Calcualtes the uptime for the client process, converts it to a string and
// stores it in the last entry of client custom info.
void SetProcessUptime();
// Crash generation server.
CrashGenerationServer* crash_server_;
// Client process ID.
DWORD pid_;
// Dump type requested by the client.
MINIDUMP_TYPE dump_type_;
// Address of an EXCEPTION_POINTERS* variable in the client
// process address space that will point to an instance of
// EXCEPTION_POINTERS containing information about crash.
//
// WARNING: Do not dereference these pointers as they are pointers
// in the address space of another process.
EXCEPTION_POINTERS** ex_info_;
// Address of an instance of MDRawAssertionInfo in the client
// process address space that will contain information about
// non-exception related crashes like invalid parameter assertion
// failures and pure calls.
//
// WARNING: Do not dereference these pointers as they are pointers
// in the address space of another process.
MDRawAssertionInfo* assert_info_;
// Custom information about the client.
CustomClientInfo custom_client_info_;
// Contains the custom client info entries read from the client process
// memory. This will be populated only if the method GetClientCustomInfo
// is called.
scoped_array<CustomInfoEntry> custom_info_entries_;
// Address of a variable in the client process address space that
// will contain the thread id of the crashing client thread.
//
// WARNING: Do not dereference these pointers as they are pointers
// in the address space of another process.
DWORD* thread_id_;
// Client process handle.
HANDLE process_handle_;
// Dump request event handle.
HANDLE dump_requested_handle_;
// Dump generated event handle.
HANDLE dump_generated_handle_;
// Wait handle for dump request event.
HANDLE dump_request_wait_handle_;
// Wait handle for process exit event.
HANDLE process_exit_wait_handle_;
// Time when the client process started. It is used to determine the uptime
// for the client process when it signals a crash.
FILETIME start_time_;
// Disallow copy ctor and operator=.
ClientInfo(const ClientInfo& client_info);
ClientInfo& operator=(const ClientInfo& client_info);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__

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

@ -1,343 +1,347 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="crash_generation"
ProjectGUID="{A820AF62-6239-4693-8430-4F516C1838F4}"
RootNamespace="CrashGenerationServer"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\client_info.cc"
>
</File>
<File
RelativePath=".\crash_generation_client.cc"
>
</File>
<File
RelativePath=".\crash_generation_server.cc"
>
</File>
<File
RelativePath="..\..\..\common\windows\guid_string.cc"
>
</File>
<File
RelativePath=".\minidump_generator.cc"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\common\auto_critical_section.h"
>
</File>
<File
RelativePath=".\client_info.h"
>
</File>
<File
RelativePath=".\crash_generation_client.h"
>
</File>
<File
RelativePath=".\crash_generation_server.h"
>
</File>
<File
RelativePath="..\common\ipc_protocol.h"
>
</File>
<File
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
>
</File>
<File
RelativePath=".\minidump_generator.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
<File
RelativePath=".\ReadMe.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="crash_generation"
ProjectGUID="{A820AF62-6239-4693-8430-4F516C1838F4}"
RootNamespace="CrashGenerationServer"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\client_info.cc"
>
</File>
<File
RelativePath=".\crash_generation_client.cc"
>
</File>
<File
RelativePath=".\crash_generation_server.cc"
>
</File>
<File
RelativePath="..\..\..\common\windows\guid_string.cc"
>
</File>
<File
RelativePath=".\minidump_generator.cc"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\common\auto_critical_section.h"
>
</File>
<File
RelativePath=".\client_info.h"
>
</File>
<File
RelativePath=".\crash_generation_client.h"
>
</File>
<File
RelativePath=".\crash_generation_server.h"
>
</File>
<File
RelativePath="..\common\ipc_protocol.h"
>
</File>
<File
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
>
</File>
<File
RelativePath=".\minidump_generator.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\string_utils-inl.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
<File
RelativePath=".\ReadMe.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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

@ -1,329 +1,337 @@
// 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.
#include "client/windows/crash_generation/crash_generation_client.h"
#include <cassert>
#include "client/windows/common/ipc_protocol.h"
namespace google_breakpad {
const int kPipeBusyWaitTimeoutMs = 2000;
#ifdef _DEBUG
const DWORD kWaitForServerTimeoutMs = INFINITE;
#else
const DWORD kWaitForServerTimeoutMs = 15000;
#endif
const int kPipeConnectMaxAttempts = 2;
const DWORD kPipeDesiredAccess = FILE_READ_DATA |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES;
const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
SECURITY_SQOS_PRESENT;
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
const size_t kWaitEventCount = 2;
// This function is orphan for production code. It can be used
// for debugging to help repro some scenarios like the client
// is slow in writing to the pipe after connecting, the client
// is slow in reading from the pipe after writing, etc. The parameter
// overlapped below is not used and it is present to match the signature
// of this function to TransactNamedPipe Win32 API. Uncomment if needed
// for debugging.
/**
static bool TransactNamedPipeDebugHelper(HANDLE pipe,
const void* in_buffer,
DWORD in_size,
void* out_buffer,
DWORD out_size,
DWORD* bytes_count,
LPOVERLAPPED) {
// Uncomment the next sleep to create a gap before writing
// to pipe.
// Sleep(5000);
if (!WriteFile(pipe,
in_buffer,
in_size,
bytes_count,
NULL)) {
return false;
}
// Uncomment the next sleep to create a gap between write
// and read.
// Sleep(5000);
return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
}
**/
CrashGenerationClient::CrashGenerationClient(const wchar_t* pipe_name,
MINIDUMP_TYPE dump_type)
: pipe_name_(pipe_name),
dump_type_(dump_type),
thread_id_(0),
server_process_id_(0),
crash_event_(NULL),
crash_generated_(NULL),
server_alive_(NULL),
exception_pointers_(NULL) {
memset(&assert_info_, 0, sizeof(assert_info_));
}
CrashGenerationClient::~CrashGenerationClient() {
if (crash_event_) {
CloseHandle(crash_event_);
}
if (crash_generated_) {
CloseHandle(crash_generated_);
}
if (server_alive_) {
CloseHandle(server_alive_);
}
}
// Performs the registration step with the server process.
// The registration step involves communicating with the server
// via a named pipe. The client sends the following pieces of
// data to the server:
//
// * Message tag indicating the client is requesting registration.
// * Process id of the client process.
// * Address of a DWORD variable in the client address space
// that will contain the thread id of the client thread that
// caused the crash.
// * Address of a EXCEPTION_POINTERS* variable in the client
// address space that will point to an instance of EXCEPTION_POINTERS
// when the crash happens.
// * Address of an instance of MDRawAssertionInfo that will contain
// relevant information in case of non-exception crashes like assertion
// failures and pure calls.
//
// In return the client expects the following information from the server:
//
// * Message tag indicating successful registration.
// * Server process id.
// * Handle to an object that client can signal to request dump
// generation from the server.
// * Handle to an object that client can wait on after requesting
// dump generation for the server to finish dump generation.
// * Handle to a mutex object that client can wait on to make sure
// server is still alive.
//
// If any step of the expected behavior mentioned above fails, the
// registration step is not considered successful and hence out-of-process
// dump generation service is not available.
//
// Returns true if the registration is successful; false otherwise.
bool CrashGenerationClient::Register() {
HANDLE pipe = ConnectToServer();
if (!pipe) {
return false;
}
bool success = RegisterClient(pipe);
CloseHandle(pipe);
return success;
}
HANDLE CrashGenerationClient::ConnectToServer() {
HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
kPipeDesiredAccess,
kPipeFlagsAndAttributes);
if (!pipe) {
return NULL;
}
DWORD mode = kPipeMode;
if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
CloseHandle(pipe);
pipe = NULL;
}
return pipe;
}
bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
GetCurrentProcessId(),
dump_type_,
&thread_id_,
&exception_pointers_,
&assert_info_,
NULL,
NULL,
NULL);
ProtocolMessage reply;
DWORD bytes_count = 0;
// The call to TransactNamedPipe below can be changed to a call
// to TransactNamedPipeDebugHelper to help repro some scenarios.
// For details see comments for TransactNamedPipeDebugHelper.
if (!TransactNamedPipe(pipe,
&msg,
sizeof(msg),
&reply,
sizeof(ProtocolMessage),
&bytes_count,
NULL)) {
return false;
}
if (!ValidateResponse(reply)) {
return false;
}
ProtocolMessage ack_msg;
ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
return false;
}
crash_event_ = reply.dump_request_handle;
crash_generated_ = reply.dump_generated_handle;
server_alive_ = reply.server_alive_handle;
server_process_id_ = reply.pid;
return true;
}
HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
DWORD pipe_access,
DWORD flags_attrs) {
for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
HANDLE pipe = CreateFile(pipe_name,
pipe_access,
0,
NULL,
OPEN_EXISTING,
flags_attrs,
NULL);
if (pipe != INVALID_HANDLE_VALUE) {
return pipe;
}
// Cannot continue retrying if error is something other than
// ERROR_PIPE_BUSY.
if (GetLastError() != ERROR_PIPE_BUSY) {
break;
}
// Cannot continue retrying if wait on pipe fails.
if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
break;
}
}
return NULL;
}
bool CrashGenerationClient::ValidateResponse(
const ProtocolMessage& msg) const {
return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
(msg.pid != 0) &&
(msg.dump_request_handle != NULL) &&
(msg.dump_generated_handle != NULL) &&
(msg.server_alive_handle != NULL);
}
bool CrashGenerationClient::IsRegistered() const {
return crash_event_ != NULL;
}
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
if (!IsRegistered()) {
return false;
}
exception_pointers_ = ex_info;
thread_id_ = GetCurrentThreadId();
assert_info_.line = 0;
assert_info_.type = 0;
assert_info_.expression[0] = 0;
assert_info_.file[0] = 0;
assert_info_.function[0] = 0;
return SignalCrashEventAndWait();
}
bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
if (!IsRegistered()) {
return false;
}
exception_pointers_ = NULL;
if (assert_info) {
memcpy(&assert_info_, assert_info, sizeof(assert_info_));
} else {
memset(&assert_info_, 0, sizeof(assert_info_));
}
thread_id_ = GetCurrentThreadId();
return SignalCrashEventAndWait();
}
bool CrashGenerationClient::SignalCrashEventAndWait() {
assert(crash_event_);
assert(crash_generated_);
assert(server_alive_);
// Reset the dump generated event before signaling the crash
// event so that the server can set the dump generated event
// once it is done generating the event.
if (!ResetEvent(crash_generated_)) {
return false;
}
if (!SetEvent(crash_event_)) {
return false;
}
HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
DWORD result = WaitForMultipleObjects(kWaitEventCount,
wait_handles,
FALSE,
kWaitForServerTimeoutMs);
// Crash dump was successfully generated only if the server
// signaled the crash generated event.
return result == WAIT_OBJECT_0;
}
} // namespace google_breakpad
// 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.
#include "client/windows/crash_generation/crash_generation_client.h"
#include <cassert>
#include <utility>
#include "client/windows/common/ipc_protocol.h"
namespace google_breakpad {
const int kPipeBusyWaitTimeoutMs = 2000;
#ifdef _DEBUG
const DWORD kWaitForServerTimeoutMs = INFINITE;
#else
const DWORD kWaitForServerTimeoutMs = 15000;
#endif
const int kPipeConnectMaxAttempts = 2;
const DWORD kPipeDesiredAccess = FILE_READ_DATA |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES;
const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
SECURITY_SQOS_PRESENT;
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
const size_t kWaitEventCount = 2;
// This function is orphan for production code. It can be used
// for debugging to help repro some scenarios like the client
// is slow in writing to the pipe after connecting, the client
// is slow in reading from the pipe after writing, etc. The parameter
// overlapped below is not used and it is present to match the signature
// of this function to TransactNamedPipe Win32 API. Uncomment if needed
// for debugging.
/**
static bool TransactNamedPipeDebugHelper(HANDLE pipe,
const void* in_buffer,
DWORD in_size,
void* out_buffer,
DWORD out_size,
DWORD* bytes_count,
LPOVERLAPPED) {
// Uncomment the next sleep to create a gap before writing
// to pipe.
// Sleep(5000);
if (!WriteFile(pipe,
in_buffer,
in_size,
bytes_count,
NULL)) {
return false;
}
// Uncomment the next sleep to create a gap between write
// and read.
// Sleep(5000);
return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
}
**/
CrashGenerationClient::CrashGenerationClient(
const wchar_t* pipe_name,
MINIDUMP_TYPE dump_type,
const CustomClientInfo* custom_info)
: pipe_name_(pipe_name),
dump_type_(dump_type),
thread_id_(0),
server_process_id_(0),
crash_event_(NULL),
crash_generated_(NULL),
server_alive_(NULL),
exception_pointers_(NULL),
custom_info_() {
memset(&assert_info_, 0, sizeof(assert_info_));
if (custom_info) {
custom_info_ = *custom_info;
}
}
CrashGenerationClient::~CrashGenerationClient() {
if (crash_event_) {
CloseHandle(crash_event_);
}
if (crash_generated_) {
CloseHandle(crash_generated_);
}
if (server_alive_) {
CloseHandle(server_alive_);
}
}
// Performs the registration step with the server process.
// The registration step involves communicating with the server
// via a named pipe. The client sends the following pieces of
// data to the server:
//
// * Message tag indicating the client is requesting registration.
// * Process id of the client process.
// * Address of a DWORD variable in the client address space
// that will contain the thread id of the client thread that
// caused the crash.
// * Address of a EXCEPTION_POINTERS* variable in the client
// address space that will point to an instance of EXCEPTION_POINTERS
// when the crash happens.
// * Address of an instance of MDRawAssertionInfo that will contain
// relevant information in case of non-exception crashes like assertion
// failures and pure calls.
//
// In return the client expects the following information from the server:
//
// * Message tag indicating successful registration.
// * Server process id.
// * Handle to an object that client can signal to request dump
// generation from the server.
// * Handle to an object that client can wait on after requesting
// dump generation for the server to finish dump generation.
// * Handle to a mutex object that client can wait on to make sure
// server is still alive.
//
// If any step of the expected behavior mentioned above fails, the
// registration step is not considered successful and hence out-of-process
// dump generation service is not available.
//
// Returns true if the registration is successful; false otherwise.
bool CrashGenerationClient::Register() {
HANDLE pipe = ConnectToServer();
if (!pipe) {
return false;
}
bool success = RegisterClient(pipe);
CloseHandle(pipe);
return success;
}
HANDLE CrashGenerationClient::ConnectToServer() {
HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
kPipeDesiredAccess,
kPipeFlagsAndAttributes);
if (!pipe) {
return NULL;
}
DWORD mode = kPipeMode;
if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
CloseHandle(pipe);
pipe = NULL;
}
return pipe;
}
bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
GetCurrentProcessId(),
dump_type_,
&thread_id_,
&exception_pointers_,
&assert_info_,
custom_info_,
NULL,
NULL,
NULL);
ProtocolMessage reply;
DWORD bytes_count = 0;
// The call to TransactNamedPipe below can be changed to a call
// to TransactNamedPipeDebugHelper to help repro some scenarios.
// For details see comments for TransactNamedPipeDebugHelper.
if (!TransactNamedPipe(pipe,
&msg,
sizeof(msg),
&reply,
sizeof(ProtocolMessage),
&bytes_count,
NULL)) {
return false;
}
if (!ValidateResponse(reply)) {
return false;
}
ProtocolMessage ack_msg;
ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
return false;
}
crash_event_ = reply.dump_request_handle;
crash_generated_ = reply.dump_generated_handle;
server_alive_ = reply.server_alive_handle;
server_process_id_ = reply.pid;
return true;
}
HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
DWORD pipe_access,
DWORD flags_attrs) {
for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
HANDLE pipe = CreateFile(pipe_name,
pipe_access,
0,
NULL,
OPEN_EXISTING,
flags_attrs,
NULL);
if (pipe != INVALID_HANDLE_VALUE) {
return pipe;
}
// Cannot continue retrying if error is something other than
// ERROR_PIPE_BUSY.
if (GetLastError() != ERROR_PIPE_BUSY) {
break;
}
// Cannot continue retrying if wait on pipe fails.
if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
break;
}
}
return NULL;
}
bool CrashGenerationClient::ValidateResponse(
const ProtocolMessage& msg) const {
return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
(msg.pid != 0) &&
(msg.dump_request_handle != NULL) &&
(msg.dump_generated_handle != NULL) &&
(msg.server_alive_handle != NULL);
}
bool CrashGenerationClient::IsRegistered() const {
return crash_event_ != NULL;
}
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
if (!IsRegistered()) {
return false;
}
exception_pointers_ = ex_info;
thread_id_ = GetCurrentThreadId();
assert_info_.line = 0;
assert_info_.type = 0;
assert_info_.expression[0] = 0;
assert_info_.file[0] = 0;
assert_info_.function[0] = 0;
return SignalCrashEventAndWait();
}
bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
if (!IsRegistered()) {
return false;
}
exception_pointers_ = NULL;
if (assert_info) {
memcpy(&assert_info_, assert_info, sizeof(assert_info_));
} else {
memset(&assert_info_, 0, sizeof(assert_info_));
}
thread_id_ = GetCurrentThreadId();
return SignalCrashEventAndWait();
}
bool CrashGenerationClient::SignalCrashEventAndWait() {
assert(crash_event_);
assert(crash_generated_);
assert(server_alive_);
// Reset the dump generated event before signaling the crash
// event so that the server can set the dump generated event
// once it is done generating the event.
if (!ResetEvent(crash_generated_)) {
return false;
}
if (!SetEvent(crash_event_)) {
return false;
}
HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
DWORD result = WaitForMultipleObjects(kWaitEventCount,
wait_handles,
FALSE,
kWaitForServerTimeoutMs);
// Crash dump was successfully generated only if the server
// signaled the crash generated event.
return result == WAIT_OBJECT_0;
}
} // namespace google_breakpad

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

@ -1,149 +1,159 @@
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
#include <string>
#include "client/windows/common/ipc_protocol.h"
namespace google_breakpad {
// Abstraction of client-side implementation of out of process
// crash generation.
//
// The process that desires to have out-of-process crash dump
// generation service can use this class in the following way:
//
// * Create an instance.
// * Call Register method so that the client tries to register
// with the server process and check the return value. If
// registration is not successful, out-of-process crash dump
// generation will not be available
// * Request dump generation by calling either of the two
// overloaded RequestDump methods - one in case of exceptions
// and the other in case of assertion failures
//
// Note that it is the responsibility of the client code of
// this class to set the unhandled exception filter with the
// system by calling the SetUnhandledExceptionFilter function
// and the client code should explicitly request dump generation.
class CrashGenerationClient {
public:
CrashGenerationClient(const wchar_t* pipe_name,
MINIDUMP_TYPE dump_type);
~CrashGenerationClient();
// Registers the client process with the crash server.
//
// Returns true if the registration is successful; false otherwise.
bool Register();
// Requests the crash server to generate a dump with the given
// exception information.
//
// Returns true if the dump was successful; false otherwise. Note that
// if the registration step was not performed or it was not successful,
// false will be returned.
bool RequestDump(EXCEPTION_POINTERS* ex_info);
// Requests the crash server to generate a dump with the given
// assertion information.
//
// Returns true if the dump was successful; false otherwise. Note that
// if the registration step was not performed or it was not successful,
// false will be returned.
bool RequestDump(MDRawAssertionInfo* assert_info);
private:
// Connects to the appropriate pipe and sets the pipe handle state.
//
// Returns the pipe handle if everything goes well; otherwise Returns NULL.
HANDLE ConnectToServer();
// Performs a handshake with the server over the given pipe which should be
// already connected to the server.
//
// Returns true if handshake with the server was successful; false otherwise.
bool RegisterClient(HANDLE pipe);
// Validates the given server response.
bool ValidateResponse(const ProtocolMessage& msg) const;
// Returns true if the registration step succeeded; false otherwise.
bool IsRegistered() const;
// Connects to the given named pipe with given parameters.
//
// Returns true if the connection is successful; false otherwise.
HANDLE ConnectToPipe(const wchar_t* pipe_name,
DWORD pipe_access,
DWORD flags_attrs);
// Signals the crash event and wait for the server to generate crash.
bool SignalCrashEventAndWait();
// Pipe name to use to talk to server.
std::wstring pipe_name_;
// Type of dump to generate.
MINIDUMP_TYPE dump_type_;
// Event to signal in case of a crash.
HANDLE crash_event_;
// Handle to wait on after signaling a crash for the server
// to finish generating crash dump.
HANDLE crash_generated_;
// Handle to a mutex that will become signaled with WAIT_ABANDONED
// if the server process goes down.
HANDLE server_alive_;
// Server process id.
DWORD server_process_id_;
// Id of the thread that caused the crash.
DWORD thread_id_;
// Exception pointers for an exception crash.
EXCEPTION_POINTERS* exception_pointers_;
// Assertion info for an invalid parameter or pure call crash.
MDRawAssertionInfo assert_info_;
// Disable copy ctor and operator=.
CrashGenerationClient(const CrashGenerationClient& crash_client);
CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
#include <windows.h>
#include <dbghelp.h>
#include <string>
#include <utility>
#include "client/windows/common/ipc_protocol.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
struct CustomClientInfo;
// Abstraction of client-side implementation of out of process
// crash generation.
//
// The process that desires to have out-of-process crash dump
// generation service can use this class in the following way:
//
// * Create an instance.
// * Call Register method so that the client tries to register
// with the server process and check the return value. If
// registration is not successful, out-of-process crash dump
// generation will not be available
// * Request dump generation by calling either of the two
// overloaded RequestDump methods - one in case of exceptions
// and the other in case of assertion failures
//
// Note that it is the responsibility of the client code of
// this class to set the unhandled exception filter with the
// system by calling the SetUnhandledExceptionFilter function
// and the client code should explicitly request dump generation.
class CrashGenerationClient {
public:
CrashGenerationClient(const wchar_t* pipe_name,
MINIDUMP_TYPE dump_type,
const CustomClientInfo* custom_info);
~CrashGenerationClient();
// Registers the client process with the crash server.
//
// Returns true if the registration is successful; false otherwise.
bool Register();
// Requests the crash server to generate a dump with the given
// exception information.
//
// Returns true if the dump was successful; false otherwise. Note that
// if the registration step was not performed or it was not successful,
// false will be returned.
bool RequestDump(EXCEPTION_POINTERS* ex_info);
// Requests the crash server to generate a dump with the given
// assertion information.
//
// Returns true if the dump was successful; false otherwise. Note that
// if the registration step was not performed or it was not successful,
// false will be returned.
bool RequestDump(MDRawAssertionInfo* assert_info);
private:
// Connects to the appropriate pipe and sets the pipe handle state.
//
// Returns the pipe handle if everything goes well; otherwise Returns NULL.
HANDLE ConnectToServer();
// Performs a handshake with the server over the given pipe which should be
// already connected to the server.
//
// Returns true if handshake with the server was successful; false otherwise.
bool RegisterClient(HANDLE pipe);
// Validates the given server response.
bool ValidateResponse(const ProtocolMessage& msg) const;
// Returns true if the registration step succeeded; false otherwise.
bool IsRegistered() const;
// Connects to the given named pipe with given parameters.
//
// Returns true if the connection is successful; false otherwise.
HANDLE ConnectToPipe(const wchar_t* pipe_name,
DWORD pipe_access,
DWORD flags_attrs);
// Signals the crash event and wait for the server to generate crash.
bool SignalCrashEventAndWait();
// Pipe name to use to talk to server.
std::wstring pipe_name_;
// Custom client information
CustomClientInfo custom_info_;
// Type of dump to generate.
MINIDUMP_TYPE dump_type_;
// Event to signal in case of a crash.
HANDLE crash_event_;
// Handle to wait on after signaling a crash for the server
// to finish generating crash dump.
HANDLE crash_generated_;
// Handle to a mutex that will become signaled with WAIT_ABANDONED
// if the server process goes down.
HANDLE server_alive_;
// Server process id.
DWORD server_process_id_;
// Id of the thread that caused the crash.
DWORD thread_id_;
// Exception pointers for an exception crash.
EXCEPTION_POINTERS* exception_pointers_;
// Assertion info for an invalid parameter or pure call crash.
MDRawAssertionInfo assert_info_;
// Disable copy ctor and operator=.
CrashGenerationClient(const CrashGenerationClient& crash_client);
CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,255 +1,269 @@
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
#include <list>
#include <string>
#include "client/windows/common/ipc_protocol.h"
#include "client/windows/crash_generation/client_info.h"
#include "client/windows/crash_generation/minidump_generator.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
// Abstraction for server side implementation of out-of-process crash
// generation protocol. It generates minidumps (Windows platform) for
// client processes that request dump generation.
class CrashGenerationServer {
public:
typedef void (*OnClientConnectedCallback)(void* context,
const ClientInfo* client_info);
typedef void (*OnClientDumpRequestCallback)(void* context,
const ClientInfo* client_info);
typedef void (*OnClientExitedCallback)(void* context,
const ClientInfo* client_info);
// Creates an instance with the given parameters.
//
// Parameter pipe_name: Name of the pipe
// Parameter connect_callback: Callback for a new client connection.
// Parameter connect_context: Context for client connection callback.
// Parameter crash_callback: Callback for a client crash dump request.
// Parameter crash_context: Context for client crash dump request callback.
// Parameter exit_callback: Callback for client process exit.
// Parameter exit_context: Context for client exit callback.
// Parameter generate_dumps: Whether to automatically generate dumps or not.
// Client code of this class might want to generate dumps explicitly in the
// crash dump request callback. In that case, false can be passed for this
// parameter.
// Parameter dump_path: Path for generating dumps; required only if true is
// passed for generateDumps parameter; NULL can be passed otherwise.
CrashGenerationServer(const wchar_t* pipe_name,
OnClientConnectedCallback connect_callback,
void* connect_context,
OnClientDumpRequestCallback dump_callback,
void* dump_context,
OnClientExitedCallback exit_callback,
void* exit_context,
bool generate_dumps,
const std::wstring* dump_path);
~CrashGenerationServer();
// Performs initialization steps needed to start listening to clients.
//
// Returns true if initialization is successful; false otherwise.
bool Start();
private:
// Various states the client can be in during the handshake with
// the server.
enum IPCServerState {
// Server is in error state and it cannot serve any clients.
IPC_SERVER_STATE_ERROR,
// Server starts in this state.
IPC_SERVER_STATE_INITIAL,
// Server has issued an async connect to the pipe and it is waiting
// for the connection to be established.
IPC_SERVER_STATE_CONNECTING,
// Server is connected successfully.
IPC_SERVER_STATE_CONNECTED,
// Server has issued an async read from the pipe and it is waiting for
// the read to finish.
IPC_SERVER_STATE_READING,
// Server is done reading from the pipe.
IPC_SERVER_STATE_READ_DONE,
// Server has issued an async write to the pipe and it is waiting for
// the write to finish.
IPC_SERVER_STATE_WRITING,
// Server is done writing to the pipe.
IPC_SERVER_STATE_WRITE_DONE,
// Server has issued an async read from the pipe for an ack and it
// is waiting for the read to finish.
IPC_SERVER_STATE_READING_ACK,
// Server is done writing to the pipe and it is now ready to disconnect
// and reconnect.
IPC_SERVER_STATE_DISCONNECTING
};
//
// Helper methods to handle various server IPC states.
//
void HandleErrorState();
void HandleInitialState();
void HandleConnectingState();
void HandleConnectedState();
void HandleReadingState();
void HandleReadDoneState();
void HandleWritingState();
void HandleWriteDoneState();
void HandleReadingAckState();
void HandleDisconnectingState();
// Prepares reply for a client from the given parameters.
bool PrepareReply(const ClientInfo& client_info,
ProtocolMessage* reply) const;
// Duplicates various handles in the ClientInfo object for the client
// process and stores them in the given ProtocolMessage instance. If
// creating any handle fails, ProtocolMessage will contain the handles
// already created successfully, which should be closed by the caller.
bool CreateClientHandles(const ClientInfo& client_info,
ProtocolMessage* reply) const;
// Response to the given client. Return true if all steps of
// responding to the client succeed, false otherwise.
bool RespondToClient(ClientInfo* client_info);
// Handles a connection request from the client.
void HandleConnectionRequest();
// Handles a dump request from the client.
void HandleDumpRequest(const ClientInfo& client_info);
// Callback for pipe connected event.
static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
// Callback for a dump request.
static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
// Callback for client process exit event.
static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
// Releases resources for a client.
static DWORD WINAPI CleanupClient(void* context);
// Cleans up for the given client.
void DoCleanup(ClientInfo* client_info);
// Adds the given client to the list of registered clients.
bool AddClient(ClientInfo* client_info);
// Generates dump for the given client.
bool GenerateDump(const ClientInfo& client);
// Sync object for thread-safe access to the shared list of clients.
CRITICAL_SECTION clients_sync_;
// List of clients.
std::list<ClientInfo*> clients_;
// Pipe name.
std::wstring pipe_name_;
// Handle to the pipe used for handshake with clients.
HANDLE pipe_;
// Pipe wait handle.
HANDLE pipe_wait_handle_;
// Handle to server-alive mutex.
HANDLE server_alive_handle_;
// Callback for a successful client connection.
OnClientConnectedCallback connect_callback_;
// Context for client connected callback.
void* connect_context_;
// Callback for a client dump request.
OnClientDumpRequestCallback dump_callback_;
// Context for client dump request callback.
void* dump_context_;
// Callback for client process exit.
OnClientExitedCallback exit_callback_;
// Context for client process exit callback.
void* exit_context_;
// Whether to generate dumps or not.
bool generate_dumps_;
// Instance of a mini dump generator.
scoped_ptr<MinidumpGenerator> dump_generator_;
// State of the server in performing the IPC with the client.
// Note that since we restrict the pipe to one instance, we
// only need to keep one state of the server. Otherwise, server
// would have one state per client it is talking to.
IPCServerState server_state_;
// Whether the server is shutting down.
volatile bool shutting_down_;
// Overlapped instance for async I/O on the pipe.
OVERLAPPED overlapped_;
// Message object used in IPC with the client.
ProtocolMessage msg_;
// Client Info for the client that's connecting to the server.
ClientInfo* client_info_;
// Count of clean-up work items that are currently running or are
// already queued to run.
volatile LONG cleanup_item_count_;
// Disable copy ctor and operator=.
CrashGenerationServer(const CrashGenerationServer& crash_server);
CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
#include <list>
#include <string>
#include "client/windows/common/ipc_protocol.h"
#include "client/windows/crash_generation/client_info.h"
#include "client/windows/crash_generation/minidump_generator.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
// Abstraction for server side implementation of out-of-process crash
// generation protocol for Windows platform only. It generates Windows
// minidump files for client processes that request dump generation. When
// the server is requested to start listening for clients (by calling the
// Start method), it creates a named pipe and waits for the clients to
// register. In response, it hands them event handles that the client can
// signal to request dump generation. When the clients request dump
// generation in this way, the server generates Windows minidump files.
class CrashGenerationServer {
public:
typedef void (*OnClientConnectedCallback)(void* context,
const ClientInfo* client_info);
typedef void (*OnClientDumpRequestCallback)(void* context,
const ClientInfo* client_info,
const std::wstring* file_path);
typedef void (*OnClientExitedCallback)(void* context,
const ClientInfo* client_info);
// Creates an instance with the given parameters.
//
// Parameter pipe_name: Name of the Windows named pipe
// Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass
// NULL to use default security on the pipe. By default, the pipe created
// allows Local System, Administrators and the Creator full control and
// the Everyone group read access on the pipe.
// Parameter connect_callback: Callback for a new client connection.
// Parameter connect_context: Context for client connection callback.
// Parameter crash_callback: Callback for a client crash dump request.
// Parameter crash_context: Context for client crash dump request callback.
// Parameter exit_callback: Callback for client process exit.
// Parameter exit_context: Context for client exit callback.
// Parameter generate_dumps: Whether to automatically generate dumps.
// Client code of this class might want to generate dumps explicitly in the
// crash dump request callback. In that case, false can be passed for this
// parameter.
// Parameter dump_path: Path for generating dumps; required only if true is
// passed for generateDumps parameter; NULL can be passed otherwise.
CrashGenerationServer(const std::wstring& pipe_name,
SECURITY_ATTRIBUTES* pipe_sec_attrs,
OnClientConnectedCallback connect_callback,
void* connect_context,
OnClientDumpRequestCallback dump_callback,
void* dump_context,
OnClientExitedCallback exit_callback,
void* exit_context,
bool generate_dumps,
const std::wstring* dump_path);
~CrashGenerationServer();
// Performs initialization steps needed to start listening to clients.
//
// Returns true if initialization is successful; false otherwise.
bool Start();
private:
// Various states the client can be in during the handshake with
// the server.
enum IPCServerState {
// Server is in error state and it cannot serve any clients.
IPC_SERVER_STATE_ERROR,
// Server starts in this state.
IPC_SERVER_STATE_INITIAL,
// Server has issued an async connect to the pipe and it is waiting
// for the connection to be established.
IPC_SERVER_STATE_CONNECTING,
// Server is connected successfully.
IPC_SERVER_STATE_CONNECTED,
// Server has issued an async read from the pipe and it is waiting for
// the read to finish.
IPC_SERVER_STATE_READING,
// Server is done reading from the pipe.
IPC_SERVER_STATE_READ_DONE,
// Server has issued an async write to the pipe and it is waiting for
// the write to finish.
IPC_SERVER_STATE_WRITING,
// Server is done writing to the pipe.
IPC_SERVER_STATE_WRITE_DONE,
// Server has issued an async read from the pipe for an ack and it
// is waiting for the read to finish.
IPC_SERVER_STATE_READING_ACK,
// Server is done writing to the pipe and it is now ready to disconnect
// and reconnect.
IPC_SERVER_STATE_DISCONNECTING
};
//
// Helper methods to handle various server IPC states.
//
void HandleErrorState();
void HandleInitialState();
void HandleConnectingState();
void HandleConnectedState();
void HandleReadingState();
void HandleReadDoneState();
void HandleWritingState();
void HandleWriteDoneState();
void HandleReadingAckState();
void HandleDisconnectingState();
// Prepares reply for a client from the given parameters.
bool PrepareReply(const ClientInfo& client_info,
ProtocolMessage* reply) const;
// Duplicates various handles in the ClientInfo object for the client
// process and stores them in the given ProtocolMessage instance. If
// creating any handle fails, ProtocolMessage will contain the handles
// already created successfully, which should be closed by the caller.
bool CreateClientHandles(const ClientInfo& client_info,
ProtocolMessage* reply) const;
// Response to the given client. Return true if all steps of
// responding to the client succeed, false otherwise.
bool RespondToClient(ClientInfo* client_info);
// Handles a connection request from the client.
void HandleConnectionRequest();
// Handles a dump request from the client.
void HandleDumpRequest(const ClientInfo& client_info);
// Callback for pipe connected event.
static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
// Callback for a dump request.
static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
// Callback for client process exit event.
static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
// Releases resources for a client.
static DWORD WINAPI CleanupClient(void* context);
// Cleans up for the given client.
void DoCleanup(ClientInfo* client_info);
// Adds the given client to the list of registered clients.
bool AddClient(ClientInfo* client_info);
// Generates dump for the given client.
bool GenerateDump(const ClientInfo& client, std::wstring* dump_path);
// Sync object for thread-safe access to the shared list of clients.
CRITICAL_SECTION clients_sync_;
// List of clients.
std::list<ClientInfo*> clients_;
// Pipe name.
std::wstring pipe_name_;
// Pipe security attributes
SECURITY_ATTRIBUTES* pipe_sec_attrs_;
// Handle to the pipe used for handshake with clients.
HANDLE pipe_;
// Pipe wait handle.
HANDLE pipe_wait_handle_;
// Handle to server-alive mutex.
HANDLE server_alive_handle_;
// Callback for a successful client connection.
OnClientConnectedCallback connect_callback_;
// Context for client connected callback.
void* connect_context_;
// Callback for a client dump request.
OnClientDumpRequestCallback dump_callback_;
// Context for client dump request callback.
void* dump_context_;
// Callback for client process exit.
OnClientExitedCallback exit_callback_;
// Context for client process exit callback.
void* exit_context_;
// Whether to generate dumps.
bool generate_dumps_;
// Instance of a mini dump generator.
scoped_ptr<MinidumpGenerator> dump_generator_;
// State of the server in performing the IPC with the client.
// Note that since we restrict the pipe to one instance, we
// only need to keep one state of the server. Otherwise, server
// would have one state per client it is talking to.
IPCServerState server_state_;
// Whether the server is shutting down.
volatile bool shutting_down_;
// Overlapped instance for async I/O on the pipe.
OVERLAPPED overlapped_;
// Message object used in IPC with the client.
ProtocolMessage msg_;
// Client Info for the client that's connecting to the server.
ClientInfo* client_info_;
// Count of clean-up work items that are currently running or are
// already queued to run.
volatile LONG cleanup_item_count_;
// Disable copy ctor and operator=.
CrashGenerationServer(const CrashGenerationServer& crash_server);
CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__

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

@ -1,228 +1,289 @@
// 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.
#include "client/windows/crash_generation/minidump_generator.h"
#include <cassert>
#include "client/windows/common/auto_critical_section.h"
#include "common/windows/guid_string.h"
using std::wstring;
namespace google_breakpad {
MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
: dbghelp_module_(NULL),
rpcrt4_module_(NULL),
dump_path_(dump_path),
write_dump_(NULL),
create_uuid_(NULL) {
InitializeCriticalSection(&module_load_sync_);
InitializeCriticalSection(&get_proc_address_sync_);
}
MinidumpGenerator::~MinidumpGenerator() {
if (dbghelp_module_) {
FreeLibrary(dbghelp_module_);
}
if (rpcrt4_module_) {
FreeLibrary(rpcrt4_module_);
}
DeleteCriticalSection(&get_proc_address_sync_);
DeleteCriticalSection(&module_load_sync_);
}
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
DWORD process_id,
DWORD thread_id,
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
MINIDUMP_TYPE dump_type,
bool is_client_pointers) {
MiniDumpWriteDumpType write_dump = GetWriteDump();
if (!write_dump) {
return false;
}
wstring dump_file_path;
if (!GenerateDumpFilePath(&dump_file_path)) {
return false;
}
HANDLE dump_file = CreateFile(dump_file_path.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (dump_file == INVALID_HANDLE_VALUE) {
return false;
}
MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
// Setup the exception information object only if it's a dump
// due to an exception.
if (exception_pointers) {
dump_exception_pointers = &dump_exception_info;
dump_exception_info.ThreadId = thread_id;
dump_exception_info.ExceptionPointers = exception_pointers;
dump_exception_info.ClientPointers = is_client_pointers;
}
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
// information about the exception handler to the Breakpad processor.
// The information will help the processor determine which threads are
// relevant. The Breakpad processor does not require this information but
// can function better with Breakpad-generated dumps when it is present.
// The native debugger is not harmed by the presence of this information.
MDRawBreakpadInfo breakpad_info;
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
breakpad_info.dump_thread_id = thread_id;
breakpad_info.requesting_thread_id = requesting_thread_id;
// Leave room in user_stream_array for a possible assertion info stream.
MINIDUMP_USER_STREAM user_stream_array[2];
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
user_stream_array[0].BufferSize = sizeof(breakpad_info);
user_stream_array[0].Buffer = &breakpad_info;
MINIDUMP_USER_STREAM_INFORMATION user_streams;
user_streams.UserStreamCount = 1;
user_streams.UserStreamArray = user_stream_array;
MDRawAssertionInfo* actual_assert_info = assert_info;
MDRawAssertionInfo client_assert_info = {0};
if (assert_info) {
// If the assertion info object lives in the client process,
// read the memory of the client process.
if (is_client_pointers) {
SIZE_T bytes_read = 0;
if (!ReadProcessMemory(process_handle,
assert_info,
&client_assert_info,
sizeof(client_assert_info),
&bytes_read)) {
CloseHandle(dump_file);
return false;
}
if (bytes_read != sizeof(client_assert_info)) {
CloseHandle(dump_file);
return false;
}
actual_assert_info = &client_assert_info;
}
user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
user_stream_array[1].Buffer = actual_assert_info;
++user_streams.UserStreamCount;
}
bool result = write_dump(process_handle,
process_id,
dump_file,
dump_type,
exception_pointers ? &dump_exception_info : NULL,
&user_streams,
NULL) != FALSE;
CloseHandle(dump_file);
return result;
}
HMODULE MinidumpGenerator::GetDbghelpModule() {
AutoCriticalSection lock(&module_load_sync_);
if (!dbghelp_module_) {
dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
}
return dbghelp_module_;
}
MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
AutoCriticalSection lock(&get_proc_address_sync_);
if (!write_dump_) {
HMODULE module = GetDbghelpModule();
if (module) {
FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
}
}
return write_dump_;
}
HMODULE MinidumpGenerator::GetRpcrt4Module() {
AutoCriticalSection lock(&module_load_sync_);
if (!rpcrt4_module_) {
rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
}
return rpcrt4_module_;
}
MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
AutoCriticalSection lock(&module_load_sync_);
if (!create_uuid_) {
HMODULE module = GetRpcrt4Module();
if (module) {
FARPROC proc = GetProcAddress(module, "UuidCreate");
create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
}
}
return create_uuid_;
}
bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
UUID id = {0};
UuidCreateType create_uuid = GetCreateUuid();
if(!create_uuid) {
return false;
}
create_uuid(&id);
wstring id_str = GUIDString::GUIDToWString(&id);
*file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
return true;
}
} // namespace google_breakpad
// 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.
#include "client/windows/crash_generation/minidump_generator.h"
#include <cassert>
#include "client/windows/common/auto_critical_section.h"
#include "common/windows/guid_string.h"
using std::wstring;
namespace google_breakpad {
MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
: dbghelp_module_(NULL),
rpcrt4_module_(NULL),
dump_path_(dump_path),
write_dump_(NULL),
create_uuid_(NULL) {
InitializeCriticalSection(&module_load_sync_);
InitializeCriticalSection(&get_proc_address_sync_);
}
MinidumpGenerator::~MinidumpGenerator() {
if (dbghelp_module_) {
FreeLibrary(dbghelp_module_);
}
if (rpcrt4_module_) {
FreeLibrary(rpcrt4_module_);
}
DeleteCriticalSection(&get_proc_address_sync_);
DeleteCriticalSection(&module_load_sync_);
}
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
DWORD process_id,
DWORD thread_id,
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
MINIDUMP_TYPE dump_type,
bool is_client_pointers,
wstring* dump_path) {
MiniDumpWriteDumpType write_dump = GetWriteDump();
if (!write_dump) {
return false;
}
wstring dump_file_path;
if (!GenerateDumpFilePath(&dump_file_path)) {
return false;
}
// If the client requests a full memory dump, we will write a normal mini
// dump and a full memory dump. Both dump files use the same uuid as file
// name prefix.
bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0;
wstring full_dump_file_path;
if (full_memory_dump) {
full_dump_file_path.assign(dump_file_path);
full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp
full_dump_file_path.append(TEXT("-full.dmp"));
}
HANDLE dump_file = CreateFile(dump_file_path.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (dump_file == INVALID_HANDLE_VALUE) {
return false;
}
HANDLE full_dump_file = INVALID_HANDLE_VALUE;
if (full_memory_dump) {
full_dump_file = CreateFile(full_dump_file_path.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (full_dump_file == INVALID_HANDLE_VALUE) {
CloseHandle(dump_file);
return false;
}
}
MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
// Setup the exception information object only if it's a dump
// due to an exception.
if (exception_pointers) {
dump_exception_pointers = &dump_exception_info;
dump_exception_info.ThreadId = thread_id;
dump_exception_info.ExceptionPointers = exception_pointers;
dump_exception_info.ClientPointers = is_client_pointers;
}
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
// information about the exception handler to the Breakpad processor.
// The information will help the processor determine which threads are
// relevant. The Breakpad processor does not require this information but
// can function better with Breakpad-generated dumps when it is present.
// The native debugger is not harmed by the presence of this information.
MDRawBreakpadInfo breakpad_info = {0};
if (!is_client_pointers) {
// Set the dump thread id and requesting thread id only in case of
// in-process dump generation.
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
breakpad_info.dump_thread_id = thread_id;
breakpad_info.requesting_thread_id = requesting_thread_id;
}
// Leave room in user_stream_array for a possible assertion info stream.
MINIDUMP_USER_STREAM user_stream_array[2];
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
user_stream_array[0].BufferSize = sizeof(breakpad_info);
user_stream_array[0].Buffer = &breakpad_info;
MINIDUMP_USER_STREAM_INFORMATION user_streams;
user_streams.UserStreamCount = 1;
user_streams.UserStreamArray = user_stream_array;
MDRawAssertionInfo* actual_assert_info = assert_info;
MDRawAssertionInfo client_assert_info = {0};
if (assert_info) {
// If the assertion info object lives in the client process,
// read the memory of the client process.
if (is_client_pointers) {
SIZE_T bytes_read = 0;
if (!ReadProcessMemory(process_handle,
assert_info,
&client_assert_info,
sizeof(client_assert_info),
&bytes_read)) {
CloseHandle(dump_file);
if (full_dump_file != INVALID_HANDLE_VALUE)
CloseHandle(full_dump_file);
return false;
}
if (bytes_read != sizeof(client_assert_info)) {
CloseHandle(dump_file);
if (full_dump_file != INVALID_HANDLE_VALUE)
CloseHandle(full_dump_file);
return false;
}
actual_assert_info = &client_assert_info;
}
user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
user_stream_array[1].Buffer = actual_assert_info;
++user_streams.UserStreamCount;
}
bool result_minidump = write_dump(
process_handle,
process_id,
dump_file,
static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory))
| MiniDumpNormal),
exception_pointers ? &dump_exception_info : NULL,
&user_streams,
NULL) != FALSE;
bool result_full_memory = true;
if (full_memory_dump) {
result_full_memory = write_dump(
process_handle,
process_id,
full_dump_file,
static_cast<MINIDUMP_TYPE>(dump_type & (~MiniDumpNormal)),
exception_pointers ? &dump_exception_info : NULL,
&user_streams,
NULL) != FALSE;
}
bool result = result_minidump && result_full_memory;
CloseHandle(dump_file);
if (full_dump_file != INVALID_HANDLE_VALUE)
CloseHandle(full_dump_file);
// Store the path of the dump file in the out parameter if dump generation
// succeeded.
if (result && dump_path) {
*dump_path = dump_file_path;
}
return result;
}
HMODULE MinidumpGenerator::GetDbghelpModule() {
AutoCriticalSection lock(&module_load_sync_);
if (!dbghelp_module_) {
dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
}
return dbghelp_module_;
}
MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
AutoCriticalSection lock(&get_proc_address_sync_);
if (!write_dump_) {
HMODULE module = GetDbghelpModule();
if (module) {
FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
}
}
return write_dump_;
}
HMODULE MinidumpGenerator::GetRpcrt4Module() {
AutoCriticalSection lock(&module_load_sync_);
if (!rpcrt4_module_) {
rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
}
return rpcrt4_module_;
}
MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
AutoCriticalSection lock(&module_load_sync_);
if (!create_uuid_) {
HMODULE module = GetRpcrt4Module();
if (module) {
FARPROC proc = GetProcAddress(module, "UuidCreate");
create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
}
}
return create_uuid_;
}
bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
UUID id = {0};
UuidCreateType create_uuid = GetCreateUuid();
if(!create_uuid) {
return false;
}
create_uuid(&id);
wstring id_str = GUIDString::GUIDToWString(&id);
*file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
return true;
}
} // namespace google_breakpad

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

@ -1,118 +1,121 @@
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
#include <Windows.h>
#include <DbgHelp.h>
#include <list>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
// Abstraction for various objects and operations needed to generate
// minidump on Windows. This abstraction is useful to hide all the gory
// details for minidump generation and provide a clean interface to
// the clients to generate minidumps.
class MinidumpGenerator {
public:
// Creates an instance with the given dump path.
explicit MinidumpGenerator(const std::wstring& dump_path);
~MinidumpGenerator();
// Writes the minidump with the given parameters.
bool WriteMinidump(HANDLE process_handle,
DWORD process_id,
DWORD thread_id,
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
MINIDUMP_TYPE dump_type,
bool is_client_pointers);
private:
// Function pointer type for MiniDumpWriteDump, which is looked up
// dynamically.
typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
// Function pointer type for UuidCreate, which is looked up dynamically.
typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
// Loads the appropriate DLL lazily in a thread safe way.
HMODULE GetDbghelpModule();
// Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
// function lazily and in a thread-safe manner.
MiniDumpWriteDumpType GetWriteDump();
// Loads the appropriate DLL lazily in a thread safe way.
HMODULE GetRpcrt4Module();
// Loads the appropriate DLL and gets a pointer to the UuidCreate
// function lazily and in a thread-safe manner.
UuidCreateType GetCreateUuid();
// Returns the path for the file to write dump to.
bool GenerateDumpFilePath(std::wstring* file_path);
// Handle to dynamically loaded DbgHelp.dll.
HMODULE dbghelp_module_;
// Pointer to the MiniDumpWriteDump function.
MiniDumpWriteDumpType write_dump_;
// Handle to dynamically loaded rpcrt4.dll.
HMODULE rpcrt4_module_;
// Pointer to the UuidCreate function.
UuidCreateType create_uuid_;
// Folder path to store dump files.
std::wstring dump_path_;
// Critical section to sychronize action of loading modules dynamically.
CRITICAL_SECTION module_load_sync_;
// Critical section to synchronize action of dynamically getting function
// addresses from modules.
CRITICAL_SECTION get_proc_address_sync_;
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
// 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.
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
#include <windows.h>
#include <dbghelp.h>
#include <list>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
// Abstraction for various objects and operations needed to generate
// minidump on Windows. This abstraction is useful to hide all the gory
// details for minidump generation and provide a clean interface to
// the clients to generate minidumps.
class MinidumpGenerator {
public:
// Creates an instance with the given dump path.
explicit MinidumpGenerator(const std::wstring& dump_path);
~MinidumpGenerator();
// Writes the minidump with the given parameters. Stores the
// dump file path in the dump_path parameter if dump generation
// succeeds.
bool WriteMinidump(HANDLE process_handle,
DWORD process_id,
DWORD thread_id,
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
MINIDUMP_TYPE dump_type,
bool is_client_pointers,
std::wstring* dump_path);
private:
// Function pointer type for MiniDumpWriteDump, which is looked up
// dynamically.
typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
// Function pointer type for UuidCreate, which is looked up dynamically.
typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
// Loads the appropriate DLL lazily in a thread safe way.
HMODULE GetDbghelpModule();
// Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
// function lazily and in a thread-safe manner.
MiniDumpWriteDumpType GetWriteDump();
// Loads the appropriate DLL lazily in a thread safe way.
HMODULE GetRpcrt4Module();
// Loads the appropriate DLL and gets a pointer to the UuidCreate
// function lazily and in a thread-safe manner.
UuidCreateType GetCreateUuid();
// Returns the path for the file to write dump to.
bool GenerateDumpFilePath(std::wstring* file_path);
// Handle to dynamically loaded DbgHelp.dll.
HMODULE dbghelp_module_;
// Pointer to the MiniDumpWriteDump function.
MiniDumpWriteDumpType write_dump_;
// Handle to dynamically loaded rpcrt4.dll.
HMODULE rpcrt4_module_;
// Pointer to the UuidCreate function.
UuidCreateType create_uuid_;
// Folder path to store dump files.
std::wstring dump_path_;
// Critical section to sychronize action of loading modules dynamically.
CRITICAL_SECTION module_load_sync_;
// Critical section to synchronize action of dynamically getting function
// addresses from modules.
CRITICAL_SECTION get_proc_address_sync_;
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__

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

@ -34,6 +34,7 @@
#include "common/windows/string_utils-inl.h"
#include "client/windows/common/ipc_protocol.h"
#include "client/windows/handler/exception_handler.h"
#include "common/windows/guid_string.h"
@ -41,80 +42,133 @@ namespace google_breakpad {
static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
vector<ExceptionHandler *> *ExceptionHandler::handler_stack_ = NULL;
vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
LONG ExceptionHandler::handler_stack_index_ = 0;
CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
bool ExceptionHandler::handler_stack_critical_section_initialized_ = false;
ExceptionHandler::ExceptionHandler(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
int handler_types,
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
const CustomClientInfo* custom_info) {
Initialize(dump_path,
filter,
callback,
callback_context,
handler_types,
dump_type,
pipe_name,
custom_info);
}
ExceptionHandler::ExceptionHandler(const wstring &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
int handler_types)
: filter_(filter),
callback_(callback),
callback_context_(callback_context),
dump_path_(),
next_minidump_id_(),
next_minidump_path_(),
dump_path_c_(),
next_minidump_id_c_(NULL),
next_minidump_path_c_(NULL),
dbghelp_module_(NULL),
minidump_write_dump_(NULL),
rpcrt4_module_(NULL),
uuid_create_(NULL),
handler_types_(handler_types),
previous_filter_(NULL),
previous_pch_(NULL),
handler_thread_(0),
handler_critical_section_(),
handler_start_semaphore_(NULL),
handler_finish_semaphore_(NULL),
requesting_thread_id_(0),
exception_info_(NULL),
assertion_(NULL),
handler_return_value_(false),
handle_debug_exceptions_(false) {
void* callback_context,
int handler_types) {
Initialize(dump_path,
filter,
callback,
callback_context,
handler_types,
MiniDumpNormal,
NULL,
NULL);
}
void ExceptionHandler::Initialize(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
int handler_types,
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
const CustomClientInfo* custom_info) {
filter_ = filter;
callback_ = callback;
callback_context_ = callback_context;
dump_path_c_ = NULL;
next_minidump_id_c_ = NULL;
next_minidump_path_c_ = NULL;
dbghelp_module_ = NULL;
minidump_write_dump_ = NULL;
dump_type_ = dump_type;
rpcrt4_module_ = NULL;
uuid_create_ = NULL;
handler_types_ = handler_types;
previous_filter_ = NULL;
#if _MSC_VER >= 1400 // MSVC 2005/8
previous_iph_ = NULL;
#endif // _MSC_VER >= 1400
previous_pch_ = NULL;
handler_thread_ = NULL;
handler_start_semaphore_ = NULL;
handler_finish_semaphore_ = NULL;
requesting_thread_id_ = 0;
exception_info_ = NULL;
assertion_ = NULL;
handler_return_value_ = false;
handle_debug_exceptions_ = false;
// Set synchronization primitives and the handler thread. Each
// ExceptionHandler object gets its own handler thread because that's the
// only way to reliably guarantee sufficient stack space in an exception,
// and it allows an easy way to get a snapshot of the requesting thread's
// context outside of an exception.
InitializeCriticalSection(&handler_critical_section_);
handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
// Attempt to use out-of-process if user has specified pipe name.
if (pipe_name != NULL) {
scoped_ptr<CrashGenerationClient> client(
new CrashGenerationClient(pipe_name,
dump_type_,
custom_info));
DWORD thread_id;
handler_thread_ = CreateThread(NULL, // lpThreadAttributes
kExceptionHandlerThreadInitialStackSize,
ExceptionHandlerThreadMain,
this, // lpParameter
0, // dwCreationFlags
&thread_id);
dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
if (dbghelp_module_) {
minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(
GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));
// If successful in registering with the monitoring process,
// there is no need to setup in-process crash generation.
if (client->Register()) {
crash_generation_client_.reset(client.release());
}
}
// Load this library dynamically to not affect existing projects. Most
// projects don't link against this directly, it's usually dynamically
// loaded by dependent code.
rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");
if (rpcrt4_module_) {
uuid_create_ = reinterpret_cast<UuidCreate_type>(
GetProcAddress(rpcrt4_module_, "UuidCreate"));
}
if (!IsOutOfProcess()) {
// Either client did not ask for out-of-process crash generation
// or registration with the server process failed. In either case,
// setup to do in-process crash generation.
// set_dump_path calls UpdateNextID. This sets up all of the path and id
// strings, and their equivalent c_str pointers.
set_dump_path(dump_path);
// Set synchronization primitives and the handler thread. Each
// ExceptionHandler object gets its own handler thread because that's the
// only way to reliably guarantee sufficient stack space in an exception,
// and it allows an easy way to get a snapshot of the requesting thread's
// context outside of an exception.
InitializeCriticalSection(&handler_critical_section_);
handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
DWORD thread_id;
handler_thread_ = CreateThread(NULL, // lpThreadAttributes
kExceptionHandlerThreadInitialStackSize,
ExceptionHandlerThreadMain,
this, // lpParameter
0, // dwCreationFlags
&thread_id);
dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
if (dbghelp_module_) {
minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(
GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));
}
// Load this library dynamically to not affect existing projects. Most
// projects don't link against this directly, it's usually dynamically
// loaded by dependent code.
rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");
if (rpcrt4_module_) {
uuid_create_ = reinterpret_cast<UuidCreate_type>(
GetProcAddress(rpcrt4_module_, "UuidCreate"));
}
// set_dump_path calls UpdateNextID. This sets up all of the path and id
// strings, and their equivalent c_str pointers.
set_dump_path(dump_path);
}
if (handler_types != HANDLER_NONE) {
if (!handler_stack_critical_section_initialized_) {
@ -127,7 +181,7 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path,
// The first time an ExceptionHandler that installs a handler is
// created, set up the handler stack.
if (!handler_stack_) {
handler_stack_ = new vector<ExceptionHandler *>();
handler_stack_ = new vector<ExceptionHandler*>();
}
handler_stack_->push_back(this);
@ -175,7 +229,7 @@ ExceptionHandler::~ExceptionHandler() {
// TODO(mmentovai): use advapi32!ReportEvent to log the warning to the
// system's application event log.
fprintf(stderr, "warning: removing Breakpad handler out of order\n");
for (vector<ExceptionHandler *>::iterator iterator =
for (vector<ExceptionHandler*>::iterator iterator =
handler_stack_->begin();
iterator != handler_stack_->end();
++iterator) {
@ -195,16 +249,20 @@ ExceptionHandler::~ExceptionHandler() {
LeaveCriticalSection(&handler_stack_critical_section_);
}
// Clean up the handler thread and synchronization primitives.
TerminateThread(handler_thread_, 1);
DeleteCriticalSection(&handler_critical_section_);
CloseHandle(handler_start_semaphore_);
CloseHandle(handler_finish_semaphore_);
// Some of the objects were only initialized if out of process
// registration was not done.
if (!IsOutOfProcess()) {
// Clean up the handler thread and synchronization primitives.
TerminateThread(handler_thread_, 1);
DeleteCriticalSection(&handler_critical_section_);
CloseHandle(handler_start_semaphore_);
CloseHandle(handler_finish_semaphore_);
}
}
// static
DWORD ExceptionHandler::ExceptionHandlerThreadMain(void *lpParameter) {
ExceptionHandler *self = reinterpret_cast<ExceptionHandler *>(lpParameter);
DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {
ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter);
assert(self);
while (true) {
@ -276,16 +334,16 @@ class AutoExceptionHandler {
LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
}
ExceptionHandler *get_handler() const { return handler_; }
ExceptionHandler* get_handler() const { return handler_; }
private:
ExceptionHandler *handler_;
ExceptionHandler* handler_;
};
// static
LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {
LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
AutoExceptionHandler auto_exception_handler;
ExceptionHandler *current_handler = auto_exception_handler.get_handler();
ExceptionHandler* current_handler = auto_exception_handler.get_handler();
// Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions. This
// logic will short-circuit before calling WriteMinidumpOnHandlerThread,
@ -296,15 +354,35 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {
LONG action;
bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
(code == EXCEPTION_SINGLE_STEP);
if ((!is_debug_exception || current_handler->get_handle_debug_exceptions()) &&
current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL)) {
// The handler fully handled the exception. Returning
// EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually
// results in the applicaiton being terminated.
//
// Note: If the application was launched from within the Cygwin
// environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the
// application to be restarted.
bool success = false;
if (!is_debug_exception ||
current_handler->get_handle_debug_exceptions()) {
// If out-of-proc crash handler client is available, we have to use that
// to generate dump and we cannot fall back on in-proc dump generation
// because we never prepared for an in-proc dump generation
// In case of out-of-process dump generation, directly call
// WriteMinidumpWithException since there is no separate thread running.
if (current_handler->IsOutOfProcess()) {
success = current_handler->WriteMinidumpWithException(
GetCurrentThreadId(),
exinfo,
NULL);
} else {
success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL);
}
}
// The handler fully handled the exception. Returning
// EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually
// results in the application being terminated.
//
// Note: If the application was launched from within the Cygwin
// environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the
// application to be restarted.
if (success) {
action = EXCEPTION_EXECUTE_HANDLER;
} else {
// There was an exception, it was a breakpoint or something else ignored
@ -327,35 +405,51 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {
#if _MSC_VER >= 1400 // MSVC 2005/8
// static
void ExceptionHandler::HandleInvalidParameter(const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t reserved) {
// This is an invalid parameter, not an exception. It's safe to play with
// sprintf here.
AutoExceptionHandler auto_exception_handler;
ExceptionHandler *current_handler = auto_exception_handler.get_handler();
ExceptionHandler* current_handler = auto_exception_handler.get_handler();
MDRawAssertionInfo assertion;
memset(&assertion, 0, sizeof(assertion));
_snwprintf_s(reinterpret_cast<wchar_t *>(assertion.expression),
_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression),
sizeof(assertion.expression) / sizeof(assertion.expression[0]),
_TRUNCATE, L"%s", expression);
_snwprintf_s(reinterpret_cast<wchar_t *>(assertion.function),
_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function),
sizeof(assertion.function) / sizeof(assertion.function[0]),
_TRUNCATE, L"%s", function);
_snwprintf_s(reinterpret_cast<wchar_t *>(assertion.file),
_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file),
sizeof(assertion.file) / sizeof(assertion.file[0]),
_TRUNCATE, L"%s", file);
assertion.line = line;
assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;
if (!current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion)) {
bool success = false;
// In case of out-of-process dump generation, directly call
// WriteMinidumpWithException since there is no separate thread running.
if (current_handler->IsOutOfProcess()) {
success = current_handler->WriteMinidumpWithException(
GetCurrentThreadId(),
NULL,
&assertion);
} else {
success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);
}
if (!success) {
if (current_handler->previous_iph_) {
// The handler didn't fully handle the exception. Give it to the
// previous invalid parameter handler.
current_handler->previous_iph_(expression, function, file, line, reserved);
current_handler->previous_iph_(expression,
function,
file,
line,
reserved);
} else {
// If there's no previous handler, pass the exception back in to the
// invalid parameter handler's core. That's the routine that called this
@ -384,13 +478,26 @@ void ExceptionHandler::HandleInvalidParameter(const wchar_t *expression,
// static
void ExceptionHandler::HandlePureVirtualCall() {
AutoExceptionHandler auto_exception_handler;
ExceptionHandler *current_handler = auto_exception_handler.get_handler();
ExceptionHandler* current_handler = auto_exception_handler.get_handler();
MDRawAssertionInfo assertion;
memset(&assertion, 0, sizeof(assertion));
assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;
if (!current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion)) {
bool success = false;
// In case of out-of-process dump generation, directly call
// WriteMinidumpWithException since there is no separate thread running.
if (current_handler->IsOutOfProcess()) {
success = current_handler->WriteMinidumpWithException(
GetCurrentThreadId(),
NULL,
&assertion);
} else {
success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);
}
if (!success) {
if (current_handler->previous_pch_) {
// The handler didn't fully handle the exception. Give it to the
// previous purecall handler.
@ -409,7 +516,7 @@ void ExceptionHandler::HandlePureVirtualCall() {
}
bool ExceptionHandler::WriteMinidumpOnHandlerThread(
EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion) {
EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) {
EnterCriticalSection(&handler_critical_section_);
// Set up data to be passed in to the handler thread.
@ -438,7 +545,15 @@ bool ExceptionHandler::WriteMinidump() {
return WriteMinidumpForException(NULL);
}
bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS *exinfo) {
bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
// In case of out-of-process dump generation, directly call
// WriteMinidumpWithException since there is no separate thread running.
if (IsOutOfProcess()) {
return WriteMinidumpWithException(GetCurrentThreadId(),
exinfo,
NULL);
}
bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);
UpdateNextID();
return success;
@ -447,7 +562,7 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS *exinfo) {
// static
bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
MinidumpCallback callback,
void *callback_context) {
void* callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context,
HANDLER_NONE);
return handler.WriteMinidump();
@ -455,8 +570,8 @@ bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
bool ExceptionHandler::WriteMinidumpWithException(
DWORD requesting_thread_id,
EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion) {
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion) {
// Give user code a chance to approve or prevent writing a minidump. If the
// filter returns false, don't handle the exception at all. If this method
// was called as a result of an exception, returning false will cause
@ -468,63 +583,77 @@ bool ExceptionHandler::WriteMinidumpWithException(
}
bool success = false;
if (minidump_write_dump_) {
HANDLE dump_file = CreateFile(next_minidump_path_c_,
GENERIC_WRITE,
0, // no sharing
NULL,
CREATE_NEW, // fail if exists
FILE_ATTRIBUTE_NORMAL,
NULL);
if (dump_file != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION except_info;
except_info.ThreadId = requesting_thread_id;
except_info.ExceptionPointers = exinfo;
except_info.ClientPointers = FALSE;
if (IsOutOfProcess()) {
// Use the EXCEPTION_POINTERS overload for RequestDump if
// both exinfo and assertion are NULL.
if (!assertion) {
success = crash_generation_client_->RequestDump(exinfo);
} else {
success = crash_generation_client_->RequestDump(assertion);
}
} else {
if (minidump_write_dump_) {
HANDLE dump_file = CreateFile(next_minidump_path_c_,
GENERIC_WRITE,
0, // no sharing
NULL,
CREATE_NEW, // fail if exists
FILE_ATTRIBUTE_NORMAL,
NULL);
if (dump_file != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION except_info;
except_info.ThreadId = requesting_thread_id;
except_info.ExceptionPointers = exinfo;
except_info.ClientPointers = FALSE;
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
// information about the exception handler to the Breakpad processor. The
// information will help the processor determine which threads are
// relevant. The Breakpad processor does not require this information but
// can function better with Breakpad-generated dumps when it is present.
// The native debugger is not harmed by the presence of this information.
MDRawBreakpadInfo breakpad_info;
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
breakpad_info.dump_thread_id = GetCurrentThreadId();
breakpad_info.requesting_thread_id = requesting_thread_id;
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
// information about the exception handler to the Breakpad processor. The
// information will help the processor determine which threads are
// relevant. The Breakpad processor does not require this information but
// can function better with Breakpad-generated dumps when it is present.
// The native debugger is not harmed by the presence of this information.
MDRawBreakpadInfo breakpad_info;
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
breakpad_info.dump_thread_id = GetCurrentThreadId();
breakpad_info.requesting_thread_id = requesting_thread_id;
// Leave room in user_stream_array for a possible assertion info stream.
MINIDUMP_USER_STREAM user_stream_array[2];
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
user_stream_array[0].BufferSize = sizeof(breakpad_info);
user_stream_array[0].Buffer = &breakpad_info;
// Leave room in user_stream_array for a possible assertion info stream.
MINIDUMP_USER_STREAM user_stream_array[2];
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
user_stream_array[0].BufferSize = sizeof(breakpad_info);
user_stream_array[0].Buffer = &breakpad_info;
MINIDUMP_USER_STREAM_INFORMATION user_streams;
user_streams.UserStreamCount = 1;
user_streams.UserStreamArray = user_stream_array;
MINIDUMP_USER_STREAM_INFORMATION user_streams;
user_streams.UserStreamCount = 1;
user_streams.UserStreamArray = user_stream_array;
if (assertion) {
user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
user_stream_array[1].Buffer = assertion;
++user_streams.UserStreamCount;
if (assertion) {
user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
user_stream_array[1].Buffer = assertion;
++user_streams.UserStreamCount;
}
// The explicit comparison to TRUE avoids a warning (C4800).
success = (minidump_write_dump_(GetCurrentProcess(),
GetCurrentProcessId(),
dump_file,
dump_type_,
exinfo ? &except_info : NULL,
&user_streams,
NULL) == TRUE);
CloseHandle(dump_file);
}
// The explicit comparison to TRUE avoids a warning (C4800).
success = (minidump_write_dump_(GetCurrentProcess(),
GetCurrentProcessId(),
dump_file,
MiniDumpNormal,
exinfo ? &except_info : NULL,
&user_streams,
NULL) == TRUE);
CloseHandle(dump_file);
}
}
if (callback_) {
// TODO(munjal): In case of out-of-process dump generation, both
// dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process
// scenario, the server process ends up creating the dump path and dump
// id so they are not known to the client.
success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
exinfo, assertion, success);
}

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

@ -68,7 +68,10 @@
#include <string>
#include <vector>
#include "client/windows/common/ipc_protocol.h"
#include "client/windows/crash_generation/crash_generation_client.h"
#include "google_breakpad/common/minidump_format.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
@ -88,8 +91,8 @@ class ExceptionHandler {
// 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, EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion);
typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion);
// A callback function to run after the minidump has been written.
// minidump_id is a unique id for the dump, so the minidump
@ -110,11 +113,16 @@ class ExceptionHandler {
// 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 wchar_t *dump_path,
const wchar_t *minidump_id,
void *context,
EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion,
//
// For out-of-process dump generation, dump path and minidump ID will always
// be NULL. In case of out-of-process dump generation, the dump path and
// minidump id are controlled by the server process and are not communicated
// back to the crashing process.
typedef bool (*MinidumpCallback)(const wchar_t* dump_path,
const wchar_t* minidump_id,
void* context,
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion,
bool succeeded);
// HandlerType specifies which types of handlers should be installed, if
@ -139,11 +147,26 @@ class ExceptionHandler {
// minidump. Minidump files will be written to dump_path, and the optional
// callback is called after writing the dump file, as described above.
// handler_types specifies the types of handlers that should be installed.
ExceptionHandler(const wstring &dump_path,
ExceptionHandler(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
void* callback_context,
int handler_types);
// Creates a new ExcetpionHandler instance that can attempt to perform
// out-of-process dump generation if pipe_name is not NULL. If pipe_name is
// NULL, or if out-of-process dump generation registration step fails,
// in-process dump generation will be used. This also allows specifying
// the dump type to generate.
ExceptionHandler(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
int handler_types,
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
const CustomClientInfo* custom_info);
~ExceptionHandler();
// Get and set the minidump path.
@ -160,12 +183,12 @@ class ExceptionHandler {
// Writes a minidump immediately, with the user-supplied exception
// information.
bool WriteMinidumpForException(EXCEPTION_POINTERS *exinfo);
bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo);
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const wstring &dump_path,
MinidumpCallback callback, void *callback_context);
MinidumpCallback callback, void* callback_context);
// Get the thread ID of the thread requesting the dump (either the exception
// thread or any other thread that called WriteMinidump directly). This
@ -179,9 +202,22 @@ class ExceptionHandler {
handle_debug_exceptions_ = handle_debug_exceptions;
}
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
private:
friend class AutoExceptionHandler;
// Initializes the instance with given values.
void Initialize(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
int handler_types,
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
const CustomClientInfo* custom_info);
// Function pointer type for MiniDumpWriteDump, which is looked up
// dynamically.
typedef BOOL (WINAPI *MiniDumpWriteDump_type)(
@ -194,14 +230,14 @@ class ExceptionHandler {
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
// Function pointer type for UuidCreate, which is looked up dynamically.
typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID *Uuid);
typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid);
// Runs the main loop for the exception handler thread.
static DWORD WINAPI ExceptionHandlerThreadMain(void *lpParameter);
static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter);
// Called on the exception thread when an unhandled exception occurs.
// Signals the exception handler thread to handle the exception.
static LONG WINAPI HandleException(EXCEPTION_POINTERS *exinfo);
static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo);
#if _MSC_VER >= 1400 // MSVC 2005/8
// This function will be called by some CRT functions when they detect
@ -209,9 +245,9 @@ class ExceptionHandler {
// the CRT may display an assertion dialog before calling this function,
// and the function will not be called unless the assertion dialog is
// dismissed by clicking "Ignore."
static void HandleInvalidParameter(const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
static void HandleInvalidParameter(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t reserved);
#endif // _MSC_VER >= 1400
@ -229,8 +265,8 @@ class ExceptionHandler {
// is NULL. If the dump is requested as a result of an assertion
// (such as an invalid parameter being passed to a CRT function),
// assertion contains data about the assertion, otherwise, it is NULL.
bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion);
bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion);
// This function does the actual writing of a minidump. It is called
// on the handler thread. requesting_thread_id is the ID of the thread
@ -238,8 +274,8 @@ class ExceptionHandler {
// an exception, exinfo contains exception information, otherwise,
// it is NULL.
bool WriteMinidumpWithException(DWORD requesting_thread_id,
EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion);
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion);
// Generates a new ID and stores it in next_minidump_id_, and stores the
// path of the next minidump to be written in next_minidump_path_.
@ -247,7 +283,9 @@ class ExceptionHandler {
FilterCallback filter_;
MinidumpCallback callback_;
void *callback_context_;
void* callback_context_;
scoped_ptr<CrashGenerationClient> crash_generation_client_;
// The directory in which a minidump will be written, set by the dump_path
// argument to the constructor, or set_dump_path.
@ -266,12 +304,13 @@ class ExceptionHandler {
// pointers are not owned by the ExceptionHandler object, but their lifetimes
// should be equivalent to the lifetimes of the associated wstring, provided
// that the wstrings are not altered.
const wchar_t *dump_path_c_;
const wchar_t *next_minidump_id_c_;
const wchar_t *next_minidump_path_c_;
const wchar_t* dump_path_c_;
const wchar_t* next_minidump_id_c_;
const wchar_t* next_minidump_path_c_;
HMODULE dbghelp_module_;
MiniDumpWriteDump_type minidump_write_dump_;
MINIDUMP_TYPE dump_type_;
HMODULE rpcrt4_module_;
UuidCreate_type uuid_create_;
@ -322,11 +361,11 @@ class ExceptionHandler {
// The exception info passed to the exception handler on the exception
// thread, if an exception occurred. NULL for user-requested dumps.
EXCEPTION_POINTERS *exception_info_;
EXCEPTION_POINTERS* exception_info_;
// If the handler is invoked due to an assertion, this will contain a
// pointer to the assertion information. It is NULL at other times.
MDRawAssertionInfo *assertion_;
MDRawAssertionInfo* assertion_;
// The return value of the handler, passed from the handler thread back to
// the requesting thread.
@ -342,7 +381,7 @@ class ExceptionHandler {
// which ExceptionHandler object to route an exception to. When an
// ExceptionHandler is created with install_handler true, it will append
// itself to this list.
static vector<ExceptionHandler *> *handler_stack_;
static vector<ExceptionHandler*>* handler_stack_;
// The index of the ExceptionHandler in handler_stack_ that will handle the
// next exception. Note that 0 means the last entry in handler_stack_, 1

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

@ -1,315 +1,323 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="exception_handler"
ProjectGUID="{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
RootNamespace="exception_handler"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\exception_handler.cc"
>
</File>
<File
RelativePath="..\..\..\common\windows\guid_string.cc"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\exception_handler.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\guid_string.h"
>
</File>
<File
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\string_utils-inl.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="exception_handler"
ProjectGUID="{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
RootNamespace="exception_handler"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
AdditionalDependencies="crash_generation.lib"
AdditionalLibraryDirectories="..\$(ConfigurationName)"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
AdditionalDependencies="crash_generation.lib"
AdditionalLibraryDirectories="..\$(ConfigurationName)"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
AdditionalDependencies="crash_generation.lib"
AdditionalLibraryDirectories="..\$(ConfigurationName)"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
AdditionalDependencies="crash_generation.lib"
AdditionalLibraryDirectories="..\$(ConfigurationName)"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\exception_handler.cc"
>
</File>
<File
RelativePath="..\..\..\common\windows\guid_string.cc"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\exception_handler.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\guid_string.h"
>
</File>
<File
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\string_utils-inl.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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

@ -71,9 +71,9 @@ ReportResult CrashReportSender::SendCrashReport(
bool result = HTTPUpload::SendRequest(
url, parameters, dump_file_name, L"upload_file_minidump", report_code,
&http_response);
ReportSent(today);
if (result) {
ReportSent(today);
return RESULT_SUCCEEDED;
} else if (http_response == 400) { // TODO: update if/when the server
// switches to a different code

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

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

@ -1,307 +1,307 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="crash_report_sender"
ProjectGUID="{9946A048-043B-4F8F-9E07-9297B204714C}"
RootNamespace="crash_report_sender"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\crash_report_sender.cc"
>
</File>
<File
RelativePath="..\..\..\common\windows\http_upload.cc"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\crash_report_sender.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\http_upload.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="crash_report_sender"
ProjectGUID="{9946A048-043B-4F8F-9E07-9297B204714C}"
RootNamespace="crash_report_sender"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\.."
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\crash_report_sender.cc"
>
</File>
<File
RelativePath="..\..\..\common\windows\http_upload.cc"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\crash_report_sender.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\http_upload.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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

@ -1,53 +1,53 @@
// 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.
#include "precompile.h"
namespace google_breakpad {
Base::Base(Derived* derived)
: derived_(derived) {
}
Base::~Base() {
derived_->DoSomething();
}
#pragma warning(push)
#pragma warning(disable:4355)
// Disable warning C4355: 'this' : used in base member initializer list.
Derived::Derived()
: Base(this) { // C4355
}
#pragma warning(pop)
void Derived::DoSomething() {
}
} // namespace google_breakpad
// 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.
#include "precompile.h"
namespace google_breakpad {
Base::Base(Derived* derived)
: derived_(derived) {
}
Base::~Base() {
derived_->DoSomething();
}
#pragma warning(push)
#pragma warning(disable:4355)
// Disable warning C4355: 'this' : used in base member initializer list.
Derived::Derived()
: Base(this) { // C4355
}
#pragma warning(pop)
void Derived::DoSomething() {
}
} // namespace google_breakpad

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

@ -1,57 +1,57 @@
// 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.
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_ABSTRACT_CLASS_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_ABSTRACT_CLASS_H__
namespace google_breakpad {
// Dummy classes to help generate a pure call violation.
class Derived;
class Base {
public:
Base(Derived* derived);
virtual ~Base();
virtual void DoSomething() = 0;
private:
Derived* derived_;
};
class Derived : public Base {
public:
Derived();
virtual void DoSomething();
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
// 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.
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_ABSTRACT_CLASS_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_ABSTRACT_CLASS_H__
namespace google_breakpad {
// Dummy classes to help generate a pure call violation.
class Derived;
class Base {
public:
Base(Derived* derived);
virtual ~Base();
virtual void DoSomething() = 0;
private:
Derived* derived_;
};
class Derived : public Base {
public:
Derived();
virtual void DoSomething();
};
} // namespace google_breakpad
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__

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

@ -1,467 +1,510 @@
// 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.
// crash_generation_app.cpp : Defines the entry point for the application.
//
#include "precompile.h"
namespace google_breakpad {
const int kMaxLoadString = 100;
const wchar_t kPipeName[] = L"\\\\.\\pipe\\GoogleCrashServices";
const DWORD kEditBoxStyles = WS_CHILD |
WS_VISIBLE |
WS_VSCROLL |
ES_LEFT |
ES_MULTILINE |
ES_AUTOVSCROLL |
ES_READONLY;
// Maximum length of a line in the edit box.
const size_t kMaximumLineLength = 256;
// CS to access edit control in a thread safe way.
static CRITICAL_SECTION* cs_edit = NULL;
// Edit control.
static HWND client_status_edit_box;
HINSTANCE current_instance; // Current instance.
TCHAR title[kMaxLoadString]; // Title bar text.
TCHAR window_class[kMaxLoadString]; // Main window class name.
ATOM MyRegisterClass(HINSTANCE instance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
static ExceptionHandler* handler = NULL;
static CrashGenerationServer* crash_server = NULL;
// Registers the window class.
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this
// function so that the application will get 'well formed' small icons
// associated with it.
ATOM MyRegisterClass(HINSTANCE instance) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = instance;
wcex.hIcon = LoadIcon(instance,
MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP);
wcex.lpszClassName = window_class;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
// Saves instance handle and creates main window
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
BOOL InitInstance(HINSTANCE instance, int command_show) {
current_instance = instance;
HWND wnd = CreateWindow(window_class,
title,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
NULL,
NULL,
instance,
NULL);
if (!wnd) {
return FALSE;
}
ShowWindow(wnd, command_show);
UpdateWindow(wnd);
return TRUE;
}
static void AppendTextToEditBox(TCHAR* text) {
EnterCriticalSection(cs_edit);
SYSTEMTIME current_time;
GetLocalTime(&current_time);
TCHAR line[kMaximumLineLength];
int result = swprintf_s(line,
kMaximumLineLength,
L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
current_time.wMonth,
current_time.wDay,
current_time.wYear,
current_time.wHour,
current_time.wMinute,
current_time.wSecond,
text);
if (result == -1) {
return;
}
int length = GetWindowTextLength(client_status_edit_box);
SendMessage(client_status_edit_box,
EM_SETSEL,
(WPARAM)length,
(LPARAM)length);
SendMessage(client_status_edit_box,
EM_REPLACESEL,
(WPARAM)FALSE,
(LPARAM)line);
LeaveCriticalSection(cs_edit);
}
static DWORD WINAPI AppendTextWorker(void* context) {
TCHAR* text = reinterpret_cast<TCHAR*>(context);
AppendTextToEditBox(text);
delete[] text;
return 0;
}
// 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.
// crash_generation_app.cpp : Defines the entry point for the application.
//
#include "precompile.h"
namespace google_breakpad {
const int kMaxLoadString = 100;
const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashServices\\TestServer";
const DWORD kEditBoxStyles = WS_CHILD |
WS_VISIBLE |
WS_VSCROLL |
ES_LEFT |
ES_MULTILINE |
ES_AUTOVSCROLL |
ES_READONLY;
// Maximum length of a line in the edit box.
const size_t kMaximumLineLength = 256;
// CS to access edit control in a thread safe way.
static CRITICAL_SECTION* cs_edit = NULL;
// Edit control.
static HWND client_status_edit_box;
HINSTANCE current_instance; // Current instance.
TCHAR title[kMaxLoadString]; // Title bar text.
TCHAR window_class[kMaxLoadString]; // Main window class name.
ATOM MyRegisterClass(HINSTANCE instance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
static int kCustomInfoCount = 2;
static CustomInfoEntry kCustomInfoEntries[] = {
CustomInfoEntry(L"prod", L"CrashTestApp"),
CustomInfoEntry(L"ver", L"1.0"),
};
static ExceptionHandler* handler = NULL;
static CrashGenerationServer* crash_server = NULL;
// Registers the window class.
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this
// function so that the application will get 'well formed' small icons
// associated with it.
ATOM MyRegisterClass(HINSTANCE instance) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = instance;
wcex.hIcon = LoadIcon(instance,
MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP);
wcex.lpszClassName = window_class;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
// Saves instance handle and creates main window
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
BOOL InitInstance(HINSTANCE instance, int command_show) {
current_instance = instance;
HWND wnd = CreateWindow(window_class,
title,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
NULL,
NULL,
instance,
NULL);
if (!wnd) {
return FALSE;
}
ShowWindow(wnd, command_show);
UpdateWindow(wnd);
return TRUE;
}
static void AppendTextToEditBox(TCHAR* text) {
EnterCriticalSection(cs_edit);
SYSTEMTIME current_time;
GetLocalTime(&current_time);
TCHAR line[kMaximumLineLength];
int result = swprintf_s(line,
kMaximumLineLength,
L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
current_time.wMonth,
current_time.wDay,
current_time.wYear,
current_time.wHour,
current_time.wMinute,
current_time.wSecond,
text);
if (result == -1) {
return;
}
int length = GetWindowTextLength(client_status_edit_box);
SendMessage(client_status_edit_box,
EM_SETSEL,
(WPARAM)length,
(LPARAM)length);
SendMessage(client_status_edit_box,
EM_REPLACESEL,
(WPARAM)FALSE,
(LPARAM)line);
LeaveCriticalSection(cs_edit);
}
static DWORD WINAPI AppendTextWorker(void* context) {
TCHAR* text = reinterpret_cast<TCHAR*>(context);
AppendTextToEditBox(text);
delete[] text;
return 0;
}
bool ShowDumpResults(const wchar_t* dump_path,
const wchar_t* minidump_id,
void* context,
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion,
bool succeeded) {
TCHAR* text = new TCHAR[kMaximumLineLength];
int result = swprintf_s(text,
kMaximumLineLength,
TEXT("Dump generation request %s\r\n"),
succeeded ? TEXT("succeeded") : TEXT("failed"));
if (result == -1) {
delete [] text;
}
AppendTextWorker(text);
return succeeded;
}
static void _cdecl ShowClientConnected(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
int result = swprintf_s(line,
kMaximumLineLength,
L"Client connected:\t\t%d\r\n",
client_info->pid());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
static void _cdecl ShowClientCrashed(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
int result = swprintf_s(line,
kMaximumLineLength,
TEXT("Client requested dump:\t%d\r\n"),
client_info->pid());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
static void _cdecl ShowClientExited(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
int result = swprintf_s(line,
kMaximumLineLength,
TEXT("Client exited:\t\t%d\r\n"),
client_info->pid());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
void CrashServerStart() {
// Do not create another instance of the server.
if (crash_server) {
return;
}
std::wstring dump_path = L"C:\\Dumps\\";
crash_server = new CrashGenerationServer(kPipeName,
ShowClientConnected,
NULL,
ShowClientCrashed,
NULL,
ShowClientExited,
NULL,
true,
&dump_path);
if (!crash_server->Start()) {
MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
delete crash_server;
crash_server = NULL;
}
}
void CrashServerStop() {
delete crash_server;
crash_server = NULL;
}
void DerefZeroCrash() {
int* x = 0;
*x = 1;
}
void InvalidParamCrash() {
printf(NULL);
}
void PureCallCrash() {
Derived derived;
}
void RequestDump() {
if (!handler->WriteMinidump()) {
MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
}
}
void CleanUp() {
if (cs_edit) {
DeleteCriticalSection(cs_edit);
delete cs_edit;
}
if (handler) {
delete handler;
}
if (crash_server) {
delete crash_server;
}
}
// Processes messages for the main window.
//
// WM_COMMAND - process the application menu.
// WM_PAINT - Paint the main window.
// WM_DESTROY - post a quit message and return.
LRESULT CALLBACK WndProc(HWND wnd,
UINT message,
WPARAM w_param,
LPARAM l_param) {
int message_id;
int message_event;
PAINTSTRUCT ps;
HDC hdc;
#pragma warning(push)
#pragma warning(disable:4312)
// Disable warning C4312: 'type cast' : conversion from 'LONG' to
// 'HINSTANCE' of greater size.
// The value returned by GetwindowLong in the case below returns unsigned.
HINSTANCE instance = (HINSTANCE)GetWindowLong(wnd, GWL_HINSTANCE);
#pragma warning(pop)
switch (message) {
case WM_COMMAND:
// Parse the menu selections.
message_id = LOWORD(w_param);
message_event = HIWORD(w_param);
switch (message_id) {
case IDM_ABOUT:
DialogBox(current_instance,
MAKEINTRESOURCE(IDD_ABOUTBOX),
wnd,
About);
break;
case IDM_EXIT:
DestroyWindow(wnd);
break;
case ID_SERVER_START:
CrashServerStart();
break;
case ID_SERVER_STOP:
CrashServerStop();
break;
case ID_CLIENT_DEREFZERO:
DerefZeroCrash();
break;
case ID_CLIENT_INVALIDPARAM:
InvalidParamCrash();
break;
case ID_CLIENT_PURECALL:
PureCallCrash();
break;
case ID_CLIENT_REQUESTEXPLICITDUMP:
RequestDump();
break;
default:
return DefWindowProc(wnd, message, w_param, l_param);
}
break;
case WM_CREATE:
client_status_edit_box = CreateWindow(TEXT("EDIT"),
NULL,
kEditBoxStyles,
0,
0,
0,
0,
wnd,
NULL,
instance,
NULL);
break;
case WM_SIZE:
// Make the edit control the size of the window's client area.
MoveWindow(client_status_edit_box,
0,
0,
LOWORD(l_param), // width of client area.
HIWORD(l_param), // height of client area.
TRUE); // repaint window.
break;
case WM_SETFOCUS:
SetFocus(client_status_edit_box);
break;
case WM_PAINT:
hdc = BeginPaint(wnd, &ps);
EndPaint(wnd, &ps);
break;
case WM_DESTROY:
CleanUp();
PostQuitMessage(0);
break;
default:
return DefWindowProc(wnd, message, w_param, l_param);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND dlg,
UINT message,
WPARAM w_param,
LPARAM l_param) {
UNREFERENCED_PARAMETER(l_param);
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
EndDialog(dlg, LOWORD(w_param));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
} // namespace google_breakpad
int APIENTRY _tWinMain(HINSTANCE instance,
HINSTANCE previous_instance,
LPTSTR command_line,
int command_show) {
using namespace google_breakpad;
UNREFERENCED_PARAMETER(previous_instance);
UNREFERENCED_PARAMETER(command_line);
cs_edit = new CRITICAL_SECTION();
InitializeCriticalSection(cs_edit);
// This is needed for CRT to not show dialog for invalid param
// failures and instead let the code handle it.
_CrtSetReportMode(_CRT_ASSERT, 0);
handler = new ExceptionHandler(L"C:\\dumps\\",
NULL,
google_breakpad::ShowDumpResults,
NULL,
ExceptionHandler::HANDLER_ALL,
MiniDumpNormal,
kPipeName);
// Initialize global strings.
LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
LoadString(instance,
IDC_CRASHGENERATIONAPP,
window_class,
kMaxLoadString);
MyRegisterClass(instance);
// Perform application initialization.
if (!InitInstance (instance, command_show)) {
return FALSE;
}
HACCEL accel_table = LoadAccelerators(
instance,
MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
// Main message loop.
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
bool succeeded) {
TCHAR* text = new TCHAR[kMaximumLineLength];
text[0] = _T('\0');
int result = swprintf_s(text,
kMaximumLineLength,
TEXT("Dump generation request %s\r\n"),
succeeded ? TEXT("succeeded") : TEXT("failed"));
if (result == -1) {
delete [] text;
}
AppendTextWorker(text);
return succeeded;
}
static void _cdecl ShowClientConnected(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
int result = swprintf_s(line,
kMaximumLineLength,
L"Client connected:\t\t%d\r\n",
client_info->pid());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
static void _cdecl ShowClientCrashed(void* context,
const ClientInfo* client_info,
const wstring* dump_path) {
TCHAR* line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
int result = swprintf_s(line,
kMaximumLineLength,
TEXT("Client requested dump:\t%d\r\n"),
client_info->pid());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
CustomClientInfo custom_info = client_info->GetCustomInfo();
if (custom_info.count <= 0) {
return;
}
wstring str_line;
for (int i = 0; i < custom_info.count; ++i) {
if (i > 0) {
str_line += L", ";
}
str_line += custom_info.entries[i].name;
str_line += L": ";
str_line += custom_info.entries[i].value;
}
line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
result = swprintf_s(line,
kMaximumLineLength,
L"%s\n",
str_line.c_str());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
static void _cdecl ShowClientExited(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
int result = swprintf_s(line,
kMaximumLineLength,
TEXT("Client exited:\t\t%d\r\n"),
client_info->pid());
if (result == -1) {
delete[] line;
return;
}
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
void CrashServerStart() {
// Do not create another instance of the server.
if (crash_server) {
return;
}
std::wstring dump_path = L"C:\\Dumps\\";
crash_server = new CrashGenerationServer(kPipeName,
NULL,
ShowClientConnected,
NULL,
ShowClientCrashed,
NULL,
ShowClientExited,
NULL,
true,
&dump_path);
if (!crash_server->Start()) {
MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
delete crash_server;
crash_server = NULL;
}
}
void CrashServerStop() {
delete crash_server;
crash_server = NULL;
}
void DerefZeroCrash() {
int* x = 0;
*x = 1;
}
void InvalidParamCrash() {
printf(NULL);
}
void PureCallCrash() {
Derived derived;
}
void RequestDump() {
if (!handler->WriteMinidump()) {
MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
}
kCustomInfoEntries[1].set_value(L"1.1");
}
void CleanUp() {
if (cs_edit) {
DeleteCriticalSection(cs_edit);
delete cs_edit;
}
if (handler) {
delete handler;
}
if (crash_server) {
delete crash_server;
}
}
// Processes messages for the main window.
//
// WM_COMMAND - process the application menu.
// WM_PAINT - Paint the main window.
// WM_DESTROY - post a quit message and return.
LRESULT CALLBACK WndProc(HWND wnd,
UINT message,
WPARAM w_param,
LPARAM l_param) {
int message_id;
int message_event;
PAINTSTRUCT ps;
HDC hdc;
#pragma warning(push)
#pragma warning(disable:4312)
// Disable warning C4312: 'type cast' : conversion from 'LONG' to
// 'HINSTANCE' of greater size.
// The value returned by GetwindowLong in the case below returns unsigned.
HINSTANCE instance = (HINSTANCE)GetWindowLong(wnd, GWL_HINSTANCE);
#pragma warning(pop)
switch (message) {
case WM_COMMAND:
// Parse the menu selections.
message_id = LOWORD(w_param);
message_event = HIWORD(w_param);
switch (message_id) {
case IDM_ABOUT:
DialogBox(current_instance,
MAKEINTRESOURCE(IDD_ABOUTBOX),
wnd,
About);
break;
case IDM_EXIT:
DestroyWindow(wnd);
break;
case ID_SERVER_START:
CrashServerStart();
break;
case ID_SERVER_STOP:
CrashServerStop();
break;
case ID_CLIENT_DEREFZERO:
DerefZeroCrash();
break;
case ID_CLIENT_INVALIDPARAM:
InvalidParamCrash();
break;
case ID_CLIENT_PURECALL:
PureCallCrash();
break;
case ID_CLIENT_REQUESTEXPLICITDUMP:
RequestDump();
break;
default:
return DefWindowProc(wnd, message, w_param, l_param);
}
break;
case WM_CREATE:
client_status_edit_box = CreateWindow(TEXT("EDIT"),
NULL,
kEditBoxStyles,
0,
0,
0,
0,
wnd,
NULL,
instance,
NULL);
break;
case WM_SIZE:
// Make the edit control the size of the window's client area.
MoveWindow(client_status_edit_box,
0,
0,
LOWORD(l_param), // width of client area.
HIWORD(l_param), // height of client area.
TRUE); // repaint window.
break;
case WM_SETFOCUS:
SetFocus(client_status_edit_box);
break;
case WM_PAINT:
hdc = BeginPaint(wnd, &ps);
EndPaint(wnd, &ps);
break;
case WM_DESTROY:
CleanUp();
PostQuitMessage(0);
break;
default:
return DefWindowProc(wnd, message, w_param, l_param);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND dlg,
UINT message,
WPARAM w_param,
LPARAM l_param) {
UNREFERENCED_PARAMETER(l_param);
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
EndDialog(dlg, LOWORD(w_param));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
} // namespace google_breakpad
int APIENTRY _tWinMain(HINSTANCE instance,
HINSTANCE previous_instance,
LPTSTR command_line,
int command_show) {
using namespace google_breakpad;
UNREFERENCED_PARAMETER(previous_instance);
UNREFERENCED_PARAMETER(command_line);
cs_edit = new CRITICAL_SECTION();
InitializeCriticalSection(cs_edit);
CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount};
// This is needed for CRT to not show dialog for invalid param
// failures and instead let the code handle it.
_CrtSetReportMode(_CRT_ASSERT, 0);
handler = new ExceptionHandler(L"C:\\dumps\\",
NULL,
google_breakpad::ShowDumpResults,
NULL,
ExceptionHandler::HANDLER_ALL,
MiniDumpNormal,
kPipeName,
&custom_info);
// Initialize global strings.
LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
LoadString(instance,
IDC_CRASHGENERATIONAPP,
window_class,
kMaxLoadString);
MyRegisterClass(instance);
// Perform application initialization.
if (!InitInstance (instance, command_show)) {
return FALSE;
}
HACCEL accel_table = LoadAccelerators(
instance,
MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
// Main message loop.
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}

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

@ -1,35 +1,35 @@
// 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.
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
#include "resource.h"
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
// 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.
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
#include "resource.h"
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

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

@ -1,144 +1,144 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_CRASHGENERATIONAPP ICON "crash_generation_app.ico"
IDI_SMALL ICON "small.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDC_CRASHGENERATIONAPP MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Server"
BEGIN
MENUITEM "&Start", ID_SERVER_START
MENUITEM "S&top", ID_SERVER_STOP
END
POPUP "&Client"
BEGIN
MENUITEM "&Deref Zero", ID_CLIENT_DEREFZERO
MENUITEM "&Invalid Param", ID_CLIENT_INVALIDPARAM
MENUITEM "&Pure Call", ID_CLIENT_PURECALL
MENUITEM "&Request Dump", ID_CLIENT_REQUESTEXPLICITDUMP
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDC_CRASHGENERATIONAPP ACCELERATORS
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG 22, 17, 230, 75
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "System"
BEGIN
ICON IDI_CRASHGENERATIONAPP,IDC_MYICON,14,9,16,16
LTEXT "CrashGenerationApp Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
LTEXT "Copyright (C) 2008",IDC_STATIC,49,20,119,8
DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_APP_TITLE "CrashGenerationApp"
IDC_CRASHGENERATIONAPP "CRASHGENERATIONAPP"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_CRASHGENERATIONAPP ICON "crash_generation_app.ico"
IDI_SMALL ICON "small.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDC_CRASHGENERATIONAPP MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Server"
BEGIN
MENUITEM "&Start", ID_SERVER_START
MENUITEM "S&top", ID_SERVER_STOP
END
POPUP "&Client"
BEGIN
MENUITEM "&Deref Zero", ID_CLIENT_DEREFZERO
MENUITEM "&Invalid Param", ID_CLIENT_INVALIDPARAM
MENUITEM "&Pure Call", ID_CLIENT_PURECALL
MENUITEM "&Request Dump", ID_CLIENT_REQUESTEXPLICITDUMP
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDC_CRASHGENERATIONAPP ACCELERATORS
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG 22, 17, 230, 75
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "System"
BEGIN
ICON IDI_CRASHGENERATIONAPP,IDC_MYICON,14,9,16,16
LTEXT "CrashGenerationApp Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
LTEXT "Copyright (C) 2008",IDC_STATIC,49,20,119,8
DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_APP_TITLE "CrashGenerationApp"
IDC_CRASHGENERATIONAPP "CRASHGENERATIONAPP"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

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

@ -1,26 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_app", "crash_generation_app.vcproj", "{A15674ED-713D-4B37-B1D2-0C29C7E533C8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugStaticCRT|Win32 = DebugStaticCRT|Win32
Release|Win32 = Release|Win32
ReleaseStaticCRT|Win32 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Debug|Win32.ActiveCfg = Debug|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Debug|Win32.Build.0 = Debug|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Release|Win32.ActiveCfg = Release|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Release|Win32.Build.0 = Release|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_app", "crash_generation_app.vcproj", "{A15674ED-713D-4B37-B1D2-0C29C7E533C8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugStaticCRT|Win32 = DebugStaticCRT|Win32
Release|Win32 = Release|Win32
ReleaseStaticCRT|Win32 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Debug|Win32.ActiveCfg = Debug|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Debug|Win32.Build.0 = Debug|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Release|Win32.ActiveCfg = Release|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Release|Win32.Build.0 = Release|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

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

@ -1,431 +1,431 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="crash_generation_app"
ProjectGUID="{A15674ED-713D-4B37-B1D2-0C29C7E533C8}"
RootNamespace="CrashGenerationServerApp"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="PreCompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="precompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="PreCompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="precompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\abstract_class.cc"
>
</File>
<File
RelativePath=".\crash_generation_app.cc"
>
</File>
<File
RelativePath=".\precompile.cc"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="DebugStaticCRT|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="ReleaseStaticCRT|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\abstract_class.h"
>
</File>
<File
RelativePath=".\crash_generation_app.h"
>
</File>
<File
RelativePath=".\precompile.h"
>
</File>
<File
RelativePath=".\Resource.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath=".\crash_generation_app.ico"
>
</File>
<File
RelativePath=".\crash_generation_app.rc"
>
</File>
<File
RelativePath=".\small.ico"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="crash_generation_app"
ProjectGUID="{A15674ED-713D-4B37-B1D2-0C29C7E533C8}"
RootNamespace="CrashGenerationServerApp"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="PreCompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="precompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="PreCompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="ReleaseStaticCRT|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\..\"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="precompile.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="exception_handler.lib"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\abstract_class.cc"
>
</File>
<File
RelativePath=".\crash_generation_app.cc"
>
</File>
<File
RelativePath=".\precompile.cc"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="DebugStaticCRT|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="ReleaseStaticCRT|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\abstract_class.h"
>
</File>
<File
RelativePath=".\crash_generation_app.h"
>
</File>
<File
RelativePath=".\precompile.h"
>
</File>
<File
RelativePath=".\Resource.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath=".\crash_generation_app.ico"
>
</File>
<File
RelativePath=".\crash_generation_app.rc"
>
</File>
<File
RelativePath=".\small.ico"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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

@ -1,37 +1,37 @@
// 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.
// precompile.cpp : source file that includes just the standard includes
// CrashGenerationApp.pch will be the pre-compiled header
// precompile.obj will contain the pre-compiled type information
#include "precompile.h"
// Reference any additional headers you need in PRECOMPILE.H
// and not in this file.
// 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.
// precompile.cpp : source file that includes just the standard includes
// CrashGenerationApp.pch will be the pre-compiled header
// precompile.obj will contain the pre-compiled type information
#include "precompile.h"
// Reference any additional headers you need in PRECOMPILE.H
// and not in this file.

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

@ -1,89 +1,90 @@
// 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.
// PreCompile.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
// Modify the following defines if you have to target a platform prior to
// the ones specified below. Refer to MSDN for the latest info on
// corresponding values for different platforms.
// Allow use of features specific to Windows XP or later.
#ifndef WINVER
// Change this to the appropriate value to target other versions of Windows.
#define WINVER 0x0501
#endif
// Allow use of features specific to Windows XP or later.
#ifndef _WIN32_WINNT
// Change this to the appropriate value to target other versions of Windows.
#define _WIN32_WINNT 0x0501
#endif
// Allow use of features specific to Windows 98 or later.
#ifndef _WIN32_WINDOWS
// Change this to the appropriate value to target Windows Me or later.
#define _WIN32_WINDOWS 0x0410
#endif
// Allow use of features specific to IE 6.0 or later.
#ifndef _WIN32_IE
// Change this to the appropriate value to target other versions of IE.
#define _WIN32_IE 0x0600
#endif
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <DbgHelp.h>
#include <malloc.h>
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <cassert>
#include <list>
#include "client/windows/crash_generation/client_info.h"
#include "client/windows/crash_generation/crash_generation_client.h"
#include "client/windows/crash_generation/crash_generation_server.h"
#include "client/windows/crash_generation/minidump_generator.h"
#include "client/windows/handler/exception_handler.h"
#include "client/windows/tests/crash_generation_app/abstract_class.h"
#include "client/windows/tests/crash_generation_app/crash_generation_app.h"
#include "google_breakpad/common/minidump_format.h"
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
// 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.
// PreCompile.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
// Modify the following defines if you have to target a platform prior to
// the ones specified below. Refer to MSDN for the latest info on
// corresponding values for different platforms.
// Allow use of features specific to Windows XP or later.
#ifndef WINVER
// Change this to the appropriate value to target other versions of Windows.
#define WINVER 0x0501
#endif
// Allow use of features specific to Windows XP or later.
#ifndef _WIN32_WINNT
// Change this to the appropriate value to target other versions of Windows.
#define _WIN32_WINNT 0x0501
#endif
// Allow use of features specific to Windows 98 or later.
#ifndef _WIN32_WINDOWS
// Change this to the appropriate value to target Windows Me or later.
#define _WIN32_WINDOWS 0x0410
#endif
// Allow use of features specific to IE 6.0 or later.
#ifndef _WIN32_IE
// Change this to the appropriate value to target other versions of IE.
#define _WIN32_IE 0x0600
#endif
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <DbgHelp.h>
#include <malloc.h>
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <cassert>
#include <list>
#include "client/windows/common/ipc_protocol.h"
#include "client/windows/crash_generation/client_info.h"
#include "client/windows/crash_generation/crash_generation_client.h"
#include "client/windows/crash_generation/crash_generation_server.h"
#include "client/windows/crash_generation/minidump_generator.h"
#include "client/windows/handler/exception_handler.h"
#include "client/windows/tests/crash_generation_app/abstract_class.h"
#include "client/windows/tests/crash_generation_app/crash_generation_app.h"
#include "google_breakpad/common/minidump_format.h"
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__

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

@ -1,73 +1,73 @@
// 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.
// PreCompile.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by crash_generation_app.rc
//
#define IDC_MYICON 2
#define IDD_CRASHGENERATIONAPP_DIALOG 102
#define IDS_APP_TITLE 103
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_CRASHGENERATIONAPP 107
#define IDI_SMALL 108
#define IDC_CRASHGENERATIONAPP 109
#define IDR_MAINFRAME 128
#define ID_SERVER_START 32771
#define ID_SERVER_STOP 32772
#define ID_CLIENT_INVALIDPARAM 32773
#define ID_CLIENT_ASSERTFAILURE 32774
#define ID_CLIENT_DEREFZERO 32775
#define ID_CLIENT_PURECALL 32777
#define ID_CLIENT_REQUESTEXPLICITDUMP 32778
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32780
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
// 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.
// PreCompile.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by crash_generation_app.rc
//
#define IDC_MYICON 2
#define IDD_CRASHGENERATIONAPP_DIALOG 102
#define IDS_APP_TITLE 103
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_CRASHGENERATIONAPP 107
#define IDI_SMALL 108
#define IDC_CRASHGENERATIONAPP 109
#define IDR_MAINFRAME 128
#define ID_SERVER_START 32771
#define ID_SERVER_STOP 32772
#define ID_CLIENT_INVALIDPARAM 32773
#define ID_CLIENT_ASSERTFAILURE 32774
#define ID_CLIENT_DEREFZERO 32775
#define ID_CLIENT_PURECALL 32777
#define ID_CLIENT_REQUESTEXPLICITDUMP 32778
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32780
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

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

@ -43,6 +43,7 @@
#include <algorithm>
#include <functional>
#include <list>
#include <vector>
#include <string.h>
@ -75,6 +76,8 @@ struct LineInfo {
int source_id;
};
typedef std::list<struct LineInfo> LineInfoList;
// Information of a function.
struct FuncInfo {
// Name of the function.
@ -93,9 +96,11 @@ struct FuncInfo {
// Is there any lines included from other files?
bool has_sol;
// Line information array.
std::vector<struct LineInfo> line_info;
LineInfoList line_info;
};
typedef std::list<struct FuncInfo> FuncInfoList;
// Information of a source file.
struct SourceFileInfo {
// Name string index into the string table.
@ -107,13 +112,15 @@ struct SourceFileInfo {
// Id of the source file.
int source_id;
// Functions information.
std::vector<struct FuncInfo> func_info;
FuncInfoList func_info;
};
typedef std::list<struct SourceFileInfo> SourceFileInfoList;
// Information of a symbol table.
// This is the root of all types of symbol.
struct SymbolInfo {
std::vector<struct SourceFileInfo> source_file_info;
SourceFileInfoList source_file_info;
// The next source id for newly found source file.
int next_source_id;
@ -270,7 +277,6 @@ static int LoadFuncSymbols(struct nlist *list,
struct nlist *cur_list = list;
assert(cur_list->n_type == N_SO);
++cur_list;
source_file_info->func_info.clear();
while (cur_list < list_end) {
// Go until the function symbol.
@ -283,11 +289,15 @@ static int LoadFuncSymbols(struct nlist *list,
}
if (cur_list->n_type == N_FUN) {
struct FuncInfo func_info;
memset(&func_info, 0, sizeof(func_info));
func_info.name =
reinterpret_cast<char *>(cur_list->n_un.n_strx +
stabstr_section->sh_offset);
func_info.addr = cur_list->n_value;
func_info.rva_to_base = 0;
func_info.size = 0;
func_info.stack_param_size = 0;
func_info.has_sol = 0;
// Stack parameter size.
cur_list += LoadStackParamSize(cur_list, list_end, &func_info);
// Line info.
@ -295,6 +305,7 @@ static int LoadFuncSymbols(struct nlist *list,
list_end,
*source_file_info,
&func_info);
// Functions in this module should have address bigger than the module
// startring address.
// There maybe a lot of duplicated entry for a function in the symbol,
@ -317,12 +328,15 @@ static bool CompareAddress(T1 *a, T2 *b) {
// Sort the array into increasing ordered array based on the virtual address.
// Return vector of pointers to the elements in the incoming array. So caller
// should make sure the returned vector lives longer than the incoming vector.
template<class T>
static std::vector<T *> SortByAddress(std::vector<T> *array) {
template<class Container>
static std::vector<typename Container::value_type *> SortByAddress(
Container *container) {
typedef typename Container::iterator It;
typedef typename Container::value_type T;
std::vector<T *> sorted_array_ptr;
sorted_array_ptr.reserve(array->size());
for (size_t i = 0; i < array->size(); ++i)
sorted_array_ptr.push_back(&(array->at(i)));
sorted_array_ptr.reserve(container->size());
for (It it = container->begin(); it != container->end(); it++)
sorted_array_ptr.push_back(&(*it));
std::sort(sorted_array_ptr.begin(),
sorted_array_ptr.end(),
std::ptr_fun(CompareAddress<T, T>));
@ -366,10 +380,11 @@ static ElfW(Addr) NextAddress(
}
static int FindFileByNameIdx(uint32_t name_index,
const std::vector<SourceFileInfo> &files) {
for (size_t i = 0; i < files.size(); ++i) {
if (files[i].name_index == name_index)
return files[i].source_id;
SourceFileInfoList &files) {
for (SourceFileInfoList::iterator it = files.begin();
it != files.end(); it++) {
if (it->name_index == name_index)
return it->source_id;
}
return -1;
@ -379,16 +394,21 @@ static int FindFileByNameIdx(uint32_t name_index,
// Also fix the source id for the line info.
static void AddIncludedFiles(struct SymbolInfo *symbols,
const ElfW(Shdr) *stabstr_section) {
size_t source_file_size = symbols->source_file_info.size();
for (SourceFileInfoList::iterator source_file_it =
symbols->source_file_info.begin();
source_file_it != symbols->source_file_info.end();
++source_file_it) {
struct SourceFileInfo &source_file = *source_file_it;
for (size_t i = 0; i < source_file_size; ++i) {
struct SourceFileInfo &source_file = symbols->source_file_info[i];
for (FuncInfoList::iterator func_info_it = source_file.func_info.begin();
func_info_it != source_file.func_info.end();
++func_info_it) {
struct FuncInfo &func_info = *func_info_it;
for (size_t j = 0; j < source_file.func_info.size(); ++j) {
struct FuncInfo &func_info = source_file.func_info[j];
for (LineInfoList::iterator line_info_it = func_info.line_info.begin();
line_info_it != func_info.line_info.end(); ++line_info_it) {
struct LineInfo &line_info = *line_info_it;
for (size_t k = 0; k < func_info.line_info.size(); ++k) {
struct LineInfo &line_info = func_info.line_info[k];
assert(line_info.source_name_index > 0);
assert(source_file.name_index > 0);
@ -476,12 +496,15 @@ static bool ComputeSizeAndRVA(ElfW(Addr) loading_addr,
func_info.size = kDefaultSize;
}
// Compute line size.
for (size_t k = 0; k < func_info.line_info.size(); ++k) {
struct LineInfo &line_info = func_info.line_info[k];
for (LineInfoList::iterator line_info_it = func_info.line_info.begin();
line_info_it != func_info.line_info.end(); line_info_it++) {
struct LineInfo &line_info = *line_info_it;
LineInfoList::iterator next_line_info_it = line_info_it;
next_line_info_it++;
line_info.size = 0;
if (k + 1 < func_info.line_info.size()) {
if (next_line_info_it != func_info.line_info.end()) {
line_info.size =
func_info.line_info[k + 1].rva_to_func - line_info.rva_to_func;
next_line_info_it->rva_to_func - line_info.rva_to_func;
} else {
// The last line in the function.
// If we can find a function or source file symbol immediately
@ -605,11 +628,12 @@ static bool WriteModuleInfo(int fd,
}
static bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) {
for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
if (symbols.source_file_info[i].source_id != -1) {
const char *name = symbols.source_file_info[i].name;
if (!WriteFormat(fd, "FILE %d %s\n",
symbols.source_file_info[i].source_id, name))
for (SourceFileInfoList::const_iterator it =
symbols.source_file_info.begin();
it != symbols.source_file_info.end(); it++) {
if (it->source_id != -1) {
const char *name = it->name;
if (!WriteFormat(fd, "FILE %d %s\n", it->source_id, name))
return false;
}
}
@ -633,8 +657,9 @@ static bool WriteOneFunction(int fd,
func_info.size,
func_info.stack_param_size,
func_name.c_str())) {
for (size_t i = 0; i < func_info.line_info.size(); ++i) {
const struct LineInfo &line_info = func_info.line_info[i];
for (LineInfoList::const_iterator it = func_info.line_info.begin();
it != func_info.line_info.end(); it++) {
const struct LineInfo &line_info = *it;
if (!WriteFormat(fd, "%lx %lx %d %d\n",
line_info.rva_to_base,
line_info.size,
@ -648,10 +673,13 @@ static bool WriteOneFunction(int fd,
}
static bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) {
for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
const struct SourceFileInfo &file_info = symbols.source_file_info[i];
for (size_t j = 0; j < file_info.func_info.size(); ++j) {
const struct FuncInfo &func_info = file_info.func_info[j];
for (SourceFileInfoList::const_iterator it =
symbols.source_file_info.begin();
it != symbols.source_file_info.end(); it++) {
const struct SourceFileInfo &file_info = *it;
for (FuncInfoList::const_iterator fiIt = file_info.func_info.begin();
fiIt != file_info.func_info.end(); fiIt++) {
const struct FuncInfo &func_info = *fiIt;
if (!WriteOneFunction(fd, func_info))
return false;
}

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

@ -30,9 +30,14 @@
// dump_syms.h: Interface for DumpSymbols. This class will take a mach-o file
// and extract the symbol information and write it to a file using the
// breakpad symbol file format.
// NOTE: Only Stabs format is currently supported -- not DWARF.
#import <Foundation/Foundation.h>
#include <mach-o/loader.h>
#include "common/mac/dwarf/dwarf2reader.h"
// This will map from an architecture string to a SectionMap, which
// will contain the offsets for all the sections in the dictionary
typedef hash_map<string, dwarf2reader::SectionMap *> ArchSectionMap;
@interface DumpSymbols : NSObject {
@protected
@ -43,8 +48,9 @@
NSMutableDictionary *sources_; // Address and Source file paths (STRONG)
NSMutableArray *cppAddresses_; // Addresses of C++ symbols (STRONG)
NSMutableDictionary *headers_; // Mach-o header information (STRONG)
NSMutableDictionary *sectionNumbers_; // Keyed by seg/sect name (STRONG)
NSMutableDictionary *sectionData_; // Keyed by seg/sect name (STRONG)
uint32_t lastStartAddress_;
ArchSectionMap *sectionsForArch_;
}
- (id)initWithContentsOfFile:(NSString *)machoFile;
@ -61,3 +67,14 @@
- (BOOL)writeSymbolFile:(NSString *)symbolFilePath;
@end
@interface MachSection : NSObject {
@protected
struct section *sect_;
uint32_t sectionNumber_;
}
- (id)initWithMachSection:(struct section *)sect andNumber:(uint32_t)sectionNumber;
- (struct section*)sectionPointer;
- (uint32_t)sectionNumber;
@end

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

@ -47,6 +47,9 @@
#import "dump_syms.h"
#import "common/mac/file_id.h"
#import "common/mac/macho_utilities.h"
#import "common/mac/dwarf/dwarf2reader.h"
#import "common/mac/dwarf/functioninfo.h"
#import "common/mac/dwarf/bytereader.h"
using google_breakpad::FileID;
@ -54,6 +57,7 @@ static NSString *kAddressSymbolKey = @"symbol";
static NSString *kAddressConvertedSymbolKey = @"converted_symbol";
static NSString *kAddressSourceLineKey = @"line";
static NSString *kFunctionSizeKey = @"size";
static NSString *kFunctionFileKey = @"source_file";
static NSString *kHeaderBaseAddressKey = @"baseAddr";
static NSString *kHeaderSizeKey = @"size";
static NSString *kHeaderOffsetKey = @"offset"; // Offset to the header
@ -65,6 +69,40 @@ static NSString *kUnknownSymbol = @"???";
// for pruning out extraneous non-function symbols.
static const int kTextSection = 1;
namespace __gnu_cxx {
template<>
struct hash<std::string> {
size_t operator()(const std::string& k) const {
return hash< const char* >()( k.c_str() );
}
};
}
// Dump FunctionMap to stdout. Print address, function name, file
// name, line number, lowpc, and highpc if available.
void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) {
for (dwarf2reader::FunctionMap::const_iterator iter = function_map.begin();
iter != function_map.end(); ++iter) {
if (iter->second->name.empty()) {
continue;
}
printf("%08llx: %s", iter->first,
iter->second->name.data());
if (!iter->second->file.empty()) {
printf(" - %s", iter->second->file.data());
if (iter->second->line != 0) {
printf(":%u", iter->second->line);
}
}
if (iter->second->lowpc != 0 && iter->second->highpc != 0) {
printf(" (%08llx - %08llx)\n",
iter->second->lowpc,
iter->second->highpc);
}
}
}
@interface DumpSymbols(PrivateMethods)
- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols;
- (void)convertSymbols;
@ -73,10 +111,17 @@ static const int kTextSection = 1;
- (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset;
- (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset;
- (BOOL)loadSymbolInfoForArchitecture;
- (BOOL)loadDWARFSymbolInfo:(void *)base offset:(uint32_t)offset;
- (BOOL)loadSTABSSymbolInfo:(void *)base offset:(uint32_t)offset;
- (void)generateSectionDictionary:(struct mach_header*)header;
- (BOOL)loadHeader:(void *)base offset:(uint32_t)offset;
- (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset;
- (BOOL)loadModuleInfo;
- (void)processDWARFLineNumberInfo:(dwarf2reader::LineMap*)line_map;
- (void)processDWARFFunctionInfo:(dwarf2reader::FunctionMap*)address_to_funcinfo;
- (void)processDWARFSourceFileInfo:(vector<dwarf2reader::SourceFileInfo>*) files;
- (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset;
- (dwarf2reader::SectionMap*)getSectionMapForArchitecture:(NSString*)architecture;
@end
@implementation DumpSymbols
@ -241,6 +286,7 @@ static const int kTextSection = 1;
if (line && ![dict objectForKey:kAddressSourceLineKey])
[dict setObject:[NSNumber numberWithUnsignedInt:line]
forKey:kAddressSourceLineKey];
}
//=============================================================================
@ -277,7 +323,9 @@ static const int kTextSection = 1;
int line = list->n_desc;
// __TEXT __text section
uint32_t mainSection = [[sectionNumbers_ objectForKey:@"__TEXT__text" ] unsignedLongValue];
NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_];
uint32_t mainSection = [[archSections objectForKey:@"__TEXT__text" ] sectionNumber];
// Extract debugging information:
// Doc: http://developer.apple.com/documentation/DeveloperTools/gdb/stabs/stabs_toc.html
@ -287,6 +335,14 @@ static const int kTextSection = 1;
NSString *ext = [src pathExtension];
NSNumber *address = [NSNumber numberWithUnsignedLongLong:list->n_value];
// Leopard puts .c files with no code as an offset of 0, but a
// crash can't happen here and it throws off our code that matches
// symbols to line numbers so we ignore them..
// Return YES because this isn't an error, just something we don't
// care to handle.
if ([address unsignedLongValue] == 0) {
return YES;
}
// TODO(waylonis):Ensure that we get the full path for the source file
// from the first N_SO record
// If there is an extension, we'll consider it source code
@ -295,7 +351,6 @@ static const int kTextSection = 1;
sources_ = [[NSMutableDictionary alloc] init];
// Save the source associated with an address
[sources_ setObject:src forKey:address];
result = YES;
}
} else if (list->n_type == N_FUN) {
@ -313,7 +368,7 @@ static const int kTextSection = 1;
[self addFunction:fn line:line address:list->n_value section:list->n_sect ];
result = YES;
} else if (list->n_type == N_SLINE && list->n_sect == mainSection ) {
} else if (list->n_type == N_SLINE && list->n_sect == mainSection) {
[self addFunction:nil line:line address:list->n_value section:list->n_sect ];
result = YES;
} else if (((list->n_type & N_TYPE) == N_SECT) && !(list->n_type & N_STAB)) {
@ -331,8 +386,169 @@ static const int kTextSection = 1;
#define SwapLongIfNeeded(a) (swap ? NXSwapLong(a) : (a))
#define SwapIntIfNeeded(a) (swap ? NXSwapInt(a) : (a))
#define SwapShortIfNeeded(a) (swap ? NXSwapShort(a) : (a))
//=============================================================================
- (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset {
NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_];
if ([archSections objectForKey:@"__DWARF__debug_info"]) {
// Treat this this as debug information
return [self loadDWARFSymbolInfo:base offset:offset];
}
return [self loadSTABSSymbolInfo:base offset:offset];
}
//=============================================================================
- (BOOL)loadDWARFSymbolInfo:(void *)base offset:(uint32_t)offset {
struct mach_header *header = (struct mach_header *)
((uint32_t)base + offset);
BOOL swap = (header->magic == MH_CIGAM);
NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_];
assert (archSections != nil);
section *dbgInfoSection = [[archSections objectForKey:@"__DWARF__debug_info"] sectionPointer];
uint32_t debugInfoSize = SwapLongIfNeeded(dbgInfoSection->size);
// i think this will break if run on a big-endian machine
dwarf2reader::ByteReader byte_reader(swap ?
dwarf2reader::ENDIANNESS_BIG :
dwarf2reader::ENDIANNESS_LITTLE);
uint64_t dbgOffset = 0;
dwarf2reader::SectionMap* oneArchitectureSectionMap = [self getSectionMapForArchitecture:architecture_];
while (dbgOffset < debugInfoSize) {
// Prepare necessary objects.
dwarf2reader::FunctionMap off_to_funcinfo;
dwarf2reader::FunctionMap address_to_funcinfo;
dwarf2reader::LineMap line_map;
vector<dwarf2reader::SourceFileInfo> files;
vector<string> dirs;
dwarf2reader::CULineInfoHandler line_info_handler(&files, &dirs,
&line_map);
dwarf2reader::CUFunctionInfoHandler function_info_handler(&files, &dirs,
&line_map,
&off_to_funcinfo,
&address_to_funcinfo,
&line_info_handler,
*oneArchitectureSectionMap,
&byte_reader);
dwarf2reader::CompilationUnit compilation_unit(*oneArchitectureSectionMap,
dbgOffset,
&byte_reader,
&function_info_handler);
dbgOffset += compilation_unit.Start();
// The next 3 functions take the info that the dwarf reader
// gives and massages them into the data structures that
// dump_syms uses
[self processDWARFSourceFileInfo:&files];
[self processDWARFFunctionInfo:&address_to_funcinfo];
[self processDWARFLineNumberInfo:&line_map];
}
return YES;
}
- (void)processDWARFSourceFileInfo:(vector<dwarf2reader::SourceFileInfo>*) files {
if (!sources_)
sources_ = [[NSMutableDictionary alloc] init];
// Save the source associated with an address
vector<dwarf2reader::SourceFileInfo>::const_iterator iter = files->begin();
for (; iter != files->end(); iter++) {
NSString *sourceFile = [NSString stringWithUTF8String:(*iter).name.c_str()];
if ((*iter).lowpc != ULLONG_MAX) {
NSNumber *address = [NSNumber numberWithUnsignedLongLong:(*iter).lowpc];
if ([address unsignedLongLongValue] == 0) {
continue;
}
[sources_ setObject:sourceFile forKey:address];
}
}
}
- (void)processDWARFFunctionInfo:(dwarf2reader::FunctionMap*)address_to_funcinfo {
for (dwarf2reader::FunctionMap::const_iterator iter = address_to_funcinfo->begin();
iter != address_to_funcinfo->end(); ++iter) {
if (iter->second->name.empty()) {
continue;
}
if (!addresses_)
addresses_ = [[NSMutableDictionary alloc] init];
NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:(*iter).second->lowpc];
[functionAddresses_ addObject:addressNum];
NSMutableDictionary *dict = [addresses_ objectForKey:addressNum];
if (!dict) {
dict = [[NSMutableDictionary alloc] init];
[addresses_ setObject:dict forKey:addressNum];
[dict release];
}
// set name of function if it isn't already set
if (![dict objectForKey:kAddressSymbolKey]) {
NSString *symbolName = [NSString stringWithUTF8String:iter->second->name.c_str()];
[dict setObject:symbolName forKey:kAddressSymbolKey];
}
// set line number for beginning of function
if (iter->second->line && ![dict objectForKey:kAddressSourceLineKey])
[dict setObject:[NSNumber numberWithUnsignedInt:iter->second->line]
forKey:kAddressSourceLineKey];
// set function size by subtracting low PC from high PC
if (![dict objectForKey:kFunctionSizeKey]) {
[dict setObject:[NSNumber numberWithUnsignedLongLong:iter->second->highpc - iter->second->lowpc]
forKey:kFunctionSizeKey];
}
// Set the file that the function is in
if (![dict objectForKey:kFunctionFileKey]) {
[dict setObject:[NSString stringWithUTF8String:iter->second->file.c_str()]
forKey:kFunctionFileKey];
}
}
}
- (void)processDWARFLineNumberInfo:(dwarf2reader::LineMap*)line_map {
for (dwarf2reader::LineMap::const_iterator iter = line_map->begin();
iter != line_map->end();
++iter) {
NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:iter->first];
NSMutableDictionary *dict = [addresses_ objectForKey:addressNum];
if (!dict) {
dict = [[NSMutableDictionary alloc] init];
[addresses_ setObject:dict forKey:addressNum];
[dict release];
}
if (iter->second.second && ![dict objectForKey:kAddressSourceLineKey]) {
[dict setObject:[NSNumber numberWithUnsignedInt:iter->second.second]
forKey:kAddressSourceLineKey];
}
// Set the file that the function's address is in
if (![dict objectForKey:kFunctionFileKey]) {
[dict setObject:[NSString stringWithUTF8String:iter->second.first.c_str()]
forKey:kFunctionFileKey];
}
}
}
//=============================================================================
- (BOOL)loadSTABSSymbolInfo:(void *)base offset:(uint32_t)offset {
struct mach_header *header = (struct mach_header *)((uint32_t)base + offset);
BOOL swap = (header->magic == MH_CIGAM);
uint32_t count = SwapLongIfNeeded(header->ncmds);
@ -363,6 +579,8 @@ static const int kTextSection = 1;
nlist64.n_desc = SwapShortIfNeeded(list->n_desc);
nlist64.n_value = (uint64_t)SwapLongIfNeeded(list->n_value);
// TODO(nealsid): is this broken? we get NO if one symbol fails
// but then we lose that information if another suceeeds
if ([self processSymbolItem:&nlist64 stringTable:strtab])
result = YES;
}
@ -424,6 +642,7 @@ static const int kTextSection = 1;
- (BOOL)loadSymbolInfoForArchitecture {
NSMutableData *data = [[NSMutableData alloc]
initWithContentsOfMappedFile:sourcePath_];
NSDictionary *headerInfo = [headers_ objectForKey:architecture_];
void *base = [data mutableBytes];
uint32_t offset =
@ -436,10 +655,28 @@ static const int kTextSection = 1;
return result;
}
- (dwarf2reader::SectionMap*)getSectionMapForArchitecture:(NSString*)architecture {
string currentArch([architecture UTF8String]);
dwarf2reader::SectionMap *oneArchitectureSectionMap;
ArchSectionMap::const_iterator iter = sectionsForArch_->find(currentArch);
if (iter == sectionsForArch_->end()) {
oneArchitectureSectionMap = new dwarf2reader::SectionMap();
sectionsForArch_->insert(make_pair(currentArch, oneArchitectureSectionMap));
} else {
oneArchitectureSectionMap = iter->second;
}
return oneArchitectureSectionMap;
}
//=============================================================================
// build a dictionary of section numbers keyed off a string
// which is the concatenation of the segment name and the section name
- (void)generateSectionDictionary:(struct mach_header*)header {
BOOL swap = (header->magic == MH_CIGAM);
uint32_t count = SwapLongIfNeeded(header->ncmds);
struct load_command *cmd =
@ -447,8 +684,29 @@ static const int kTextSection = 1;
uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT);
uint32_t sectionNumber = 1; // section numbers are counted from 1
if (!sectionNumbers_)
sectionNumbers_ = [[NSMutableDictionary alloc] init];
cpu_type_t cpu = SwapIntIfNeeded(header->cputype);
NSString *arch;
if (cpu & CPU_ARCH_ABI64)
arch = ((cpu & ~CPU_ARCH_ABI64) == CPU_TYPE_X86) ?
@"x86_64" : @"ppc64";
else
arch = (cpu == CPU_TYPE_X86) ? @"x86" : @"ppc";
NSMutableDictionary *archSections;
if (!sectionData_) {
sectionData_ = [[NSMutableDictionary alloc] init];
}
if (![sectionData_ objectForKey:architecture_]) {
[sectionData_ setObject:[[NSMutableDictionary alloc] init] forKey:arch];
}
archSections = [sectionData_ objectForKey:arch];
dwarf2reader::SectionMap* oneArchitectureSectionMap = [self getSectionMapForArchitecture:arch];
// loop through every segment command, then through every section
// contained inside each of them
@ -459,13 +717,18 @@ static const int kTextSection = 1;
uint32_t nsects = SwapLongIfNeeded(seg->nsects);
for (uint32_t j = 0; j < nsects; ++j) {
//printf("%d: %s %s\n", sectionNumber, seg->segname, sect->sectname );
NSString *segSectName = [NSString stringWithFormat:@"%s%s",
seg->segname, sect->sectname ];
[sectionNumbers_ setValue:[NSNumber numberWithUnsignedLong:sectionNumber]
forKey:segSectName ];
seg->segname, sect->sectname];
[archSections setObject:[[MachSection alloc] initWithMachSection:sect andNumber:sectionNumber]
forKey:segSectName];
// filter out sections with size 0, offset 0
if (sect->offset != 0 && sect->size != 0) {
// fill sectionmap for dwarf reader
oneArchitectureSectionMap->insert(make_pair(sect->sectname,make_pair(((const char*)header) + SwapLongIfNeeded(sect->offset), (size_t)SwapLongIfNeeded(sect->size))));
}
++sect;
++sectionNumber;
}
@ -682,11 +945,15 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
// Sources ordered by address
NSArray *sources = [[sources_ allKeys]
sortedArrayUsingSelector:@selector(compare:)];
NSMutableDictionary *fileNameToFileIndex = [[NSMutableDictionary alloc] init];
unsigned int sourceCount = [sources count];
for (unsigned int i = 0; i < sourceCount; ++i) {
NSString *file = [sources_ objectForKey:[sources objectAtIndex:i]];
if (!WriteFormat(fd, "FILE %d %s\n", i + 1, [file UTF8String]))
return NO;
[fileNameToFileIndex setObject:[NSNumber numberWithUnsignedInt:i+1]
forKey:file];
}
// Symbols
@ -696,9 +963,16 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
NSNumber *nextAddress;
uint64_t nextAddressVal;
unsigned int addressCount = [sortedAddresses count];
bool insideFunction = false;
for (unsigned int i = 0; i < addressCount; ++i) {
NSNumber *address = [sortedAddresses objectAtIndex:i];
// skip sources that have a starting address of 0
if ([address unsignedLongValue] == 0) {
continue;
}
uint64_t addressVal = [address unsignedLongLongValue] - baseAddress;
// Get the next address to calculate the length
@ -734,7 +1008,7 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
if ([symbol hasPrefix:@"__static_initialization_and_destruction_0"])
continue;
if ([symbol hasPrefix:@"_GLOBAL__I__"])
if ([symbol hasPrefix:@"_GLOBAL__I_"])
continue;
if ([symbol hasPrefix:@"__func__."])
@ -752,6 +1026,12 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
if ([symbol hasPrefix:@"GCC_except_table"])
continue;
if ([symbol hasPrefix:@"__tcf"])
continue;
if ([symbol hasPrefix:@"non-virtual thunk"])
continue;
// Find the source file (if any) that contains this address
while (sourceCount && (addressVal >= nextSourceFileAddress)) {
fileIdx = nextFileIdx;
@ -770,8 +1050,10 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
if (line) {
if (symbol && functionLength) {
uint64_t functionLengthVal = [functionLength unsignedLongLongValue];
insideFunction = true;
// sanity check to make sure the length we were told does not exceed
// the space between this function and the next
if (nextFunctionAddress != 0) {
@ -788,16 +1070,30 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
return NO;
}
// Source line
uint64_t length = nextAddressVal - addressVal;
if (!WriteFormat(fd, "%llx %llx %d %d\n", addressVal, length,
[line unsignedIntValue], fileIdx))
return NO;
// Throw out line number information that doesn't correspond to
// any function
if (insideFunction) {
// Source line
uint64_t length = nextAddressVal - addressVal;
// if fileNameToFileIndex/dict has an entry for the
// file/kFunctionFileKey, we're processing DWARF and have stored
// files for each program counter. If there is no entry, we're
// processing STABS and can use the old method of mapping
// addresses to files(which was basically iterating over a set
// of addresses until we reached one that was greater than the
// high PC of the current file, then moving on to the next file)
NSNumber *fileIndex = [fileNameToFileIndex objectForKey:[dict objectForKey:kFunctionFileKey]];
if (!WriteFormat(fd, "%llx %llx %d %d\n", addressVal, length,
[line unsignedIntValue], fileIndex ? [fileIndex unsignedIntValue] : fileIdx))
return NO;
}
} else {
// PUBLIC <address> <stack-size> <name>
if (!WriteFormat(fd, "PUBLIC %llx 0 %s\n", addressVal,
[symbol UTF8String]))
return NO;
insideFunction = false;
}
}
@ -815,6 +1111,50 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
sourcePath_ = [path copy];
// Test for .DSYM bundle
NSBundle *dsymBundle = [NSBundle bundleWithPath:sourcePath_];
if (dsymBundle) {
// we need to take the DSYM bundle path and remove it's
// extension to get the name of the file inside the resources
// directory of the bundle that actually has the DWARF
// information
// But, Xcode supports something called "Wrapper extension"(see
// build settings), which would make the bundle name
// /tmp/foo/test.kext.dSYM, but the dwarf binary name would
// still be "test". so, now we loop through until deleting the
// extension doesn't change the string
// e.g. suppose sourcepath_ is /tmp/foo/test.dSYM
NSString *dwarfBinName = [sourcePath_ lastPathComponent];
NSString *dwarfBinPath;
// We use a do/while loop so we can handle files without an extension
do {
dwarfBinName = [dwarfBinName stringByDeletingPathExtension];
// now, dwarfBinName is "test"
dwarfBinPath = [dsymBundle pathForResource:dwarfBinName ofType:nil inDirectory:@"DWARF"];
if (dwarfBinPath != nil)
break;
} while (![[dwarfBinName stringByDeletingPathExtension] isEqualToString:dwarfBinName]);
if (dwarfBinPath == nil) {
NSLog(@"The bundle passed on the command line does not appear to be a DWARF dSYM bundle");
[self autorelease];
return nil;
}
// otherwise we're good to go
[sourcePath_ release];
sourcePath_ = [dwarfBinPath copy];
NSLog(@"Loading DWARF dSYM file from %@", sourcePath_);
}
sectionsForArch_ = new ArchSectionMap();
if (![self loadModuleInfo]) {
[self autorelease];
return nil;
@ -858,7 +1198,8 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
[functionAddresses_ release];
[sources_ release];
[headers_ release];
delete sectionsForArch_;
[super dealloc];
}
@ -889,7 +1230,7 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
return NO;
[architecture_ autorelease];
architecture_ = [architecture copy];
architecture_ = [normalized copy];
}
return isValid;
@ -921,3 +1262,23 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
}
@end
@implementation MachSection
- (id)initWithMachSection:(section *)sect andNumber:(uint32_t)sectionNumber {
if ((self = [super init])) {
sect_ = sect;
sectionNumber_ = sectionNumber;
}
return self;
}
- (section*)sectionPointer {
return sect_;
}
- (uint32_t)sectionNumber {
return sectionNumber_;
}
@end

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

@ -0,0 +1,141 @@
// Copyright 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 UTIL_DEBUGINFO_BYTEREADER_INL_H__
#define UTIL_DEBUGINFO_BYTEREADER_INL_H__
#include "common/mac/dwarf/bytereader.h"
namespace dwarf2reader {
inline uint8 ByteReader::ReadOneByte(const char* buffer) const {
return buffer[0];
}
inline uint16 ByteReader::ReadTwoBytes(const char* buffer) const {
const uint16 buffer0 = static_cast<uint16>(buffer[0]);
const uint16 buffer1 = static_cast<uint16>(buffer[1]);
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8;
} else {
return buffer1 | buffer0 << 8;
}
}
inline uint64 ByteReader::ReadFourBytes(const char* buffer) const {
const uint32 buffer0 = static_cast<uint32>(buffer[0]);
const uint32 buffer1 = static_cast<uint32>(buffer[1]);
const uint32 buffer2 = static_cast<uint32>(buffer[2]);
const uint32 buffer3 = static_cast<uint32>(buffer[3]);
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24;
} else {
return buffer3 | buffer2 << 8 | buffer1 << 16 | buffer0 << 24;
}
}
inline uint64 ByteReader::ReadEightBytes(const char* buffer) const {
const uint64 buffer0 = static_cast<uint64>(buffer[0]);
const uint64 buffer1 = static_cast<uint64>(buffer[1]);
const uint64 buffer2 = static_cast<uint64>(buffer[2]);
const uint64 buffer3 = static_cast<uint64>(buffer[3]);
const uint64 buffer4 = static_cast<uint64>(buffer[4]);
const uint64 buffer5 = static_cast<uint64>(buffer[5]);
const uint64 buffer6 = static_cast<uint64>(buffer[6]);
const uint64 buffer7 = static_cast<uint64>(buffer[7]);
if (endian_ == ENDIANNESS_LITTLE) {
return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24 |
buffer4 << 32 | buffer5 << 40 | buffer6 << 48 | buffer7 << 56;
} else {
return buffer7 | buffer6 << 8 | buffer5 << 16 | buffer4 << 24 |
buffer3 << 32 | buffer2 << 40 | buffer1 << 48 | buffer0 << 56;
}
}
// Read an unsigned LEB128 number. Each byte contains 7 bits of
// information, plus one bit saying whether the number continues or
// not.
inline uint64 ByteReader::ReadUnsignedLEB128(const char* buffer,
size_t* len) const {
uint64 result = 0;
size_t num_read = 0;
unsigned int shift = 0;
unsigned char byte;
do {
byte = *buffer++;
num_read++;
result |= (static_cast<uint64>(byte & 0x7f)) << shift;
shift += 7;
} while (byte & 0x80);
*len = num_read;
return result;
}
// Read a signed LEB128 number. These are like regular LEB128
// numbers, except the last byte may have a sign bit set.
inline int64 ByteReader::ReadSignedLEB128(const char* buffer,
size_t* len) const {
int64 result = 0;
unsigned int shift = 0;
size_t num_read = 0;
unsigned char byte;
do {
byte = *buffer++;
num_read++;
result |= (static_cast<uint64>(byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);
if ((shift < 8 * sizeof (result)) && (byte & 0x40))
result |= -((static_cast<int64>(1)) << shift);
*len = num_read;
return result;
}
inline uint64 ByteReader::ReadOffset(const char* buffer) const {
assert(this->offset_reader_);
return (this->*offset_reader_)(buffer);
}
inline uint64 ByteReader::ReadAddress(const char* buffer) const {
assert(this->address_reader_);
return (this->*address_reader_)(buffer);
}
} // namespace dwarf2reader
#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__

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

@ -0,0 +1,62 @@
// Copyright 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/mac/dwarf/bytereader-inl.h"
#include "common/mac/dwarf/bytereader.h"
namespace dwarf2reader {
ByteReader::ByteReader(enum Endianness endian)
:offset_reader_(NULL), address_reader_(NULL), endian_(endian),
address_size_(0), offset_size_(0)
{ }
ByteReader::~ByteReader() { }
void ByteReader::SetOffsetSize(uint8 size) {
offset_size_ = size;
assert(size == 4 || size == 8);
if (size == 4) {
this->offset_reader_ = &ByteReader::ReadFourBytes;
} else {
this->offset_reader_ = &ByteReader::ReadEightBytes;
}
}
void ByteReader::SetAddressSize(uint8 size) {
address_size_ = size;
assert(size == 4 || size == 8);
if (size == 4) {
this->address_reader_ = &ByteReader::ReadFourBytes;
} else {
this->address_reader_ = &ByteReader::ReadEightBytes;
}
}
} // namespace dwarf2reader

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

@ -0,0 +1,132 @@
// Copyright 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_MAC_DWARF_BYTEREADER_H__
#define COMMON_MAC_DWARF_BYTEREADER_H__
#include <string>
#include "common/mac/dwarf/types.h"
namespace dwarf2reader {
// We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN
// because it conflicts with a macro
enum Endianness {
ENDIANNESS_BIG,
ENDIANNESS_LITTLE
};
// Class that knows how to read both big endian and little endian
// numbers, for use in DWARF2/3 reader.
// Takes an endianness argument.
// To read addresses and offsets, SetAddressSize and SetOffsetSize
// must be called first.
class ByteReader {
public:
explicit ByteReader(enum Endianness endian);
virtual ~ByteReader();
// Set the address size to SIZE, which sets up the ReadAddress member
// so that it works.
void SetAddressSize(uint8 size);
// Set the offset size to SIZE, which sets up the ReadOffset member
// so that it works.
void SetOffsetSize(uint8 size);
// Return the current offset size
uint8 OffsetSize() const { return offset_size_; }
// Return the current address size
uint8 AddressSize() const { return address_size_; }
// Read a single byte from BUFFER and return it as an unsigned 8 bit
// number.
uint8 ReadOneByte(const char* buffer) const;
// Read two bytes from BUFFER and return it as an unsigned 16 bit
// number.
uint16 ReadTwoBytes(const char* buffer) const;
// Read four bytes from BUFFER and return it as an unsigned 32 bit
// number. This function returns a uint64 so that it is compatible
// with ReadAddress and ReadOffset. The number it returns will
// never be outside the range of an unsigned 32 bit integer.
uint64 ReadFourBytes(const char* buffer) const;
// Read eight bytes from BUFFER and return it as an unsigned 64 bit
// number
uint64 ReadEightBytes(const char* buffer) const;
// Read an unsigned LEB128 (Little Endian Base 128) number from
// BUFFER and return it as an unsigned 64 bit integer. LEN is set
// to the length read. Everybody seems to reinvent LEB128 as a
// variable size integer encoding, DWARF has had it for a long time.
uint64 ReadUnsignedLEB128(const char* buffer, size_t* len) const;
// Read a signed LEB128 number from BUFFER and return it as an
// signed 64 bit integer. LEN is set to the length read.
int64 ReadSignedLEB128(const char* buffer, size_t* len) const;
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
// generally depending on the amount of DWARF2/3 info present.
uint64 ReadOffset(const char* buffer) const;
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 allow addresses to be any size from 0-255
// bytes currently. Internally we support 4 and 8 byte addresses,
// and will CHECK on anything else.
uint64 ReadAddress(const char* buffer) const;
private:
// Function pointer type for our address and offset readers.
typedef uint64 (ByteReader::*AddressReader)(const char*) const;
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
// generally depending on the amount of DWARF2/3 info present.
// This function pointer gets set by SetOffsetSize.
AddressReader offset_reader_;
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 allow addresses to be any size from 0-255
// bytes currently. Internally we support 4 and 8 byte addresses,
// and will CHECK on anything else.
// This function pointer gets set by SetAddressSize.
AddressReader address_reader_;
Endianness endian_;
uint8 address_size_;
uint8 offset_size_;
};
} // namespace dwarf2reader
#endif // COMMON_MAC_DWARF_BYTEREADER_H__

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

@ -0,0 +1,490 @@
// Copyright 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_MAC_DWARF_DWARF2ENUMS_H__
#define COMMON_MAC_DWARF_DWARF2ENUMS_H__
namespace dwarf2reader {
// These enums do not follow the google3 style only because they are
// known universally (specs, other implementations) by the names in
// exactly this capitalization.
// Tag names and codes.
enum DwarfTag {
DW_TAG_padding = 0x00,
DW_TAG_array_type = 0x01,
DW_TAG_class_type = 0x02,
DW_TAG_entry_point = 0x03,
DW_TAG_enumeration_type = 0x04,
DW_TAG_formal_parameter = 0x05,
DW_TAG_imported_declaration = 0x08,
DW_TAG_label = 0x0a,
DW_TAG_lexical_block = 0x0b,
DW_TAG_member = 0x0d,
DW_TAG_pointer_type = 0x0f,
DW_TAG_reference_type = 0x10,
DW_TAG_compile_unit = 0x11,
DW_TAG_string_type = 0x12,
DW_TAG_structure_type = 0x13,
DW_TAG_subroutine_type = 0x15,
DW_TAG_typedef = 0x16,
DW_TAG_union_type = 0x17,
DW_TAG_unspecified_parameters = 0x18,
DW_TAG_variant = 0x19,
DW_TAG_common_block = 0x1a,
DW_TAG_common_inclusion = 0x1b,
DW_TAG_inheritance = 0x1c,
DW_TAG_inlined_subroutine = 0x1d,
DW_TAG_module = 0x1e,
DW_TAG_ptr_to_member_type = 0x1f,
DW_TAG_set_type = 0x20,
DW_TAG_subrange_type = 0x21,
DW_TAG_with_stmt = 0x22,
DW_TAG_access_declaration = 0x23,
DW_TAG_base_type = 0x24,
DW_TAG_catch_block = 0x25,
DW_TAG_const_type = 0x26,
DW_TAG_constant = 0x27,
DW_TAG_enumerator = 0x28,
DW_TAG_file_type = 0x29,
DW_TAG_friend = 0x2a,
DW_TAG_namelist = 0x2b,
DW_TAG_namelist_item = 0x2c,
DW_TAG_packed_type = 0x2d,
DW_TAG_subprogram = 0x2e,
DW_TAG_template_type_param = 0x2f,
DW_TAG_template_value_param = 0x30,
DW_TAG_thrown_type = 0x31,
DW_TAG_try_block = 0x32,
DW_TAG_variant_part = 0x33,
DW_TAG_variable = 0x34,
DW_TAG_volatile_type = 0x35,
// DWARF 3.
DW_TAG_dwarf_procedure = 0x36,
DW_TAG_restrict_type = 0x37,
DW_TAG_interface_type = 0x38,
DW_TAG_namespace = 0x39,
DW_TAG_imported_module = 0x3a,
DW_TAG_unspecified_type = 0x3b,
DW_TAG_partial_unit = 0x3c,
DW_TAG_imported_unit = 0x3d,
// SGI/MIPS Extensions.
DW_TAG_MIPS_loop = 0x4081,
// HP extensions. See:
// ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz
DW_TAG_HP_array_descriptor = 0x4090,
// GNU extensions.
DW_TAG_format_label = 0x4101, // For FORTRAN 77 and Fortran 90.
DW_TAG_function_template = 0x4102, // For C++.
DW_TAG_class_template = 0x4103, // For C++.
DW_TAG_GNU_BINCL = 0x4104,
DW_TAG_GNU_EINCL = 0x4105,
// Extensions for UPC. See: http://upc.gwu.edu/~upc.
DW_TAG_upc_shared_type = 0x8765,
DW_TAG_upc_strict_type = 0x8766,
DW_TAG_upc_relaxed_type = 0x8767,
// PGI (STMicroelectronics) extensions. No documentation available.
DW_TAG_PGI_kanji_type = 0xA000,
DW_TAG_PGI_interface_block = 0xA020
};
enum DwarfHasChild {
DW_children_no = 0,
DW_children_yes = 1
};
// Form names and codes.
enum DwarfForm {
DW_FORM_addr = 0x01,
DW_FORM_block2 = 0x03,
DW_FORM_block4 = 0x04,
DW_FORM_data2 = 0x05,
DW_FORM_data4 = 0x06,
DW_FORM_data8 = 0x07,
DW_FORM_string = 0x08,
DW_FORM_block = 0x09,
DW_FORM_block1 = 0x0a,
DW_FORM_data1 = 0x0b,
DW_FORM_flag = 0x0c,
DW_FORM_sdata = 0x0d,
DW_FORM_strp = 0x0e,
DW_FORM_udata = 0x0f,
DW_FORM_ref_addr = 0x10,
DW_FORM_ref1 = 0x11,
DW_FORM_ref2 = 0x12,
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16
};
// Attribute names and codes
enum DwarfAttribute {
DW_AT_sibling = 0x01,
DW_AT_location = 0x02,
DW_AT_name = 0x03,
DW_AT_ordering = 0x09,
DW_AT_subscr_data = 0x0a,
DW_AT_byte_size = 0x0b,
DW_AT_bit_offset = 0x0c,
DW_AT_bit_size = 0x0d,
DW_AT_element_list = 0x0f,
DW_AT_stmt_list = 0x10,
DW_AT_low_pc = 0x11,
DW_AT_high_pc = 0x12,
DW_AT_language = 0x13,
DW_AT_member = 0x14,
DW_AT_discr = 0x15,
DW_AT_discr_value = 0x16,
DW_AT_visibility = 0x17,
DW_AT_import = 0x18,
DW_AT_string_length = 0x19,
DW_AT_common_reference = 0x1a,
DW_AT_comp_dir = 0x1b,
DW_AT_const_value = 0x1c,
DW_AT_containing_type = 0x1d,
DW_AT_default_value = 0x1e,
DW_AT_inline = 0x20,
DW_AT_is_optional = 0x21,
DW_AT_lower_bound = 0x22,
DW_AT_producer = 0x25,
DW_AT_prototyped = 0x27,
DW_AT_return_addr = 0x2a,
DW_AT_start_scope = 0x2c,
DW_AT_stride_size = 0x2e,
DW_AT_upper_bound = 0x2f,
DW_AT_abstract_origin = 0x31,
DW_AT_accessibility = 0x32,
DW_AT_address_class = 0x33,
DW_AT_artificial = 0x34,
DW_AT_base_types = 0x35,
DW_AT_calling_convention = 0x36,
DW_AT_count = 0x37,
DW_AT_data_member_location = 0x38,
DW_AT_decl_column = 0x39,
DW_AT_decl_file = 0x3a,
DW_AT_decl_line = 0x3b,
DW_AT_declaration = 0x3c,
DW_AT_discr_list = 0x3d,
DW_AT_encoding = 0x3e,
DW_AT_external = 0x3f,
DW_AT_frame_base = 0x40,
DW_AT_friend = 0x41,
DW_AT_identifier_case = 0x42,
DW_AT_macro_info = 0x43,
DW_AT_namelist_items = 0x44,
DW_AT_priority = 0x45,
DW_AT_segment = 0x46,
DW_AT_specification = 0x47,
DW_AT_static_link = 0x48,
DW_AT_type = 0x49,
DW_AT_use_location = 0x4a,
DW_AT_variable_parameter = 0x4b,
DW_AT_virtuality = 0x4c,
DW_AT_vtable_elem_location = 0x4d,
// DWARF 3 values.
DW_AT_allocated = 0x4e,
DW_AT_associated = 0x4f,
DW_AT_data_location = 0x50,
DW_AT_stride = 0x51,
DW_AT_entry_pc = 0x52,
DW_AT_use_UTF8 = 0x53,
DW_AT_extension = 0x54,
DW_AT_ranges = 0x55,
DW_AT_trampoline = 0x56,
DW_AT_call_column = 0x57,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
// SGI/MIPS extensions.
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
DW_AT_MIPS_tail_loop_begin = 0x2003,
DW_AT_MIPS_epilog_begin = 0x2004,
DW_AT_MIPS_loop_unroll_factor = 0x2005,
DW_AT_MIPS_software_pipeline_depth = 0x2006,
DW_AT_MIPS_linkage_name = 0x2007,
DW_AT_MIPS_stride = 0x2008,
DW_AT_MIPS_abstract_name = 0x2009,
DW_AT_MIPS_clone_origin = 0x200a,
DW_AT_MIPS_has_inlines = 0x200b,
// HP extensions.
DW_AT_HP_block_index = 0x2000,
DW_AT_HP_unmodifiable = 0x2001, // Same as DW_AT_MIPS_fde.
DW_AT_HP_actuals_stmt_list = 0x2010,
DW_AT_HP_proc_per_section = 0x2011,
DW_AT_HP_raw_data_ptr = 0x2012,
DW_AT_HP_pass_by_reference = 0x2013,
DW_AT_HP_opt_level = 0x2014,
DW_AT_HP_prof_version_id = 0x2015,
DW_AT_HP_opt_flags = 0x2016,
DW_AT_HP_cold_region_low_pc = 0x2017,
DW_AT_HP_cold_region_high_pc = 0x2018,
DW_AT_HP_all_variables_modifiable = 0x2019,
DW_AT_HP_linkage_name = 0x201a,
DW_AT_HP_prof_flags = 0x201b, // In comp unit of procs_info for -g.
// GNU extensions.
DW_AT_sf_names = 0x2101,
DW_AT_src_info = 0x2102,
DW_AT_mac_info = 0x2103,
DW_AT_src_coords = 0x2104,
DW_AT_body_begin = 0x2105,
DW_AT_body_end = 0x2106,
DW_AT_GNU_vector = 0x2107,
// VMS extensions.
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
// UPC extension.
DW_AT_upc_threads_scaled = 0x3210,
// PGI (STMicroelectronics) extensions.
DW_AT_PGI_lbase = 0x3a00,
DW_AT_PGI_soffset = 0x3a01,
DW_AT_PGI_lstride = 0x3a02
};
// Line number opcodes.
enum DwarfLineNumberOps {
DW_LNS_extended_op = 0,
DW_LNS_copy = 1,
DW_LNS_advance_pc = 2,
DW_LNS_advance_line = 3,
DW_LNS_set_file = 4,
DW_LNS_set_column = 5,
DW_LNS_negate_stmt = 6,
DW_LNS_set_basic_block = 7,
DW_LNS_const_add_pc = 8,
DW_LNS_fixed_advance_pc = 9,
// DWARF 3.
DW_LNS_set_prologue_end = 10,
DW_LNS_set_epilogue_begin = 11,
DW_LNS_set_isa = 12
};
// Line number extended opcodes.
enum DwarfLineNumberExtendedOps {
DW_LNE_end_sequence = 1,
DW_LNE_set_address = 2,
DW_LNE_define_file = 3,
// HP extensions.
DW_LNE_HP_negate_is_UV_update = 0x11,
DW_LNE_HP_push_context = 0x12,
DW_LNE_HP_pop_context = 0x13,
DW_LNE_HP_set_file_line_column = 0x14,
DW_LNE_HP_set_routine_name = 0x15,
DW_LNE_HP_set_sequence = 0x16,
DW_LNE_HP_negate_post_semantics = 0x17,
DW_LNE_HP_negate_function_exit = 0x18,
DW_LNE_HP_negate_front_end_logical = 0x19,
DW_LNE_HP_define_proc = 0x20
};
// Type encoding names and codes
enum DwarfEncoding {
DW_ATE_address =0x1,
DW_ATE_boolean =0x2,
DW_ATE_complex_float =0x3,
DW_ATE_float =0x4,
DW_ATE_signed =0x5,
DW_ATE_signed_char =0x6,
DW_ATE_unsigned =0x7,
DW_ATE_unsigned_char =0x8,
// DWARF3/DWARF3f
DW_ATE_imaginary_float =0x9,
DW_ATE_packed_decimal =0xa,
DW_ATE_numeric_string =0xb,
DW_ATE_edited =0xc,
DW_ATE_signed_fixed =0xd,
DW_ATE_unsigned_fixed =0xe,
DW_ATE_decimal_float =0xf,
DW_ATE_lo_user =0x80,
DW_ATE_hi_user =0xff
};
// Location virtual machine opcodes
enum DwarfOpcode {
DW_OP_addr =0x03,
DW_OP_deref =0x06,
DW_OP_const1u =0x08,
DW_OP_const1s =0x09,
DW_OP_const2u =0x0a,
DW_OP_const2s =0x0b,
DW_OP_const4u =0x0c,
DW_OP_const4s =0x0d,
DW_OP_const8u =0x0e,
DW_OP_const8s =0x0f,
DW_OP_constu =0x10,
DW_OP_consts =0x11,
DW_OP_dup =0x12,
DW_OP_drop =0x13,
DW_OP_over =0x14,
DW_OP_pick =0x15,
DW_OP_swap =0x16,
DW_OP_rot =0x17,
DW_OP_xderef =0x18,
DW_OP_abs =0x19,
DW_OP_and =0x1a,
DW_OP_div =0x1b,
DW_OP_minus =0x1c,
DW_OP_mod =0x1d,
DW_OP_mul =0x1e,
DW_OP_neg =0x1f,
DW_OP_not =0x20,
DW_OP_or =0x21,
DW_OP_plus =0x22,
DW_OP_plus_uconst =0x23,
DW_OP_shl =0x24,
DW_OP_shr =0x25,
DW_OP_shra =0x26,
DW_OP_xor =0x27,
DW_OP_bra =0x28,
DW_OP_eq =0x29,
DW_OP_ge =0x2a,
DW_OP_gt =0x2b,
DW_OP_le =0x2c,
DW_OP_lt =0x2d,
DW_OP_ne =0x2e,
DW_OP_skip =0x2f,
DW_OP_lit0 =0x30,
DW_OP_lit1 =0x31,
DW_OP_lit2 =0x32,
DW_OP_lit3 =0x33,
DW_OP_lit4 =0x34,
DW_OP_lit5 =0x35,
DW_OP_lit6 =0x36,
DW_OP_lit7 =0x37,
DW_OP_lit8 =0x38,
DW_OP_lit9 =0x39,
DW_OP_lit10 =0x3a,
DW_OP_lit11 =0x3b,
DW_OP_lit12 =0x3c,
DW_OP_lit13 =0x3d,
DW_OP_lit14 =0x3e,
DW_OP_lit15 =0x3f,
DW_OP_lit16 =0x40,
DW_OP_lit17 =0x41,
DW_OP_lit18 =0x42,
DW_OP_lit19 =0x43,
DW_OP_lit20 =0x44,
DW_OP_lit21 =0x45,
DW_OP_lit22 =0x46,
DW_OP_lit23 =0x47,
DW_OP_lit24 =0x48,
DW_OP_lit25 =0x49,
DW_OP_lit26 =0x4a,
DW_OP_lit27 =0x4b,
DW_OP_lit28 =0x4c,
DW_OP_lit29 =0x4d,
DW_OP_lit30 =0x4e,
DW_OP_lit31 =0x4f,
DW_OP_reg0 =0x50,
DW_OP_reg1 =0x51,
DW_OP_reg2 =0x52,
DW_OP_reg3 =0x53,
DW_OP_reg4 =0x54,
DW_OP_reg5 =0x55,
DW_OP_reg6 =0x56,
DW_OP_reg7 =0x57,
DW_OP_reg8 =0x58,
DW_OP_reg9 =0x59,
DW_OP_reg10 =0x5a,
DW_OP_reg11 =0x5b,
DW_OP_reg12 =0x5c,
DW_OP_reg13 =0x5d,
DW_OP_reg14 =0x5e,
DW_OP_reg15 =0x5f,
DW_OP_reg16 =0x60,
DW_OP_reg17 =0x61,
DW_OP_reg18 =0x62,
DW_OP_reg19 =0x63,
DW_OP_reg20 =0x64,
DW_OP_reg21 =0x65,
DW_OP_reg22 =0x66,
DW_OP_reg23 =0x67,
DW_OP_reg24 =0x68,
DW_OP_reg25 =0x69,
DW_OP_reg26 =0x6a,
DW_OP_reg27 =0x6b,
DW_OP_reg28 =0x6c,
DW_OP_reg29 =0x6d,
DW_OP_reg30 =0x6e,
DW_OP_reg31 =0x6f,
DW_OP_breg0 =0x70,
DW_OP_breg1 =0x71,
DW_OP_breg2 =0x72,
DW_OP_breg3 =0x73,
DW_OP_breg4 =0x74,
DW_OP_breg5 =0x75,
DW_OP_breg6 =0x76,
DW_OP_breg7 =0x77,
DW_OP_breg8 =0x78,
DW_OP_breg9 =0x79,
DW_OP_breg10 =0x7a,
DW_OP_breg11 =0x7b,
DW_OP_breg12 =0x7c,
DW_OP_breg13 =0x7d,
DW_OP_breg14 =0x7e,
DW_OP_breg15 =0x7f,
DW_OP_breg16 =0x80,
DW_OP_breg17 =0x81,
DW_OP_breg18 =0x82,
DW_OP_breg19 =0x83,
DW_OP_breg20 =0x84,
DW_OP_breg21 =0x85,
DW_OP_breg22 =0x86,
DW_OP_breg23 =0x87,
DW_OP_breg24 =0x88,
DW_OP_breg25 =0x89,
DW_OP_breg26 =0x8a,
DW_OP_breg27 =0x8b,
DW_OP_breg28 =0x8c,
DW_OP_breg29 =0x8d,
DW_OP_breg30 =0x8e,
DW_OP_breg31 =0x8f,
DW_OP_regX =0x90,
DW_OP_fbreg =0x91,
DW_OP_bregX =0x92,
DW_OP_piece =0x93,
DW_OP_deref_size =0x94,
DW_OP_xderef_size =0x95,
DW_OP_nop =0x96,
// DWARF3/DWARF3f
DW_OP_push_object_address =0x97,
DW_OP_call2 =0x98,
DW_OP_call4 =0x99,
DW_OP_call_ref =0x9a,
DW_OP_form_tls_address =0x9b,
DW_OP_call_frame_cfa =0x9c,
DW_OP_bit_piece =0x9d,
DW_OP_lo_user =0xe0,
DW_OP_hi_user =0xff,
// GNU extensions
DW_OP_GNU_push_tls_address =0xe0
};
} // namespace dwarf2reader
#endif // COMMON_MAC_DWARF_DWARF2ENUMS_H__

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

@ -0,0 +1,830 @@
// Copyright 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 <ext/hash_map>
#include <stack>
#include <utility>
#include "common/mac/dwarf/bytereader-inl.h"
#include "common/mac/dwarf/dwarf2reader.h"
#include "common/mac/dwarf/bytereader.h"
#include "common/mac/dwarf/line_state_machine.h"
namespace __gnu_cxx
{
template<> struct hash< std::string >
{
size_t operator()( const std::string& x ) const
{
return hash< const char* >()( x.c_str() );
}
};
}
namespace dwarf2reader {
// Read a DWARF2/3 initial length field from START, using READER, and
// report the length in LEN. Return the actual initial length.
static uint64 ReadInitialLength(const char* start,
ByteReader* reader, size_t* len) {
const uint64 initial_length = reader->ReadFourBytes(start);
start += 4;
// In DWARF2/3, if the initial length is all 1 bits, then the offset
// size is 8 and we need to read the next 8 bytes for the real length.
if (initial_length == 0xffffffff) {
reader->SetOffsetSize(8);
*len = 12;
return reader->ReadOffset(start);
} else {
reader->SetOffsetSize(4);
*len = 4;
}
return initial_length;
}
CompilationUnit::CompilationUnit(const SectionMap& sections, uint64 offset,
ByteReader* reader, Dwarf2Handler* handler)
: offset_from_section_start_(offset), reader_(reader),
sections_(sections), handler_(handler), abbrevs_(NULL),
string_buffer_(NULL), string_buffer_length_(0) {}
// Read a DWARF2/3 abbreviation section.
// Each abbrev consists of a abbreviation number, a tag, a byte
// specifying whether the tag has children, and a list of
// attribute/form pairs.
// The list of forms is terminated by a 0 for the attribute, and a
// zero for the form. The entire abbreviation section is terminated
// by a zero for the code.
void CompilationUnit::ReadAbbrevs() {
if (abbrevs_)
return;
// First get the debug_abbrev section
SectionMap::const_iterator iter = sections_.find("__debug_abbrev");
assert(iter != sections_.end());
abbrevs_ = new vector<Abbrev>;
abbrevs_->resize(1);
// The only way to check whether we are reading over the end of the
// buffer would be to first compute the size of the leb128 data by
// reading it, then go back and read it again.
const char* abbrev_start = iter->second.first +
header_.abbrev_offset;
const char* abbrevptr = abbrev_start;
const uint64 abbrev_length = iter->second.second - header_.abbrev_offset;
while (1) {
CompilationUnit::Abbrev abbrev;
size_t len;
const uint32 number = reader_->ReadUnsignedLEB128(abbrevptr, &len);
if (number == 0)
break;
abbrev.number = number;
abbrevptr += len;
assert(abbrevptr < abbrev_start + abbrev_length);
const uint32 tag = reader_->ReadUnsignedLEB128(abbrevptr, &len);
abbrevptr += len;
abbrev.tag = static_cast<enum DwarfTag>(tag);
assert(abbrevptr < abbrev_start + abbrev_length);
abbrev.has_children = reader_->ReadOneByte(abbrevptr);
abbrevptr += 1;
assert(abbrevptr < abbrev_start + abbrev_length);
while (1) {
const uint32 nametemp = reader_->ReadUnsignedLEB128(abbrevptr, &len);
abbrevptr += len;
assert(abbrevptr < abbrev_start + abbrev_length);
const uint32 formtemp = reader_->ReadUnsignedLEB128(abbrevptr, &len);
abbrevptr += len;
if (nametemp == 0 && formtemp == 0)
break;
const enum DwarfAttribute name =
static_cast<enum DwarfAttribute>(nametemp);
const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp);
abbrev.attributes.push_back(make_pair(name, form));
}
assert(abbrev.number == abbrevs_->size());
abbrevs_->push_back(abbrev);
}
}
// Skips a single DIE's attributes.
const char* CompilationUnit::SkipDIE(const char* start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
start = SkipAttribute(start, i->second);
}
return start;
}
// Skips a single attribute form's data.
const char* CompilationUnit::SkipAttribute(const char* start,
enum DwarfForm form) {
size_t len;
switch (form) {
case DW_FORM_indirect:
form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start,
&len));
start += len;
return SkipAttribute(start, form);
break;
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
return start + 1;
break;
case DW_FORM_ref2:
case DW_FORM_data2:
return start + 2;
break;
case DW_FORM_ref4:
case DW_FORM_data4:
return start + 4;
break;
case DW_FORM_ref8:
case DW_FORM_data8:
return start + 8;
break;
case DW_FORM_string:
return start + strlen(start) + 1;
break;
case DW_FORM_udata:
case DW_FORM_ref_udata:
reader_->ReadUnsignedLEB128(start, &len);
return start + len;
break;
case DW_FORM_sdata:
reader_->ReadSignedLEB128(start, &len);
return start + len;
break;
case DW_FORM_addr:
return start + reader_->AddressSize();
break;
case DW_FORM_ref_addr:
// DWARF2 and 3 differ on whether ref_addr is address size or
// offset size.
assert(header_.version == 2 || header_.version == 3);
if (header_.version == 2) {
return start + reader_->AddressSize();
} else if (header_.version == 3) {
return start + reader_->OffsetSize();
}
break;
case DW_FORM_block1:
return start + 1 + reader_->ReadOneByte(start);
break;
case DW_FORM_block2:
return start + 2 + reader_->ReadTwoBytes(start);
break;
case DW_FORM_block4:
return start + 4 + reader_->ReadFourBytes(start);
break;
case DW_FORM_block: {
uint64 size = reader_->ReadUnsignedLEB128(start, &len);
return start + size + len;
}
break;
case DW_FORM_strp:
return start + reader_->OffsetSize();
break;
default:
fprintf(stderr,"Unhandled form type");
}
fprintf(stderr,"Unhandled form type");
return NULL;
}
// Read a DWARF2/3 header.
// The header is variable length in DWARF3 (and DWARF2 as extended by
// most compilers), and consists of an length field, a version number,
// the offset in the .debug_abbrev section for our abbrevs, and an
// address size.
void CompilationUnit::ReadHeader() {
const char* headerptr = buffer_;
size_t initial_length_size;
assert(headerptr + 4 < buffer_ + buffer_length_);
const uint64 initial_length = ReadInitialLength(headerptr, reader_,
&initial_length_size);
headerptr += initial_length_size;
header_.length = initial_length;
assert(headerptr + 2 < buffer_ + buffer_length_);
header_.version = reader_->ReadTwoBytes(headerptr);
headerptr += 2;
assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_);
header_.abbrev_offset = reader_->ReadOffset(headerptr);
headerptr += reader_->OffsetSize();
assert(headerptr + 1 < buffer_ + buffer_length_);
header_.address_size = reader_->ReadOneByte(headerptr);
reader_->SetAddressSize(header_.address_size);
headerptr += 1;
after_header_ = headerptr;
// This check ensures that we don't have to do checking during the
// reading of DIEs. header_.length does not include the size of the
// initial length.
assert(buffer_ + initial_length_size + header_.length <=
buffer_ + buffer_length_);
}
uint64 CompilationUnit::Start() {
// First get the debug_info section
SectionMap::const_iterator iter = sections_.find("__debug_info");
assert(iter != sections_.end());
// Set up our buffer
buffer_ = iter->second.first + offset_from_section_start_;
buffer_length_ = iter->second.second - offset_from_section_start_;
// Read the header
ReadHeader();
// Figure out the real length from the end of the initial length to
// the end of the compilation unit, since that is the value we
// return.
uint64 ourlength = header_.length;
if (reader_->OffsetSize() == 8)
ourlength += 12;
else
ourlength += 4;
// See if the user wants this compilation unit, and if not, just return.
if (!handler_->StartCompilationUnit(offset_from_section_start_,
reader_->AddressSize(),
reader_->OffsetSize(),
header_.length,
header_.version))
return ourlength;
// Otherwise, continue by reading our abbreviation entries.
ReadAbbrevs();
// Set the string section if we have one.
iter = sections_.find("__debug_str");
if (iter != sections_.end()) {
string_buffer_ = iter->second.first;
string_buffer_length_ = iter->second.second;
}
// Now that we have our abbreviations, start processing DIE's.
ProcessDIEs();
return ourlength;
}
// If one really wanted, you could merge SkipAttribute and
// ProcessAttribute
// This is all boring data manipulation and calling of the handler.
const char* CompilationUnit::ProcessAttribute(
uint64 dieoffset, const char* start, enum DwarfAttribute attr,
enum DwarfForm form) {
size_t len;
switch (form) {
// DW_FORM_indirect is never used because it is such a space
// waster.
case DW_FORM_indirect:
form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start,
&len));
start += len;
return ProcessAttribute(dieoffset, start, attr, form);
break;
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOneByte(start));
return start + 1;
break;
case DW_FORM_ref2:
case DW_FORM_data2:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadTwoBytes(start));
return start + 2;
break;
case DW_FORM_ref4:
case DW_FORM_data4:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadFourBytes(start));
return start + 4;
break;
case DW_FORM_ref8:
case DW_FORM_data8:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadEightBytes(start));
return start + 8;
break;
case DW_FORM_string: {
const char* str = start;
handler_->ProcessAttributeString(dieoffset, attr, form,
str);
return start + strlen(str) + 1;
}
break;
case DW_FORM_udata:
case DW_FORM_ref_udata:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadUnsignedLEB128(start,
&len));
return start + len;
break;
case DW_FORM_sdata:
handler_->ProcessAttributeSigned(dieoffset, attr, form,
reader_->ReadSignedLEB128(start, &len));
return start + len;
break;
case DW_FORM_addr:
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadAddress(start));
return start + reader_->AddressSize();
break;
case DW_FORM_ref_addr:
// DWARF2 and 3 differ on whether ref_addr is address size or
// offset size.
assert(header_.version == 2 || header_.version == 3);
if (header_.version == 2) {
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadAddress(start));
return start + reader_->AddressSize();
} else if (header_.version == 3) {
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOffset(start));
return start + reader_->OffsetSize();
}
break;
case DW_FORM_block1: {
uint64 datalen = reader_->ReadOneByte(start);
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1,
datalen);
return start + 1 + datalen;
}
break;
case DW_FORM_block2: {
uint64 datalen = reader_->ReadTwoBytes(start);
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 2,
datalen);
return start + 2 + datalen;
}
break;
case DW_FORM_block4: {
uint64 datalen = reader_->ReadFourBytes(start);
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 4,
datalen);
return start + 4 + datalen;
}
break;
case DW_FORM_block: {
uint64 datalen = reader_->ReadUnsignedLEB128(start, &len);
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + len,
datalen);
return start + datalen + len;
}
break;
case DW_FORM_strp: {
assert(string_buffer_ != NULL);
const uint64 offset = reader_->ReadOffset(start);
assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_);
const char* str = string_buffer_ + offset;
handler_->ProcessAttributeString(dieoffset, attr, form,
str);
return start + reader_->OffsetSize();
}
break;
default:
fprintf(stderr, "Unhandled form type");
}
fprintf(stderr, "Unhandled form type");
return NULL;
}
const char* CompilationUnit::ProcessDIE(uint64 dieoffset,
const char* start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
start = ProcessAttribute(dieoffset, start, i->first, i->second);
}
return start;
}
void CompilationUnit::ProcessDIEs() {
const char* dieptr = after_header_;
size_t len;
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
const char* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
if (reader_->OffsetSize() == 8)
lengthstart += 12;
else
lengthstart += 4;
// we need semantics of boost scoped_ptr here - no intention of trasnferring
// ownership of the stack. use const, but then we limit ourselves to not
// ever being able to call .reset() on the smart pointer.
auto_ptr<stack<uint64> > const die_stack(new stack<uint64>);
while (dieptr < (lengthstart + header_.length)) {
// We give the user the absolute offset from the beginning of
// debug_info, since they need it to deal with ref_addr forms.
uint64 absolute_offset = (dieptr - buffer_) + offset_from_section_start_;
uint64 abbrev_num = reader_->ReadUnsignedLEB128(dieptr, &len);
dieptr += len;
// Abbrev == 0 represents the end of a list of children.
if (abbrev_num == 0) {
const uint64 offset = die_stack->top();
die_stack->pop();
handler_->EndDIE(offset);
continue;
}
const Abbrev& abbrev = abbrevs_->at(abbrev_num);
const enum DwarfTag tag = abbrev.tag;
if (!handler_->StartDIE(absolute_offset, tag, abbrev.attributes)) {
dieptr = SkipDIE(dieptr, abbrev);
} else {
dieptr = ProcessDIE(absolute_offset, dieptr, abbrev);
}
if (abbrev.has_children) {
die_stack->push(absolute_offset);
} else {
handler_->EndDIE(absolute_offset);
}
}
}
LineInfo::LineInfo(const char* buffer, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler):
handler_(handler), reader_(reader), buffer_(buffer),
buffer_length_(buffer_length) {
header_.std_opcode_lengths = NULL;
}
uint64 LineInfo::Start() {
ReadHeader();
ReadLines();
return after_header_ - buffer_;
}
// The header for a debug_line section is mildly complicated, because
// the line info is very tightly encoded.
void LineInfo::ReadHeader() {
const char* lineptr = buffer_;
size_t initial_length_size;
const uint64 initial_length = ReadInitialLength(lineptr, reader_,
&initial_length_size);
lineptr += initial_length_size;
header_.total_length = initial_length;
assert(buffer_ + initial_length_size + header_.total_length <=
buffer_ + buffer_length_);
// Address size *must* be set by CU ahead of time.
assert(reader_->AddressSize() != 0);
header_.version = reader_->ReadTwoBytes(lineptr);
lineptr += 2;
header_.prologue_length = reader_->ReadOffset(lineptr);
lineptr += reader_->OffsetSize();
header_.min_insn_length = reader_->ReadOneByte(lineptr);
lineptr += 1;
header_.default_is_stmt = reader_->ReadOneByte(lineptr);
lineptr += 1;
header_.line_base = *reinterpret_cast<const int8*>(lineptr);
lineptr += 1;
header_.line_range = reader_->ReadOneByte(lineptr);
lineptr += 1;
header_.opcode_base = reader_->ReadOneByte(lineptr);
lineptr += 1;
header_.std_opcode_lengths = new vector<unsigned char>;
header_.std_opcode_lengths->resize(header_.opcode_base + 1);
(*header_.std_opcode_lengths)[0] = 0;
for (int i = 1; i < header_.opcode_base; i++) {
(*header_.std_opcode_lengths)[i] = reader_->ReadOneByte(lineptr);
lineptr += 1;
}
// It is legal for the directory entry table to be empty.
if (*lineptr) {
uint32 dirindex = 1;
while (*lineptr) {
const char* dirname = lineptr;
handler_->DefineDir(dirname, dirindex);
lineptr += strlen(dirname) + 1;
dirindex++;
}
}
lineptr++;
// It is also legal for the file entry table to be empty.
if (*lineptr) {
uint32 fileindex = 1;
size_t len;
while (*lineptr) {
const char* filename = lineptr;
lineptr += strlen(filename) + 1;
uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len);
lineptr += len;
uint64 mod_time = reader_->ReadUnsignedLEB128(lineptr, &len);
lineptr += len;
uint64 filelength = reader_->ReadUnsignedLEB128(lineptr, &len);
lineptr += len;
handler_->DefineFile(filename, fileindex, dirindex, mod_time,
filelength);
fileindex++;
}
}
lineptr++;
after_header_ = lineptr;
}
/* static */
bool LineInfo::ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
const char* start,
struct LineStateMachine* lsm,
size_t* len,
uintptr_t pc,
bool *lsm_passes_pc) {
size_t oplen = 0;
size_t templen;
uint8 opcode = reader->ReadOneByte(start);
oplen++;
start++;
// If the opcode is great than the opcode_base, it is a special
// opcode. Most line programs consist mainly of special opcodes.
if (opcode >= header.opcode_base) {
opcode -= header.opcode_base;
const int64 advance_address = (opcode / header.line_range)
* header.min_insn_length;
const int64 advance_line = (opcode % header.line_range)
+ header.line_base;
// Check if the lsm passes "pc". If so, mark it as passed.
if (lsm_passes_pc &&
lsm->address <= pc && pc < lsm->address + advance_address) {
*lsm_passes_pc = true;
}
lsm->address += advance_address;
lsm->line_num += advance_line;
lsm->basic_block = true;
*len = oplen;
return true;
}
// Otherwise, we have the regular opcodes
switch (opcode) {
case DW_LNS_copy: {
lsm->basic_block = false;
*len = oplen;
return true;
}
case DW_LNS_advance_pc: {
uint64 advance_address = reader->ReadUnsignedLEB128(start, &templen);
oplen += templen;
// Check if the lsm passes "pc". If so, mark it as passed.
if (lsm_passes_pc && lsm->address <= pc &&
pc < lsm->address + header.min_insn_length * advance_address) {
*lsm_passes_pc = true;
}
lsm->address += header.min_insn_length * advance_address;
}
break;
case DW_LNS_advance_line: {
const int64 advance_line = reader->ReadSignedLEB128(start, &templen);
oplen += templen;
lsm->line_num += advance_line;
// With gcc 4.2.1, we can get the line_no here for the first time
// since DW_LNS_advance_line is called after DW_LNE_set_address is
// called. So we check if the lsm passes "pc" here, not in
// DW_LNE_set_address.
if (lsm_passes_pc && lsm->address == pc) {
*lsm_passes_pc = true;
}
}
break;
case DW_LNS_set_file: {
const uint64 fileno = reader->ReadUnsignedLEB128(start, &templen);
oplen += templen;
lsm->file_num = fileno;
}
break;
case DW_LNS_set_column: {
const uint64 colno = reader->ReadUnsignedLEB128(start, &templen);
oplen += templen;
lsm->column_num = colno;
}
break;
case DW_LNS_negate_stmt: {
lsm->is_stmt = !lsm->is_stmt;
}
break;
case DW_LNS_set_basic_block: {
lsm->basic_block = true;
}
break;
case DW_LNS_fixed_advance_pc: {
const uint16 advance_address = reader->ReadTwoBytes(start);
oplen += 2;
// Check if the lsm passes "pc". If so, mark it as passed.
if (lsm_passes_pc &&
lsm->address <= pc && pc < lsm->address + advance_address) {
*lsm_passes_pc = true;
}
lsm->address += advance_address;
}
break;
case DW_LNS_const_add_pc: {
const int64 advance_address = header.min_insn_length
* ((255 - header.opcode_base)
/ header.line_range);
// Check if the lsm passes "pc". If so, mark it as passed.
if (lsm_passes_pc &&
lsm->address <= pc && pc < lsm->address + advance_address) {
*lsm_passes_pc = true;
}
lsm->address += advance_address;
}
break;
case DW_LNS_extended_op: {
const size_t extended_op_len = reader->ReadUnsignedLEB128(start,
&templen);
start += templen;
oplen += templen + extended_op_len;
const uint64 extended_op = reader->ReadOneByte(start);
start++;
switch (extended_op) {
case DW_LNE_end_sequence: {
lsm->end_sequence = true;
*len = oplen;
return true;
}
break;
case DW_LNE_set_address: {
// With gcc 4.2.1, we cannot tell the line_no here since
// DW_LNE_set_address is called before DW_LNS_advance_line is
// called. So we do not check if the lsm passes "pc" here. See
// also the comment in DW_LNS_advance_line.
uint64 address = reader->ReadAddress(start);
lsm->address = address;
}
break;
case DW_LNE_define_file: {
const char* filename = start;
templen = strlen(filename) + 1;
start += templen;
uint64 dirindex = reader->ReadUnsignedLEB128(start, &templen);
oplen += templen;
const uint64 mod_time = reader->ReadUnsignedLEB128(start,
&templen);
oplen += templen;
const uint64 filelength = reader->ReadUnsignedLEB128(start,
&templen);
oplen += templen;
if (handler) {
handler->DefineFile(filename, -1, dirindex, mod_time,
filelength);
}
}
break;
}
}
break;
default: {
// Ignore unknown opcode silently
if (header.std_opcode_lengths) {
for (int i = 0; i < (*header.std_opcode_lengths)[opcode]; i++) {
size_t templen;
reader->ReadUnsignedLEB128(start, &templen);
start += templen;
oplen += templen;
}
}
}
break;
}
*len = oplen;
return false;
}
void LineInfo::ReadLines() {
struct LineStateMachine lsm;
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
const char* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
if (reader_->OffsetSize() == 8)
lengthstart += 12;
else
lengthstart += 4;
const char* lineptr = after_header_;
while (lineptr < lengthstart + header_.total_length) {
lsm.Reset(header_.default_is_stmt);
while (!lsm.end_sequence) {
size_t oplength;
bool add_line = ProcessOneOpcode(reader_, handler_, header_,
lineptr, &lsm, &oplength, (uintptr_t)-1, NULL);
if (add_line)
handler_->AddLine(lsm.address, lsm.file_num, lsm.line_num,
lsm.column_num);
lineptr += oplength;
}
}
after_header_ = lengthstart + header_.total_length;
}
} // namespace dwarf2reader

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

@ -0,0 +1,393 @@
// Copyright 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.
// This file contains definitions related to the DWARF2/3 reader and
// it's handler interfaces.
// The DWARF2/3 specification can be found at
// http://dwarf.freestandards.org and should be considered required
// reading if you wish to modify the implementation.
// Only a cursory attempt is made to explain terminology that is
// used here, as it is much better explained in the standard documents
#ifndef COMMON_MAC_DWARF_DWARF2READER_H__
#define COMMON_MAC_DWARF_DWARF2READER_H__
#include <ext/hash_map>
#include <list>
#include <string>
#include <utility>
#include <vector>
#include "common/mac/dwarf/dwarf2enums.h"
#include "common/mac/dwarf/types.h"
using namespace std;
using namespace __gnu_cxx;
namespace dwarf2reader {
struct LineStateMachine;
class ByteReader;
class Dwarf2Handler;
class LineInfoHandler;
// This maps from a string naming a section to a pair containing a
// the data for the section, and the size of the section.
typedef hash_map<string, pair<const char*, uint64> > SectionMap;
typedef list<pair<enum DwarfAttribute, enum DwarfForm> > AttributeList;
typedef AttributeList::iterator AttributeIterator;
typedef AttributeList::const_iterator ConstAttributeIterator;
struct LineInfoHeader {
uint64 total_length;
uint16 version;
uint64 prologue_length;
uint8 min_insn_length; // insn stands for instructin
bool default_is_stmt; // stmt stands for statement
int8 line_base;
uint8 line_range;
uint8 opcode_base;
// Use a pointer so that signalsafe_addr2line is able to use this structure
// without heap allocation problem.
vector<unsigned char> *std_opcode_lengths;
};
class LineInfo {
public:
// Initializes a .debug_line reader. Buffer and buffer length point
// to the beginning and length of the line information to read.
// Reader is a ByteReader class that has the endianness set
// properly.
LineInfo(const char* buffer_, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler);
virtual ~LineInfo() {
if (header_.std_opcode_lengths) {
delete header_.std_opcode_lengths;
}
}
// Start processing line info, and calling callbacks in the handler.
// Consumes the line number information for a single compilation unit.
// Returns the number of bytes processed.
uint64 Start();
// Process a single line info opcode at START using the state
// machine at LSM. Return true if we should define a line using the
// current state of the line state machine. Place the length of the
// opcode in LEN.
// If LSM_PASSES_PC is non-NULL, this function also checks if the lsm
// passes the address of PC. In other words, LSM_PASSES_PC will be
// set to true, if the following condition is met.
//
// lsm's old address < PC <= lsm's new address
static bool ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
const char* start,
struct LineStateMachine* lsm,
size_t* len,
uintptr_t pc,
bool *lsm_passes_pc);
private:
// Reads the DWARF2/3 header for this line info.
void ReadHeader();
// Reads the DWARF2/3 line information
void ReadLines();
// The associated handler to call processing functions in
LineInfoHandler* handler_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
// A DWARF2/3 line info header. This is not the same size as
// in the actual file, as the one in the file may have a 32 bit or
// 64 bit lengths
struct LineInfoHeader header_;
// buffer is the buffer for our line info, starting at exactly where
// the line info to read is. after_header is the place right after
// the end of the line information header.
const char* buffer_;
uint64 buffer_length_;
const char* after_header_;
};
// This class is the main interface between the line info reader and
// the client. The virtual functions inside this get called for
// interesting events that happen during line info reading. The
// default implementation does nothing
class LineInfoHandler {
public:
LineInfoHandler() { }
virtual ~LineInfoHandler() { }
// Called when we define a directory. NAME is the directory name,
// DIR_NUM is the directory number
virtual void DefineDir(const string& name, uint32 dir_num) { }
// Called when we define a filename. NAME is the filename, FILE_NUM
// is the file number which is -1 if the file index is the next
// index after the last numbered index (this happens when files are
// dynamically defined by the line program), DIR_NUM is the
// directory index for the directory name of this file, MOD_TIME is
// the modification time of the file, and LENGTH is the length of
// the file
virtual void DefineFile(const string& name, int32 file_num,
uint32 dir_num, uint64 mod_time,
uint64 length) { }
// Called when the line info reader has a new line, address pair
// ready for us. ADDRESS is the address of the code, FILE_NUM is
// the file number containing the code, LINE_NUM is the line number in
// that file for the code, and COLUMN_NUM is the column number the code
// starts at, if we know it (0 otherwise).
virtual void AddLine(uint64 address, uint32 file_num, uint32 line_num,
uint32 column_num) { }
};
// The base of DWARF2/3 debug info is a DIE (Debugging Information
// Entry.
// DWARF groups DIE's into a tree and calls the root of this tree a
// "compilation unit". Most of the time, their is one compilation
// unit in the .debug_info section for each file that had debug info
// generated.
// Each DIE consists of
// 1. a tag specifying a thing that is being described (ie
// DW_TAG_subprogram for functions, DW_TAG_variable for variables, etc
// 2. attributes (such as DW_AT_location for location in memory,
// DW_AT_name for name), and data for each attribute.
// 3. A flag saying whether the DIE has children or not
// In order to gain some amount of compression, the format of
// each DIE (tag name, attributes and data forms for the attributes)
// are stored in a separate table called the "abbreviation table".
// This is done because a large number of DIEs have the exact same tag
// and list of attributes, but different data for those attributes.
// As a result, the .debug_info section is just a stream of data, and
// requires reading of the .debug_abbrev section to say what the data
// means.
// As a warning to the user, it should be noted that the reason for
// using absolute offsets from the beginning of .debug_info is that
// DWARF2/3 support referencing DIE's from other DIE's by their offset
// from either the current compilation unit start, *or* the beginning
// of the .debug_info section. This means it is possible to reference
// a DIE in one compilation unit from a DIE in another compilation
// unit. This style of reference is usually used to eliminate
// duplicated information that occurs across compilation
// units, such as base types, etc. GCC 3.4+ support this with
// -feliminate-dwarf2-dups. Other toolchains will sometimes do
// duplicate elimination in the linker.
class CompilationUnit {
public:
// Initialize a compilation unit. This requires a map of sections,
// the offset of this compilation unit in the debug_info section, a
// ByteReader, and a Dwarf2Handler class to call callbacks in.
CompilationUnit(const SectionMap& sections, uint64 offset,
ByteReader* reader, Dwarf2Handler* handler);
virtual ~CompilationUnit() {
if (abbrevs_) delete abbrevs_;
}
// Begin reading a Dwarf2 compilation unit, and calling the
// callbacks in the Dwarf2Handler
// Return the offset of the end of the compilation unit - the passed
// in offset.
uint64 Start();
private:
// This struct represents a single DWARF2/3 abbreviation
// The abbreviation tells how to read a DWARF2/3 DIE, and consist of a
// tag and a list of attributes, as well as the data form of each attribute.
struct Abbrev {
uint32 number;
enum DwarfTag tag;
bool has_children;
AttributeList attributes;
};
// A DWARF2/3 compilation unit header. This is not the same size as
// in the actual file, as the one in the file may have a 32 bit or
// 64 bit length.
struct CompilationUnitHeader {
uint64 length;
uint16 version;
uint64 abbrev_offset;
uint8 address_size;
} header_;
// Reads the DWARF2/3 header for this compilation unit.
void ReadHeader();
// Reads the DWARF2/3 abbreviations for this compilation unit
void ReadAbbrevs();
// Processes a single DIE for this compilation unit and return a new
// pointer just past the end of it
const char* ProcessDIE(uint64 dieoffset,
const char* start,
const Abbrev& abbrev);
// Processes a single attribute and return a new pointer just past the
// end of it
const char* ProcessAttribute(uint64 dieoffset,
const char* start,
enum DwarfAttribute attr,
enum DwarfForm form);
// Processes all DIEs for this compilation unit
void ProcessDIEs();
// Skips the die with attributes specified in ABBREV starting at
// START, and return the new place to position the stream to.
const char* SkipDIE(const char* start,
const Abbrev& abbrev);
// Skips the attribute starting at START, with FORM, and return the
// new place to position the stream to.
const char* SkipAttribute(const char* start,
enum DwarfForm form);
// Offset from section start is the offset of this compilation unit
// from the beginning of the .debug_info section.
uint64 offset_from_section_start_;
// buffer is the buffer for our CU, starting at .debug_info + offset
// passed in from constructor.
// after_header points to right after the compilation unit header.
const char* buffer_;
uint64 buffer_length_;
const char* after_header_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
// The map of sections in our file to buffers containing their data
const SectionMap& sections_;
// The associated handler to call processing functions in
Dwarf2Handler* handler_;
// Set of DWARF2/3 abbreviations for this compilation unit. Indexed
// by abbreviation number, which means that abbrevs_[0] is not
// valid.
vector<Abbrev>* abbrevs_;
// String section buffer and length, if we have a string section.
// This is here to avoid doing a section lookup for strings in
// ProcessAttribute, which is in the hot path for DWARF2 reading.
const char* string_buffer_;
uint64 string_buffer_length_;
};
// This class is the main interface between the reader and the
// client. The virtual functions inside this get called for
// interesting events that happen during DWARF2 reading.
// The default implementation skips everything.
class Dwarf2Handler {
public:
Dwarf2Handler() { }
virtual ~Dwarf2Handler() { }
// Start to process a compilation unit at OFFSET from the beginning of the
// debug_info section. Return false if you would like
// to skip this compilation unit.
virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
uint8 offset_size, uint64 cu_length,
uint8 dwarf_version) { return false; }
// Start to process a DIE at OFFSET from the beginning of the
// debug_info section. Return false if you would like to skip this
// DIE.
virtual bool StartDIE(uint64 offset, enum DwarfTag tag,
const AttributeList& attrs) { return false; }
// Called when we have an attribute with unsigned data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) { }
// Called when we have an attribute with signed data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeSigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64 data) { }
// Called when we have an attribute with a buffer of data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA, and the
// length of the buffer is LENGTH. The buffer is owned by the
// caller, not the callee, and may not persist for very long. If
// you want the data to be available later, it needs to be copied.
virtual void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
uint64 len) { }
// Called when we have an attribute with string data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) { }
// Called when finished processing the DIE at OFFSET.
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
// before ends of the previous DIE, as we process children before
// ending the parent.
virtual void EndDIE(uint64 offset) { }
};
} // namespace dwarf2reader
#endif // UTIL_DEBUGINFO_DWARF2READER_H__

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

@ -0,0 +1,198 @@
// Copyright 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.
// This is a client for the dwarf2reader to extract function and line
// information from the debug info.
#include <map>
#include <queue>
#include <vector>
#include "common/mac/dwarf/functioninfo.h"
#include "common/mac/dwarf/bytereader.h"
namespace __gnu_cxx
{
template<>
struct hash<std::string>
{
size_t operator()(const std::string& k) const;
};
}
namespace dwarf2reader {
CULineInfoHandler::CULineInfoHandler(vector<SourceFileInfo>* files,
vector<string>* dirs,
LineMap* linemap):linemap_(linemap),
files_(files),
dirs_(dirs) {
// The dirs and files are 1 indexed, so just make sure we put
// nothing in the 0 vector.
assert(dirs->size() == 0);
assert(files->size() == 0);
dirs->push_back("");
SourceFileInfo s;
s.name = "";
s.lowpc = ULLONG_MAX;
files->push_back(s);
}
void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) {
// These should never come out of order, actually
assert(dir_num == dirs_->size());
dirs_->push_back(name);
}
void CULineInfoHandler::DefineFile(const string& name,
int32 file_num, uint32 dir_num,
uint64 mod_time, uint64 length) {
assert(dir_num >= 0);
assert(dir_num < dirs_->size());
// These should never come out of order, actually.
if (file_num == (int32)files_->size() || file_num == -1) {
string dir = dirs_->at(dir_num);
SourceFileInfo s;
s.lowpc = ULLONG_MAX;
if (dir == "") {
s.name = name;
} else {
s.name = dir + "/" + name;
}
files_->push_back(s);
} else {
fprintf(stderr, "error in DefineFile");
}
}
void CULineInfoHandler::AddLine(uint64 address, uint32 file_num,
uint32 line_num, uint32 column_num) {
if (file_num < files_->size()) {
linemap_->insert(make_pair(address, make_pair(files_->at(file_num).name.c_str(),
line_num)));
if(address < files_->at(file_num).lowpc) {
files_->at(file_num).lowpc = address;
}
} else {
fprintf(stderr,"error in AddLine");
}
}
bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset,
uint8 address_size,
uint8 offset_size,
uint64 cu_length,
uint8 dwarf_version) {
return true;
}
// For function info, we only care about subprograms and inlined
// subroutines. For line info, the DW_AT_stmt_list lives in the
// compile unit tag.
bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag,
const AttributeList& attrs) {
switch (tag) {
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine: {
current_function_info_ = new FunctionInfo;
current_function_info_->lowpc = current_function_info_->highpc = 0;
current_function_info_->name = "";
current_function_info_->line = 0;
current_function_info_->file = "";
offset_to_funcinfo_->insert(make_pair(offset, current_function_info_));
};
// FALLTHROUGH
case DW_TAG_compile_unit:
return true;
default:
return false;
}
return false;
}
// Only care about the name attribute for functions
void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
if (attr == DW_AT_name && current_function_info_)
current_function_info_->name = data;
}
void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) {
if (attr == DW_AT_stmt_list) {
SectionMap::const_iterator iter = sections_.find("__debug_line");
assert(iter != sections_.end());
// this should be a scoped_ptr but we dont' use boost :-(
auto_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
iter->second.second - data,
reader_, linehandler_));
lireader->Start();
} else if (current_function_info_) {
switch (attr) {
case DW_AT_low_pc:
current_function_info_->lowpc = data;
break;
case DW_AT_high_pc:
current_function_info_->highpc = data;
break;
case DW_AT_decl_line:
current_function_info_->line = data;
break;
case DW_AT_decl_file:
current_function_info_->file = files_->at(data).name;
break;
default:
break;
}
}
}
void CUFunctionInfoHandler::EndDIE(uint64 offset) {
if (current_function_info_ && current_function_info_->lowpc)
address_to_funcinfo_->insert(make_pair(current_function_info_->lowpc,
current_function_info_));
}
} // namespace dwarf2reader

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

@ -0,0 +1,175 @@
// Copyright 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.
// This file contains the definitions for a DWARF2/3 information
// collector that uses the DWARF2/3 reader interface to build a mapping
// of addresses to files, lines, and functions.
#ifndef COMMON_MAC_DWARF_FUNCTIONINFO_H__
#define COMMON_MAC_DWARF_FUNCTIONINFO_H__
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "common/mac/dwarf/dwarf2reader.h"
namespace dwarf2reader {
struct FunctionInfo {
// Name of the function
string name;
// File containing this function
string file;
// Line number for start of function.
uint32 line;
// Beginning address for this function
uint64 lowpc;
// End address for this function.
uint64 highpc;
};
struct SourceFileInfo {
// Name of the source file name
string name;
// Low address of source file name
uint64 lowpc;
};
typedef map<uint64, FunctionInfo*> FunctionMap;
typedef map<uint64, pair<string, uint32> > LineMap;
// This class is a basic line info handler that fills in the dirs,
// file, and linemap passed into it with the data produced from the
// LineInfoHandler.
class CULineInfoHandler: public LineInfoHandler {
public:
//
CULineInfoHandler(vector<SourceFileInfo>* files,
vector<string>* dirs,
LineMap* linemap);
virtual ~CULineInfoHandler() { }
// Called when we define a directory. We just place NAME into dirs_
// at position DIR_NUM.
virtual void DefineDir(const string& name, uint32 dir_num);
// Called when we define a filename. We just place
// concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM.
virtual void DefineFile(const string& name, int32 file_num,
uint32 dir_num, uint64 mod_time, uint64 length);
// Called when the line info reader has a new line, address pair
// ready for us. ADDRESS is the address of the code, FILE_NUM is
// the file number containing the code, LINE_NUM is the line number
// in that file for the code, and COLUMN_NUM is the column number
// the code starts at, if we know it (0 otherwise).
virtual void AddLine(uint64 address, uint32 file_num, uint32 line_num,
uint32 column_num);
private:
LineMap* linemap_;
vector<SourceFileInfo>* files_;
vector<string>* dirs_;
};
class CUFunctionInfoHandler: public Dwarf2Handler {
public:
CUFunctionInfoHandler(vector<SourceFileInfo>* files,
vector<string>* dirs,
LineMap* linemap,
FunctionMap* offset_to_funcinfo,
FunctionMap* address_to_funcinfo,
CULineInfoHandler* linehandler,
const SectionMap& sections,
ByteReader* reader)
: files_(files), dirs_(dirs), linemap_(linemap),
offset_to_funcinfo_(offset_to_funcinfo),
address_to_funcinfo_(address_to_funcinfo),
linehandler_(linehandler), sections_(sections),
reader_(reader), current_function_info_(NULL) { }
virtual ~CUFunctionInfoHandler() { }
// Start to process a compilation unit at OFFSET from the beginning of the
// debug_info section. We want to see all compilation units, so we
// always return true.
virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
uint8 offset_size, uint64 cu_length,
uint8 dwarf_version);
// Start to process a DIE at OFFSET from the beginning of the
// debug_info section. We only care about function related DIE's.
virtual bool StartDIE(uint64 offset, enum DwarfTag tag,
const AttributeList& attrs);
// Called when we have an attribute with unsigned data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data);
// Called when we have an attribute with string data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
virtual void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data);
// Called when finished processing the DIE at OFFSET.
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
// before ends of the previous DIE, as we process children before
// ending the parent.
virtual void EndDIE(uint64 offset);
private:
vector<SourceFileInfo>* files_;
vector<string>* dirs_;
LineMap* linemap_;
FunctionMap* offset_to_funcinfo_;
FunctionMap* address_to_funcinfo_;
CULineInfoHandler* linehandler_;
const SectionMap& sections_;
ByteReader* reader_;
FunctionInfo* current_function_info_;
};
} // namespace dwarf2reader
#endif // COMMON_MAC_DWARF_FUNCTIONINFO_H__

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

@ -0,0 +1,61 @@
// Copyright 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.
#ifndef COMMON_MAC_DWARF_LINE_STATE_MACHINE_H__
#define COMMON_MAC_DWARF_LINE_STATE_MACHINE_H__
namespace dwarf2reader {
// This is the format of a DWARF2/3 line state machine that we process
// opcodes using. There is no need for anything outside the lineinfo
// processor to know how this works.
struct LineStateMachine {
void Reset(bool default_is_stmt) {
file_num = 1;
address = 0;
line_num = 1;
column_num = 0;
is_stmt = default_is_stmt;
basic_block = false;
end_sequence = false;
}
uint32 file_num;
uint64 address;
uint64 line_num;
uint32 column_num;
bool is_stmt; // stmt means statement.
bool basic_block;
bool end_sequence;
};
} // namespace dwarf2reader
#endif // COMMON_MAC_DWARF_LINE_STATE_MACHINE_H__

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

@ -0,0 +1,46 @@
// Copyright 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.
// This file contains some typedefs for basic types
#ifndef _COMMON_MAC_DWARF_TYPES_H__
#define _COMMON_MAC_DWARF_TYPES_H__
typedef signed char int8;
typedef short int16;
typedef int int32;
typedef long long int64;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
#endif // _COMMON_MAC_DWARF_TYPES_H__

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

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

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

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

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

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

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

0
toolkit/crashreporter/google-breakpad/src/config.h.in Executable file → Normal file
Просмотреть файл

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

@ -104,6 +104,11 @@ typedef struct {
#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. */
#pragma pack(push, 4)
typedef struct {
/* context_flags is not present in ppc_thread_state, but it aids
* identification of MDRawContextPPC among other raw context types,
@ -131,6 +136,8 @@ typedef struct {
MDVectorSaveAreaPPC vector_save;
} MDRawContextPPC; /* Based on ppc_thread_state */
#pragma pack(pop)
/* 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

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

@ -109,6 +109,8 @@ class MinidumpObject {
public:
virtual ~MinidumpObject() {}
bool valid() const { return valid_; }
protected:
explicit MinidumpObject(Minidump* minidump);

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

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

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

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

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

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

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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше