mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-01 00:04:16 +01:00
Make dump_syms output an INFO CODE_ID line that includes the code file and code identifier. (Currently disabled to give Breakpad users time to update their processor code.)
R=mark at http://breakpad.appspot.com/180001/show git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@710 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
d192a71e24
commit
d35f113d02
@ -28,8 +28,8 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <atlbase.h>
|
#include <atlbase.h>
|
||||||
#include <DbgHelp.h>
|
|
||||||
#include <dia2.h>
|
#include <dia2.h>
|
||||||
|
#include <ImageHlp.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "common/windows/string_utils-inl.h"
|
#include "common/windows/string_utils-inl.h"
|
||||||
@ -45,6 +45,24 @@
|
|||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
// A helper class to scope a PLOADED_IMAGE.
|
||||||
|
class AutoImage {
|
||||||
|
public:
|
||||||
|
explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
|
||||||
|
~AutoImage() {
|
||||||
|
if (img_)
|
||||||
|
ImageUnload(img_);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator PLOADED_IMAGE() { return img_; }
|
||||||
|
PLOADED_IMAGE operator->() { return img_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PLOADED_IMAGE img_;
|
||||||
|
};
|
||||||
|
|
||||||
PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
|
PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +96,7 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
|
|||||||
fprintf(stderr, "loadDataForExe failed\n");
|
fprintf(stderr, "loadDataForExe failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
code_file_ = file;
|
||||||
break;
|
break;
|
||||||
case ANY_FILE:
|
case ANY_FILE:
|
||||||
if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
|
if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
|
||||||
@ -85,6 +104,7 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
|
|||||||
fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n");
|
fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
code_file_ = file;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -498,6 +518,18 @@ bool PDBSourceLineWriter::PrintPDBInfo() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDBSourceLineWriter::PrintPEInfo() {
|
||||||
|
PEModuleInfo info;
|
||||||
|
if (!GetPEInfo(&info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(output_, "INFO CODE_ID %ws %ws\n",
|
||||||
|
info.code_identifier.c_str(),
|
||||||
|
info.code_file.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// wcstol_positive_strict is sort of like wcstol, but much stricter. string
|
// wcstol_positive_strict is sort of like wcstol, but much stricter. string
|
||||||
// should be a buffer pointing to a null-terminated string containing only
|
// should be a buffer pointing to a null-terminated string containing only
|
||||||
// decimal digits. If the entire string can be converted to an integer
|
// decimal digits. If the entire string can be converted to an integer
|
||||||
@ -535,6 +567,35 @@ static bool wcstol_positive_strict(wchar_t *string, int *result) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDBSourceLineWriter::FindPEFile() {
|
||||||
|
CComPtr<IDiaSymbol> global;
|
||||||
|
if (FAILED(session_->get_globalScope(&global))) {
|
||||||
|
fprintf(stderr, "get_globalScope failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CComBSTR symbols_file;
|
||||||
|
if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) {
|
||||||
|
wstring file(symbols_file);
|
||||||
|
|
||||||
|
// Look for an EXE or DLL file.
|
||||||
|
const wchar_t *extensions[] = { L"exe", L"dll" };
|
||||||
|
for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
|
||||||
|
size_t dot_pos = file.find_last_of(L".");
|
||||||
|
if (dot_pos != wstring::npos) {
|
||||||
|
file.replace(dot_pos + 1, wstring::npos, extensions[i]);
|
||||||
|
// Check if this file exists.
|
||||||
|
if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) {
|
||||||
|
code_file_ = file;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
|
bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
|
||||||
BSTR *name,
|
BSTR *name,
|
||||||
@ -737,7 +798,12 @@ next_child:
|
|||||||
bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
|
bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
|
||||||
output_ = map_file;
|
output_ = map_file;
|
||||||
|
|
||||||
bool ret = PrintPDBInfo() &&
|
bool ret = PrintPDBInfo();
|
||||||
|
// TODO(ted): This is currently disabled to allow Breakpad users to update
|
||||||
|
// processing infrastructure.
|
||||||
|
// This is not a critical piece of the symbol file.
|
||||||
|
// PrintPEInfo();
|
||||||
|
ret = ret &&
|
||||||
PrintSourceFiles() &&
|
PrintSourceFiles() &&
|
||||||
PrintFunctions() &&
|
PrintFunctions() &&
|
||||||
PrintFrameData();
|
PrintFrameData();
|
||||||
@ -846,6 +912,54 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
|
||||||
|
if (!info) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code_file_.empty() && !FindPEFile()) {
|
||||||
|
fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert wchar to native charset because ImageLoad only takes
|
||||||
|
// a PSTR as input.
|
||||||
|
string code_file;
|
||||||
|
if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
|
||||||
|
if (!img) {
|
||||||
|
fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->code_file = WindowsStringUtils::GetBaseName(code_file_);
|
||||||
|
|
||||||
|
// The date and time that the file was created by the linker.
|
||||||
|
DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
|
||||||
|
// The size of the file in bytes, including all headers.
|
||||||
|
DWORD SizeOfImage = 0;
|
||||||
|
PIMAGE_OPTIONAL_HEADER64 opt =
|
||||||
|
&((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
|
||||||
|
if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||||
|
// 64-bit PE file.
|
||||||
|
SizeOfImage = opt->SizeOfImage;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 32-bit PE file.
|
||||||
|
SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
|
||||||
|
}
|
||||||
|
wchar_t code_identifier[32];
|
||||||
|
swprintf(code_identifier,
|
||||||
|
sizeof(code_identifier) / sizeof(code_identifier[0]),
|
||||||
|
L"%08X%X", TimeDateStamp, SizeOfImage);
|
||||||
|
info->code_identifier = code_identifier;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
|
bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
|
||||||
if (!uses_guid)
|
if (!uses_guid)
|
||||||
return false;
|
return false;
|
||||||
|
@ -67,6 +67,21 @@ struct PDBModuleInfo {
|
|||||||
wstring cpu;
|
wstring cpu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A structure that carries information that identifies a PE file,
|
||||||
|
// either an EXE or a DLL.
|
||||||
|
struct PEModuleInfo {
|
||||||
|
// The basename of the PE file.
|
||||||
|
wstring code_file;
|
||||||
|
|
||||||
|
// The PE file's code identifier, which consists of its timestamp
|
||||||
|
// and file size concatenated together into a single hex string.
|
||||||
|
// (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and
|
||||||
|
// IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp
|
||||||
|
// documentation.) This is not well documented, if it's documented
|
||||||
|
// at all, but it's what symstore does and what DbgHelp supports.
|
||||||
|
wstring code_identifier;
|
||||||
|
};
|
||||||
|
|
||||||
class PDBSourceLineWriter {
|
class PDBSourceLineWriter {
|
||||||
public:
|
public:
|
||||||
enum FileFormat {
|
enum FileFormat {
|
||||||
@ -100,6 +115,10 @@ class PDBSourceLineWriter {
|
|||||||
// true on success and false on failure.
|
// true on success and false on failure.
|
||||||
bool GetModuleInfo(PDBModuleInfo *info);
|
bool GetModuleInfo(PDBModuleInfo *info);
|
||||||
|
|
||||||
|
// Retrieves information about the module's PE file. Returns
|
||||||
|
// true on success and false on failure.
|
||||||
|
bool GetPEInfo(PEModuleInfo *info);
|
||||||
|
|
||||||
// Sets uses_guid to true if the opened file uses a new-style CodeView
|
// 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
|
// 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
|
// CodeView record. When no GUID is available, a 32-bit signature should be
|
||||||
@ -139,6 +158,11 @@ class PDBSourceLineWriter {
|
|||||||
// its uuid and age.
|
// its uuid and age.
|
||||||
bool PrintPDBInfo();
|
bool PrintPDBInfo();
|
||||||
|
|
||||||
|
// Outputs a line identifying the PE file corresponding to the PDB
|
||||||
|
// file that is being dumped, along with its code identifier,
|
||||||
|
// which consists of its timestamp and file size.
|
||||||
|
bool PrintPEInfo();
|
||||||
|
|
||||||
// Returns true if this filename has already been seen,
|
// Returns true if this filename has already been seen,
|
||||||
// and an ID is stored for it, or false if it has not.
|
// and an ID is stored for it, or false if it has not.
|
||||||
bool FileIDIsCached(const wstring &file) {
|
bool FileIDIsCached(const wstring &file) {
|
||||||
@ -170,6 +194,10 @@ class PDBSourceLineWriter {
|
|||||||
return iter->second;
|
return iter->second;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Find the PE file corresponding to the loaded PDB file, and
|
||||||
|
// set the code_file_ member. Returns false on failure.
|
||||||
|
bool FindPEFile();
|
||||||
|
|
||||||
// Returns the function name for a symbol. If possible, the name is
|
// Returns the function name for a symbol. If possible, the name is
|
||||||
// undecorated. If the symbol's decorated form indicates the size of
|
// undecorated. If the symbol's decorated form indicates the size of
|
||||||
// parameters on the stack, this information is returned in stack_param_size.
|
// parameters on the stack, this information is returned in stack_param_size.
|
||||||
@ -183,6 +211,10 @@ class PDBSourceLineWriter {
|
|||||||
// a failure, returns 0, which is also a valid number of bytes.
|
// a failure, returns 0, which is also a valid number of bytes.
|
||||||
static int GetFunctionStackParamSize(IDiaSymbol *function);
|
static int GetFunctionStackParamSize(IDiaSymbol *function);
|
||||||
|
|
||||||
|
// The filename of the PE file corresponding to the currently-open
|
||||||
|
// pdb file.
|
||||||
|
wstring code_file_;
|
||||||
|
|
||||||
// The session for the currently-open pdb file.
|
// The session for the currently-open pdb file.
|
||||||
CComPtr<IDiaSession> session_;
|
CComPtr<IDiaSession> session_;
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@ class WindowsStringUtils {
|
|||||||
// without setting wcs.
|
// without setting wcs.
|
||||||
static bool safe_mbstowcs(const string &mbs, wstring *wcs);
|
static bool safe_mbstowcs(const string &mbs, wstring *wcs);
|
||||||
|
|
||||||
|
// The inverse of safe_mbstowcs.
|
||||||
|
static bool safe_wcstombs(const wstring &wcs, string *mbs);
|
||||||
|
|
||||||
// Returns the base name of a file, e.g. strips off the path.
|
// Returns the base name of a file, e.g. strips off the path.
|
||||||
static wstring GetBaseName(const wstring &filename);
|
static wstring GetBaseName(const wstring &filename);
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/windows/string_utils-inl.h"
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
|
|||||||
if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) {
|
if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
assert(wcs_length > 0);
|
||||||
#else // _MSC_VER >= 1400
|
#else // _MSC_VER >= 1400
|
||||||
if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) < 0) {
|
if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) < 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -64,28 +66,67 @@ bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
|
|||||||
++wcs_length;
|
++wcs_length;
|
||||||
#endif // _MSC_VER >= 1400
|
#endif // _MSC_VER >= 1400
|
||||||
|
|
||||||
// TODO(mmentovai): move scoped_ptr into common and use it for wcs_c.
|
std::vector<wchar_t> wcs_v(wcs_length);
|
||||||
wchar_t *wcs_c = new wchar_t[wcs_length];
|
|
||||||
|
|
||||||
// Now, convert.
|
// Now, convert.
|
||||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||||
if ((err = mbstowcs_s(NULL, wcs_c, wcs_length, mbs.c_str(),
|
if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(),
|
||||||
_TRUNCATE)) != 0) {
|
_TRUNCATE)) != 0) {
|
||||||
delete[] wcs_c;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else // _MSC_VER >= 1400
|
#else // _MSC_VER >= 1400
|
||||||
if (mbstowcs(wcs_c, mbs.c_str(), mbs.length()) < 0) {
|
if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) < 0) {
|
||||||
delete[] wcs_c;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure presence of 0-terminator.
|
// Ensure presence of 0-terminator.
|
||||||
wcs_c[wcs_length - 1] = '\0';
|
wcs_v[wcs_length - 1] = '\0';
|
||||||
#endif // _MSC_VER >= 1400
|
#endif // _MSC_VER >= 1400
|
||||||
|
|
||||||
*wcs = wcs_c;
|
*wcs = &wcs_v[0];
|
||||||
delete[] wcs_c;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) {
|
||||||
|
assert(mbs);
|
||||||
|
|
||||||
|
// First, determine the length of the destination buffer.
|
||||||
|
size_t mbs_length;
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||||
|
errno_t err;
|
||||||
|
if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assert(mbs_length > 0);
|
||||||
|
#else // _MSC_VER >= 1400
|
||||||
|
if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave space for the 0-terminator.
|
||||||
|
++mbs_length;
|
||||||
|
#endif // _MSC_VER >= 1400
|
||||||
|
|
||||||
|
std::vector<char> mbs_v(mbs_length);
|
||||||
|
|
||||||
|
// Now, convert.
|
||||||
|
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||||
|
if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(),
|
||||||
|
_TRUNCATE)) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else // _MSC_VER >= 1400
|
||||||
|
if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure presence of 0-terminator.
|
||||||
|
mbs_v[mbs_length - 1] = '\0';
|
||||||
|
#endif // _MSC_VER >= 1400
|
||||||
|
|
||||||
|
*mbs = &mbs_v[0];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,6 +394,10 @@ bool BasicSourceLineResolver::Module::LoadMapFromBuffer(
|
|||||||
// be accessed by a SymbolSupplier.
|
// be accessed by a SymbolSupplier.
|
||||||
//
|
//
|
||||||
// MODULE <guid> <age> <filename>
|
// MODULE <guid> <age> <filename>
|
||||||
|
} else if (strncmp(buffer, "INFO ", 5) == 0) {
|
||||||
|
// Ignore these as well, they're similarly just for housekeeping.
|
||||||
|
//
|
||||||
|
// INFO CODE_ID <code id> <filename>
|
||||||
} else {
|
} else {
|
||||||
if (!cur_func.get()) {
|
if (!cur_func.get()) {
|
||||||
BPLOG(ERROR) << "Found source line data without a function at " <<
|
BPLOG(ERROR) << "Found source line data without a function at " <<
|
||||||
|
1
src/processor/testdata/module1.out
vendored
1
src/processor/testdata/module1.out
vendored
@ -1,4 +1,5 @@
|
|||||||
MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
MODULE windows x86 111111111111111111111111111111111 module1.pdb
|
||||||
|
INFO CODE_ID FFFFFFFF module1.exe
|
||||||
FILE 1 file1_1.cc
|
FILE 1 file1_1.cc
|
||||||
FILE 2 file1_2.cc
|
FILE 2 file1_2.cc
|
||||||
FILE 3 file1_3.cc
|
FILE 3 file1_3.cc
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalDependencies=""$(VSInstallDir)\DIA SDK\lib\diaguids.lib""
|
AdditionalDependencies=""$(VSInstallDir)\DIA SDK\lib\diaguids.lib" imagehlp.lib"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
SubSystem="1"
|
SubSystem="1"
|
||||||
@ -133,7 +133,7 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalDependencies=""$(VSInstallDir)\DIA SDK\lib\diaguids.lib""
|
AdditionalDependencies=""$(VSInstallDir)\DIA SDK\lib\diaguids.lib" imagehlp.lib"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
SubSystem="1"
|
SubSystem="1"
|
||||||
|
Loading…
Reference in New Issue
Block a user