aboutsummaryrefslogtreecommitdiff
path: root/src/common/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/windows')
-rw-r--r--src/common/windows/pdb_source_line_writer.cc124
-rw-r--r--src/common/windows/pdb_source_line_writer.h32
-rw-r--r--src/common/windows/string_utils-inl.h3
-rw-r--r--src/common/windows/string_utils.cc59
4 files changed, 204 insertions, 14 deletions
diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc
index 48a35bed..9969530b 100644
--- a/src/common/windows/pdb_source_line_writer.cc
+++ b/src/common/windows/pdb_source_line_writer.cc
@@ -28,8 +28,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <atlbase.h>
-#include <DbgHelp.h>
#include <dia2.h>
+#include <ImageHlp.h>
#include <stdio.h>
#include "common/windows/string_utils-inl.h"
@@ -45,6 +45,24 @@
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) {
}
@@ -78,6 +96,7 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
fprintf(stderr, "loadDataForExe failed\n");
return false;
}
+ code_file_ = file;
break;
case ANY_FILE:
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");
return false;
}
+ code_file_ = file;
}
break;
default:
@@ -498,6 +518,18 @@ bool PDBSourceLineWriter::PrintPDBInfo() {
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
// should be a buffer pointing to a null-terminated string containing only
// 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;
}
+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
bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
BSTR *name,
@@ -737,10 +798,15 @@ next_child:
bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
output_ = map_file;
- bool ret = PrintPDBInfo() &&
- PrintSourceFiles() &&
- PrintFunctions() &&
- PrintFrameData();
+ 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() &&
+ PrintFunctions() &&
+ PrintFrameData();
output_ = NULL;
return ret;
@@ -846,6 +912,54 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
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) {
if (!uses_guid)
return false;
diff --git a/src/common/windows/pdb_source_line_writer.h b/src/common/windows/pdb_source_line_writer.h
index 8524d8b0..ef2a27db 100644
--- a/src/common/windows/pdb_source_line_writer.h
+++ b/src/common/windows/pdb_source_line_writer.h
@@ -67,6 +67,21 @@ struct PDBModuleInfo {
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 {
public:
enum FileFormat {
@@ -100,6 +115,10 @@ class PDBSourceLineWriter {
// true on success and false on failure.
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
// 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
@@ -139,6 +158,11 @@ class PDBSourceLineWriter {
// its uuid and age.
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,
// and an ID is stored for it, or false if it has not.
bool FileIDIsCached(const wstring &file) {
@@ -170,6 +194,10 @@ class PDBSourceLineWriter {
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
// undecorated. If the symbol's decorated form indicates the size of
// 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.
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.
CComPtr<IDiaSession> session_;
diff --git a/src/common/windows/string_utils-inl.h b/src/common/windows/string_utils-inl.h
index 6f650812..d281aaa1 100644
--- a/src/common/windows/string_utils-inl.h
+++ b/src/common/windows/string_utils-inl.h
@@ -87,6 +87,9 @@ class WindowsStringUtils {
// without setting 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.
static wstring GetBaseName(const wstring &filename);
diff --git a/src/common/windows/string_utils.cc b/src/common/windows/string_utils.cc
index 5d464802..e6ffa082 100644
--- a/src/common/windows/string_utils.cc
+++ b/src/common/windows/string_utils.cc
@@ -28,6 +28,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cassert>
+#include <vector>
#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) {
return false;
}
+ assert(wcs_length > 0);
#else // _MSC_VER >= 1400
if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) < 0) {
return false;
@@ -64,28 +66,67 @@ bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
++wcs_length;
#endif // _MSC_VER >= 1400
- // TODO(mmentovai): move scoped_ptr into common and use it for wcs_c.
- wchar_t *wcs_c = new wchar_t[wcs_length];
+ std::vector<wchar_t> wcs_v(wcs_length);
// Now, convert.
#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) {
- delete[] wcs_c;
return false;
}
#else // _MSC_VER >= 1400
- if (mbstowcs(wcs_c, mbs.c_str(), mbs.length()) < 0) {
- delete[] wcs_c;
+ if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) < 0) {
return false;
}
// Ensure presence of 0-terminator.
- wcs_c[wcs_length - 1] = '\0';
+ wcs_v[wcs_length - 1] = '\0';
#endif // _MSC_VER >= 1400
- *wcs = wcs_c;
- delete[] wcs_c;
+ *wcs = &wcs_v[0];
+ 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;
}