aboutsummaryrefslogtreecommitdiff
path: root/src/common/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/windows')
-rw-r--r--src/common/windows/common_windows.gyp112
-rw-r--r--src/common/windows/dia_util.cc182
-rw-r--r--src/common/windows/dia_util.h4
-rw-r--r--src/common/windows/guid_string.cc5
-rw-r--r--src/common/windows/guid_string.h5
-rw-r--r--src/common/windows/http_upload.cc62
-rw-r--r--src/common/windows/http_upload.h9
-rw-r--r--src/common/windows/module_info.h149
-rw-r--r--src/common/windows/omap.cc12
-rw-r--r--src/common/windows/omap.h4
-rw-r--r--src/common/windows/omap_internal.h4
-rw-r--r--src/common/windows/omap_unittest.cc658
-rw-r--r--src/common/windows/pdb_source_line_writer.cc528
-rw-r--r--src/common/windows/pdb_source_line_writer.h156
-rw-r--r--src/common/windows/pe_source_line_writer.cc153
-rw-r--r--src/common/windows/pe_source_line_writer.h135
-rw-r--r--src/common/windows/pe_util.cc818
-rw-r--r--src/common/windows/pe_util.h155
-rw-r--r--src/common/windows/string_utils-inl.h27
-rw-r--r--src/common/windows/string_utils.cc11
-rw-r--r--src/common/windows/sym_upload_v2_protocol.cc118
-rw-r--r--src/common/windows/sym_upload_v2_protocol.h66
-rw-r--r--src/common/windows/symbol_collector_client.cc34
-rw-r--r--src/common/windows/symbol_collector_client.h21
24 files changed, 2005 insertions, 1423 deletions
diff --git a/src/common/windows/common_windows.gyp b/src/common/windows/common_windows.gyp
deleted file mode 100644
index 5f7594b1..00000000
--- a/src/common/windows/common_windows.gyp
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright 2013 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.
-
-{
- 'includes': [
- '../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'dia_sdk',
- 'type': 'none',
- 'all_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)',
- '$(VSInstallDir)/DIA SDK/include',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'diaguids.lib',
- 'imagehlp.lib',
- ],
- },
- },
- 'configurations': {
- 'x86_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalLibraryDirectories':
- ['$(VSInstallDir)/DIA SDK/lib'],
- },
- },
- },
- 'x64_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalLibraryDirectories':
- ['$(VSInstallDir)/DIA SDK/lib/amd64'],
- },
- },
- },
- },
- },
- },
- {
- 'target_name': 'common_windows_lib',
- 'type': 'static_library',
- 'sources': [
- 'dia_util.cc',
- 'dia_util.h',
- 'guid_string.cc',
- 'guid_string.h',
- 'http_upload.cc',
- 'http_upload.h',
- 'module_info.h',
- 'omap.cc',
- 'omap.h',
- 'omap_internal.h',
- 'pdb_source_line_writer.cc',
- 'pdb_source_line_writer.h',
- 'pe_source_line_writer.cc',
- 'pe_source_line_writer.h',
- 'pe_util.h',
- 'pe_util.cc',
- 'string_utils.cc',
- 'string_utils-inl.h',
- 'symbol_collector_client.cc',
- 'symbol_collector_client.h',
- ],
- 'dependencies': [
- 'dia_sdk',
- ],
- },
- {
- 'target_name': 'common_windows_unittests',
- 'type': 'executable',
- 'sources': [
- 'omap_unittest.cc',
- ],
- 'dependencies': [
- '<(DEPTH)/client/windows/unittests/testing.gyp:gmock',
- '<(DEPTH)/client/windows/unittests/testing.gyp:gtest',
- 'common_windows_lib',
- ],
- },
- ],
-}
diff --git a/src/common/windows/dia_util.cc b/src/common/windows/dia_util.cc
index ed8cb5b6..dcfe0ef9 100644
--- a/src/common/windows/dia_util.cc
+++ b/src/common/windows/dia_util.cc
@@ -1,92 +1,92 @@
-// Copyright 2013 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/windows/dia_util.h"
-
-#include <atlbase.h>
-
-namespace google_breakpad {
-
-bool FindDebugStream(const wchar_t* name,
- IDiaSession* session,
- IDiaEnumDebugStreamData** debug_stream) {
- CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
- if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
- fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
- return false;
- }
-
- CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
- fetched == 1) {
- CComBSTR stream_name;
- if (FAILED(temp_debug_stream->get_name(&stream_name))) {
- fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
- return false;
- }
-
- // Found the stream?
- if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
- *debug_stream = temp_debug_stream.Detach();
- return true;
- }
-
- temp_debug_stream.Release();
- }
-
- // No table was found.
- return false;
-}
-
-bool FindTable(REFIID iid, IDiaSession* session, void** table) {
- // Get the table enumerator.
- CComPtr<IDiaEnumTables> enum_tables;
- if (FAILED(session->getEnumTables(&enum_tables))) {
- fprintf(stderr, "IDiaSession::getEnumTables failed\n");
- return false;
- }
-
- // Iterate through the tables.
- CComPtr<IDiaTable> temp_table;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
- fetched == 1) {
- void* temp = NULL;
- if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
- *table = temp;
- return true;
- }
- temp_table.Release();
- }
-
- // The table was not found.
- return false;
-}
-
+// Copyright 2013 Google LLC
+//
+// 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 LLC 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/windows/dia_util.h"
+
+#include <atlbase.h>
+
+namespace google_breakpad {
+
+bool FindDebugStream(const wchar_t* name,
+ IDiaSession* session,
+ IDiaEnumDebugStreamData** debug_stream) {
+ CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
+ if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
+ fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
+ fetched == 1) {
+ CComBSTR stream_name;
+ if (FAILED(temp_debug_stream->get_name(&stream_name))) {
+ fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
+ return false;
+ }
+
+ // Found the stream?
+ if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
+ *debug_stream = temp_debug_stream.Detach();
+ return true;
+ }
+
+ temp_debug_stream.Release();
+ }
+
+ // No table was found.
+ return false;
+}
+
+bool FindTable(REFIID iid, IDiaSession* session, void** table) {
+ // Get the table enumerator.
+ CComPtr<IDiaEnumTables> enum_tables;
+ if (FAILED(session->getEnumTables(&enum_tables))) {
+ fprintf(stderr, "IDiaSession::getEnumTables failed\n");
+ return false;
+ }
+
+ // Iterate through the tables.
+ CComPtr<IDiaTable> temp_table;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
+ fetched == 1) {
+ void* temp = NULL;
+ if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
+ *table = temp;
+ return true;
+ }
+ temp_table.Release();
+ }
+
+ // The table was not found.
+ return false;
+}
+
} // namespace google_breakpad \ No newline at end of file
diff --git a/src/common/windows/dia_util.h b/src/common/windows/dia_util.h
index b9e0df2d..16ed8380 100644
--- a/src/common/windows/dia_util.h
+++ b/src/common/windows/dia_util.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/guid_string.cc b/src/common/windows/guid_string.cc
index b7f877e6..be9eb8a3 100644
--- a/src/common/windows/guid_string.cc
+++ b/src/common/windows/guid_string.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/guid_string.h b/src/common/windows/guid_string.h
index 48a5c1d3..ee3d1006 100644
--- a/src/common/windows/guid_string.h
+++ b/src/common/windows/guid_string.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/http_upload.cc b/src/common/windows/http_upload.cc
index b0cc9078..088a5e54 100644
--- a/src/common/windows/http_upload.cc
+++ b/src/common/windows/http_upload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,7 +64,7 @@ namespace {
HINTERNET handle_;
};
- wstring UTF8ToWide(const string &utf8) {
+ wstring UTF8ToWide(const string& utf8) {
if (utf8.length() == 0) {
return wstring();
}
@@ -85,7 +84,7 @@ namespace {
return result;
}
- string WideToMBCP(const wstring &wide, unsigned int cp) {
+ string WideToMBCP(const wstring& wide, unsigned int cp) {
if (wide.length() == 0) {
return string();
}
@@ -107,7 +106,7 @@ namespace {
return result;
}
- bool GetFileContents(const wstring &filename, vector<char> *contents) {
+ bool GetFileContents(const wstring& filename, vector<char>* contents) {
bool rv = false;
// The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
// wchar_t* filename, so use _wfopen directly in that case. For VC8 and
@@ -141,10 +140,10 @@ namespace {
return rv;
}
- bool CheckParameters(const map<wstring, wstring> &parameters) {
+ bool CheckParameters(const map<wstring, wstring>& parameters) {
for (map<wstring, wstring>::const_iterator pos = parameters.begin();
pos != parameters.end(); ++pos) {
- const wstring &str = pos->first;
+ const wstring& str = pos->first;
if (str.size() == 0) {
return false; // disallow empty parameter names
}
@@ -159,7 +158,7 @@ namespace {
}
// Converts a UTF16 string to UTF8.
- string WideToUTF8(const wstring &wide) {
+ string WideToUTF8(const wstring& wide) {
return WideToMBCP(wide, CP_UTF8);
}
@@ -262,7 +261,7 @@ namespace {
NULL, // password
INTERNET_SERVICE_HTTP,
0, // flags
- NULL)); // context
+ 0)); // context
if (!connection.get()) {
return false;
}
@@ -276,7 +275,7 @@ namespace {
NULL, // referer
NULL, // agent type
http_open_flags,
- NULL)); // context
+ 0)); // context
if (!request.get()) {
return false;
}
@@ -305,7 +304,7 @@ namespace {
}
if (!HttpSendRequest(request.get(), NULL, 0,
- const_cast<char *>(request_body.data()),
+ const_cast<char*>(request_body.data()),
static_cast<DWORD>(request_body.size()))) {
return false;
}
@@ -351,16 +350,16 @@ namespace {
return wstring(temp);
}
- wstring GenerateMultipartPostRequestHeader(const wstring &boundary) {
+ wstring GenerateMultipartPostRequestHeader(const wstring& boundary) {
wstring header = L"Content-Type: multipart/form-data; boundary=";
header += boundary;
return header;
}
- bool AppendFileToRequestBody(
- const wstring& file_part_name,
- const wstring& filename,
- string* request_body) {
+ bool AppendFileToRequestBody(const wstring& file_part_name,
+ const wstring& filename,
+ string* request_body,
+ bool set_content_type = true) {
string file_part_name_utf8 = WideToUTF8(file_part_name);
if (file_part_name_utf8.empty()) {
return false;
@@ -371,11 +370,17 @@ namespace {
return false;
}
- request_body->append("Content-Disposition: form-data; "
- "name=\"" + file_part_name_utf8 + "\"; "
- "filename=\"" + filename_utf8 + "\"\r\n");
- request_body->append("Content-Type: application/octet-stream\r\n");
- request_body->append("\r\n");
+ if (set_content_type) {
+ request_body->append(
+ "Content-Disposition: form-data; "
+ "name=\"" +
+ file_part_name_utf8 +
+ "\"; "
+ "filename=\"" +
+ filename_utf8 + "\"\r\n");
+ request_body->append("Content-Type: application/octet-stream\r\n");
+ request_body->append("\r\n");
+ }
vector<char> contents;
if (!GetFileContents(filename, &contents)) {
@@ -385,14 +390,13 @@ namespace {
if (!contents.empty()) {
request_body->append(&(contents[0]), contents.size());
}
- request_body->append("\r\n");
return true;
}
- bool GenerateRequestBody(const map<wstring, wstring> &parameters,
- const map<wstring, wstring> &files,
- const wstring &boundary,
+ bool GenerateRequestBody(const map<wstring, wstring>& parameters,
+ const map<wstring, wstring>& files,
+ const wstring& boundary,
string *request_body) {
string boundary_str = WideToUTF8(boundary);
if (boundary_str.empty()) {
@@ -432,7 +436,11 @@ namespace google_breakpad {
wstring* response_body,
int* response_code) {
string request_body;
- if (!AppendFileToRequestBody(L"symbol_file", path, &request_body)) {
+ // Turn off content-type in the body. If content-type is set then binary
+ // files uploaded to GCS end up with the it prepended to the file
+ // contents.
+ if (!AppendFileToRequestBody(L"symbol_file", path, &request_body,
+ /*set_content_type=*/false)) {
return false;
}
diff --git a/src/common/windows/http_upload.h b/src/common/windows/http_upload.h
index 57e526e3..e117840e 100644
--- a/src/common/windows/http_upload.h
+++ b/src/common/windows/http_upload.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -114,8 +113,8 @@ class HTTPUpload {
// No instances of this class should be created.
// Disallow all constructors, destructors, and operator=.
HTTPUpload();
- explicit HTTPUpload(const HTTPUpload &);
- void operator=(const HTTPUpload &);
+ explicit HTTPUpload(const HTTPUpload&);
+ void operator=(const HTTPUpload&);
~HTTPUpload();
};
diff --git a/src/common/windows/module_info.h b/src/common/windows/module_info.h
index 3dccc808..ade32c11 100644
--- a/src/common/windows/module_info.h
+++ b/src/common/windows/module_info.h
@@ -1,75 +1,74 @@
-// Copyright (c) 2019, 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_WINDOWS_MODULE_INFO_H_
-#define COMMON_WINDOWS_MODULE_INFO_H_
-
-#include <string>
-
-namespace google_breakpad {
-
-using std::wstring;
-// A structure that carries information that identifies a module.
-struct PDBModuleInfo {
-public:
- // The basename of the pe/pdb file from which information was loaded.
- wstring debug_file;
-
- // The module's identifier. For recent pe/pdb files, the identifier consists
- // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes
- // or separators, followed immediately by the pe/pdb's age, also in
- // uppercase hexadecimal form. For older pe/pdb files which have no guid,
- // the identifier is the pe/pdb's 32-bit signature value, in zero-padded
- // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase
- // hexadecimal form.
- wstring debug_identifier;
-
- // A string identifying the cpu that the pe/pdb is associated with.
- // Currently, this may be "x86" or "unknown".
- 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;
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_MODULE_INFO_H_
+// Copyright 2019 Google LLC
+//
+// 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 LLC 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_WINDOWS_MODULE_INFO_H_
+#define COMMON_WINDOWS_MODULE_INFO_H_
+
+#include <string>
+
+namespace google_breakpad {
+
+using std::wstring;
+// A structure that carries information that identifies a module.
+struct PDBModuleInfo {
+public:
+ // The basename of the pe/pdb file from which information was loaded.
+ wstring debug_file;
+
+ // The module's identifier. For recent pe/pdb files, the identifier consists
+ // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes
+ // or separators, followed immediately by the pe/pdb's age, also in
+ // uppercase hexadecimal form. For older pe/pdb files which have no guid,
+ // the identifier is the pe/pdb's 32-bit signature value, in zero-padded
+ // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase
+ // hexadecimal form.
+ wstring debug_identifier;
+
+ // A string identifying the cpu that the pe/pdb is associated with.
+ // Currently, this may be "x86" or "unknown".
+ 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;
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_MODULE_INFO_H_
diff --git a/src/common/windows/omap.cc b/src/common/windows/omap.cc
index ba3ce86b..ad916997 100644
--- a/src/common/windows/omap.cc
+++ b/src/common/windows/omap.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -449,11 +449,11 @@ void BuildEndpointIndexMap(ImageMap* image_map) {
}
}
-void BuildSubsequentRVAMap(const OmapData &omap_data,
- std::map<DWORD, DWORD> *subsequent) {
+void BuildSubsequentRVAMap(const OmapData& omap_data,
+ std::map<DWORD, DWORD>* subsequent) {
assert(subsequent->empty());
- const OmapFromTable &orig2tran =
- reinterpret_cast<const OmapFromTable &>(omap_data.omap_from);
+ const OmapFromTable& orig2tran =
+ reinterpret_cast<const OmapFromTable&>(omap_data.omap_from);
if (orig2tran.empty())
return;
diff --git a/src/common/windows/omap.h b/src/common/windows/omap.h
index bc293afb..51601fa9 100644
--- a/src/common/windows/omap.h
+++ b/src/common/windows/omap.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/omap_internal.h b/src/common/windows/omap_internal.h
index 2a4713d9..cd20d9fb 100644
--- a/src/common/windows/omap_internal.h
+++ b/src/common/windows/omap_internal.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/omap_unittest.cc b/src/common/windows/omap_unittest.cc
index 7fe66bd4..841e5391 100644
--- a/src/common/windows/omap_unittest.cc
+++ b/src/common/windows/omap_unittest.cc
@@ -1,329 +1,329 @@
-// Copyright 2013 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.
-
-// Unittests for OMAP related functions.
-
-#include "common/windows/omap.h"
-
-#include "breakpad_googletest_includes.h"
-
-namespace google_breakpad {
-
-// Equality operators for ContainerEq. These must be outside of the anonymous
-// namespace in order for them to be found.
-bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
- return mr1.rva_original == mr2.rva_original &&
- mr1.rva_transformed == mr2.rva_transformed &&
- mr1.length == mr2.length &&
- mr1.injected == mr2.injected &&
- mr1.removed == mr2.removed;
-}
-bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
- return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
-}
-
-// Pretty printers for more meaningful error messages. Also need to be outside
-// the anonymous namespace.
-std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
- os << "MappedRange(rva_original=" << mr.rva_original
- << ", rva_transformed=" << mr.rva_transformed
- << ", length=" << mr.length
- << ", injected=" << mr.injected
- << ", removed=" << mr.removed << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
- os << "EndpointIndex(endpoint=" << ei.endpoint
- << ", index=" << ei.index << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
- os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
- return os;
-}
-
-namespace {
-
-OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
- OMAP o = { rva, rvaTo };
- return o;
-}
-
-MappedRange CreateMappedRange(DWORD rva_original,
- DWORD rva_transformed,
- DWORD length,
- DWORD injected,
- DWORD removed) {
- MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
- return mr;
-}
-
-EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
- EndpointIndex ei = { endpoint, index };
- return ei;
-}
-
-// (C is removed)
-// Original : A B C D E F G H
-// Transformed: A B D F E * H1 G1 G2 H2
-// (* is injected, G is copied, H is split)
-// A is implied.
-
-// Layout of the original image.
-const AddressRange B(100, 15);
-const AddressRange C(B.end(), 10);
-const AddressRange D(C.end(), 25);
-const AddressRange E(D.end(), 10);
-const AddressRange F(E.end(), 40);
-const AddressRange G(F.end(), 3);
-const AddressRange H(G.end(), 7);
-
-// Layout of the transformed image.
-const AddressRange Bt(100, 15);
-const AddressRange Dt(Bt.end(), 20); // D is shortened.
-const AddressRange Ft(Dt.end(), F.length);
-const AddressRange Et(Ft.end(), E.length);
-const AddressRange injected(Et.end(), 5);
-const AddressRange H1t(injected.end(), 4); // H is split.
-const AddressRange G1t(H1t.end(), G.length); // G is copied.
-const AddressRange G2t(G1t.end(), G.length); // G is copied.
-const AddressRange H2t(G2t.end(), 3); // H is split.
-
-class BuildImageMapTest : public testing::Test {
- public:
- static const DWORD kInvalidAddress = 0xFFFFFFFF;
-
- void InitOmapData() {
- omap_data.length_original = H.end();
-
- // Build the OMAPTO vector (from transformed to original).
- omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
- omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
- omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
- omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
- omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
- omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
- omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
- omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
-
- // Build the OMAPFROM vector (from original to transformed).
- omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
- omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
- omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
- omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
- omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
- omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
- }
-
- OmapData omap_data;
-};
-
-} // namespace
-
-TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
- ASSERT_EQ(0u, omap_data.omap_from.size());
- ASSERT_EQ(0u, omap_data.omap_to.size());
- ASSERT_EQ(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_EQ(0u, image_map.mapping.size());
- EXPECT_EQ(0u, image_map.endpoint_index_map.size());
-}
-
-TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
- InitOmapData();
- ASSERT_LE(0u, omap_data.omap_from.size());
- ASSERT_LE(0u, omap_data.omap_to.size());
- ASSERT_LE(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_LE(9u, image_map.mapping.size());
- EXPECT_LE(9u, image_map.endpoint_index_map.size());
-
- Mapping mapping;
- mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
- // C is removed, and it originally comes immediately after B.
- mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
- // D is shortened by a length of 5.
- mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
- // The injected content comes immediately after E in the transformed image.
- mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
- 0));
- mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
- // G is copied so creates two entries.
- mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
- mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
- // H is split, so create two entries.
- mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
- mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
- 0, 0));
- EXPECT_THAT(mapping,
- testing::ContainerEq(image_map.mapping));
-
- EndpointIndexMap endpoint_index_map;
- endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
- endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
- endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
- endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
- endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
- // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
- endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
- // H is split so we expect 2 endpoints to show up attributed to it.
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
- endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
- EXPECT_THAT(endpoint_index_map,
- testing::ContainerEq(image_map.endpoint_index_map));
-}
-
-namespace {
-
-class MapAddressRangeTest : public BuildImageMapTest {
- public:
- typedef BuildImageMapTest Super;
- virtual void SetUp() {
- Super::SetUp();
- InitOmapData();
- BuildImageMap(omap_data, &image_map);
- }
-
- ImageMap image_map;
-
- private:
- using BuildImageMapTest::InitOmapData;
- using BuildImageMapTest::omap_data;
-};
-
-} // namespace
-
-TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
- ImageMap im;
- AddressRangeVector mapped_ranges;
- AddressRange ar(0, 1024);
- MapAddressRange(im, ar, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_EQ(ar, mapped_ranges[0]);
-}
-
-TEST_F(MapAddressRangeTest, MapOutOfImage) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapIdentity) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, B, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
-}
-
-TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
- AddressRangeVector mapped_ranges;
-
- AddressRange DEF(D.rva, F.end() - D.rva);
- MapAddressRange(image_map, DEF, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptySingle) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptyCopied) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
- AddressRange(G2t.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, G, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(
- AddressRange(G1t.rva, G2t.end() - G1t.rva)));
-}
-
-TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, H, &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
-}
-
-TEST_F(MapAddressRangeTest, MapInjected) {
- AddressRangeVector mapped_ranges;
-
- AddressRange EFGH(E.rva, H.end() - E.rva);
- MapAddressRange(image_map, EFGH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, C, &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedPartly) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, D, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
-}
-
-TEST_F(MapAddressRangeTest, MapFull) {
- AddressRangeVector mapped_ranges;
-
- AddressRange AH(0, H.end());
- MapAddressRange(image_map, AH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange AHt(0, H2t.end());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
-}
-
-} // namespace google_breakpad
+// Copyright 2013 Google LLC
+//
+// 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 LLC 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.
+
+// Unittests for OMAP related functions.
+
+#include "common/windows/omap.h"
+
+#include "breakpad_googletest_includes.h"
+
+namespace google_breakpad {
+
+// Equality operators for ContainerEq. These must be outside of the anonymous
+// namespace in order for them to be found.
+bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
+ return mr1.rva_original == mr2.rva_original &&
+ mr1.rva_transformed == mr2.rva_transformed &&
+ mr1.length == mr2.length &&
+ mr1.injected == mr2.injected &&
+ mr1.removed == mr2.removed;
+}
+bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
+ return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
+}
+
+// Pretty printers for more meaningful error messages. Also need to be outside
+// the anonymous namespace.
+std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
+ os << "MappedRange(rva_original=" << mr.rva_original
+ << ", rva_transformed=" << mr.rva_transformed
+ << ", length=" << mr.length
+ << ", injected=" << mr.injected
+ << ", removed=" << mr.removed << ")";
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
+ os << "EndpointIndex(endpoint=" << ei.endpoint
+ << ", index=" << ei.index << ")";
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
+ os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
+ return os;
+}
+
+namespace {
+
+OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
+ OMAP o = { rva, rvaTo };
+ return o;
+}
+
+MappedRange CreateMappedRange(DWORD rva_original,
+ DWORD rva_transformed,
+ DWORD length,
+ DWORD injected,
+ DWORD removed) {
+ MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
+ return mr;
+}
+
+EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
+ EndpointIndex ei = { endpoint, index };
+ return ei;
+}
+
+// (C is removed)
+// Original : A B C D E F G H
+// Transformed: A B D F E * H1 G1 G2 H2
+// (* is injected, G is copied, H is split)
+// A is implied.
+
+// Layout of the original image.
+const AddressRange B(100, 15);
+const AddressRange C(B.end(), 10);
+const AddressRange D(C.end(), 25);
+const AddressRange E(D.end(), 10);
+const AddressRange F(E.end(), 40);
+const AddressRange G(F.end(), 3);
+const AddressRange H(G.end(), 7);
+
+// Layout of the transformed image.
+const AddressRange Bt(100, 15);
+const AddressRange Dt(Bt.end(), 20); // D is shortened.
+const AddressRange Ft(Dt.end(), F.length);
+const AddressRange Et(Ft.end(), E.length);
+const AddressRange injected(Et.end(), 5);
+const AddressRange H1t(injected.end(), 4); // H is split.
+const AddressRange G1t(H1t.end(), G.length); // G is copied.
+const AddressRange G2t(G1t.end(), G.length); // G is copied.
+const AddressRange H2t(G2t.end(), 3); // H is split.
+
+class BuildImageMapTest : public testing::Test {
+ public:
+ static const DWORD kInvalidAddress = 0xFFFFFFFF;
+
+ void InitOmapData() {
+ omap_data.length_original = H.end();
+
+ // Build the OMAPTO vector (from transformed to original).
+ omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
+ omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
+ omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
+ omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
+ omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
+ omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
+ omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
+ omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
+ omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
+ omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
+
+ // Build the OMAPFROM vector (from original to transformed).
+ omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
+ omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
+ omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
+ omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
+ omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
+ omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
+ }
+
+ OmapData omap_data;
+};
+
+} // namespace
+
+TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
+ ASSERT_EQ(0u, omap_data.omap_from.size());
+ ASSERT_EQ(0u, omap_data.omap_to.size());
+ ASSERT_EQ(0u, omap_data.length_original);
+
+ ImageMap image_map;
+ BuildImageMap(omap_data, &image_map);
+ EXPECT_EQ(0u, image_map.mapping.size());
+ EXPECT_EQ(0u, image_map.endpoint_index_map.size());
+}
+
+TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
+ InitOmapData();
+ ASSERT_LE(0u, omap_data.omap_from.size());
+ ASSERT_LE(0u, omap_data.omap_to.size());
+ ASSERT_LE(0u, omap_data.length_original);
+
+ ImageMap image_map;
+ BuildImageMap(omap_data, &image_map);
+ EXPECT_LE(9u, image_map.mapping.size());
+ EXPECT_LE(9u, image_map.endpoint_index_map.size());
+
+ Mapping mapping;
+ mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
+ // C is removed, and it originally comes immediately after B.
+ mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
+ // D is shortened by a length of 5.
+ mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
+ // The injected content comes immediately after E in the transformed image.
+ mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
+ 0));
+ mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
+ // G is copied so creates two entries.
+ mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
+ mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
+ // H is split, so create two entries.
+ mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
+ mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
+ 0, 0));
+ EXPECT_THAT(mapping,
+ testing::ContainerEq(image_map.mapping));
+
+ EndpointIndexMap endpoint_index_map;
+ endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
+ endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
+ endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
+ endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
+ endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
+ // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
+ endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
+ // H is split so we expect 2 endpoints to show up attributed to it.
+ endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
+ endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
+ endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
+ EXPECT_THAT(endpoint_index_map,
+ testing::ContainerEq(image_map.endpoint_index_map));
+}
+
+namespace {
+
+class MapAddressRangeTest : public BuildImageMapTest {
+ public:
+ typedef BuildImageMapTest Super;
+ virtual void SetUp() {
+ Super::SetUp();
+ InitOmapData();
+ BuildImageMap(omap_data, &image_map);
+ }
+
+ ImageMap image_map;
+
+ private:
+ using BuildImageMapTest::InitOmapData;
+ using BuildImageMapTest::omap_data;
+};
+
+} // namespace
+
+TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
+ ImageMap im;
+ AddressRangeVector mapped_ranges;
+ AddressRange ar(0, 1024);
+ MapAddressRange(im, ar, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_EQ(ar, mapped_ranges[0]);
+}
+
+TEST_F(MapAddressRangeTest, MapOutOfImage) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
+ EXPECT_EQ(0u, mapped_ranges.size());
+}
+
+TEST_F(MapAddressRangeTest, MapIdentity) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, B, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
+}
+
+TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange DEF(D.rva, F.end() - D.rva);
+ MapAddressRange(image_map, DEF, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
+}
+
+TEST_F(MapAddressRangeTest, MapEmptySingle) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
+}
+
+TEST_F(MapAddressRangeTest, MapEmptyCopied) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
+ EXPECT_EQ(2u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
+ AddressRange(G2t.rva, 0)));
+}
+
+TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, G, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(
+ AddressRange(G1t.rva, G2t.end() - G1t.rva)));
+}
+
+TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, H, &mapped_ranges);
+ EXPECT_EQ(2u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
+}
+
+TEST_F(MapAddressRangeTest, MapInjected) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange EFGH(E.rva, H.end() - E.rva);
+ MapAddressRange(image_map, EFGH, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
+}
+
+TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, C, &mapped_ranges);
+ EXPECT_EQ(0u, mapped_ranges.size());
+}
+
+TEST_F(MapAddressRangeTest, MapRemovedPartly) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, D, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
+}
+
+TEST_F(MapAddressRangeTest, MapFull) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange AH(0, H.end());
+ MapAddressRange(image_map, AH, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange AHt(0, H2t.end());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc
index 4030a2e9..800c316f 100644
--- a/src/common/windows/pdb_source_line_writer.cc
+++ b/src/common/windows/pdb_source_line_writer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,6 +39,7 @@
#include <algorithm>
#include <limits>
#include <map>
+#include <memory>
#include <set>
#include <utility>
@@ -58,6 +58,8 @@ namespace google_breakpad {
namespace {
+using std::set;
+using std::unique_ptr;
using std::vector;
// The symbol (among possibly many) selected to represent an rva.
@@ -120,7 +122,7 @@ bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) {
return a_section == b_section && a_offset == b_offset;
}
-bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
+bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource>& data_source) {
if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) {
return true;
}
@@ -134,7 +136,7 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
// We can try loading the DLL corresponding to the #included DIA SDK, but
// the DIA headers don't provide a version. Lets try to figure out which DIA
// version we're compiling against by comparing CLSIDs.
- const wchar_t *msdia_dll = nullptr;
+ const wchar_t* msdia_dll = nullptr;
if (CLSID_DiaSource == _uuidof(DiaSource100)) {
msdia_dll = L"msdia100.dll";
} else if (CLSID_DiaSource == _uuidof(DiaSource110)) {
@@ -147,23 +149,261 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
if (msdia_dll &&
SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
- reinterpret_cast<void **>(&data_source)))) {
+ reinterpret_cast<void**>(&data_source)))) {
return true;
}
return false;
}
+const DWORD kUndecorateOptions = UNDNAME_NO_MS_KEYWORDS |
+ UNDNAME_NO_FUNCTION_RETURNS |
+ UNDNAME_NO_ALLOCATION_MODEL |
+ UNDNAME_NO_ALLOCATION_LANGUAGE |
+ UNDNAME_NO_THISTYPE |
+ UNDNAME_NO_ACCESS_SPECIFIERS |
+ UNDNAME_NO_THROW_SIGNATURES |
+ UNDNAME_NO_MEMBER_TYPE |
+ UNDNAME_NO_RETURN_UDT_MODEL |
+ UNDNAME_NO_ECSU;
+
+#define arraysize(f) (sizeof(f) / sizeof(*f))
+
+void StripLlvmSuffixAndUndecorate(BSTR* name) {
+ // LLVM sometimes puts a suffix on symbols to give them a globally unique
+ // name. The suffix is either some string preceded by a period (like in the
+ // Itanium ABI; also on Windows this is safe since periods are otherwise
+ // never part of mangled names), or a dollar sign followed by a 32-char hex
+ // string (this should go away in future LLVM versions). Strip such suffixes
+ // and try demangling again.
+ //
+ //
+ // Example symbol names with such suffixes:
+ //
+ // ?foo@@YAXXZ$5520c83448162c04f2b239db4b5a2c61
+ // ?foo@@YAXXZ.llvm.13040715209719948753
+
+ if (**name != L'?')
+ return; // The name is already demangled.
+
+ for (size_t i = 0, len = wcslen(*name); i < len; i++) {
+ wchar_t c = (*name)[i];
+
+ if (c == L'.' || (c == L'$' && len - i == 32 + 1)) {
+ (*name)[i] = L'\0';
+ wchar_t undecorated[1024];
+ DWORD res = UnDecorateSymbolNameW(*name, undecorated,
+ arraysize(undecorated),
+ kUndecorateOptions);
+ if (res == 0 || undecorated[0] == L'?') {
+ // Demangling failed; restore the symbol name and return.
+ (*name)[i] = c;
+ return;
+ }
+
+ SysFreeString(*name);
+ *name = SysAllocString(undecorated);
+ return;
+ }
+ }
+}
+
+// Prints the error message related to the error code as seen in
+// Microsoft's MSVS documentation for loadDataFromPdb and loadDataForExe.
+void PrintOpenError(HRESULT hr, const char* fn_name, const wchar_t* file) {
+ switch (hr) {
+ case E_PDB_NOT_FOUND:
+ fprintf(stderr, "%s: Failed to open %ws, or the file has an "
+ "invalid format.\n", fn_name, file);
+ break;
+ case E_PDB_FORMAT:
+ fprintf(stderr, "%s: Attempted to access %ws with an obsolete "
+ "format.\n", fn_name, file);
+ break;
+ case E_PDB_INVALID_SIG:
+ fprintf(stderr, "%s: Signature does not match for %ws.\n", fn_name,
+ file);
+ break;
+ case E_PDB_INVALID_AGE:
+ fprintf(stderr, "%s: Age does not match for %ws.\n", fn_name, file);
+ break;
+ case E_INVALIDARG:
+ fprintf(stderr, "%s: Invalid parameter for %ws.\n", fn_name, file);
+ break;
+ case E_UNEXPECTED:
+ fprintf(stderr, "%s: Data source has already been prepared for %ws.\n",
+ fn_name, file);
+ break;
+ default:
+ fprintf(stderr, "%s: Unexpected error 0x%lx, file: %ws.\n",
+ fn_name, hr, file);
+ break;
+ }
+}
+
} // namespace
-PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
+PDBSourceLineWriter::Inline::Inline(int inline_nest_level)
+ : inline_nest_level_(inline_nest_level) {}
+
+void PDBSourceLineWriter::Inline::SetOriginId(int origin_id) {
+ origin_id_ = origin_id;
+}
+
+void PDBSourceLineWriter::Inline::ExtendRanges(const Line& line) {
+ if (ranges_.empty()) {
+ ranges_[line.rva] = line.length;
+ return;
+ }
+ auto iter = ranges_.lower_bound(line.rva);
+ // There is no overlap if this function is called with inlinee lines from
+ // the same callsite.
+ if (iter == ranges_.begin()) {
+ return;
+ }
+ if (line.rva + line.length == iter->first) {
+ // If they are connected, merge their ranges into one.
+ DWORD length = line.length + iter->second;
+ ranges_.erase(iter);
+ ranges_[line.rva] = length;
+ } else {
+ --iter;
+ if (iter->first + iter->second == line.rva) {
+ ranges_[iter->first] = iter->second + line.length;
+ } else {
+ ranges_[line.rva] = line.length;
+ }
+ }
+}
+
+void PDBSourceLineWriter::Inline::SetCallSiteLine(DWORD call_site_line) {
+ call_site_line_ = call_site_line;
}
+void PDBSourceLineWriter::Inline::SetCallSiteFileId(DWORD call_site_file_id) {
+ call_site_file_id_ = call_site_file_id;
+}
+
+void PDBSourceLineWriter::Inline::SetChildInlines(
+ vector<unique_ptr<Inline>> child_inlines) {
+ child_inlines_ = std::move(child_inlines);
+}
+
+void PDBSourceLineWriter::Inline::Print(FILE* output) const {
+ // Ignore INLINE record that doesn't have any range.
+ if (ranges_.empty())
+ return;
+ fprintf(output, "INLINE %d %lu %lu %d", inline_nest_level_, call_site_line_,
+ call_site_file_id_, origin_id_);
+ for (const auto& r : ranges_) {
+ fprintf(output, " %lx %lx", r.first, r.second);
+ }
+ fprintf(output, "\n");
+ for (const unique_ptr<Inline>& in : child_inlines_) {
+ in->Print(output);
+ }
+}
+
+const PDBSourceLineWriter::Line* PDBSourceLineWriter::Lines::GetLine(
+ DWORD rva) const {
+ auto iter = line_map_.find(rva);
+ if (iter == line_map_.end()) {
+ // If not found exact rva, check if it's within any range.
+ iter = line_map_.lower_bound(rva);
+ if (iter == line_map_.begin())
+ return nullptr;
+ --iter;
+ auto l = iter->second;
+ // This happens when there is no top level lines cover this rva (e.g. empty
+ // lines found for the function). Then we don't know the call site line
+ // number for this inlined function.
+ if (rva >= l.rva + l.length)
+ return nullptr;
+ }
+ return &iter->second;
+}
+
+DWORD PDBSourceLineWriter::Lines::GetLineNum(DWORD rva) const {
+ const Line* line = GetLine(rva);
+ return line ? line->line_num : 0;
+}
+
+DWORD PDBSourceLineWriter::Lines::GetFileId(DWORD rva) const {
+ const Line* line = GetLine(rva);
+ return line ? line->file_id : 0;
+}
+
+void PDBSourceLineWriter::Lines::AddLine(const Line& line) {
+ if (line_map_.empty()) {
+ line_map_[line.rva] = line;
+ return;
+ }
+
+ // Given an existing line in line_map_, remove it from line_map_ if it
+ // overlaps with the line and add a new line for the non-overlap range. Return
+ // true if there is an overlap.
+ auto intercept = [&](Line old_line) {
+ DWORD end = old_line.rva + old_line.length;
+ // No overlap.
+ if (old_line.rva >= line.rva + line.length || line.rva >= end)
+ return false;
+ // old_line is within the line.
+ if (old_line.rva >= line.rva && end <= line.rva + line.length) {
+ line_map_.erase(old_line.rva);
+ return true;
+ }
+ // Then there is a overlap.
+ if (old_line.rva < line.rva) {
+ old_line.length -= end - line.rva;
+ if (end > line.rva + line.length) {
+ Line new_line = old_line;
+ new_line.rva = line.rva + line.length;
+ new_line.length = end - new_line.rva;
+ line_map_[new_line.rva] = new_line;
+ }
+ } else {
+ line_map_.erase(old_line.rva);
+ old_line.length -= line.rva + line.length - old_line.rva;
+ old_line.rva = line.rva + line.length;
+ }
+ line_map_[old_line.rva] = old_line;
+ return true;
+ };
+
+ bool is_intercept;
+ // Use a loop in cases that there are multiple lines within the given line.
+ do {
+ auto iter = line_map_.lower_bound(line.rva);
+ if (iter == line_map_.end()) {
+ if (!line_map_.empty()) {
+ --iter;
+ intercept(iter->second);
+ }
+ break;
+ }
+ is_intercept = false;
+ if (iter != line_map_.begin()) {
+ // Check if the given line overlaps a line with smaller in the map.
+ auto prev = line_map_.lower_bound(line.rva);
+ --prev;
+ is_intercept = intercept(prev->second);
+ }
+ // Check if the given line overlaps a line with greater or equal rva in the
+ // map. Using operator |= here since it's possible that there are multiple
+ // lines with greater rva in the map overlap with the given line.
+ is_intercept |= intercept(iter->second);
+ } while (is_intercept);
+ line_map_[line.rva] = line;
+}
+
+PDBSourceLineWriter::PDBSourceLineWriter(bool handle_inline)
+ : output_(NULL), handle_inline_(handle_inline) {}
+
PDBSourceLineWriter::~PDBSourceLineWriter() {
Close();
}
-bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
+bool PDBSourceLineWriter::SetCodeFile(const wstring& exe_file) {
if (code_file_.empty()) {
code_file_ = exe_file;
return true;
@@ -173,7 +413,7 @@ bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
return exe_file == code_file_;
}
-bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
+bool PDBSourceLineWriter::Open(const wstring& file, FileFormat format) {
Close();
code_file_.clear();
@@ -192,25 +432,32 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
return false;
}
+ HRESULT from_pdb_result;
+ HRESULT for_exe_result;
+ const wchar_t* file_name = file.c_str();
switch (format) {
case PDB_FILE:
- if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
- fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str());
+ from_pdb_result = data_source->loadDataFromPdb(file_name);
+ if (FAILED(from_pdb_result)) {
+ PrintOpenError(from_pdb_result, "loadDataFromPdb", file_name);
return false;
}
break;
case EXE_FILE:
- if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
- fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str());
+ for_exe_result = data_source->loadDataForExe(file_name, NULL, NULL);
+ if (FAILED(for_exe_result)) {
+ PrintOpenError(for_exe_result, "loadDataForExe", file_name);
return false;
}
code_file_ = file;
break;
case ANY_FILE:
- if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
- if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
- fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n",
- file.c_str());
+ from_pdb_result = data_source->loadDataFromPdb(file_name);
+ if (FAILED(from_pdb_result)) {
+ for_exe_result = data_source->loadDataForExe(file_name, NULL, NULL);
+ if (FAILED(for_exe_result)) {
+ PrintOpenError(from_pdb_result, "loadDataFromPdb", file_name);
+ PrintOpenError(for_exe_result, "loadDataForExe", file_name);
return false;
}
code_file_ = file;
@@ -228,52 +475,65 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
return true;
}
-bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) {
- // The line number format is:
- // <rva> <line number> <source file id>
- CComPtr<IDiaLineNumber> line;
- ULONG count;
+bool PDBSourceLineWriter::GetLine(IDiaLineNumber* dia_line, Line* line) const {
+ if (FAILED(dia_line->get_relativeVirtualAddress(&line->rva))) {
+ fprintf(stderr, "failed to get line rva\n");
+ return false;
+ }
- while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
- DWORD rva;
- if (FAILED(line->get_relativeVirtualAddress(&rva))) {
- fprintf(stderr, "failed to get line rva\n");
- return false;
- }
+ if (FAILED(dia_line->get_length(&line->length))) {
+ fprintf(stderr, "failed to get line code length\n");
+ return false;
+ }
- DWORD length;
- if (FAILED(line->get_length(&length))) {
- fprintf(stderr, "failed to get line code length\n");
- return false;
- }
+ DWORD dia_source_id;
+ if (FAILED(dia_line->get_sourceFileId(&dia_source_id))) {
+ fprintf(stderr, "failed to get line source file id\n");
+ return false;
+ }
+ // duplicate file names are coalesced to share one ID
+ line->file_id = GetRealFileID(dia_source_id);
- DWORD dia_source_id;
- if (FAILED(line->get_sourceFileId(&dia_source_id))) {
- fprintf(stderr, "failed to get line source file id\n");
- return false;
- }
- // duplicate file names are coalesced to share one ID
- DWORD source_id = GetRealFileID(dia_source_id);
+ if (FAILED(dia_line->get_lineNumber(&line->line_num))) {
+ fprintf(stderr, "failed to get line number\n");
+ return false;
+ }
+ return true;
+}
- DWORD line_num;
- if (FAILED(line->get_lineNumber(&line_num))) {
- fprintf(stderr, "failed to get line number\n");
+bool PDBSourceLineWriter::GetLines(IDiaEnumLineNumbers* lines,
+ Lines* line_list) const {
+ CComPtr<IDiaLineNumber> line;
+ ULONG count;
+
+ while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
+ Line l;
+ if (!GetLine(line, &l))
return false;
- }
+ // Silently ignore zero-length lines.
+ if (l.length != 0)
+ line_list->AddLine(l);
+ line.Release();
+ }
+ return true;
+}
+void PDBSourceLineWriter::PrintLines(const Lines& lines) const {
+ // The line number format is:
+ // <rva> <line number> <source file id>
+ for (const auto& kv : lines.GetLineMap()) {
+ const Line& l = kv.second;
AddressRangeVector ranges;
- MapAddressRange(image_map_, AddressRange(rva, length), &ranges);
- for (size_t i = 0; i < ranges.size(); ++i) {
- fprintf(output_, "%lx %lx %lu %lu\n", ranges[i].rva, ranges[i].length,
- line_num, source_id);
+ MapAddressRange(image_map_, AddressRange(l.rva, l.length), &ranges);
+ for (auto& range : ranges) {
+ fprintf(output_, "%lx %lx %lu %lu\n", range.rva, range.length, l.line_num,
+ l.file_id);
}
- line.Release();
}
- return true;
}
-bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
- IDiaSymbol *block,
+bool PDBSourceLineWriter::PrintFunction(IDiaSymbol* function,
+ IDiaSymbol* block,
bool has_multiple_symbols) {
// The function format is:
// FUNC <address> <length> <param_stack_size> <function>
@@ -320,9 +580,20 @@ bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
return false;
}
- if (!PrintLines(lines)) {
+ // Get top level lines first, which later may be split into multiple smaller
+ // lines if any inline exists in their ranges if we want to handle inline.
+ Lines line_list;
+ if (!GetLines(lines, &line_list)) {
return false;
}
+ if (handle_inline_) {
+ vector<unique_ptr<Inline>> inlines;
+ if (!GetInlines(block, &line_list, 0, &inlines)) {
+ return false;
+ }
+ PrintInlines(inlines);
+ }
+ PrintLines(line_list);
return true;
}
@@ -340,6 +611,10 @@ bool PDBSourceLineWriter::PrintSourceFiles() {
return false;
}
+ // Print a dummy file with id equals 0 to represent unknown file, because
+ // inline records might have unknown call site.
+ fwprintf(output_, L"FILE %d unknown file\n", 0);
+
CComPtr<IDiaSymbol> compiland;
ULONG count;
while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
@@ -503,6 +778,97 @@ bool PDBSourceLineWriter::PrintFunctions() {
return true;
}
+void PDBSourceLineWriter::PrintInlineOrigins() const {
+ struct OriginCompare {
+ bool operator()(const InlineOrigin lhs, const InlineOrigin rhs) const {
+ return lhs.id < rhs.id;
+ }
+ };
+ set<InlineOrigin, OriginCompare> origins;
+ // Sort by origin id.
+ for (auto const& origin : inline_origins_)
+ origins.insert(origin.second);
+ for (auto o : origins) {
+ fprintf(output_, "INLINE_ORIGIN %d %ls\n", o.id, o.name.c_str());
+ }
+}
+
+bool PDBSourceLineWriter::GetInlines(IDiaSymbol* block,
+ Lines* line_list,
+ int inline_nest_level,
+ vector<unique_ptr<Inline>>* inlines) {
+ CComPtr<IDiaEnumSymbols> inline_callsites;
+ if (FAILED(block->findChildrenEx(SymTagInlineSite, nullptr, nsNone,
+ &inline_callsites))) {
+ return false;
+ }
+ ULONG count;
+ CComPtr<IDiaSymbol> callsite;
+ while (SUCCEEDED(inline_callsites->Next(1, &callsite, &count)) &&
+ count == 1) {
+ unique_ptr<Inline> new_inline(new Inline(inline_nest_level));
+ CComPtr<IDiaEnumLineNumbers> lines;
+ // All inlinee lines have the same file id.
+ DWORD file_id = 0;
+ DWORD call_site_line = 0;
+ if (FAILED(session_->findInlineeLines(callsite, &lines))) {
+ return false;
+ }
+ CComPtr<IDiaLineNumber> dia_line;
+ while (SUCCEEDED(lines->Next(1, &dia_line, &count)) && count == 1) {
+ Line line;
+ if (!GetLine(dia_line, &line)) {
+ return false;
+ }
+ // Silently ignore zero-length lines.
+ if (line.length != 0) {
+ // Use the first line num and file id at rva as this inline's call site
+ // line number, because after adding lines it may be changed to inner
+ // line number and inner file id.
+ if (call_site_line == 0)
+ call_site_line = line_list->GetLineNum(line.rva);
+ if (file_id == 0)
+ file_id = line_list->GetFileId(line.rva);
+ line_list->AddLine(line);
+ new_inline->ExtendRanges(line);
+ }
+ dia_line.Release();
+ }
+ BSTR name;
+ callsite->get_name(&name);
+ if (SysStringLen(name) == 0) {
+ name = SysAllocString(L"<name omitted>");
+ }
+ auto iter = inline_origins_.find(name);
+ if (iter == inline_origins_.end()) {
+ InlineOrigin origin;
+ origin.id = inline_origins_.size();
+ origin.name = name;
+ inline_origins_[name] = origin;
+ }
+ new_inline->SetOriginId(inline_origins_[name].id);
+ new_inline->SetCallSiteLine(call_site_line);
+ new_inline->SetCallSiteFileId(file_id);
+ // Go to next level.
+ vector<unique_ptr<Inline>> child_inlines;
+ if (!GetInlines(callsite, line_list, inline_nest_level + 1,
+ &child_inlines)) {
+ return false;
+ }
+ new_inline->SetChildInlines(std::move(child_inlines));
+ inlines->push_back(std::move(new_inline));
+ callsite.Release();
+ }
+ return true;
+}
+
+void PDBSourceLineWriter::PrintInlines(
+ const vector<unique_ptr<Inline>>& inlines) const {
+ for (const unique_ptr<Inline>& in : inlines) {
+ in->Print(output_);
+ }
+}
+
#undef max
bool PDBSourceLineWriter::PrintFrameDataUsingPDB() {
@@ -673,13 +1039,11 @@ bool PDBSourceLineWriter::PrintFrameData() {
PDBModuleInfo info;
if (GetModuleInfo(&info) && info.cpu == L"x86_64") {
return PrintFrameDataUsingEXE();
- } else {
- return PrintFrameDataUsingPDB();
}
- return false;
+ return PrintFrameDataUsingPDB();
}
-bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol,
+bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol* symbol,
bool has_multiple_symbols) {
BOOL is_code;
if (FAILED(symbol->get_code(&is_code))) {
@@ -781,9 +1145,9 @@ bool PDBSourceLineWriter::PrintPEInfo() {
// and scanf families, which are not as strict about input and in some cases
// don't provide a good way for the caller to determine if a conversion was
// successful.
-static bool wcstol_positive_strict(wchar_t *string, int *result) {
+static bool wcstol_positive_strict(wchar_t* string, int* result) {
int value = 0;
- for (wchar_t *c = string; *c != '\0'; ++c) {
+ for (wchar_t* c = string; *c != '\0'; ++c) {
int last_value = value;
value *= 10;
// Detect overflow.
@@ -821,7 +1185,7 @@ bool PDBSourceLineWriter::FindPEFile() {
wstring file(symbols_file);
// Look for an EXE or DLL file.
- const wchar_t *extensions[] = { L"exe", L"dll" };
+ const wchar_t* extensions[] = { L"exe", L"dll" };
for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
size_t dot_pos = file.find_last_of(L".");
if (dot_pos != wstring::npos) {
@@ -839,23 +1203,13 @@ bool PDBSourceLineWriter::FindPEFile() {
}
// static
-bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
- BSTR *name,
- int *stack_param_size) {
+bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol* function,
+ BSTR* name,
+ int* stack_param_size) {
*stack_param_size = -1;
- const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS |
- UNDNAME_NO_FUNCTION_RETURNS |
- UNDNAME_NO_ALLOCATION_MODEL |
- UNDNAME_NO_ALLOCATION_LANGUAGE |
- UNDNAME_NO_THISTYPE |
- UNDNAME_NO_ACCESS_SPECIFIERS |
- UNDNAME_NO_THROW_SIGNATURES |
- UNDNAME_NO_MEMBER_TYPE |
- UNDNAME_NO_RETURN_UDT_MODEL |
- UNDNAME_NO_ECSU;
// Use get_undecoratedNameEx to get readable C++ names with arguments.
- if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) {
+ if (function->get_undecoratedNameEx(kUndecorateOptions, name) != S_OK) {
if (function->get_name(name) != S_OK) {
fprintf(stderr, "failed to get function name\n");
return false;
@@ -879,15 +1233,17 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
// all of the parameter and return type information may not be included in
// the name string.
} else {
+ StripLlvmSuffixAndUndecorate(name);
+
// C++ uses a bogus "void" argument for functions and methods that don't
// take any parameters. Take it out of the undecorated name because it's
// ugly and unnecessary.
- const wchar_t *replace_string = L"(void)";
+ const wchar_t* replace_string = L"(void)";
const size_t replace_length = wcslen(replace_string);
- const wchar_t *replacement_string = L"()";
+ const wchar_t* replacement_string = L"()";
size_t length = wcslen(*name);
if (length >= replace_length) {
- wchar_t *name_end = *name + length - replace_length;
+ wchar_t* name_end = *name + length - replace_length;
if (wcscmp(name_end, replace_string) == 0) {
WindowsStringUtils::safe_wcscpy(name_end, replace_length,
replacement_string);
@@ -903,7 +1259,7 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
// whether the undecorated name contains any ':' or '(' characters.
if (!wcschr(*name, ':') && !wcschr(*name, '(') &&
(*name[0] == '_' || *name[0] == '@')) {
- wchar_t *last_at = wcsrchr(*name + 1, '@');
+ wchar_t* last_at = wcsrchr(*name + 1, '@');
if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) {
// If this function adheres to the fastcall convention, it accepts up
// to the first 8 bytes of parameters in registers (%ecx and %edx).
@@ -935,7 +1291,7 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
}
// static
-int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) {
+int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol* function) {
// This implementation is highly x86-specific.
// Gather the symbols corresponding to data.
@@ -1050,7 +1406,7 @@ next_child:
return param_size;
}
-bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) {
+bool PDBSourceLineWriter::WriteSymbols(FILE* symbol_file) {
output_ = symbol_file;
// Load the OMAP information, and disable auto-translation of addresses in
@@ -1063,10 +1419,8 @@ bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) {
bool ret = PrintPDBInfo();
// This is not a critical piece of the symbol file.
PrintPEInfo();
- ret = ret &&
- PrintSourceFiles() &&
- PrintFunctions() &&
- PrintFrameData();
+ ret = ret && PrintSourceFiles() && PrintFunctions() && PrintFrameData();
+ PrintInlineOrigins();
output_ = NULL;
return ret;
@@ -1078,7 +1432,7 @@ void PDBSourceLineWriter::Close() {
}
}
-bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
+bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
if (!info) {
return false;
}
@@ -1143,7 +1497,7 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
return true;
}
-bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
+bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo* info) {
if (!info) {
return false;
}
@@ -1156,7 +1510,7 @@ bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
return ReadPEInfo(code_file_, info);
}
-bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
+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 c0adf29f..8c74e2ca 100644
--- a/src/common/windows/pdb_source_line_writer.h
+++ b/src/common/windows/pdb_source_line_writer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,8 +34,11 @@
#include <atlcomcli.h>
+#include <map>
+#include <memory>
#include <string>
#include <unordered_map>
+#include <vector>
#include "common/windows/module_info.h"
#include "common/windows/omap.h"
@@ -47,6 +49,8 @@ struct IDiaSymbol;
namespace google_breakpad {
+using std::map;
+using std::vector;
using std::wstring;
using std::unordered_map;
@@ -58,14 +62,14 @@ class PDBSourceLineWriter {
ANY_FILE // try PDB_FILE and then EXE_FILE
};
- explicit PDBSourceLineWriter();
+ explicit PDBSourceLineWriter(bool handle_inline = false);
~PDBSourceLineWriter();
// Opens the given file. For executable files, the corresponding pdb
// file must be available; Open will be if it is not.
// If there is already a pdb file open, it is automatically closed.
// Returns true on success.
- bool Open(const wstring &file, FileFormat format);
+ bool Open(const wstring& file, FileFormat format);
// Closes the current pdb file and its associated resources.
void Close();
@@ -77,7 +81,7 @@ class PDBSourceLineWriter {
// file and it must be called after Open() and before WriteMap().
// If Open() was called for an executable file, then it is an error to call
// SetCodeFile() with a different file path and it will return false.
- bool SetCodeFile(const wstring &exe_file);
+ bool SetCodeFile(const wstring& exe_file);
// Writes a Breakpad symbol file from the current pdb file to |symbol_file|.
// Returns true on success.
@@ -99,9 +103,110 @@ class PDBSourceLineWriter {
bool UsesGUID(bool *uses_guid);
private:
- // Outputs the line/address pairs for each line in the enumerator.
+ // InlineOrigin represents INLINE_ORIGIN record in a symbol file. It's an
+ // inlined function.
+ struct InlineOrigin {
+ // The unique id for an InlineOrigin.
+ int id;
+ // The name of the inlined function.
+ wstring name;
+ };
+
+ // Line represents LINE record in a symbol file. It represents a source code
+ // line.
+ struct Line {
+ // The relative address of a line.
+ DWORD rva;
+ // The number bytes this line has.
+ DWORD length;
+ // The source line number.
+ DWORD line_num;
+ // The source file id where the source line is located at.
+ DWORD file_id;
+ };
+
+ // Inline represents INLINE record in a symbol file.
+ class Inline {
+ public:
+ explicit Inline(int inline_nest_level);
+
+ void SetOriginId(int origin_id);
+
+ // Adding inlinee line's range into ranges. If line is adjacent with any
+ // existing lines, extend the range. Otherwise, add line as a new range.
+ void ExtendRanges(const Line& line);
+
+ void SetCallSiteLine(DWORD call_site_line);
+
+ void SetCallSiteFileId(DWORD call_site_file_id);
+
+ void SetChildInlines(std::vector<std::unique_ptr<Inline>> child_inlines);
+
+ void Print(FILE* output) const;
+
+ private:
+ // The nest level of this inline record.
+ int inline_nest_level_;
+ // The source line number at where this inlined function is called.
+ DWORD call_site_line_ = 0;
+ // The call site file id at where this inlined function is called.
+ DWORD call_site_file_id_ = 0;
+ // The id used for referring to an InlineOrigin.
+ int origin_id_ = 0;
+ // A map from rva to length. This is the address ranges covered by this
+ // Inline.
+ map<DWORD, DWORD> ranges_;
+ // The list of direct Inlines inlined inside this Inline.
+ vector<std::unique_ptr<Inline>> child_inlines_;
+ };
+
+ // Lines represents a map of lines inside a function with rva as the key.
+ // AddLine function adds a line into the map and ensures that there is no
+ // overlap between any two lines in the map.
+ class Lines {
+ public:
+ const map<DWORD, Line>& GetLineMap() const { return line_map_; }
+
+ // Finds the line from line_map_ that contains the given rva returns its
+ // line_num. If not found, return 0.
+ DWORD GetLineNum(DWORD rva) const;
+
+ // Finds the line from line_map_ that contains the given rva returns its
+ // file_id. If not found, return 0.
+ DWORD GetFileId(DWORD rva) const;
+
+ // Add the `line` into line_map_. If the `line` overlaps with existing
+ // lines, truncate the existing lines and add the given line. It ensures
+ // that all lines in line_map_ do not overlap with each other. For example,
+ // suppose there is a line A in the map and we call AddLine with Line B.
+ // Line A: rva: 100, length: 20, line_num: 10, file_id: 1
+ // Line B: rva: 105, length: 10, line_num: 4, file_id: 2
+ // After calling AddLine with Line B, we will have the following lines:
+ // Line 1: rva: 100, length: 5, line_num: 10, file_id: 1
+ // Line 2: rva: 105, length: 10, line_num: 4, file_id: 2
+ // Line 3: rva: 115, length: 5, line_num: 10, file_id: 1
+ void AddLine(const Line& line);
+
+ private:
+ // Finds the line from line_map_ that contains the given rva. If not found,
+ // return nullptr.
+ const Line* GetLine(DWORD rva) const;
+ // The key is rva. AddLine function ensures that any two lines in the map do
+ // not overlap.
+ map<DWORD, Line> line_map_;
+ };
+
+ // Construct Line from IDiaLineNumber. The output Line is stored at line.
+ // Return true on success.
+ bool GetLine(IDiaLineNumber* dia_line, Line* line) const;
+
+ // Construct Lines from IDiaEnumLineNumbers. The list of Lines are stored at
+ // line_list.
// Returns true on success.
- bool PrintLines(IDiaEnumLineNumbers *lines);
+ bool GetLines(IDiaEnumLineNumbers* lines, Lines* line_list) const;
+
+ // Outputs the line/address pairs for each line in the enumerator.
+ void PrintLines(const Lines& lines) const;
// Outputs a function address and name, followed by its source line list.
// block can be the same object as function, or it can be a reference to a
@@ -118,6 +223,25 @@ class PDBSourceLineWriter {
// Returns true on success.
bool PrintSourceFiles();
+ // Output all inline origins.
+ void PrintInlineOrigins() const;
+
+ // Retrieve inlines inside the given block. It also adds inlinee lines to
+ // `line_list` since inner lines are more precise source location. If the
+ // block has children wih SymTagInlineSite Tag, it will recursively (DFS) call
+ // itself with each child as first argument. Returns true on success.
+ // `block`: the IDiaSymbol that may have inline sites.
+ // `line_list`: the list of lines inside current function.
+ // `inline_nest_level`: the nest level of block's Inlines.
+ // `inlines`: the vector to store the list of inlines for the block.
+ bool GetInlines(IDiaSymbol* block,
+ Lines* line_list,
+ int inline_nest_level,
+ vector<std::unique_ptr<Inline>>* inlines);
+
+ // Outputs all inlines.
+ void PrintInlines(const vector<std::unique_ptr<Inline>>& inlines) const;
+
// Outputs all of the frame information necessary to construct stack
// backtraces in the absence of frame pointers. For x86 data stored in
// .pdb files. Returns true on success.
@@ -150,17 +274,17 @@ class PDBSourceLineWriter {
// 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) {
+ bool FileIDIsCached(const wstring& file) {
return unique_files_.find(file) != unique_files_.end();
}
// Cache this filename and ID for later reuse.
- void CacheFileID(const wstring &file, DWORD id) {
+ void CacheFileID(const wstring& file, DWORD id) {
unique_files_[file] = id;
}
// Store this ID in the cache as a duplicate for this filename.
- void StoreDuplicateFileID(const wstring &file, DWORD id) {
+ void StoreDuplicateFileID(const wstring& file, DWORD id) {
unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file);
if (iter != unique_files_.end()) {
// map this id to the previously seen one
@@ -172,8 +296,8 @@ class PDBSourceLineWriter {
// reference it. There may be multiple files with identical filenames
// but different unique IDs. The cache attempts to coalesce these into
// one ID per unique filename.
- DWORD GetRealFileID(DWORD id) {
- unordered_map<DWORD, DWORD>::iterator iter = file_ids_.find(id);
+ DWORD GetRealFileID(DWORD id) const {
+ unordered_map<DWORD, DWORD>::const_iterator iter = file_ids_.find(id);
if (iter == file_ids_.end())
return id;
return iter->second;
@@ -213,9 +337,15 @@ class PDBSourceLineWriter {
// This maps unique filenames to file IDs.
unordered_map<wstring, DWORD> unique_files_;
+ // The INLINE_ORIGINS records. The key is the function name.
+ std::map<wstring, InlineOrigin> inline_origins_;
+
// This is used for calculating post-transform symbol addresses and lengths.
ImageMap image_map_;
+ // If we should output INLINE/INLINE_ORIGIN records
+ bool handle_inline_;
+
// Disallow copy ctor and operator=
PDBSourceLineWriter(const PDBSourceLineWriter&);
void operator=(const PDBSourceLineWriter&);
diff --git a/src/common/windows/pe_source_line_writer.cc b/src/common/windows/pe_source_line_writer.cc
index cb6cc713..a568e0c7 100644
--- a/src/common/windows/pe_source_line_writer.cc
+++ b/src/common/windows/pe_source_line_writer.cc
@@ -1,77 +1,76 @@
-// Copyright (c) 2019, 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/windows/pe_source_line_writer.h"
-
-#include "common/windows/pe_util.h"
-
-namespace google_breakpad {
-PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) :
- pe_file_(pe_file) {
-}
-
-PESourceLineWriter::~PESourceLineWriter() {
-}
-
-bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) {
- PDBModuleInfo module_info;
- if (!GetModuleInfo(&module_info)) {
- return false;
- }
- // 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(symbol_file, "MODULE windows %ws %ws %ws\n",
- module_info.cpu.c_str(), module_info.debug_identifier.c_str(),
- module_info.debug_file.c_str());
-
- PEModuleInfo pe_info;
- if (!GetPEInfo(&pe_info)) {
- return false;
- }
- fprintf(symbol_file, "INFO CODE_ID %ws %ws\n",
- pe_info.code_identifier.c_str(),
- pe_info.code_file.c_str());
-
- if (!PrintPEFrameData(pe_file_, symbol_file)) {
- return false;
- }
-
- return true;
-}
-
-bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
- return ReadModuleInfo(pe_file_, info);
-}
-
-bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) {
- return ReadPEInfo(pe_file_, info);
-}
-
-} // namespace google_breakpad
+// Copyright 2019 Google LLC
+//
+// 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 LLC 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/windows/pe_source_line_writer.h"
+
+#include "common/windows/pe_util.h"
+
+namespace google_breakpad {
+PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) :
+ pe_file_(pe_file) {
+}
+
+PESourceLineWriter::~PESourceLineWriter() {
+}
+
+bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) {
+ PDBModuleInfo module_info;
+ if (!GetModuleInfo(&module_info)) {
+ return false;
+ }
+ // 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(symbol_file, "MODULE windows %ws %ws %ws\n",
+ module_info.cpu.c_str(), module_info.debug_identifier.c_str(),
+ module_info.debug_file.c_str());
+
+ PEModuleInfo pe_info;
+ if (!GetPEInfo(&pe_info)) {
+ return false;
+ }
+ fprintf(symbol_file, "INFO CODE_ID %ws %ws\n",
+ pe_info.code_identifier.c_str(),
+ pe_info.code_file.c_str());
+
+ if (!PrintPEFrameData(pe_file_, symbol_file)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
+ return ReadModuleInfo(pe_file_, info);
+}
+
+bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) {
+ return ReadPEInfo(pe_file_, info);
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/pe_source_line_writer.h b/src/common/windows/pe_source_line_writer.h
index 2bf1d4fd..a3748145 100644
--- a/src/common/windows/pe_source_line_writer.h
+++ b/src/common/windows/pe_source_line_writer.h
@@ -1,69 +1,68 @@
-// Copyright (c) 2019, 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_WINDOWS_PE_SOURCE_LINE_WRITER_H_
-#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
-
-#include <string>
-
-#include "common/basictypes.h"
-#include "common/windows/module_info.h"
-
-namespace google_breakpad {
-
-using std::wstring;
-
-// PESourceLineWriter uses a pe file produced by Visual C++ to output
-// a line/address map for use with BasicSourceLineResolver.
-// NOTE: Only supports PE32+ format, ie. a 64bit PE file.
-class PESourceLineWriter {
-public:
- explicit PESourceLineWriter(const wstring& pe_file);
- ~PESourceLineWriter();
-
- // Writes Breakpad symbols from the pe file to |symbol_file|.
- // Returns true on success.
- bool WriteSymbols(FILE* symbol_file);
-
- // Retrieves information about the module. Returns true on success.
- bool GetModuleInfo(PDBModuleInfo* info);
-
+// Copyright 2019 Google LLC
+//
+// 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 LLC 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_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+
+#include <string>
+
+#include "common/basictypes.h"
+#include "common/windows/module_info.h"
+
+namespace google_breakpad {
+
+using std::wstring;
+
+// PESourceLineWriter uses a pe file produced by Visual C++ to output
+// a line/address map for use with BasicSourceLineResolver.
+// NOTE: Only supports PE32+ format, ie. a 64bit PE file.
+class PESourceLineWriter {
+public:
+ explicit PESourceLineWriter(const wstring& pe_file);
+ ~PESourceLineWriter();
+
+ // Writes Breakpad symbols from the pe file to |symbol_file|.
+ // Returns true on success.
+ bool WriteSymbols(FILE* symbol_file);
+
+ // Retrieves information about the module. Returns true on success.
+ bool GetModuleInfo(PDBModuleInfo* info);
+
// Retrieves information about the module's PE file. Returns
- // true on success.
- bool GetPEInfo(PEModuleInfo* info);
-
-private:
- const wstring pe_file_;
-
- DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter);
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+ // true on success.
+ bool GetPEInfo(PEModuleInfo* info);
+
+private:
+ const wstring pe_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter);
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
diff --git a/src/common/windows/pe_util.cc b/src/common/windows/pe_util.cc
index 6fa63fa3..1df93105 100644
--- a/src/common/windows/pe_util.cc
+++ b/src/common/windows/pe_util.cc
@@ -1,407 +1,411 @@
-// Copyright (c) 2019, 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 "pe_util.h"
-
-#include <windows.h>
-#include <winnt.h>
-#include <atlbase.h>
-#include <ImageHlp.h>
-
-#include <functional>
-
-#include "common/windows/string_utils-inl.h"
-#include "common/windows/guid_string.h"
-
-namespace {
-
-/*
- * Not defined in WinNT.h for some reason. Definitions taken from:
- * http://uninformed.org/index.cgi?v=4&a=1&p=13
- *
- */
-typedef unsigned char UBYTE;
-
-#if !defined(_WIN64)
-#define UNW_FLAG_EHANDLER 0x01
-#define UNW_FLAG_UHANDLER 0x02
-#define UNW_FLAG_CHAININFO 0x04
-#endif
-
-union UnwindCode {
- struct {
- UBYTE offset_in_prolog;
- UBYTE unwind_operation_code : 4;
- UBYTE operation_info : 4;
- };
- USHORT frame_offset;
-};
-
-enum UnwindOperationCodes {
- UWOP_PUSH_NONVOL = 0, /* info == register number */
- UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
- UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
- UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
- UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
- UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
- // XXX: these are missing from MSDN!
- // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
- UWOP_SAVE_XMM,
- UWOP_SAVE_XMM_FAR,
- UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
- UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
- UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
-};
-
-// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
-// Note: some fields removed as we don't use them.
-struct UnwindInfo {
- UBYTE version : 3;
- UBYTE flags : 5;
- UBYTE size_of_prolog;
- UBYTE count_of_codes;
- UBYTE frame_register : 4;
- UBYTE frame_offset : 4;
- UnwindCode unwind_code[1];
-};
-
-struct CV_INFO_PDB70 {
- ULONG cv_signature;
- GUID signature;
- ULONG age;
- CHAR pdb_filename[ANYSIZE_ARRAY];
-};
-
-#define CV_SIGNATURE_RSDS 'SDSR'
-
-// 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_;
-};
-} // namespace
-
-namespace google_breakpad {
-
-using std::unique_ptr;
-using google_breakpad::GUIDString;
-
-bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) {
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", img_file.c_str());
- return false;
- }
-
- info->cpu = FileHeaderMachineToCpuString(
- img->FileHeader->FileHeader.Machine);
-
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
-
- // Search debug directories for a guid signature & age
- DWORD debug_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
- DWORD debug_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
- PIMAGE_DEBUG_DIRECTORY debug_directories =
- static_cast<PIMAGE_DEBUG_DIRECTORY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- debug_rva,
- &img->LastRvaSection));
-
- for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) {
- if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW ||
- debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) {
- continue;
- }
-
- struct CV_INFO_PDB70* cv_info = static_cast<CV_INFO_PDB70*>(ImageRvaToVa(
- img->FileHeader,
- img->MappedAddress,
- debug_directories[i].AddressOfRawData,
- &img->LastRvaSection));
- if (cv_info->cv_signature != CV_SIGNATURE_RSDS) {
- continue;
- }
-
- info->debug_identifier = GenerateDebugIdentifier(cv_info->age,
- cv_info->signature);
-
- // This code assumes that the pdb_filename is stored as ASCII without
- // multibyte characters, but it's not clear if that's true.
- size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH);
- if (debug_file_length < 0 || debug_file_length >= MAX_PATH) {
- fprintf(stderr, "PE debug directory is corrupt.\n");
- return false;
- }
- std::string debug_file(cv_info->pdb_filename, debug_file_length);
- if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) {
- fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n",
- debug_file.c_str());
- return false;
- }
- info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file);
-
- return true;
- }
-
- fprintf(stderr, "Image is missing debug information.\n");
- return false;
-}
-
-bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) {
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str());
- return false;
- }
-
- info->code_file = WindowsStringUtils::GetBaseName(pe_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 PrintPEFrameData(const wstring & pe_file, FILE * out_file)
-{
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", img_file.c_str());
- return false;
- }
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
- if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- fprintf(stderr, "Not a PE32+ image\n");
- return false;
- }
-
- // Read Exception Directory
- DWORD exception_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
- DWORD exception_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
- PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- exception_rva,
- &img->LastRvaSection));
- for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
- DWORD unwind_rva = funcs[i].UnwindInfoAddress;
- // handle chaining
- while (unwind_rva & 0x1) {
- unwind_rva ^= 0x1;
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
- unwind_rva = chained_func->UnwindInfoAddress;
- }
-
- UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
-
- DWORD stack_size = 8; // minimal stack size is 8 for RIP
- DWORD rip_offset = 8;
- do {
- for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
- UnwindCode *unwind_code = &unwind_info->unwind_code[c];
- switch (unwind_code->unwind_operation_code) {
- case UWOP_PUSH_NONVOL: {
- stack_size += 8;
- break;
- }
- case UWOP_ALLOC_LARGE: {
- if (unwind_code->operation_info == 0) {
- c++;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset * 8;
- }
- else {
- c += 2;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset |
- ((unwind_code + 2)->frame_offset << 16);
- }
- break;
- }
- case UWOP_ALLOC_SMALL: {
- stack_size += unwind_code->operation_info * 8 + 8;
- break;
- }
- case UWOP_SET_FPREG:
- case UWOP_SAVE_XMM:
- case UWOP_SAVE_XMM_FAR:
- break;
- case UWOP_SAVE_NONVOL:
- case UWOP_SAVE_XMM128: {
- c++; // skip slot with offset
- break;
- }
- case UWOP_SAVE_NONVOL_FAR:
- case UWOP_SAVE_XMM128_FAR: {
- c += 2; // skip 2 slots with offset
- break;
- }
- case UWOP_PUSH_MACHFRAME: {
- if (unwind_code->operation_info) {
- stack_size += 88;
- }
- else {
- stack_size += 80;
- }
- rip_offset += 80;
- break;
- }
- }
- }
- if (unwind_info->flags & UNW_FLAG_CHAININFO) {
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- (unwind_info->unwind_code +
- ((unwind_info->count_of_codes + 1) & ~1)));
-
- unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- chained_func->UnwindInfoAddress,
- &img->LastRvaSection));
- }
- else {
- unwind_info = NULL;
- }
- } while (unwind_info);
- fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
- funcs[i].BeginAddress,
- funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
- fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n",
- funcs[i].BeginAddress, stack_size);
- }
-
- return true;
-}
-
-wstring GenerateDebugIdentifier(DWORD age, GUID signature)
-{
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t age_string[9];
- swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
- L"%x", age);
-
- // remove when VC++7.1 is no longer supported
- age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
-
- wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature);
- debug_identifier.append(age_string);
-
- return debug_identifier;
-}
-
-wstring GenerateDebugIdentifier(DWORD age, DWORD signature)
-{
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t identifier_string[17];
- swprintf(identifier_string,
- sizeof(identifier_string) / sizeof(identifier_string[0]),
- L"%08X%x", signature, age);
-
- // remove when VC++7.1 is no longer supported
- identifier_string[sizeof(identifier_string) /
- sizeof(identifier_string[0]) - 1] = L'\0';
-
- return wstring(identifier_string);
-}
-
-} // namespace google_breakpad
+// Copyright 2019 Google LLC
+//
+// 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 LLC 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 "pe_util.h"
+
+#include <windows.h>
+#include <winnt.h>
+#include <atlbase.h>
+#include <ImageHlp.h>
+
+#include <functional>
+#include <memory>
+
+#include "common/windows/string_utils-inl.h"
+#include "common/windows/guid_string.h"
+
+namespace {
+
+/*
+ * Not defined in WinNT.h prior to SDK 10.0.20348.0 for some reason.
+ * Definitions taken from: http://uninformed.org/index.cgi?v=4&a=1&p=13
+ *
+ */
+typedef unsigned char UBYTE;
+
+#if !defined(UNW_FLAG_EHANDLER)
+#define UNW_FLAG_EHANDLER 0x01
+#endif
+#if !defined(UNW_FLAG_UHANDLER)
+#define UNW_FLAG_UHANDLER 0x02
+#endif
+#if !defined(UNW_FLAG_CHAININFO)
+#define UNW_FLAG_CHAININFO 0x04
+#endif
+
+union UnwindCode {
+ struct {
+ UBYTE offset_in_prolog;
+ UBYTE unwind_operation_code : 4;
+ UBYTE operation_info : 4;
+ };
+ USHORT frame_offset;
+};
+
+enum UnwindOperationCodes {
+ UWOP_PUSH_NONVOL = 0, /* info == register number */
+ UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
+ UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
+ UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+ UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
+ UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
+ // XXX: these are missing from MSDN!
+ // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
+ UWOP_SAVE_XMM,
+ UWOP_SAVE_XMM_FAR,
+ UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
+ UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
+ UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
+};
+
+// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
+// Note: some fields removed as we don't use them.
+struct UnwindInfo {
+ UBYTE version : 3;
+ UBYTE flags : 5;
+ UBYTE size_of_prolog;
+ UBYTE count_of_codes;
+ UBYTE frame_register : 4;
+ UBYTE frame_offset : 4;
+ UnwindCode unwind_code[1];
+};
+
+struct CV_INFO_PDB70 {
+ ULONG cv_signature;
+ GUID signature;
+ ULONG age;
+ CHAR pdb_filename[ANYSIZE_ARRAY];
+};
+
+#define CV_SIGNATURE_RSDS 'SDSR'
+
+// 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_;
+};
+} // namespace
+
+namespace google_breakpad {
+
+using std::unique_ptr;
+using google_breakpad::GUIDString;
+
+bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) {
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string img_file;
+ if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
+ fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
+ pe_file.c_str());
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to load %s\n", img_file.c_str());
+ return false;
+ }
+
+ info->cpu = FileHeaderMachineToCpuString(
+ img->FileHeader->FileHeader.Machine);
+
+ PIMAGE_OPTIONAL_HEADER64 optional_header =
+ &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
+
+ // Search debug directories for a guid signature & age
+ DWORD debug_rva = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
+ DWORD debug_size = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+ PIMAGE_DEBUG_DIRECTORY debug_directories =
+ static_cast<PIMAGE_DEBUG_DIRECTORY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ debug_rva,
+ &img->LastRvaSection));
+
+ for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) {
+ if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW ||
+ debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) {
+ continue;
+ }
+
+ struct CV_INFO_PDB70* cv_info = static_cast<CV_INFO_PDB70*>(ImageRvaToVa(
+ img->FileHeader,
+ img->MappedAddress,
+ debug_directories[i].AddressOfRawData,
+ &img->LastRvaSection));
+ if (cv_info->cv_signature != CV_SIGNATURE_RSDS) {
+ continue;
+ }
+
+ info->debug_identifier = GenerateDebugIdentifier(cv_info->age,
+ cv_info->signature);
+
+ // This code assumes that the pdb_filename is stored as ASCII without
+ // multibyte characters, but it's not clear if that's true.
+ size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH);
+ if (debug_file_length < 0 || debug_file_length >= MAX_PATH) {
+ fprintf(stderr, "PE debug directory is corrupt.\n");
+ return false;
+ }
+ std::string debug_file(cv_info->pdb_filename, debug_file_length);
+ if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) {
+ fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n",
+ debug_file.c_str());
+ return false;
+ }
+ info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file);
+
+ return true;
+ }
+
+ fprintf(stderr, "Image is missing debug information.\n");
+ return false;
+}
+
+bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) {
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string img_file;
+ if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
+ fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
+ pe_file.c_str());
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str());
+ return false;
+ }
+
+ info->code_file = WindowsStringUtils::GetBaseName(pe_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 PrintPEFrameData(const wstring & pe_file, FILE * out_file)
+{
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string img_file;
+ if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
+ fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
+ pe_file.c_str());
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to load %s\n", img_file.c_str());
+ return false;
+ }
+ PIMAGE_OPTIONAL_HEADER64 optional_header =
+ &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
+ if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ fprintf(stderr, "Not a PE32+ image\n");
+ return false;
+ }
+
+ // Read Exception Directory
+ DWORD exception_rva = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
+ DWORD exception_size = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
+ PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
+ static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ exception_rva,
+ &img->LastRvaSection));
+ for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
+ DWORD unwind_rva = funcs[i].UnwindInfoAddress;
+ // handle chaining
+ while (unwind_rva & 0x1) {
+ unwind_rva ^= 0x1;
+ PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
+ static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ unwind_rva,
+ &img->LastRvaSection));
+ unwind_rva = chained_func->UnwindInfoAddress;
+ }
+
+ UnwindInfo *unwind_info = static_cast<UnwindInfo*>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ unwind_rva,
+ &img->LastRvaSection));
+
+ DWORD stack_size = 8; // minimal stack size is 8 for RIP
+ DWORD rip_offset = 8;
+ do {
+ for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
+ UnwindCode *unwind_code = &unwind_info->unwind_code[c];
+ switch (unwind_code->unwind_operation_code) {
+ case UWOP_PUSH_NONVOL: {
+ stack_size += 8;
+ break;
+ }
+ case UWOP_ALLOC_LARGE: {
+ if (unwind_code->operation_info == 0) {
+ c++;
+ if (c < unwind_info->count_of_codes)
+ stack_size += (unwind_code + 1)->frame_offset * 8;
+ }
+ else {
+ c += 2;
+ if (c < unwind_info->count_of_codes)
+ stack_size += (unwind_code + 1)->frame_offset |
+ ((unwind_code + 2)->frame_offset << 16);
+ }
+ break;
+ }
+ case UWOP_ALLOC_SMALL: {
+ stack_size += unwind_code->operation_info * 8 + 8;
+ break;
+ }
+ case UWOP_SET_FPREG:
+ case UWOP_SAVE_XMM:
+ case UWOP_SAVE_XMM_FAR:
+ break;
+ case UWOP_SAVE_NONVOL:
+ case UWOP_SAVE_XMM128: {
+ c++; // skip slot with offset
+ break;
+ }
+ case UWOP_SAVE_NONVOL_FAR:
+ case UWOP_SAVE_XMM128_FAR: {
+ c += 2; // skip 2 slots with offset
+ break;
+ }
+ case UWOP_PUSH_MACHFRAME: {
+ if (unwind_code->operation_info) {
+ stack_size += 88;
+ }
+ else {
+ stack_size += 80;
+ }
+ rip_offset += 80;
+ break;
+ }
+ }
+ }
+ if (unwind_info->flags & UNW_FLAG_CHAININFO) {
+ PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
+ reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ (unwind_info->unwind_code +
+ ((unwind_info->count_of_codes + 1) & ~1)));
+
+ unwind_info = static_cast<UnwindInfo*>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ chained_func->UnwindInfoAddress,
+ &img->LastRvaSection));
+ }
+ else {
+ unwind_info = NULL;
+ }
+ } while (unwind_info);
+ fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
+ funcs[i].BeginAddress,
+ funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
+ fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n",
+ funcs[i].BeginAddress, stack_size);
+ }
+
+ return true;
+}
+
+wstring GenerateDebugIdentifier(DWORD age, GUID signature)
+{
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ wchar_t age_string[9];
+ swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
+ L"%x", age);
+
+ // remove when VC++7.1 is no longer supported
+ age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
+
+ wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature);
+ debug_identifier.append(age_string);
+
+ return debug_identifier;
+}
+
+wstring GenerateDebugIdentifier(DWORD age, DWORD signature)
+{
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ wchar_t identifier_string[17];
+ swprintf(identifier_string,
+ sizeof(identifier_string) / sizeof(identifier_string[0]),
+ L"%08X%x", signature, age);
+
+ // remove when VC++7.1 is no longer supported
+ identifier_string[sizeof(identifier_string) /
+ sizeof(identifier_string[0]) - 1] = L'\0';
+
+ return wstring(identifier_string);
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/pe_util.h b/src/common/windows/pe_util.h
index 634ba293..6c6b364f 100644
--- a/src/common/windows/pe_util.h
+++ b/src/common/windows/pe_util.h
@@ -1,78 +1,77 @@
-// Copyright (c) 2019, 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_WINDOWS_PE_UTIL_H_
-#define COMMON_WINDOWS_PE_UTIL_H_
-
-#include <windows.h>
-
-#include "common/windows/module_info.h"
-
-namespace google_breakpad {
-
-using std::wstring;
-
-// Reads |pe_file| and populates |info|. Returns true on success.
-// Only supports PE32+ format, ie. a 64bit PE file.
-// Will fail if |pe_file| does not contain a valid CodeView record.
-bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info);
-
-// Reads |pe_file| and populates |info|. Returns true on success.
-bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info);
-
-// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|.
-// Only supports PE32+ format, ie. a 64bit PE file.
-bool PrintPEFrameData(const wstring& pe_file, FILE* out_file);
-
-// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug
-// identifier.
-wstring GenerateDebugIdentifier(DWORD age, GUID signature);
-
-// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug
-// identifier.
-wstring GenerateDebugIdentifier(DWORD age, DWORD signature);
-
-// Converts |machine| enum value to the corresponding string used by Breakpad.
-// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h.
-constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) {
- switch (machine) {
- case IMAGE_FILE_MACHINE_I386: {
- return L"x86";
- }
- case IMAGE_FILE_MACHINE_IA64:
- case IMAGE_FILE_MACHINE_AMD64: {
- return L"x86_64";
- }
- default: { return L"unknown"; }
- }
-}
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_PE_UTIL_H_
+// Copyright 2019 Google LLC
+//
+// 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 LLC 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_WINDOWS_PE_UTIL_H_
+#define COMMON_WINDOWS_PE_UTIL_H_
+
+#include <windows.h>
+
+#include "common/windows/module_info.h"
+
+namespace google_breakpad {
+
+using std::wstring;
+
+// Reads |pe_file| and populates |info|. Returns true on success.
+// Only supports PE32+ format, ie. a 64bit PE file.
+// Will fail if |pe_file| does not contain a valid CodeView record.
+bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info);
+
+// Reads |pe_file| and populates |info|. Returns true on success.
+bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info);
+
+// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|.
+// Only supports PE32+ format, ie. a 64bit PE file.
+bool PrintPEFrameData(const wstring& pe_file, FILE* out_file);
+
+// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug
+// identifier.
+wstring GenerateDebugIdentifier(DWORD age, GUID signature);
+
+// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug
+// identifier.
+wstring GenerateDebugIdentifier(DWORD age, DWORD signature);
+
+// Converts |machine| enum value to the corresponding string used by Breakpad.
+// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h.
+constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) {
+ switch (machine) {
+ case IMAGE_FILE_MACHINE_I386: {
+ return L"x86";
+ }
+ case IMAGE_FILE_MACHINE_IA64:
+ case IMAGE_FILE_MACHINE_AMD64: {
+ return L"x86_64";
+ }
+ default: { return L"unknown"; }
+ }
+}
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_PE_UTIL_H_
diff --git a/src/common/windows/string_utils-inl.h b/src/common/windows/string_utils-inl.h
index 9b636072..c6f5e0ac 100644
--- a/src/common/windows/string_utils-inl.h
+++ b/src/common/windows/string_utils-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -72,26 +71,26 @@ class WindowsStringUtils {
// Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does
// not fail if source is longer than destination_size. The destination
// buffer is always 0-terminated.
- static void safe_wcscpy(wchar_t *destination, size_t destination_size,
- const wchar_t *source);
+ static void safe_wcscpy(wchar_t* destination, size_t destination_size,
+ const wchar_t* source);
// Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot
// be passed directly, and pre-MSVC8, this will not fail if source or count
// are longer than destination_size. The destination buffer is always
// 0-terminated.
- static void safe_wcsncpy(wchar_t *destination, size_t destination_size,
- const wchar_t *source, size_t count);
+ static void safe_wcsncpy(wchar_t* destination, size_t destination_size,
+ const wchar_t* source, size_t count);
// Performs multi-byte to wide character conversion on C++ strings, using
// mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure,
// 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);
+ 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);
+ static wstring GetBaseName(const wstring& filename);
private:
// Disallow instantiation and other object-based operations.
@@ -102,9 +101,9 @@ class WindowsStringUtils {
};
// static
-inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
+inline void WindowsStringUtils::safe_wcscpy(wchar_t* destination,
size_t destination_size,
- const wchar_t *source) {
+ const wchar_t* source) {
#if _MSC_VER >= 1400 // MSVC 2005/8
wcscpy_s(destination, destination_size, source);
#else // _MSC_VER >= 1400
@@ -118,9 +117,9 @@ inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
}
// static
-inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,
+inline void WindowsStringUtils::safe_wcsncpy(wchar_t* destination,
size_t destination_size,
- const wchar_t *source,
+ const wchar_t* source,
size_t count) {
#if _MSC_VER >= 1400 // MSVC 2005/8
wcsncpy_s(destination, destination_size, source, count);
diff --git a/src/common/windows/string_utils.cc b/src/common/windows/string_utils.cc
index 27280003..01dca193 100644
--- a/src/common/windows/string_utils.cc
+++ b/src/common/windows/string_utils.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,7 +34,7 @@
namespace google_breakpad {
// static
-wstring WindowsStringUtils::GetBaseName(const wstring &filename) {
+wstring WindowsStringUtils::GetBaseName(const wstring& filename) {
wstring base_name(filename);
size_t slash_pos = base_name.find_last_of(L"/\\");
if (slash_pos != wstring::npos) {
@@ -45,7 +44,7 @@ wstring WindowsStringUtils::GetBaseName(const wstring &filename) {
}
// static
-bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
+bool WindowsStringUtils::safe_mbstowcs(const string& mbs, wstring* wcs) {
assert(wcs);
// First, determine the length of the destination buffer.
@@ -88,7 +87,7 @@ bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
}
// static
-bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) {
+bool WindowsStringUtils::safe_wcstombs(const wstring& wcs, string* mbs) {
assert(mbs);
// First, determine the length of the destination buffer.
diff --git a/src/common/windows/sym_upload_v2_protocol.cc b/src/common/windows/sym_upload_v2_protocol.cc
new file mode 100644
index 00000000..f2dc660c
--- /dev/null
+++ b/src/common/windows/sym_upload_v2_protocol.cc
@@ -0,0 +1,118 @@
+// Copyright 2022 Google LLC
+//
+// 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 LLC 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/windows/sym_upload_v2_protocol.h"
+
+#include <cstdio>
+
+#include "common/windows/http_upload.h"
+#include "common/windows/symbol_collector_client.h"
+
+using google_breakpad::CompleteUploadResult;
+using google_breakpad::HTTPUpload;
+using google_breakpad::SymbolCollectorClient;
+using google_breakpad::SymbolStatus;
+using google_breakpad::UploadUrlResponse;
+using std::wstring;
+
+namespace google_breakpad {
+
+static bool SymUploadV2ProtocolSend(const wchar_t* api_url,
+ const wchar_t* api_key,
+ int* timeout_ms,
+ const wstring& debug_file,
+ const wstring& debug_id,
+ const wstring& symbol_filename,
+ const wstring& symbol_type,
+ const wstring& product_name,
+ bool force) {
+ wstring url(api_url);
+ wstring key(api_key);
+
+ if (!force) {
+ SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus(
+ url, key, timeout_ms, debug_file, debug_id);
+ if (symbolStatus == SymbolStatus::Found) {
+ wprintf(
+ L"Symbol file already exists, upload aborted."
+ L" Use \"-f\" to overwrite.\n");
+ return true;
+ } else if (symbolStatus == SymbolStatus::Unknown) {
+ wprintf(L"Failed to get check for existing symbol.\n");
+ return false;
+ }
+ }
+
+ UploadUrlResponse uploadUrlResponse;
+ if (!SymbolCollectorClient::CreateUploadUrl(url, key, timeout_ms,
+ &uploadUrlResponse)) {
+ wprintf(L"Failed to create upload URL.\n");
+ return false;
+ }
+
+ wstring signed_url = uploadUrlResponse.upload_url;
+ wstring upload_key = uploadUrlResponse.upload_key;
+ wstring response;
+ int response_code;
+ bool success = HTTPUpload::SendPutRequest(
+ signed_url, symbol_filename, timeout_ms, &response, &response_code);
+ if (!success) {
+ wprintf(L"Failed to send symbol file.\n");
+ wprintf(L"Response code: %ld\n", response_code);
+ wprintf(L"Response:\n");
+ wprintf(L"%s\n", response.c_str());
+ return false;
+ } else if (response_code == 0) {
+ wprintf(L"Failed to send symbol file: No response code\n");
+ return false;
+ } else if (response_code != 200) {
+ wprintf(L"Failed to send symbol file: Response code %ld\n", response_code);
+ wprintf(L"Response:\n");
+ wprintf(L"%s\n", response.c_str());
+ return false;
+ }
+
+ CompleteUploadResult completeUploadResult =
+ SymbolCollectorClient::CompleteUpload(url, key, timeout_ms, upload_key,
+ debug_file, debug_id, symbol_type,
+ product_name);
+ if (completeUploadResult == CompleteUploadResult::Error) {
+ wprintf(L"Failed to complete upload.\n");
+ return false;
+ } else if (completeUploadResult == CompleteUploadResult::DuplicateData) {
+ wprintf(
+ L"Uploaded file checksum matched existing file checksum,"
+ L" no change necessary.\n");
+ } else {
+ wprintf(L"Successfully sent the symbol file.\n");
+ }
+
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/sym_upload_v2_protocol.h b/src/common/windows/sym_upload_v2_protocol.h
new file mode 100644
index 00000000..19e6f87a
--- /dev/null
+++ b/src/common/windows/sym_upload_v2_protocol.h
@@ -0,0 +1,66 @@
+// Copyright 2022 Google LLC
+//
+// 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 LLC 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_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_
+#define COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_
+
+#include <string>
+
+namespace google_breakpad {
+
+// Sends file at |symbol_filename| using the sym-upload-v2 protocol to
+// |api_url| using key |api_key|, and using identifiers |debug_file| and
+// |debug_id|. |timeout_ms| is the number of milliseconds to wait before
+// terminating the upload attempt. |symbol_type| is the type of the symbol
+// file, which is one of:
+// "BREAKPAD"
+// "ELF"
+// "PE"
+// "MACHO"
+// "DEBUG_ONLY"
+// "DWP"
+// "DSYM"
+// "PDB"
+// "SOURCE_MAP"
+// If |product_name| is non-empty then it will be sent as part of the symbol
+// metadata.
+// If |force| is set then it will overwrite an existing file with the
+// same |debug_file| and |debug_id| in the store.
+bool SymUploadV2ProtocolSend(const wchar_t* api_url,
+ const wchar_t* api_key,
+ int* timeout_ms,
+ const std::wstring& debug_file,
+ const std::wstring& debug_id,
+ const std::wstring& symbol_filename,
+ const std::wstring& symbol_type,
+ const std::wstring& product_name,
+ bool force);
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_ \ No newline at end of file
diff --git a/src/common/windows/symbol_collector_client.cc b/src/common/windows/symbol_collector_client.cc
index 30c663ed..187b100e 100644
--- a/src/common/windows/symbol_collector_client.cc
+++ b/src/common/windows/symbol_collector_client.cc
@@ -12,6 +12,7 @@ namespace google_breakpad {
bool SymbolCollectorClient::CreateUploadUrl(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
UploadUrlResponse *uploadUrlResponse) {
wstring url = api_url +
L"/v1/uploads:create"
@@ -23,7 +24,7 @@ namespace google_breakpad {
url,
L"",
L"",
- NULL,
+ timeout_ms,
&response,
&response_code)) {
wprintf(L"Failed to create upload url.\n");
@@ -66,17 +67,35 @@ namespace google_breakpad {
CompleteUploadResult SymbolCollectorClient::CompleteUpload(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
const wstring& upload_key,
const wstring& debug_file,
- const wstring& debug_id) {
+ const wstring& debug_id,
+ const wstring& type,
+ const wstring& product_name) {
wstring url = api_url +
L"/v1/uploads/" + upload_key + L":complete"
L"?key=" + api_key;
wstring body =
L"{ symbol_id: {"
- L"debug_file: \"" + debug_file + L"\", "
- L"debug_id: \"" + debug_id + L"\" "
- L"} }";
+ L"debug_file: \"" +
+ debug_file +
+ L"\", "
+ L"debug_id: \"" +
+ debug_id +
+ L"\" "
+ L"}, ";
+ if (!product_name.empty()) {
+ body +=
+ L"metadata: {"
+ L"product_name: \"" +
+ product_name +
+ L"\""
+ L"},";
+ }
+ body += L"symbol_upload_type: \"" + type +
+ L"\", "
+ L"use_async_processing: true }";
wstring response;
int response_code;
@@ -84,7 +103,7 @@ namespace google_breakpad {
url,
body,
L"application/json",
- NULL,
+ timeout_ms,
&response,
&response_code)) {
wprintf(L"Failed to complete upload.\n");
@@ -116,6 +135,7 @@ namespace google_breakpad {
SymbolStatus SymbolCollectorClient::CheckSymbolStatus(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
const wstring& debug_file,
const wstring& debug_id) {
wstring response;
@@ -126,7 +146,7 @@ namespace google_breakpad {
if (!HTTPUpload::SendGetRequest(
url,
- NULL,
+ timeout_ms,
&response,
&response_code)) {
wprintf(L"Failed to check symbol status.\n");
diff --git a/src/common/windows/symbol_collector_client.h b/src/common/windows/symbol_collector_client.h
index 30e0cb32..4e9bf3b6 100644
--- a/src/common/windows/symbol_collector_client.h
+++ b/src/common/windows/symbol_collector_client.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -64,22 +63,26 @@ namespace google_breakpad {
static bool CreateUploadUrl(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
UploadUrlResponse *uploadUrlResponse);
// Notify the API that symbol file upload is finished and its contents
// are ready to be read and/or used for further processing.
- static CompleteUploadResult CompleteUpload(
- wstring& api_url,
- wstring& api_key,
- const wstring& upload_key,
- const wstring& debug_file,
- const wstring& debug_id);
+ static CompleteUploadResult CompleteUpload(wstring& api_url,
+ wstring& api_key,
+ int* timeout_ms,
+ const wstring& upload_key,
+ const wstring& debug_file,
+ const wstring& debug_id,
+ const wstring& type,
+ const wstring& product_name);
// Returns whether or not a symbol file corresponding to the debug_file/
// debug_id pair is already present in symbol storage.
static SymbolStatus CheckSymbolStatus(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
const wstring& debug_file,
const wstring& debug_id);
};