Refactor the Windows MinidumpGenerator interface to get rid of the overloads when generating dumps.
All required params are now passed to the constructor and the various options are set through new methods. BUG=N/A TEST=Existing minidump generation tests R=mark@chromium.org Review URL: https://breakpad.appspot.com/1074002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1274 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
d9f582edce
commit
8b65346242
@ -121,17 +121,13 @@ CrashGenerationServer::CrashGenerationServer(
|
|||||||
upload_request_callback_(upload_request_callback),
|
upload_request_callback_(upload_request_callback),
|
||||||
upload_context_(upload_context),
|
upload_context_(upload_context),
|
||||||
generate_dumps_(generate_dumps),
|
generate_dumps_(generate_dumps),
|
||||||
dump_generator_(NULL),
|
dump_path_(*dump_path),
|
||||||
server_state_(IPC_SERVER_STATE_UNINITIALIZED),
|
server_state_(IPC_SERVER_STATE_UNINITIALIZED),
|
||||||
shutting_down_(false),
|
shutting_down_(false),
|
||||||
overlapped_(),
|
overlapped_(),
|
||||||
client_info_(NULL),
|
client_info_(NULL),
|
||||||
pre_fetch_custom_info_(true) {
|
pre_fetch_custom_info_(true) {
|
||||||
InitializeCriticalSection(&sync_);
|
InitializeCriticalSection(&sync_);
|
||||||
|
|
||||||
if (dump_path) {
|
|
||||||
dump_generator_.reset(new MinidumpGenerator(*dump_path));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should never be called from the OnPipeConnected callback.
|
// This should never be called from the OnPipeConnected callback.
|
||||||
@ -917,15 +913,19 @@ bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dump_generator_->WriteMinidump(client.process_handle(),
|
MinidumpGenerator dump_generator(dump_path_,
|
||||||
client.pid(),
|
client.process_handle(),
|
||||||
client_thread_id,
|
client.pid(),
|
||||||
GetCurrentThreadId(),
|
client_thread_id,
|
||||||
client_ex_info,
|
GetCurrentThreadId(),
|
||||||
client.assert_info(),
|
client_ex_info,
|
||||||
client.dump_type(),
|
client.assert_info(),
|
||||||
true,
|
client.dump_type(),
|
||||||
dump_path);
|
true);
|
||||||
|
if (!dump_generator.GenerateDumpFile(dump_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return dump_generator.WriteMinidump();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
@ -268,8 +268,8 @@ class CrashGenerationServer {
|
|||||||
// Wether to populate custom information up-front.
|
// Wether to populate custom information up-front.
|
||||||
bool pre_fetch_custom_info_;
|
bool pre_fetch_custom_info_;
|
||||||
|
|
||||||
// Instance of a mini dump generator.
|
// The dump path for the server.
|
||||||
scoped_ptr<MinidumpGenerator> dump_generator_;
|
const std::wstring dump_path_;
|
||||||
|
|
||||||
// State of the server in performing the IPC with the client.
|
// State of the server in performing the IPC with the client.
|
||||||
// Note that since we restrict the pipe to one instance, we
|
// Note that since we restrict the pipe to one instance, we
|
||||||
|
@ -243,10 +243,33 @@ ULONG CALLBACK HandleTraceData::RecordHandleOperations(
|
|||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
|
MinidumpGenerator::MinidumpGenerator(
|
||||||
|
const std::wstring& dump_path,
|
||||||
|
const HANDLE process_handle,
|
||||||
|
const DWORD process_id,
|
||||||
|
const DWORD thread_id,
|
||||||
|
const DWORD requesting_thread_id,
|
||||||
|
EXCEPTION_POINTERS* exception_pointers,
|
||||||
|
MDRawAssertionInfo* assert_info,
|
||||||
|
const MINIDUMP_TYPE dump_type,
|
||||||
|
const bool is_client_pointers)
|
||||||
: dbghelp_module_(NULL),
|
: dbghelp_module_(NULL),
|
||||||
rpcrt4_module_(NULL),
|
rpcrt4_module_(NULL),
|
||||||
dump_path_(dump_path),
|
dump_path_(dump_path),
|
||||||
|
process_handle_(process_handle),
|
||||||
|
process_id_(process_id),
|
||||||
|
thread_id_(thread_id),
|
||||||
|
requesting_thread_id_(requesting_thread_id),
|
||||||
|
exception_pointers_(exception_pointers),
|
||||||
|
assert_info_(assert_info),
|
||||||
|
dump_type_(dump_type),
|
||||||
|
is_client_pointers_(is_client_pointers),
|
||||||
|
dump_file_(INVALID_HANDLE_VALUE),
|
||||||
|
full_dump_file_(INVALID_HANDLE_VALUE),
|
||||||
|
dump_file_is_internal_(false),
|
||||||
|
full_dump_file_is_internal_(false),
|
||||||
|
additional_streams_(NULL),
|
||||||
|
callback_info_(NULL),
|
||||||
write_dump_(NULL),
|
write_dump_(NULL),
|
||||||
create_uuid_(NULL) {
|
create_uuid_(NULL) {
|
||||||
InitializeCriticalSection(&module_load_sync_);
|
InitializeCriticalSection(&module_load_sync_);
|
||||||
@ -254,6 +277,14 @@ MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MinidumpGenerator::~MinidumpGenerator() {
|
MinidumpGenerator::~MinidumpGenerator() {
|
||||||
|
if (dump_file_is_internal_ && dump_file_ != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(dump_file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (full_dump_file_is_internal_ && full_dump_file_ != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(full_dump_file_);
|
||||||
|
}
|
||||||
|
|
||||||
if (dbghelp_module_) {
|
if (dbghelp_module_) {
|
||||||
FreeLibrary(dbghelp_module_);
|
FreeLibrary(dbghelp_module_);
|
||||||
}
|
}
|
||||||
@ -266,141 +297,10 @@ MinidumpGenerator::~MinidumpGenerator() {
|
|||||||
DeleteCriticalSection(&module_load_sync_);
|
DeleteCriticalSection(&module_load_sync_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
bool MinidumpGenerator::WriteMinidump() {
|
||||||
DWORD process_id,
|
bool full_memory_dump = (dump_type_ & MiniDumpWithFullMemory) != 0;
|
||||||
DWORD thread_id,
|
if (dump_file_ == INVALID_HANDLE_VALUE ||
|
||||||
DWORD requesting_thread_id,
|
(full_memory_dump && full_dump_file_ == INVALID_HANDLE_VALUE)) {
|
||||||
EXCEPTION_POINTERS* exception_pointers,
|
|
||||||
MDRawAssertionInfo* assert_info,
|
|
||||||
MINIDUMP_TYPE dump_type,
|
|
||||||
bool is_client_pointers,
|
|
||||||
wstring* dump_path) {
|
|
||||||
// Just call the full WriteMinidump with NULL as the full_dump_path.
|
|
||||||
return this->WriteMinidump(process_handle, process_id, thread_id,
|
|
||||||
requesting_thread_id, exception_pointers,
|
|
||||||
assert_info, dump_type, is_client_pointers,
|
|
||||||
dump_path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
wstring* full_dump_path) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = WriteMinidump(process_handle,
|
|
||||||
process_id,
|
|
||||||
thread_id,
|
|
||||||
requesting_thread_id,
|
|
||||||
exception_pointers,
|
|
||||||
assert_info,
|
|
||||||
dump_type,
|
|
||||||
is_client_pointers,
|
|
||||||
dump_file,
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (result && full_memory_dump && full_dump_path) {
|
|
||||||
*full_dump_path = full_dump_file_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(dump_file);
|
|
||||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
|
||||||
CloseHandle(full_dump_file);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
HANDLE dump_file,
|
|
||||||
HANDLE full_dump_file) {
|
|
||||||
return WriteMinidump(process_handle,
|
|
||||||
process_id,
|
|
||||||
thread_id,
|
|
||||||
requesting_thread_id,
|
|
||||||
exception_pointers,
|
|
||||||
assert_info,
|
|
||||||
dump_type,
|
|
||||||
is_client_pointers,
|
|
||||||
dump_file,
|
|
||||||
full_dump_file,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
HANDLE dump_file,
|
|
||||||
HANDLE full_dump_file,
|
|
||||||
MINIDUMP_USER_STREAM_INFORMATION* additional_streams) {
|
|
||||||
bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0;
|
|
||||||
if (dump_file == INVALID_HANDLE_VALUE ||
|
|
||||||
(full_memory_dump && full_dump_file == INVALID_HANDLE_VALUE)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,11 +314,11 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
|
|
||||||
// Setup the exception information object only if it's a dump
|
// Setup the exception information object only if it's a dump
|
||||||
// due to an exception.
|
// due to an exception.
|
||||||
if (exception_pointers) {
|
if (exception_pointers_) {
|
||||||
dump_exception_pointers = &dump_exception_info;
|
dump_exception_pointers = &dump_exception_info;
|
||||||
dump_exception_info.ThreadId = thread_id;
|
dump_exception_info.ThreadId = thread_id_;
|
||||||
dump_exception_info.ExceptionPointers = exception_pointers;
|
dump_exception_info.ExceptionPointers = exception_pointers_;
|
||||||
dump_exception_info.ClientPointers = is_client_pointers;
|
dump_exception_info.ClientPointers = is_client_pointers_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
|
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
|
||||||
@ -428,17 +328,17 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
// can function better with Breakpad-generated dumps when it is present.
|
// can function better with Breakpad-generated dumps when it is present.
|
||||||
// The native debugger is not harmed by the presence of this information.
|
// The native debugger is not harmed by the presence of this information.
|
||||||
MDRawBreakpadInfo breakpad_info = {0};
|
MDRawBreakpadInfo breakpad_info = {0};
|
||||||
if (!is_client_pointers) {
|
if (!is_client_pointers_) {
|
||||||
// Set the dump thread id and requesting thread id only in case of
|
// Set the dump thread id and requesting thread id only in case of
|
||||||
// in-process dump generation.
|
// in-process dump generation.
|
||||||
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
|
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
|
||||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
|
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
|
||||||
breakpad_info.dump_thread_id = thread_id;
|
breakpad_info.dump_thread_id = thread_id_;
|
||||||
breakpad_info.requesting_thread_id = requesting_thread_id;
|
breakpad_info.requesting_thread_id = requesting_thread_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int additional_streams_count = additional_streams ?
|
int additional_streams_count = additional_streams_ ?
|
||||||
additional_streams->UserStreamCount : 0;
|
additional_streams_->UserStreamCount : 0;
|
||||||
scoped_array<MINIDUMP_USER_STREAM> user_stream_array(
|
scoped_array<MINIDUMP_USER_STREAM> user_stream_array(
|
||||||
new MINIDUMP_USER_STREAM[3 + additional_streams_count]);
|
new MINIDUMP_USER_STREAM[3 + additional_streams_count]);
|
||||||
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
|
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
|
||||||
@ -449,29 +349,33 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
user_streams.UserStreamCount = 1;
|
user_streams.UserStreamCount = 1;
|
||||||
user_streams.UserStreamArray = user_stream_array.get();
|
user_streams.UserStreamArray = user_stream_array.get();
|
||||||
|
|
||||||
MDRawAssertionInfo* actual_assert_info = assert_info;
|
MDRawAssertionInfo* actual_assert_info = assert_info_;
|
||||||
MDRawAssertionInfo client_assert_info = {0};
|
MDRawAssertionInfo client_assert_info = {0};
|
||||||
|
|
||||||
if (assert_info) {
|
if (assert_info_) {
|
||||||
// If the assertion info object lives in the client process,
|
// If the assertion info object lives in the client process,
|
||||||
// read the memory of the client process.
|
// read the memory of the client process.
|
||||||
if (is_client_pointers) {
|
if (is_client_pointers_) {
|
||||||
SIZE_T bytes_read = 0;
|
SIZE_T bytes_read = 0;
|
||||||
if (!ReadProcessMemory(process_handle,
|
if (!ReadProcessMemory(process_handle_,
|
||||||
assert_info,
|
assert_info_,
|
||||||
&client_assert_info,
|
&client_assert_info,
|
||||||
sizeof(client_assert_info),
|
sizeof(client_assert_info),
|
||||||
&bytes_read)) {
|
&bytes_read)) {
|
||||||
CloseHandle(dump_file);
|
if (dump_file_is_internal_)
|
||||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
CloseHandle(dump_file_);
|
||||||
CloseHandle(full_dump_file);
|
if (full_dump_file_is_internal_ &&
|
||||||
|
full_dump_file_ != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(full_dump_file_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read != sizeof(client_assert_info)) {
|
if (bytes_read != sizeof(client_assert_info)) {
|
||||||
CloseHandle(dump_file);
|
if (dump_file_is_internal_)
|
||||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
CloseHandle(dump_file_);
|
||||||
CloseHandle(full_dump_file);
|
if (full_dump_file_is_internal_ &&
|
||||||
|
full_dump_file_ != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(full_dump_file_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,16 +388,16 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
++user_streams.UserStreamCount;
|
++user_streams.UserStreamCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (additional_streams) {
|
if (additional_streams_) {
|
||||||
for (size_t i = 0;
|
for (size_t i = 0;
|
||||||
i < additional_streams->UserStreamCount;
|
i < additional_streams_->UserStreamCount;
|
||||||
i++, user_streams.UserStreamCount++) {
|
i++, user_streams.UserStreamCount++) {
|
||||||
user_stream_array[user_streams.UserStreamCount].Type =
|
user_stream_array[user_streams.UserStreamCount].Type =
|
||||||
additional_streams->UserStreamArray[i].Type;
|
additional_streams_->UserStreamArray[i].Type;
|
||||||
user_stream_array[user_streams.UserStreamCount].BufferSize =
|
user_stream_array[user_streams.UserStreamCount].BufferSize =
|
||||||
additional_streams->UserStreamArray[i].BufferSize;
|
additional_streams_->UserStreamArray[i].BufferSize;
|
||||||
user_stream_array[user_streams.UserStreamCount].Buffer =
|
user_stream_array[user_streams.UserStreamCount].Buffer =
|
||||||
additional_streams->UserStreamArray[i].Buffer;
|
additional_streams_->UserStreamArray[i].Buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,12 +405,14 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
// the trace of operations for the offending handle value. Do nothing special
|
// the trace of operations for the offending handle value. Do nothing special
|
||||||
// if the client already requested the handle trace to be stored in the dump.
|
// if the client already requested the handle trace to be stored in the dump.
|
||||||
HandleTraceData handle_trace_data;
|
HandleTraceData handle_trace_data;
|
||||||
if (exception_pointers && (dump_type & MiniDumpWithHandleData) == 0) {
|
if (exception_pointers_ && (dump_type_ & MiniDumpWithHandleData) == 0) {
|
||||||
if (!handle_trace_data.CollectHandleData(process_handle,
|
if (!handle_trace_data.CollectHandleData(process_handle_,
|
||||||
exception_pointers)) {
|
exception_pointers_)) {
|
||||||
CloseHandle(dump_file);
|
if (dump_file_is_internal_)
|
||||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
CloseHandle(dump_file_);
|
||||||
CloseHandle(full_dump_file);
|
if (full_dump_file_is_internal_ &&
|
||||||
|
full_dump_file_ != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(full_dump_file_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,12 +420,12 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
bool result_full_memory = true;
|
bool result_full_memory = true;
|
||||||
if (full_memory_dump) {
|
if (full_memory_dump) {
|
||||||
result_full_memory = write_dump(
|
result_full_memory = write_dump(
|
||||||
process_handle,
|
process_handle_,
|
||||||
process_id,
|
process_id_,
|
||||||
full_dump_file,
|
full_dump_file_,
|
||||||
static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpNormal))
|
static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal))
|
||||||
| MiniDumpWithHandleData),
|
| MiniDumpWithHandleData),
|
||||||
exception_pointers ? &dump_exception_info : NULL,
|
exception_pointers_ ? &dump_exception_info : NULL,
|
||||||
&user_streams,
|
&user_streams,
|
||||||
NULL) != FALSE;
|
NULL) != FALSE;
|
||||||
}
|
}
|
||||||
@ -531,18 +437,81 @@ bool MinidumpGenerator::WriteMinidump(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool result_minidump = write_dump(
|
bool result_minidump = write_dump(
|
||||||
process_handle,
|
process_handle_,
|
||||||
process_id,
|
process_id_,
|
||||||
dump_file,
|
dump_file_,
|
||||||
static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory))
|
static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory))
|
||||||
| MiniDumpNormal),
|
| MiniDumpNormal),
|
||||||
exception_pointers ? &dump_exception_info : NULL,
|
exception_pointers_ ? &dump_exception_info : NULL,
|
||||||
&user_streams,
|
&user_streams,
|
||||||
NULL) != FALSE;
|
callback_info_) != FALSE;
|
||||||
|
|
||||||
return result_minidump && result_full_memory;
|
return result_minidump && result_full_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MinidumpGenerator::GenerateDumpFile(wstring* dump_path) {
|
||||||
|
// The dump file was already set by handle or this function was previously
|
||||||
|
// called.
|
||||||
|
if (dump_file_ != INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring dump_file_path;
|
||||||
|
if (!GenerateDumpFilePath(&dump_file_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_file_is_internal_ = true;
|
||||||
|
*dump_path = dump_file_path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MinidumpGenerator::GenerateFullDumpFile(wstring* full_dump_path) {
|
||||||
|
// A full minidump was not requested.
|
||||||
|
if ((dump_type_ & MiniDumpWithFullMemory) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The dump file was already set by handle or this function was previously
|
||||||
|
// called.
|
||||||
|
if (full_dump_file_ != INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring full_dump_file_path;
|
||||||
|
if (!GenerateDumpFilePath(&full_dump_file_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp
|
||||||
|
full_dump_file_path.append(TEXT("-full.dmp"));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_dump_file_is_internal_ = true;
|
||||||
|
*full_dump_path = full_dump_file_path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
HMODULE MinidumpGenerator::GetDbghelpModule() {
|
HMODULE MinidumpGenerator::GetDbghelpModule() {
|
||||||
AutoCriticalSection lock(&module_load_sync_);
|
AutoCriticalSection lock(&module_load_sync_);
|
||||||
if (!dbghelp_module_) {
|
if (!dbghelp_module_) {
|
||||||
|
@ -44,66 +44,55 @@ namespace google_breakpad {
|
|||||||
// the clients to generate minidumps.
|
// the clients to generate minidumps.
|
||||||
class MinidumpGenerator {
|
class MinidumpGenerator {
|
||||||
public:
|
public:
|
||||||
// Creates an instance with the given dump path.
|
// Creates an instance with the given parameters.
|
||||||
explicit MinidumpGenerator(const std::wstring& dump_path);
|
// is_client_pointers specifies whether the exception_pointers and
|
||||||
|
// assert_info point into the process that is being dumped.
|
||||||
|
// Before calling WriteMinidump on the returned instance a dump file muct be
|
||||||
|
// specified by a call to either SetDumpFile() or GenerateDumpFile().
|
||||||
|
// If a full dump file will be requested via a subsequent call to either
|
||||||
|
// SetFullDumpFile or GenerateFullDumpFile() dump_type must include
|
||||||
|
// MiniDumpWithFullMemory.
|
||||||
|
MinidumpGenerator(const std::wstring& dump_path,
|
||||||
|
const HANDLE process_handle,
|
||||||
|
const DWORD process_id,
|
||||||
|
const DWORD thread_id,
|
||||||
|
const DWORD requesting_thread_id,
|
||||||
|
EXCEPTION_POINTERS* exception_pointers,
|
||||||
|
MDRawAssertionInfo* assert_info,
|
||||||
|
const MINIDUMP_TYPE dump_type,
|
||||||
|
const bool is_client_pointers);
|
||||||
|
|
||||||
~MinidumpGenerator();
|
~MinidumpGenerator();
|
||||||
|
|
||||||
|
void SetDumpFile(const HANDLE dump_file) { dump_file_ = dump_file; }
|
||||||
|
void SetFullDumpFile(const HANDLE full_dump_file) {
|
||||||
|
full_dump_file_ = full_dump_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the name for the dump file that will be written to once
|
||||||
|
// WriteMinidump() is called. Can only be called once and cannot be called
|
||||||
|
// if the dump file is set via SetDumpFile().
|
||||||
|
bool GenerateDumpFile(std::wstring* dump_path);
|
||||||
|
|
||||||
|
// Generate the name for the full dump file that will be written to once
|
||||||
|
// WriteMinidump() is called. Cannot be called unless the minidump type
|
||||||
|
// includes MiniDumpWithFullMemory. Can only be called once and cannot be
|
||||||
|
// called if the dump file is set via SetFullDumpFile().
|
||||||
|
bool GenerateFullDumpFile(std::wstring* full_dump_path);
|
||||||
|
|
||||||
|
void SetAdditionalStreams(
|
||||||
|
MINIDUMP_USER_STREAM_INFORMATION* additional_streams) {
|
||||||
|
additional_streams_ = additional_streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCallback(MINIDUMP_CALLBACK_INFORMATION* callback_info) {
|
||||||
|
callback_info_ = callback_info;
|
||||||
|
}
|
||||||
|
|
||||||
// Writes the minidump with the given parameters. Stores the
|
// Writes the minidump with the given parameters. Stores the
|
||||||
// dump file path in the dump_path parameter if dump generation
|
// dump file path in the dump_path parameter if dump generation
|
||||||
// succeeds.
|
// succeeds.
|
||||||
bool WriteMinidump(HANDLE process_handle,
|
bool WriteMinidump();
|
||||||
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);
|
|
||||||
|
|
||||||
// Writes the minidump with the given parameters. Stores the dump file
|
|
||||||
// path in the dump_path (and full_dump_path) parameter if dump
|
|
||||||
// generation succeeds. full_dump_path and dump_path can be NULL.
|
|
||||||
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,
|
|
||||||
std::wstring* full_dump_path);
|
|
||||||
|
|
||||||
// Writes the minidump with the given parameters. Writes the minidump and
|
|
||||||
// full dump to the file handles supplied. This allows the caller to handle
|
|
||||||
// the creation of the files for the dump. The file handles are not closed
|
|
||||||
// by this function.
|
|
||||||
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,
|
|
||||||
HANDLE dump_file,
|
|
||||||
HANDLE full_dump_file);
|
|
||||||
|
|
||||||
// Writes the minidump with the given parameters. Allows the user to include
|
|
||||||
// additional streams in the dump that would not otherwise be included.
|
|
||||||
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,
|
|
||||||
HANDLE dump_file,
|
|
||||||
HANDLE full_dump_file,
|
|
||||||
MINIDUMP_USER_STREAM_INFORMATION* additional_streams);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||||
@ -149,9 +138,53 @@ class MinidumpGenerator {
|
|||||||
// Pointer to the UuidCreate function.
|
// Pointer to the UuidCreate function.
|
||||||
UuidCreateType create_uuid_;
|
UuidCreateType create_uuid_;
|
||||||
|
|
||||||
|
// Handle for the process to dump.
|
||||||
|
HANDLE process_handle_;
|
||||||
|
|
||||||
|
// Process ID for the process to dump.
|
||||||
|
DWORD process_id_;
|
||||||
|
|
||||||
|
// The crashing thread ID.
|
||||||
|
DWORD thread_id_;
|
||||||
|
|
||||||
|
// The thread ID which is requesting the dump.
|
||||||
|
DWORD requesting_thread_id_;
|
||||||
|
|
||||||
|
// Pointer to the exception information for the crash. This may point to an
|
||||||
|
// address in the crashing process so it should not be dereferenced.
|
||||||
|
EXCEPTION_POINTERS* exception_pointers_;
|
||||||
|
|
||||||
|
// Assertion info for the report.
|
||||||
|
MDRawAssertionInfo* assert_info_;
|
||||||
|
|
||||||
|
// Type of minidump to generate.
|
||||||
|
MINIDUMP_TYPE dump_type_;
|
||||||
|
|
||||||
|
// Specifies whether the exception_pointers_ reference memory in the crashing
|
||||||
|
// process.
|
||||||
|
bool is_client_pointers_;
|
||||||
|
|
||||||
// Folder path to store dump files.
|
// Folder path to store dump files.
|
||||||
std::wstring dump_path_;
|
std::wstring dump_path_;
|
||||||
|
|
||||||
|
// The file where the dump will be written.
|
||||||
|
HANDLE dump_file_;
|
||||||
|
|
||||||
|
// The file where the full dump will be written.
|
||||||
|
HANDLE full_dump_file_;
|
||||||
|
|
||||||
|
// Tracks whether the dump file handle is managed externally.
|
||||||
|
bool dump_file_is_internal_;
|
||||||
|
|
||||||
|
// Tracks whether the full dump file handle is managed externally.
|
||||||
|
bool full_dump_file_is_internal_;
|
||||||
|
|
||||||
|
// Additional streams to be written to the dump.
|
||||||
|
MINIDUMP_USER_STREAM_INFORMATION* additional_streams_;
|
||||||
|
|
||||||
|
// The user defined callback for the various stages of the dump process.
|
||||||
|
MINIDUMP_CALLBACK_INFORMATION* callback_info_;
|
||||||
|
|
||||||
// Critical section to sychronize action of loading modules dynamically.
|
// Critical section to sychronize action of loading modules dynamically.
|
||||||
CRITICAL_SECTION module_load_sync_;
|
CRITICAL_SECTION module_load_sync_;
|
||||||
|
|
||||||
|
@ -104,19 +104,19 @@ class MinidumpTest: public testing::Test {
|
|||||||
&ctx_record,
|
&ctx_record,
|
||||||
};
|
};
|
||||||
|
|
||||||
MinidumpGenerator generator(dump_path_);
|
MinidumpGenerator generator(dump_path_,
|
||||||
|
::GetCurrentProcess(),
|
||||||
|
::GetCurrentProcessId(),
|
||||||
|
::GetCurrentThreadId(),
|
||||||
|
::GetCurrentThreadId(),
|
||||||
|
&ex_ptrs,
|
||||||
|
NULL,
|
||||||
|
static_cast<MINIDUMP_TYPE>(flags),
|
||||||
|
TRUE);
|
||||||
|
generator.GenerateDumpFile(&dump_file_);
|
||||||
|
generator.GenerateFullDumpFile(&full_dump_file_);
|
||||||
// And write a dump
|
// And write a dump
|
||||||
bool result = generator.WriteMinidump(::GetCurrentProcess(),
|
bool result = generator.WriteMinidump();
|
||||||
::GetCurrentProcessId(),
|
|
||||||
::GetCurrentThreadId(),
|
|
||||||
::GetCurrentThreadId(),
|
|
||||||
&ex_ptrs,
|
|
||||||
NULL,
|
|
||||||
static_cast<MINIDUMP_TYPE>(flags),
|
|
||||||
TRUE,
|
|
||||||
&dump_file_,
|
|
||||||
&full_dump_file_);
|
|
||||||
return result == TRUE;
|
return result == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user