Support GUID-less PDBs (#77). r=bryner
- Handle MDCVInfoPDB20-based PDBs by outputting a signature instead of a guid in the MODULE line. - Identify the OS and CPU in the MODULE line. - Suppress multiple subsequent identical STACK WIN lines. http://groups.google.com/group/airbag-dev/browse_thread/thread/0f54e2c33ed5d82d git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@70 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
042ca733d3
commit
4365e2fe41
@ -287,6 +287,11 @@ bool PDBSourceLineWriter::PrintFrameData() {
|
||||
if (!frame_data_enum)
|
||||
return false;
|
||||
|
||||
DWORD last_type = -1;
|
||||
DWORD last_rva = -1;
|
||||
DWORD last_code_size = 0;
|
||||
DWORD last_prolog_size = -1;
|
||||
|
||||
CComPtr<IDiaFrameData> frame_data;
|
||||
while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) &&
|
||||
count == 1) {
|
||||
@ -348,14 +353,27 @@ bool PDBSourceLineWriter::PrintFrameData() {
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ",
|
||||
type, rva, code_size, prolog_size, epilog_size,
|
||||
parameter_size, saved_register_size, local_size, max_stack_size,
|
||||
program_string_result == S_OK);
|
||||
if (program_string_result == S_OK) {
|
||||
fprintf(output_, "%ws\n", program_string);
|
||||
} else {
|
||||
fprintf(output_, "%d\n", allocates_base_pointer);
|
||||
// Only print out a line if type, rva, code_size, or prolog_size have
|
||||
// changed from the last line. It is surprisingly common (especially in
|
||||
// system library PDBs) for DIA to return a series of identical
|
||||
// IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86,
|
||||
// this check reduces the size of the dumped symbol file by a third.
|
||||
if (type != last_type || rva != last_rva || code_size != last_code_size ||
|
||||
prolog_size != last_prolog_size) {
|
||||
fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ",
|
||||
type, rva, code_size, prolog_size, epilog_size,
|
||||
parameter_size, saved_register_size, local_size, max_stack_size,
|
||||
program_string_result == S_OK);
|
||||
if (program_string_result == S_OK) {
|
||||
fprintf(output_, "%ws\n", program_string);
|
||||
} else {
|
||||
fprintf(output_, "%d\n", allocates_base_pointer);
|
||||
}
|
||||
|
||||
last_type = type;
|
||||
last_rva = rva;
|
||||
last_code_size = code_size;
|
||||
last_prolog_size = prolog_size;
|
||||
}
|
||||
|
||||
frame_data.Release();
|
||||
@ -390,13 +408,17 @@ bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
|
||||
}
|
||||
|
||||
bool PDBSourceLineWriter::PrintPDBInfo() {
|
||||
wstring guid, filename;
|
||||
wstring guid, filename, cpu;
|
||||
int age;
|
||||
if (!GetModuleInfo(&guid, &age, &filename)) {
|
||||
if (!GetModuleInfo(&guid, &age, &filename, &cpu)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(output_, "MODULE %ws %x %ws\n", guid.c_str(), age, filename.c_str());
|
||||
// Hard-code "windows" for the OS because that's the only thing that makes
|
||||
// sense for PDB files. (This might not be strictly correct for Windows CE
|
||||
// support, but we don't care about that at the moment.)
|
||||
fprintf(output_, "MODULE windows %ws %ws %x %ws\n",
|
||||
cpu.c_str(), guid.c_str(), age, filename.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -663,7 +685,7 @@ wstring PDBSourceLineWriter::GetBaseName(const wstring &filename) {
|
||||
}
|
||||
|
||||
bool PDBSourceLineWriter::GetModuleInfo(wstring *guid, int *age,
|
||||
wstring *filename) {
|
||||
wstring *filename, wstring *cpu) {
|
||||
guid->clear();
|
||||
*age = 0;
|
||||
filename->clear();
|
||||
@ -673,11 +695,44 @@ bool PDBSourceLineWriter::GetModuleInfo(wstring *guid, int *age,
|
||||
return false;
|
||||
}
|
||||
|
||||
GUID guid_number;
|
||||
if (FAILED(global->get_guid(&guid_number))) {
|
||||
// cpu is permitted to be NULL.
|
||||
if (cpu) {
|
||||
// All CPUs in CV_CPU_TYPE_e (cvconst.h) below 0x10 are x86. There's no
|
||||
// single specific constant to use.
|
||||
DWORD platform;
|
||||
if (SUCCEEDED(global->get_platform(&platform)) && platform < 0x10) {
|
||||
*cpu = L"x86";
|
||||
} else {
|
||||
// Unexpected, but handle gracefully.
|
||||
*cpu = L"unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool uses_guid;
|
||||
if (!UsesGUID(&uses_guid)) {
|
||||
return false;
|
||||
}
|
||||
*guid = GUIDString::GUIDToWString(&guid_number);
|
||||
|
||||
if (uses_guid) {
|
||||
GUID guid_number;
|
||||
if (FAILED(global->get_guid(&guid_number))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*guid = GUIDString::GUIDToWString(&guid_number);
|
||||
} else {
|
||||
DWORD signature;
|
||||
if (FAILED(global->get_signature(&signature))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t signature_string[9];
|
||||
WindowsStringUtils::safe_swprintf(
|
||||
signature_string,
|
||||
sizeof(signature_string) / sizeof(signature_string[0]),
|
||||
L"%08x", signature);
|
||||
*guid = signature_string;
|
||||
}
|
||||
|
||||
// DWORD* and int* are not compatible. This is clean and avoids a cast.
|
||||
DWORD age_dword;
|
||||
@ -695,4 +750,39 @@ bool PDBSourceLineWriter::GetModuleInfo(wstring *guid, int *age,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
|
||||
if (!uses_guid)
|
||||
return false;
|
||||
|
||||
CComPtr<IDiaSymbol> global;
|
||||
if (FAILED(session_->get_globalScope(&global)))
|
||||
return false;
|
||||
|
||||
GUID guid;
|
||||
if (FAILED(global->get_guid(&guid)))
|
||||
return false;
|
||||
|
||||
DWORD signature;
|
||||
if (FAILED(global->get_signature(&signature)))
|
||||
return false;
|
||||
|
||||
// There are two possibilities for guid: either it's a real 128-bit GUID
|
||||
// as identified in a code module by a new-style CodeView record, or it's
|
||||
// a 32-bit signature (timestamp) as identified by an old-style record.
|
||||
// See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h.
|
||||
//
|
||||
// Because DIA doesn't provide a way to directly determine whether a module
|
||||
// uses a GUID or a 32-bit signature, this code checks whether the first 32
|
||||
// bits of guid are the same as the signature, and if the rest of guid is
|
||||
// zero. If so, then with a pretty high degree of certainty, there's an
|
||||
// old-style CodeView record in use. This method will only falsely find an
|
||||
// an old-style CodeView record if a real 128-bit GUID has its first 32
|
||||
// bits set the same as the module's signature (timestamp) and the rest of
|
||||
// the GUID is set to 0. This is highly unlikely.
|
||||
|
||||
GUID signature_guid = {signature}; // 0-initializes other members
|
||||
*uses_guid = !IsEqualGUID(guid, signature_guid);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_airbag
|
||||
|
@ -75,10 +75,21 @@ class PDBSourceLineWriter {
|
||||
void Close();
|
||||
|
||||
// Sets guid to the GUID for the module, as a string,
|
||||
// e.g. "11111111-2222-3333-4444-555555555555". age will be set to the
|
||||
// age of the pdb file, and filename will be set to the basename of the
|
||||
// PDB's file name. Returns true on success and false on failure.
|
||||
bool GetModuleInfo(wstring *guid, int *age, wstring *filename);
|
||||
// e.g. "11111111-2222-3333-4444-555555555555". If the module has no guid,
|
||||
// guid will instead be set to the module's 32-bit signature value, in
|
||||
// zero-padded hexadecimal form, such as "0004beef". age will be set to the
|
||||
// age of the pdb file, filename will be set to the basename of the pdb's
|
||||
// file name, and cpu will be set to a string identifying the associated CPU
|
||||
// architecture. cpu is permitted to be NULL, in which case CPU information
|
||||
// will not be returned. Returns true on success and false on failure.
|
||||
bool GetModuleInfo(wstring *guid, int *age, wstring *filename, wstring *cpu);
|
||||
|
||||
// Sets uses_guid to true if the opened file uses a new-style CodeView
|
||||
// record with a 128-bit GUID, or false if the opened file uses an old-style
|
||||
// CodeView record. When no GUID is available, a 32-bit signature should be
|
||||
// used to identify the module instead. If the information cannot be
|
||||
// determined, this method returns false.
|
||||
bool UsesGUID(bool *uses_guid);
|
||||
|
||||
private:
|
||||
// Outputs the line/address pairs for each line in the enumerator.
|
||||
|
2
src/processor/testdata/module1.out
vendored
2
src/processor/testdata/module1.out
vendored
@ -1,4 +1,4 @@
|
||||
MODULE 11111111-1111-1111-1111-111111111111 1 module1.pdb
|
||||
MODULE windows x86 11111111-1111-1111-1111-111111111111 1 module1.pdb
|
||||
FILE 1 file1_1.cc
|
||||
FILE 2 file1_2.cc
|
||||
FILE 3 file1_3.cc
|
||||
|
2
src/processor/testdata/module2.out
vendored
2
src/processor/testdata/module2.out
vendored
@ -1,4 +1,4 @@
|
||||
MODULE 22222222-2222-2222-2222-222222222222 2 module2.pdb
|
||||
MODULE windows x86 22222222 2 module2.pdb
|
||||
FILE 1 file2_1.cc
|
||||
FILE 2 file2_2.cc
|
||||
FILE 3 file2_3.cc
|
||||
|
2
src/processor/testdata/module3_bad.out
vendored
2
src/processor/testdata/module3_bad.out
vendored
@ -1,3 +1,3 @@
|
||||
MODULE 33333333-3333-3333-3333-333333333333 3 module3.pdb
|
||||
MODULE windows x86 33333333-3333-3333-3333-333333333333 3 module3.pdb
|
||||
FILE 1 file1.cc
|
||||
FUNC 1000
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
MODULE 8ddb7e9a-3657-4893-8d6e-b08b1dca31aa 1 test_app.pdb
|
||||
MODULE windows x86 8ddb7e9a-3657-4893-8d6e-b08b1dca31aa 1 test_app.pdb
|
||||
FILE 1 c:\program files\microsoft visual studio 8\vc\platformsdk\include\pshpack2.h
|
||||
FILE 2 c:\program files\microsoft visual studio 8\vc\platformsdk\include\winuser.h
|
||||
FILE 3 c:\program files\microsoft visual studio 8\vc\include\wtime.inl
|
||||
|
@ -41,7 +41,7 @@ using google_airbag::PDBSourceLineWriter;
|
||||
|
||||
int wmain(int argc, wchar_t **argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %ws <pdb file>\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %ws <file.[pdb|exe|dll]>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
MODULE 21b67c7e-eef6-4504-b05a-a650d11afce4 2 dump_syms_regtest.pdb
|
||||
MODULE windows x86 21b67c7e-eef6-4504-b05a-a650d11afce4 2 dump_syms_regtest.pdb
|
||||
FILE 1 c:\airbag\tools\windows\dump_syms\Release\dump_syms.exe.embed.manifest.res
|
||||
FILE 2 c:\program files\microsoft visual studio 8\vc\platformsdk\include\propidl.h
|
||||
FILE 3 c:\program files\microsoft visual studio 8\vc\include\xlocinfo
|
||||
@ -1535,14 +1535,6 @@ STACK WIN 4 1000 187 39 0 8 8 23c 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0
|
||||
STACK WIN 4 1023 164 16 0 8 c 23c 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 576 - ^ =
|
||||
STACK WIN 4 1190 a 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11a0 f 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11b0 15 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11d0 10 2 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 11e0 163 24 0 4 8 10 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
@ -1586,7 +1578,6 @@ STACK WIN 4 2215 23 0 0 10 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .ra
|
||||
STACK WIN 4 2238 29 1 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 2239 27 0 0 0 4 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 2261 3 0 0 0 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 2261 3 0 0 4 0 0 0 1 $T2 $esp .cbLocals + .cbSavedRegs + = $T0 .raSearchStart = $eip $T0 ^ = $esp $T0 4 + =
|
||||
STACK WIN 4 2264 94 15 0 0 0 10 0 1 $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =
|
||||
STACK WIN 4 2278 7e 1 0 0 4 10 0 1 $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 20 - ^ =
|
||||
STACK WIN 4 2279 7c 0 0 0 8 10 0 1 $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 20 - ^ =
|
||||
|
@ -139,7 +139,7 @@ static bool DumpSymbolsToTempFile(const wchar_t *file,
|
||||
|
||||
*temp_file_path = temp_filename;
|
||||
|
||||
return writer.GetModuleInfo(module_guid, module_age, module_filename);
|
||||
return writer.GetModuleInfo(module_guid, module_age, module_filename, NULL);
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t *argv[]) {
|
||||
|
Loading…
Reference in New Issue
Block a user