diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common/windows')
16 files changed, 0 insertions, 4093 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp b/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp deleted file mode 100644 index c98333a34..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp +++ /dev/null @@ -1,105 +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', - 'omap.cc', - 'omap.h', - 'omap_internal.h', - 'pdb_source_line_writer.cc', - 'pdb_source_line_writer.h', - 'string_utils.cc', - 'string_utils-inl.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/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc deleted file mode 100644 index ed8cb5b65..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc +++ /dev/null @@ -1,92 +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.
-
-#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/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h deleted file mode 100644 index b9e0df2d5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h +++ /dev/null @@ -1,64 +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. - -// Utilities for loading debug streams and tables from a PDB file. - -#ifndef COMMON_WINDOWS_DIA_UTIL_H_ -#define COMMON_WINDOWS_DIA_UTIL_H_ - -#include <Windows.h> -#include <dia2.h> - -namespace google_breakpad { - -// Find the debug stream of the given |name| in the given |session|. Returns -// true on success, false on error of if the stream does not exist. On success -// the stream will be returned via |debug_stream|. -bool FindDebugStream(const wchar_t* name, - IDiaSession* session, - IDiaEnumDebugStreamData** debug_stream); - -// Finds the first table implementing the COM interface with ID |iid| in the -// given |session|. Returns true on success, false on error or if no such -// table is found. On success the table will be returned via |table|. -bool FindTable(REFIID iid, IDiaSession* session, void** table); - -// A templated version of FindTable. Finds the first table implementing type -// |InterfaceType| in the given |session|. Returns true on success, false on -// error or if no such table is found. On success the table will be returned via -// |table|. -template<typename InterfaceType> -bool FindTable(IDiaSession* session, InterfaceType** table) { - return FindTable(__uuidof(InterfaceType), - session, - reinterpret_cast<void**>(table)); -} - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_DIA_UTIL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc deleted file mode 100644 index b7f877e66..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2006, 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. - -// guid_string.cc: Convert GUIDs to strings. -// -// See guid_string.h for documentation. - -#include <wchar.h> - -#include "common/windows/string_utils-inl.h" - -#include "common/windows/guid_string.h" - -namespace google_breakpad { - -// static -wstring GUIDString::GUIDToWString(GUID *guid) { - wchar_t guid_string[37]; - swprintf( - guid_string, sizeof(guid_string) / sizeof(guid_string[0]), - L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], - guid->Data4[3], guid->Data4[4], guid->Data4[5], - guid->Data4[6], guid->Data4[7]); - - // remove when VC++7.1 is no longer supported - guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; - - return wstring(guid_string); -} - -// static -wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) { - wchar_t guid_string[33]; - swprintf( - guid_string, sizeof(guid_string) / sizeof(guid_string[0]), - L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], - guid->Data4[3], guid->Data4[4], guid->Data4[5], - guid->Data4[6], guid->Data4[7]); - - // remove when VC++7.1 is no longer supported - guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; - - return wstring(guid_string); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h deleted file mode 100644 index 48a5c1d37..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2006, 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. - -// guid_string.cc: Convert GUIDs to strings. - -#ifndef COMMON_WINDOWS_GUID_STRING_H_ -#define COMMON_WINDOWS_GUID_STRING_H_ - -#include <guiddef.h> - -#include <string> - -namespace google_breakpad { - -using std::wstring; - -class GUIDString { - public: - // Converts guid to a string in the format recommended by RFC 4122 and - // returns the string. - static wstring GUIDToWString(GUID *guid); - - // Converts guid to a string formatted as uppercase hexadecimal, with - // no separators, and returns the string. This is the format used for - // symbol server identifiers, although identifiers have an age tacked - // on to the string. - static wstring GUIDToSymbolServerWString(GUID *guid); -}; - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_GUID_STRING_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc deleted file mode 100644 index 7676bdc5a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright (c) 2006, 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 <assert.h> - -// Disable exception handler warnings. -#pragma warning(disable:4530) - -#include <fstream> - -#include "common/windows/string_utils-inl.h" - -#include "common/windows/http_upload.h" - -namespace google_breakpad { - -using std::ifstream; -using std::ios; - -static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)"; - -// Helper class which closes an internet handle when it goes away -class HTTPUpload::AutoInternetHandle { - public: - explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {} - ~AutoInternetHandle() { - if (handle_) { - InternetCloseHandle(handle_); - } - } - - HINTERNET get() { return handle_; } - - private: - HINTERNET handle_; -}; - -// static -bool HTTPUpload::SendRequest(const wstring &url, - const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - int *timeout, - wstring *response_body, - int *response_code) { - if (response_code) { - *response_code = 0; - } - - // TODO(bryner): support non-ASCII parameter names - if (!CheckParameters(parameters)) { - return false; - } - - // Break up the URL and make sure we can handle it - wchar_t scheme[16], host[256], path[256]; - URL_COMPONENTS components; - memset(&components, 0, sizeof(components)); - components.dwStructSize = sizeof(components); - components.lpszScheme = scheme; - components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]); - components.lpszHostName = host; - components.dwHostNameLength = sizeof(host) / sizeof(host[0]); - components.lpszUrlPath = path; - components.dwUrlPathLength = sizeof(path) / sizeof(path[0]); - if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()), - 0, &components)) { - return false; - } - bool secure = false; - if (wcscmp(scheme, L"https") == 0) { - secure = true; - } else if (wcscmp(scheme, L"http") != 0) { - return false; - } - - AutoInternetHandle internet(InternetOpen(kUserAgent, - INTERNET_OPEN_TYPE_PRECONFIG, - NULL, // proxy name - NULL, // proxy bypass - 0)); // flags - if (!internet.get()) { - return false; - } - - AutoInternetHandle connection(InternetConnect(internet.get(), - host, - components.nPort, - NULL, // user name - NULL, // password - INTERNET_SERVICE_HTTP, - 0, // flags - NULL)); // context - if (!connection.get()) { - return false; - } - - DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0; - http_open_flags |= INTERNET_FLAG_NO_COOKIES; - AutoInternetHandle request(HttpOpenRequest(connection.get(), - L"POST", - path, - NULL, // version - NULL, // referer - NULL, // agent type - http_open_flags, - NULL)); // context - if (!request.get()) { - return false; - } - - wstring boundary = GenerateMultipartBoundary(); - wstring content_type_header = GenerateRequestHeader(boundary); - HttpAddRequestHeaders(request.get(), - content_type_header.c_str(), - static_cast<DWORD>(-1), - HTTP_ADDREQ_FLAG_ADD); - - string request_body; - if (!GenerateRequestBody(parameters, files, boundary, &request_body)) { - return false; - } - - if (timeout) { - if (!InternetSetOption(request.get(), - INTERNET_OPTION_SEND_TIMEOUT, - timeout, - sizeof(*timeout))) { - fwprintf(stderr, L"Could not unset send timeout, continuing...\n"); - } - - if (!InternetSetOption(request.get(), - INTERNET_OPTION_RECEIVE_TIMEOUT, - timeout, - sizeof(*timeout))) { - fwprintf(stderr, L"Could not unset receive timeout, continuing...\n"); - } - } - - if (!HttpSendRequest(request.get(), NULL, 0, - const_cast<char *>(request_body.data()), - static_cast<DWORD>(request_body.size()))) { - return false; - } - - // The server indicates a successful upload with HTTP status 200. - wchar_t http_status[4]; - DWORD http_status_size = sizeof(http_status); - if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE, - static_cast<LPVOID>(&http_status), &http_status_size, - 0)) { - return false; - } - - int http_response = wcstol(http_status, NULL, 10); - if (response_code) { - *response_code = http_response; - } - - bool result = (http_response == 200); - - if (result) { - result = ReadResponse(request.get(), response_body); - } - - return result; -} - -// static -bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) { - bool has_content_length_header = false; - wchar_t content_length[32]; - DWORD content_length_size = sizeof(content_length); - DWORD claimed_size = 0; - string response_body; - - if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH, - static_cast<LPVOID>(&content_length), - &content_length_size, 0)) { - has_content_length_header = true; - claimed_size = wcstol(content_length, NULL, 10); - response_body.reserve(claimed_size); - } - - - DWORD bytes_available; - DWORD total_read = 0; - BOOL return_code; - - while (((return_code = InternetQueryDataAvailable(request, &bytes_available, - 0, 0)) != 0) && bytes_available > 0) { - vector<char> response_buffer(bytes_available); - DWORD size_read; - - return_code = InternetReadFile(request, - &response_buffer[0], - bytes_available, &size_read); - - if (return_code && size_read > 0) { - total_read += size_read; - response_body.append(&response_buffer[0], size_read); - } else { - break; - } - } - - bool succeeded = return_code && (!has_content_length_header || - (total_read == claimed_size)); - if (succeeded && response) { - *response = UTF8ToWide(response_body); - } - - return succeeded; -} - -// static -wstring HTTPUpload::GenerateMultipartBoundary() { - // The boundary has 27 '-' characters followed by 16 hex digits - static const wchar_t kBoundaryPrefix[] = L"---------------------------"; - static const int kBoundaryLength = 27 + 16 + 1; - - // Generate some random numbers to fill out the boundary - int r0 = rand(); - int r1 = rand(); - - wchar_t temp[kBoundaryLength]; - swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1); - - // remove when VC++7.1 is no longer supported - temp[kBoundaryLength - 1] = L'\0'; - - return wstring(temp); -} - -// static -wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) { - wstring header = L"Content-Type: multipart/form-data; boundary="; - header += boundary; - return header; -} - -// static -bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - const wstring &boundary, - string *request_body) { - string boundary_str = WideToUTF8(boundary); - if (boundary_str.empty()) { - return false; - } - - request_body->clear(); - - // Append each of the parameter pairs as a form-data part - for (map<wstring, wstring>::const_iterator pos = parameters.begin(); - pos != parameters.end(); ++pos) { - request_body->append("--" + boundary_str + "\r\n"); - request_body->append("Content-Disposition: form-data; name=\"" + - WideToUTF8(pos->first) + "\"\r\n\r\n" + - WideToUTF8(pos->second) + "\r\n"); - } - - for (map<wstring, wstring>::const_iterator pos = files.begin(); - pos != files.end(); ++pos) { - vector<char> contents; - if (!GetFileContents(pos->second, &contents)) { - return false; - } - - // Now append the upload files as a binary (octet-stream) part - string filename_utf8 = WideToUTF8(pos->second); - if (filename_utf8.empty()) { - return false; - } - - string file_part_name_utf8 = WideToUTF8(pos->first); - if (file_part_name_utf8.empty()) { - return false; - } - - request_body->append("--" + boundary_str + "\r\n"); - 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 (!contents.empty()) { - request_body->append(&(contents[0]), contents.size()); - } - request_body->append("\r\n"); - } - request_body->append("--" + boundary_str + "--\r\n"); - return true; -} - -// static -bool HTTPUpload::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 - // later, _wfopen has been deprecated in favor of _wfopen_s, which does - // not exist in earlier versions, so let the ifstream open the file itself. - // GCC doesn't support wide file name and opening on FILE* requires ugly - // hacks, so fallback to multi byte file. -#ifdef _MSC_VER - ifstream file; - file.open(filename.c_str(), ios::binary); -#else // GCC - ifstream file(WideToMBCP(filename, CP_ACP).c_str(), ios::binary); -#endif // _MSC_VER >= 1400 - if (file.is_open()) { - file.seekg(0, ios::end); - std::streamoff length = file.tellg(); - // Check for loss of data when converting lenght from std::streamoff into - // std::vector<char>::size_type - std::vector<char>::size_type vector_size = - static_cast<std::vector<char>::size_type>(length); - if (static_cast<std::streamoff>(vector_size) == length) { - contents->resize(vector_size); - if (length != 0) { - file.seekg(0, ios::beg); - file.read(&((*contents)[0]), length); - } - rv = true; - } - file.close(); - } - return rv; -} - -// static -wstring HTTPUpload::UTF8ToWide(const string &utf8) { - if (utf8.length() == 0) { - return wstring(); - } - - // compute the length of the buffer we'll need - int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0); - - if (charcount == 0) { - return wstring(); - } - - // convert - wchar_t* buf = new wchar_t[charcount]; - MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount); - wstring result(buf); - delete[] buf; - return result; -} - -// static -string HTTPUpload::WideToMBCP(const wstring &wide, unsigned int cp) { - if (wide.length() == 0) { - return string(); - } - - // compute the length of the buffer we'll need - int charcount = WideCharToMultiByte(cp, 0, wide.c_str(), -1, - NULL, 0, NULL, NULL); - if (charcount == 0) { - return string(); - } - - // convert - char *buf = new char[charcount]; - WideCharToMultiByte(cp, 0, wide.c_str(), -1, buf, charcount, - NULL, NULL); - - string result(buf); - delete[] buf; - return result; -} - -// static -bool HTTPUpload::CheckParameters(const map<wstring, wstring> ¶meters) { - for (map<wstring, wstring>::const_iterator pos = parameters.begin(); - pos != parameters.end(); ++pos) { - const wstring &str = pos->first; - if (str.size() == 0) { - return false; // disallow empty parameter names - } - for (unsigned int i = 0; i < str.size(); ++i) { - wchar_t c = str[i]; - if (c < 32 || c == '"' || c > 127) { - return false; - } - } - } - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h deleted file mode 100644 index f8d48cb1b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2006, 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. - -// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST -// request using wininet. It currently supports requests that contain -// a set of string parameters (key/value pairs), and a file to upload. - -#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H_ -#define COMMON_WINDOWS_HTTP_UPLOAD_H_ - -#pragma warning(push) -// Disable exception handler warnings. -#pragma warning(disable : 4530) - -#include <windows.h> -#include <wininet.h> - -#include <map> -#include <string> -#include <vector> - -namespace google_breakpad { - -using std::string; -using std::wstring; -using std::map; -using std::vector; - -class HTTPUpload { - public: - // Sends the given sets of parameters and files as a multipart POST - // request to the given URL. - // Each key in |files| is the name of the file part of the request - // (i.e. it corresponds to the name= attribute on an <input type="file">. - // Parameter names must contain only printable ASCII characters, - // and may not contain a quote (") character. - // Only HTTP(S) URLs are currently supported. Returns true on success. - // If the request is successful and response_body is non-NULL, - // the response body will be returned in response_body. - // If response_code is non-NULL, it will be set to the HTTP response code - // received (or 0 if the request failed before getting an HTTP response). - static bool SendRequest(const wstring &url, - const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - int *timeout, - wstring *response_body, - int *response_code); - - private: - class AutoInternetHandle; - - // Retrieves the HTTP response. If NULL is passed in for response, - // this merely checks (via the return value) that we were successfully - // able to retrieve exactly as many bytes of content in the response as - // were specified in the Content-Length header. - static bool ReadResponse(HINTERNET request, wstring* response); - - // Generates a new multipart boundary for a POST request - static wstring GenerateMultipartBoundary(); - - // Generates a HTTP request header for a multipart form submit. - static wstring GenerateRequestHeader(const wstring &boundary); - - // Given a set of parameters, a set of upload files, and a file part name, - // generates a multipart request body string with these parameters - // and minidump contents. Returns true on success. - static bool GenerateRequestBody(const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - const wstring &boundary, - string *request_body); - - // Fills the supplied vector with the contents of filename. - static bool GetFileContents(const wstring &filename, vector<char> *contents); - - // Converts a UTF8 string to UTF16. - static wstring UTF8ToWide(const string &utf8); - - // Converts a UTF16 string to UTF8. - static string WideToUTF8(const wstring &wide) { - return WideToMBCP(wide, CP_UTF8); - } - - // Converts a UTF16 string to specified code page. - static string WideToMBCP(const wstring &wide, unsigned int cp); - - // Checks that the given list of parameters has only printable - // ASCII characters in the parameter name, and does not contain - // any quote (") characters. Returns true if so. - static bool CheckParameters(const map<wstring, wstring> ¶meters); - - // No instances of this class should be created. - // Disallow all constructors, destructors, and operator=. - HTTPUpload(); - explicit HTTPUpload(const HTTPUpload &); - void operator=(const HTTPUpload &); - ~HTTPUpload(); -}; - -} // namespace google_breakpad - -#pragma warning(pop) - -#endif // COMMON_WINDOWS_HTTP_UPLOAD_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild b/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild deleted file mode 100644 index 5fcdae5a3..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -lobjs_common = [ - 'guid_string.cc', - 'string_utils.cc', -] - -subdir = 'toolkit/crashreporter/google-breakpad/src/common/windows' -objs_common = [ - '/%s/%s' % (subdir, s) for s in lobjs_common -] diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc deleted file mode 100644 index 554a57c2d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc +++ /dev/null @@ -1,694 +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. - -// This contains a suite of tools for transforming symbol information when -// when that information has been extracted from a PDB containing OMAP -// information. - -// OMAP information is a lightweight description of a mapping between two -// address spaces. It consists of two streams, each of them a vector 2-tuples. -// The OMAPTO stream contains tuples of the form -// -// (RVA in transformed image, RVA in original image) -// -// while the OMAPFROM stream contains tuples of the form -// -// (RVA in original image, RVA in transformed image) -// -// The entries in each vector are sorted by the first value of the tuple, and -// the lengths associated with a mapping are implicit as the distance between -// two successive addresses in the vector. - -// Consider a trivial 10-byte function described by the following symbol: -// -// Function: RVA 0x00001000, length 10, "foo" -// -// Now consider the same function, but with 5-bytes of instrumentation injected -// at offset 5. The OMAP streams describing this would look like: -// -// OMAPTO : [ [0x00001000, 0x00001000], -// [0x00001005, 0xFFFFFFFF], -// [0x0000100a, 0x00001005] ] -// OMAPFROM: [ [0x00001000, 0x00001000], -// [0x00001005, 0x0000100a] ] -// -// In this case the injected code has been marked as not originating in the -// source image, and thus it will have no symbol information at all. However, -// the injected code may also be associated with an original address range; -// for example, when prepending instrumentation to a basic block the -// instrumentation can be labelled as originating from the same source BB such -// that symbol resolution will still find the appropriate source code line -// number. In this case the OMAP stream would look like: -// -// OMAPTO : [ [0x00001000, 0x00001000], -// [0x00001005, 0x00001005], -// [0x0000100a, 0x00001005] ] -// OMAPFROM: [ [0x00001000, 0x00001000], -// [0x00001005, 0x0000100a] ] -// -// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the -// instrumented image. It would first run this through the OMAPTO table and -// translate that address to 0x00001005. It would then lookup the symbol -// at that address and return the symbol for the function "foo". This is the -// correct result. -// -// However, if we query DIA for the length and address of the symbol it will -// tell us that it has length 10 and is at RVA 0x00001000. The location is -// correct, but the length doesn't take into account the 5-bytes of injected -// code. Symbol resolution works (starting from an instrumented address, -// mapping to an original address, and looking up a symbol), but the symbol -// metadata is incorrect. -// -// If we dump the symbols using DIA they will have their addresses -// appropriately transformed and reflect positions in the instrumented image. -// However, if we try to do a lookup using those symbols resolution can fail. -// For example, the address 0x0000100a will not map to the symbol for "foo", -// because DIA tells us it is at location 0x00001000 (correct) with length -// 10 (incorrect). The problem is one of order of operations: in this case -// we're attempting symbol resolution by looking up an instrumented address -// in the table of translated symbols. -// -// One way to handle this is to dump the OMAP information as part of the -// breakpad symbols. This requires the rest of the toolchain to be aware of -// OMAP information and to use it when present prior to performing lookup. The -// other option is to properly transform the symbols (updating length as well as -// position) so that resolution will work as expected for translated addresses. -// This is transparent to the rest of the toolchain. - -#include "common/windows/omap.h" - -#include <atlbase.h> - -#include <algorithm> -#include <cassert> -#include <set> - -#include "common/windows/dia_util.h" - -namespace google_breakpad { - -namespace { - -static const wchar_t kOmapToDebugStreamName[] = L"OMAPTO"; -static const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM"; - -// Dependending on where this is used in breakpad we sometimes get min/max from -// windef, and other times from algorithm. To get around this we simply -// define our own min/max functions. -template<typename T> -const T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; } -template<typename T> -const T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; } - -// It makes things more readable to have two different OMAP types. We cast -// normal OMAPs into these. They must be the same size as the OMAP structure -// for this to work, hence the static asserts. -struct OmapOrigToTran { - DWORD rva_original; - DWORD rva_transformed; -}; -struct OmapTranToOrig { - DWORD rva_transformed; - DWORD rva_original; -}; -static_assert(sizeof(OmapOrigToTran) == sizeof(OMAP), - "OmapOrigToTran must have same size as OMAP."); -static_assert(sizeof(OmapTranToOrig) == sizeof(OMAP), - "OmapTranToOrig must have same size as OMAP."); -typedef std::vector<OmapOrigToTran> OmapFromTable; -typedef std::vector<OmapTranToOrig> OmapToTable; - -// Used for sorting and searching through a Mapping. -bool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) { - if (lhs.rva_original < rhs.rva_original) - return true; - if (lhs.rva_original > rhs.rva_original) - return false; - return lhs.length < rhs.length; -} -bool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) { - if (lhs.rva_transformed < rhs.rva_transformed) - return true; - if (lhs.rva_transformed > rhs.rva_transformed) - return false; - return lhs.length < rhs.length; -} - -// Used for searching through the EndpointIndexMap. -bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) { - return ei1.endpoint < ei2.endpoint; -} - -// Finds the debug stream with the given |name| in the given |session|, and -// populates |table| with its contents. Casts the data directly into OMAP -// structs. -bool FindAndLoadOmapTable(const wchar_t* name, - IDiaSession* session, - OmapTable* table) { - assert(name != NULL); - assert(session != NULL); - assert(table != NULL); - - CComPtr<IDiaEnumDebugStreamData> stream; - if (!FindDebugStream(name, session, &stream)) - return false; - assert(stream.p != NULL); - - LONG count = 0; - if (FAILED(stream->get_Count(&count))) { - fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream " - "\"%ws\"\n", name); - return false; - } - - // Get the length of the stream in bytes. - DWORD bytes_read = 0; - ULONG count_read = 0; - if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) { - fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " - "length of stream \"%ws\"\n", name); - return false; - } - - // Ensure it's consistent with the OMAP data type. - DWORD bytes_expected = count * sizeof(OmapTable::value_type); - if (count * sizeof(OmapTable::value_type) != bytes_read) { - fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name); - return false; - } - - // Read the table. - table->resize(count); - bytes_read = 0; - count_read = 0; - if (FAILED(stream->Next(count, bytes_expected, &bytes_read, - reinterpret_cast<BYTE*>(&table->at(0)), - &count_read))) { - fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " - "data from stream \"%ws\"\n", name); - return false; - } - - return true; -} - -// This determines the original image length by looking through the segment -// table. -bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { - assert(session != NULL); - assert(image_length != NULL); - - CComPtr<IDiaEnumSegments> enum_segments; - if (!FindTable(session, &enum_segments)) - return false; - assert(enum_segments.p != NULL); - - DWORD temp_image_length = 0; - CComPtr<IDiaSegment> segment; - ULONG fetched = 0; - while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) && - fetched == 1) { - assert(segment.p != NULL); - - DWORD rva = 0; - DWORD length = 0; - DWORD frame = 0; - if (FAILED(segment->get_relativeVirtualAddress(&rva)) || - FAILED(segment->get_length(&length)) || - FAILED(segment->get_frame(&frame))) { - fprintf(stderr, "Failed to get basic properties for IDiaSegment\n"); - return false; - } - - if (frame > 0) { - DWORD segment_end = rva + length; - if (segment_end > temp_image_length) - temp_image_length = segment_end; - } - segment.Release(); - } - - *image_length = temp_image_length; - return true; -} - -// Detects regions of the original image that have been removed in the -// transformed image, and sets the 'removed' property on all mapped ranges -// immediately preceding a gap. The mapped ranges must be sorted by -// 'rva_original'. -void FillInRemovedLengths(Mapping* mapping) { - assert(mapping != NULL); - - // Find and fill gaps. We do this with two sweeps. We first sweep forward - // looking for gaps. When we identify a gap we then sweep forward with a - // second scan and set the 'removed' property for any intervals that - // immediately precede the gap. - // - // Gaps are typically between two successive intervals, but not always: - // - // Range 1: --------------- - // Range 2: ------- - // Range 3: ------------- - // Gap : ****** - // - // In the above example the gap is between range 1 and range 3. A forward - // sweep finds the gap, and a second forward sweep identifies that range 1 - // immediately precedes the gap and sets its 'removed' property. - - size_t fill = 0; - DWORD rva_front = 0; - for (size_t find = 0; find < mapping->size(); ++find) { -#ifndef NDEBUG - // We expect the mapped ranges to be sorted by 'rva_original'. - if (find > 0) { - assert(mapping->at(find - 1).rva_original <= - mapping->at(find).rva_original); - } -#endif - - if (rva_front < mapping->at(find).rva_original) { - // We've found a gap. Fill it in by setting the 'removed' property for - // any affected intervals. - DWORD removed = mapping->at(find).rva_original - rva_front; - for (; fill < find; ++fill) { - if (mapping->at(fill).rva_original + mapping->at(fill).length != - rva_front) { - continue; - } - - // This interval ends right where the gap starts. It needs to have its - // 'removed' information filled in. - mapping->at(fill).removed = removed; - } - } - - // Advance the front that indicates the covered portion of the image. - rva_front = mapping->at(find).rva_original + mapping->at(find).length; - } -} - -// Builds a unified view of the mapping between the original and transformed -// image space by merging OMAPTO and OMAPFROM data. -void BuildMapping(const OmapData& omap_data, Mapping* mapping) { - assert(mapping != NULL); - - mapping->clear(); - - if (omap_data.omap_from.empty() || omap_data.omap_to.empty()) - return; - - // The names 'omap_to' and 'omap_from' are awfully confusing, so we make - // ourselves more explicit here. This cast is only safe because the underlying - // types have the exact same size. - const OmapToTable& tran2orig = - reinterpret_cast<const OmapToTable&>(omap_data.omap_to); - const OmapFromTable& orig2tran = reinterpret_cast<const OmapFromTable&>( - omap_data.omap_from); - - // Handle the range of data at the beginning of the image. This is not usually - // specified by the OMAP data. - if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) { - DWORD header_transformed = tran2orig[0].rva_transformed; - DWORD header_original = orig2tran[0].rva_original; - DWORD header = Min(header_transformed, header_original); - - MappedRange mr = {}; - mr.length = header; - mr.injected = header_transformed - header; - mr.removed = header_original - header; - mapping->push_back(mr); - } - - // Convert the implied lengths to explicit lengths, and infer which content - // has been injected into the transformed image. Injected content is inferred - // as regions of the transformed address space that does not map back to - // known valid content in the original image. - for (size_t i = 0; i < tran2orig.size(); ++i) { - const OmapTranToOrig& o1 = tran2orig[i]; - - // This maps to content that is outside the original image, thus it - // describes injected content. We can skip this entry. - if (o1.rva_original >= omap_data.length_original) - continue; - - // Calculate the length of the current OMAP entry. This is implicit as the - // distance between successive |rva| values, capped at the end of the - // original image. - DWORD length = 0; - if (i + 1 < tran2orig.size()) { - const OmapTranToOrig& o2 = tran2orig[i + 1]; - - // We expect the table to be sorted by rva_transformed. - assert(o1.rva_transformed <= o2.rva_transformed); - - length = o2.rva_transformed - o1.rva_transformed; - if (o1.rva_original + length > omap_data.length_original) { - length = omap_data.length_original - o1.rva_original; - } - } else { - length = omap_data.length_original - o1.rva_original; - } - - // Zero-length entries don't describe anything and can be ignored. - if (length == 0) - continue; - - // Any gaps in the transformed address-space are due to injected content. - if (!mapping->empty()) { - MappedRange& prev_mr = mapping->back(); - prev_mr.injected += o1.rva_transformed - - (prev_mr.rva_transformed + prev_mr.length); - } - - MappedRange mr = {}; - mr.rva_original = o1.rva_original; - mr.rva_transformed = o1.rva_transformed; - mr.length = length; - mapping->push_back(mr); - } - - // Sort based on the original image addresses. - std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess); - - // Fill in the 'removed' lengths by looking for gaps in the coverage of the - // original address space. - FillInRemovedLengths(mapping); - - return; -} - -void BuildEndpointIndexMap(ImageMap* image_map) { - assert(image_map != NULL); - - if (image_map->mapping.size() == 0) - return; - - const Mapping& mapping = image_map->mapping; - EndpointIndexMap& eim = image_map->endpoint_index_map; - - // Get the unique set of interval endpoints. - std::set<DWORD> endpoints; - for (size_t i = 0; i < mapping.size(); ++i) { - endpoints.insert(mapping[i].rva_original); - endpoints.insert(mapping[i].rva_original + - mapping[i].length + - mapping[i].removed); - } - - // Use the endpoints to initialize the secondary search structure for the - // mapping. - eim.resize(endpoints.size()); - std::set<DWORD>::const_iterator it = endpoints.begin(); - for (size_t i = 0; it != endpoints.end(); ++it, ++i) { - eim[i].endpoint = *it; - eim[i].index = mapping.size(); - } - - // For each endpoint we want the smallest index of any interval containing - // it. We iterate over the intervals and update the indices associated with - // each interval endpoint contained in the current interval. In the general - // case of an arbitrary set of intervals this is O(n^2), but the structure of - // OMAP data makes this O(n). - for (size_t i = 0; i < mapping.size(); ++i) { - EndpointIndex ei1 = { mapping[i].rva_original, 0 }; - EndpointIndexMap::iterator it1 = std::lower_bound( - eim.begin(), eim.end(), ei1, EndpointIndexLess); - - EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length + - mapping[i].removed, 0 }; - EndpointIndexMap::iterator it2 = std::lower_bound( - eim.begin(), eim.end(), ei2, EndpointIndexLess); - - for (; it1 != it2; ++it1) - it1->index = Min(i, it1->index); - } -} - -// Clips the given mapped range. -void ClipMappedRangeOriginal(const AddressRange& clip_range, - MappedRange* mapped_range) { - assert(mapped_range != NULL); - - // The clipping range is entirely outside of the mapped range. - if (clip_range.end() <= mapped_range->rva_original || - mapped_range->rva_original + mapped_range->length + - mapped_range->removed <= clip_range.rva) { - mapped_range->length = 0; - mapped_range->injected = 0; - mapped_range->removed = 0; - return; - } - - // Clip the left side. - if (mapped_range->rva_original < clip_range.rva) { - DWORD clip_left = clip_range.rva - mapped_range->rva_original; - mapped_range->rva_original += clip_left; - mapped_range->rva_transformed += clip_left; - - if (clip_left > mapped_range->length) { - // The left clipping boundary entirely erases the content section of the - // range. - DWORD trim = clip_left - mapped_range->length; - mapped_range->length = 0; - mapped_range->injected -= Min(trim, mapped_range->injected); - // We know that trim <= mapped_range->remove. - mapped_range->removed -= trim; - } else { - // The left clipping boundary removes some, but not all, of the content. - // As such it leaves the removed/injected component intact. - mapped_range->length -= clip_left; - } - } - - // Clip the right side. - DWORD end_original = mapped_range->rva_original + mapped_range->length; - if (clip_range.end() < end_original) { - // The right clipping boundary lands in the 'content' section of the range, - // entirely clearing the injected/removed portion. - DWORD clip_right = end_original - clip_range.end(); - mapped_range->length -= clip_right; - mapped_range->injected = 0; - mapped_range->removed = 0; - return; - } else { - // The right clipping boundary is outside of the content, but may affect - // the removed/injected portion of the range. - DWORD end_removed = end_original + mapped_range->removed; - if (clip_range.end() < end_removed) - mapped_range->removed = clip_range.end() - end_original; - - DWORD end_injected = end_original + mapped_range->injected; - if (clip_range.end() < end_injected) - mapped_range->injected = clip_range.end() - end_original; - } - - return; -} - -} // namespace - -int AddressRange::Compare(const AddressRange& rhs) const { - if (end() <= rhs.rva) - return -1; - if (rhs.end() <= rva) - return 1; - return 0; -} - -bool GetOmapDataAndDisableTranslation(IDiaSession* session, - OmapData* omap_data) { - assert(session != NULL); - assert(omap_data != NULL); - - CComPtr<IDiaAddressMap> address_map; - if (FAILED(session->QueryInterface(&address_map))) { - fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n"); - return false; - } - assert(address_map.p != NULL); - - BOOL omap_enabled = FALSE; - if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) { - fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n"); - return false; - } - - if (!omap_enabled) { - // We indicate the non-presence of OMAP data by returning empty tables. - omap_data->omap_from.clear(); - omap_data->omap_to.clear(); - omap_data->length_original = 0; - return true; - } - - // OMAP data is present. Disable translation. - if (FAILED(address_map->put_addressMapEnabled(FALSE))) { - fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n"); - return false; - } - - // Read the OMAP streams. - if (!FindAndLoadOmapTable(kOmapFromDebugStreamName, - session, - &omap_data->omap_from)) { - return false; - } - if (!FindAndLoadOmapTable(kOmapToDebugStreamName, - session, - &omap_data->omap_to)) { - return false; - } - - // Get the lengths of the address spaces. - if (!GetOriginalImageLength(session, &omap_data->length_original)) - return false; - - return true; -} - -void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { - assert(image_map != NULL); - - BuildMapping(omap_data, &image_map->mapping); - BuildEndpointIndexMap(image_map); -} - -void MapAddressRange(const ImageMap& image_map, - const AddressRange& original_range, - AddressRangeVector* mapped_ranges) { - assert(mapped_ranges != NULL); - - const Mapping& map = image_map.mapping; - - // Handle the trivial case of an empty image_map. This means that there is - // no transformation to be applied, and we can simply return the original - // range. - if (map.empty()) { - mapped_ranges->push_back(original_range); - return; - } - - // If we get a query of length 0 we need to handle it by using a non-zero - // query length. - AddressRange query_range(original_range); - if (query_range.length == 0) - query_range.length = 1; - - // Find the range of intervals that can potentially intersect our query range. - size_t imin = 0; - size_t imax = 0; - { - // The index of the earliest possible range that can affect is us done by - // searching through the secondary indexing structure. - const EndpointIndexMap& eim = image_map.endpoint_index_map; - EndpointIndex q1 = { query_range.rva, 0 }; - EndpointIndexMap::const_iterator it1 = std::lower_bound( - eim.begin(), eim.end(), q1, EndpointIndexLess); - if (it1 == eim.end()) { - imin = map.size(); - } else { - // Backup to find the interval that contains our query point. - if (it1 != eim.begin() && query_range.rva < it1->endpoint) - --it1; - imin = it1->index; - } - - // The first range that can't possibly intersect us is found by searching - // through the image map directly as it is already sorted by interval start - // point. - MappedRange q2 = { query_range.end(), 0 }; - Mapping::const_iterator it2 = std::lower_bound( - map.begin(), map.end(), q2, MappedRangeOriginalLess); - imax = it2 - map.begin(); - } - - // Find all intervals that intersect the query range. - Mapping temp_map; - for (size_t i = imin; i < imax; ++i) { - MappedRange mr = map[i]; - ClipMappedRangeOriginal(query_range, &mr); - if (mr.length + mr.injected > 0) - temp_map.push_back(mr); - } - - // If there are no intersecting ranges then the query range has been removed - // from the image in question. - if (temp_map.empty()) - return; - - // Sort based on transformed addresses. - std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess); - - // Zero-length queries can't actually be merged. We simply output the set of - // unique RVAs that correspond to the query RVA. - if (original_range.length == 0) { - mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0)); - for (size_t i = 1; i < temp_map.size(); ++i) { - if (temp_map[i].rva_transformed > mapped_ranges->back().rva) - mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0)); - } - return; - } - - // Merge any ranges that are consecutive in the mapped image. We merge over - // injected content if it makes ranges contiguous, but we ignore any injected - // content at the tail end of a range. This allows us to detect symbols that - // have been lengthened by injecting content in the middle. However, it - // misses the case where content has been injected at the head or the tail. - // The problem is that it doesn't know whether to attribute it to the - // preceding or following symbol. It is up to the author of the transform to - // output explicit OMAP info in these cases to ensure full coverage of the - // transformed address space. - DWORD rva_begin = temp_map[0].rva_transformed; - DWORD rva_cur_content = rva_begin + temp_map[0].length; - DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected; - for (size_t i = 1; i < temp_map.size(); ++i) { - if (rva_cur_injected < temp_map[i].rva_transformed) { - // This marks the end of a continuous range in the image. Output the - // current range and start a new one. - if (rva_begin < rva_cur_content) { - mapped_ranges->push_back( - AddressRange(rva_begin, rva_cur_content - rva_begin)); - } - rva_begin = temp_map[i].rva_transformed; - } - - rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length; - rva_cur_injected = rva_cur_content + temp_map[i].injected; - } - - // Output the range in progress. - if (rva_begin < rva_cur_content) { - mapped_ranges->push_back( - AddressRange(rva_begin, rva_cur_content - rva_begin)); - } - - return; -} - -} // namespace google_breakpad
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h deleted file mode 100644 index bc293afb5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h +++ /dev/null @@ -1,72 +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. - -// Provides an API for mapping symbols through OMAP information, if a PDB file -// is augmented with it. This allows breakpad to work with addresses in -// transformed images by transforming the symbols themselves, rather than -// transforming addresses prior to querying symbols (the way it is typically -// done by Windows-native tools, including the DIA). - -#ifndef COMMON_WINDOWS_OMAP_H_ -#define COMMON_WINDOWS_OMAP_H_ - -#include "common/windows/omap_internal.h" - -namespace google_breakpad { - -// If the given session contains OMAP data this extracts it, populating -// |omap_data|, and then disabling automatic translation for the session. -// OMAP data is present in the PDB if |omap_data| is not empty. This returns -// true on success, false otherwise. -bool GetOmapDataAndDisableTranslation(IDiaSession* dia_session, - OmapData* omap_data); - -// Given raw OMAP data builds an ImageMap. This can be used to query individual -// image ranges using MapAddressRange. -// |omap_data|| is the OMAP data extracted from the PDB. -// |image_map| will be populated with a description of the image mapping. If -// |omap_data| is empty then this will also be empty. -void BuildImageMap(const OmapData& omap_data, ImageMap* image_map); - -// Given an address range in the original image space determines how exactly it -// has been tranformed. -// |omap_data| is the OMAP data extracted from the PDB, which must not be -// empty. -// |original_range| is the address range in the original image being queried. -// |mapped_ranges| will be populated with a full description of the mapping. -// They may be disjoint in the transformed image so a vector is needed to -// fully represent the mapping. This will be appended to if it is not -// empty. If |omap_data| is empty then |mapped_ranges| will simply be -// populated with a copy of |original_range| (the identity transform). -void MapAddressRange(const ImageMap& image_map, - const AddressRange& original_range, - AddressRangeVector* mapped_ranges); - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_OMAP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h deleted file mode 100644 index 3f904d7a7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h +++ /dev/null @@ -1,137 +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. - -// Declares internal implementation details for functionality in omap.h and -// omap.cc. - -#ifndef COMMON_WINDOWS_OMAP_INTERNAL_H_ -#define COMMON_WINDOWS_OMAP_INTERNAL_H_ - -#include <windows.h> -#include <dia2.h> - -#include <vector> - -namespace google_breakpad { - -// The OMAP struct is defined by debughlp.h, which doesn't play nicely with -// imagehlp.h. We simply redefine it. -struct OMAP { - DWORD rva; - DWORD rvaTo; -}; -static_assert(sizeof(OMAP) == 8, "Wrong size for OMAP structure."); -typedef std::vector<OMAP> OmapTable; - -// This contains the OMAP data extracted from an image. -struct OmapData { - // The table of OMAP entries describing the transformation from the - // original image to the transformed image. - OmapTable omap_from; - // The table of OMAP entries describing the transformation from the - // instrumented image to the original image. - OmapTable omap_to; - // The length of the original untransformed image. - DWORD length_original; - - OmapData() : length_original(0) { } -}; - -// This represents a range of addresses in an image. -struct AddressRange { - DWORD rva; - DWORD length; - - AddressRange() : rva(0), length(0) { } - AddressRange(DWORD rva, DWORD length) : rva(rva), length(length) { } - - // Returns the end address of this range. - DWORD end() const { return rva + length; } - - // Addreses only compare as less-than or greater-than if they are not - // overlapping. Otherwise, they compare equal. - int Compare(const AddressRange& rhs) const; - bool operator<(const AddressRange& rhs) const { return Compare(rhs) == -1; } - bool operator>(const AddressRange& rhs) const { return Compare(rhs) == 1; } - - // Equality operators compare exact values. - bool operator==(const AddressRange& rhs) const { - return rva == rhs.rva && length == rhs.length; - } - bool operator!=(const AddressRange& rhs) const { return !((*this) == rhs); } -}; - -typedef std::vector<AddressRange> AddressRangeVector; - -// This represents an address range in an original image, and its corresponding -// range in the transformed image. -struct MappedRange { - // An address in the original image. - DWORD rva_original; - // The corresponding addresses in the transformed image. - DWORD rva_transformed; - // The length of the address range. - DWORD length; - // It is possible for code to be injected into a transformed image, for which - // there is no corresponding code in the original image. If this range of - // transformed image is immediately followed by such injected code we maintain - // a record of its length here. - DWORD injected; - // It is possible for code to be removed from the original image. This happens - // for things like padding between blocks. There is no actual content lost, - // but the spacing between items may be lost. This keeps track of any removed - // content immediately following the |original| range. - DWORD removed; -}; -// A vector of mapped ranges is used as a more useful representation of -// OMAP data. -typedef std::vector<MappedRange> Mapping; - -// Used as a secondary search structure accompanying a Mapping. -struct EndpointIndex { - DWORD endpoint; - size_t index; -}; -typedef std::vector<EndpointIndex> EndpointIndexMap; - -// An ImageMap is vector of mapped ranges, plus a secondary index into it for -// doing interval searches. (An interval tree would also work, but is overkill -// because we don't need insertion and deletion.) -struct ImageMap { - // This is a description of the mapping between original and transformed - // image, sorted by addresses in the original image. - Mapping mapping; - // For all interval endpoints in |mapping| this stores the minimum index of - // an interval in |mapping| that contains the endpoint. Useful for doing - // interval intersection queries. - EndpointIndexMap endpoint_index_map; -}; - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_OMAP_INTERNAL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc deleted file mode 100644 index 960a33f46..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc +++ /dev/null @@ -1,330 +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.
-
-// Unittests for OMAP related functions.
-
-#include "common/windows/omap.h"
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.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/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc deleted file mode 100644 index 01f4ce3b7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc +++ /dev/null @@ -1,1369 +0,0 @@ -// Copyright (c) 2006, 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/pdb_source_line_writer.h" - -#include <windows.h> -#include <winnt.h> -#include <atlbase.h> -#include <dia2.h> -#include <diacreate.h> -#include <ImageHlp.h> -#include <stdio.h> - -#include <limits> -#include <set> - -#include "common/windows/dia_util.h" -#include "common/windows/guid_string.h" -#include "common/windows/string_utils-inl.h" - -// This constant may be missing from DbgHelp.h. See the documentation for -// IDiaSymbol::get_undecoratedNameEx. -#ifndef UNDNAME_NO_ECSU -#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union. -#endif // UNDNAME_NO_ECSU - -/* - * 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]; -}; - -namespace google_breakpad { - -namespace { - -using std::vector; - -// A helper class to scope a PLOADED_IMAGE. -class AutoImage { - public: - explicit AutoImage(PLOADED_IMAGE img) : img_(img) {} - ~AutoImage() { - if (img_) - ImageUnload(img_); - } - - operator PLOADED_IMAGE() { return img_; } - PLOADED_IMAGE operator->() { return img_; } - - private: - PLOADED_IMAGE img_; -}; - -bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) { - if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) { - return true; - } - - class DECLSPEC_UUID("B86AE24D-BF2F-4ac9-B5A2-34B14E4CE11D") DiaSource100; - class DECLSPEC_UUID("761D3BCD-1304-41D5-94E8-EAC54E4AC172") DiaSource110; - class DECLSPEC_UUID("3BFCEA48-620F-4B6B-81F7-B9AF75454C7D") DiaSource120; - class DECLSPEC_UUID("E6756135-1E65-4D17-8576-610761398C3C") DiaSource140; - - // If the CoCreateInstance call above failed, msdia*.dll is not registered. - // 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; - if (CLSID_DiaSource == _uuidof(DiaSource100)) { - msdia_dll = L"msdia100.dll"; - } else if (CLSID_DiaSource == _uuidof(DiaSource110)) { - msdia_dll = L"msdia110.dll"; - } else if (CLSID_DiaSource == _uuidof(DiaSource120)) { - msdia_dll = L"msdia120.dll"; - } else if (CLSID_DiaSource == _uuidof(DiaSource140)) { - msdia_dll = L"msdia140.dll"; - } - - if (msdia_dll && - SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, - reinterpret_cast<void **>(&data_source)))) { - return true; - } - - return false; -} - -} // namespace - -PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { -} - -PDBSourceLineWriter::~PDBSourceLineWriter() { -} - -bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) { - if (code_file_.empty()) { - code_file_ = exe_file; - return true; - } - // Setting a different code file path is an error. It is success only if the - // file paths are the same. - return exe_file == code_file_; -} - -bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { - Close(); - code_file_.clear(); - - if (FAILED(CoInitialize(NULL))) { - fprintf(stderr, "CoInitialize failed\n"); - return false; - } - - CComPtr<IDiaDataSource> data_source; - if (!CreateDiaDataSourceInstance(data_source)) { - const int kGuidSize = 64; - wchar_t classid[kGuidSize] = {0}; - StringFromGUID2(CLSID_DiaSource, classid, kGuidSize); - fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed " - "(msdia*.dll unregistered?)\n", classid); - return false; - } - - switch (format) { - case PDB_FILE: - if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { - fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str()); - 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()); - 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()); - return false; - } - code_file_ = file; - } - break; - default: - fprintf(stderr, "Unknown file format\n"); - return false; - } - - if (FAILED(data_source->openSession(&session_))) { - fprintf(stderr, "openSession failed\n"); - } - - return true; -} - -bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { - // The line number format is: - // <rva> <line number> <source file id> - CComPtr<IDiaLineNumber> line; - ULONG count; - - 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; - } - - 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(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); - - DWORD line_num; - if (FAILED(line->get_lineNumber(&line_num))) { - fprintf(stderr, "failed to get line number\n"); - return false; - } - - AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, length), &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "%x %x %d %d\n", ranges[i].rva, ranges[i].length, - line_num, source_id); - } - line.Release(); - } - return true; -} - -bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function, - IDiaSymbol *block) { - // The function format is: - // FUNC <address> <length> <param_stack_size> <function> - DWORD rva; - if (FAILED(block->get_relativeVirtualAddress(&rva))) { - fprintf(stderr, "couldn't get rva\n"); - return false; - } - - ULONGLONG length; - if (FAILED(block->get_length(&length))) { - fprintf(stderr, "failed to get function length\n"); - return false; - } - - if (length == 0) { - // Silently ignore zero-length functions, which can infrequently pop up. - return true; - } - - CComBSTR name; - int stack_param_size; - if (!GetSymbolFunctionName(function, &name, &stack_param_size)) { - return false; - } - - // If the decorated name didn't give the parameter size, try to - // calculate it. - if (stack_param_size < 0) { - stack_param_size = GetFunctionStackParamSize(function); - } - - AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, static_cast<DWORD>(length)), - &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "FUNC %x %x %x %ws\n", - ranges[i].rva, ranges[i].length, stack_param_size, - name.m_str); - } - - CComPtr<IDiaEnumLineNumbers> lines; - if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) { - return false; - } - - if (!PrintLines(lines)) { - return false; - } - return true; -} - -bool PDBSourceLineWriter::PrintSourceFiles() { - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) { - fprintf(stderr, "get_globalScope failed\n"); - return false; - } - - CComPtr<IDiaEnumSymbols> compilands; - if (FAILED(global->findChildren(SymTagCompiland, NULL, - nsNone, &compilands))) { - fprintf(stderr, "findChildren failed\n"); - return false; - } - - CComPtr<IDiaSymbol> compiland; - ULONG count; - while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { - CComPtr<IDiaEnumSourceFiles> source_files; - if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) { - return false; - } - CComPtr<IDiaSourceFile> file; - while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) { - DWORD file_id; - if (FAILED(file->get_uniqueId(&file_id))) { - return false; - } - - CComBSTR file_name; - if (FAILED(file->get_fileName(&file_name))) { - return false; - } - - wstring file_name_string(file_name); - if (!FileIDIsCached(file_name_string)) { - // this is a new file name, cache it and output a FILE line. - CacheFileID(file_name_string, file_id); - fwprintf(output_, L"FILE %d %ws\n", file_id, file_name_string.c_str()); - } else { - // this file name has already been seen, just save this - // ID for later lookup. - StoreDuplicateFileID(file_name_string, file_id); - } - file.Release(); - } - compiland.Release(); - } - return true; -} - -bool PDBSourceLineWriter::PrintFunctions() { - ULONG count = 0; - DWORD rva = 0; - CComPtr<IDiaSymbol> global; - HRESULT hr; - - if (FAILED(session_->get_globalScope(&global))) { - fprintf(stderr, "get_globalScope failed\n"); - return false; - } - - CComPtr<IDiaEnumSymbols> symbols = NULL; - - // Find all function symbols first. - std::set<DWORD> rvas; - hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols); - - if (SUCCEEDED(hr)) { - CComPtr<IDiaSymbol> symbol = NULL; - - while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { - if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { - // To maintain existing behavior of one symbol per address, place the - // rva onto a set here to uniquify them. - rvas.insert(rva); - } else { - fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n"); - return false; - } - - symbol.Release(); - } - - symbols.Release(); - } - - // Find all public symbols. Store public symbols that are not also private - // symbols for later. - std::set<DWORD> public_only_rvas; - hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols); - - if (SUCCEEDED(hr)) { - CComPtr<IDiaSymbol> symbol = NULL; - - while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { - if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { - if (rvas.count(rva) == 0) { - rvas.insert(rva); // Keep symbols in rva order. - public_only_rvas.insert(rva); - } - } else { - fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n"); - return false; - } - - symbol.Release(); - } - - symbols.Release(); - } - - std::set<DWORD>::iterator it; - - // For each rva, dump the first symbol DIA knows about at the address. - for (it = rvas.begin(); it != rvas.end(); ++it) { - CComPtr<IDiaSymbol> symbol = NULL; - // If the symbol is not in the public list, look for SymTagFunction. This is - // a workaround to a bug where DIA will hang if searching for a private - // symbol at an address where only a public symbol exists. - // See http://connect.microsoft.com/VisualStudio/feedback/details/722366 - if (public_only_rvas.count(*it) == 0) { - if (SUCCEEDED(session_->findSymbolByRVA(*it, SymTagFunction, &symbol))) { - // Sometimes findSymbolByRVA returns S_OK, but NULL. - if (symbol) { - if (!PrintFunction(symbol, symbol)) - return false; - symbol.Release(); - } - } else { - fprintf(stderr, "findSymbolByRVA SymTagFunction failed\n"); - return false; - } - } else if (SUCCEEDED(session_->findSymbolByRVA(*it, - SymTagPublicSymbol, - &symbol))) { - // Sometimes findSymbolByRVA returns S_OK, but NULL. - if (symbol) { - if (!PrintCodePublicSymbol(symbol)) - return false; - symbol.Release(); - } - } else { - fprintf(stderr, "findSymbolByRVA SymTagPublicSymbol failed\n"); - return false; - } - } - - // When building with PGO, the compiler can split functions into - // "hot" and "cold" blocks, and move the "cold" blocks out to separate - // pages, so the function can be noncontiguous. To find these blocks, - // we have to iterate over all the compilands, and then find blocks - // that are children of them. We can then find the lexical parents - // of those blocks and print out an extra FUNC line for blocks - // that are not contained in their parent functions. - CComPtr<IDiaEnumSymbols> compilands; - if (FAILED(global->findChildren(SymTagCompiland, NULL, - nsNone, &compilands))) { - fprintf(stderr, "findChildren failed on the global\n"); - return false; - } - - CComPtr<IDiaSymbol> compiland; - while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { - CComPtr<IDiaEnumSymbols> blocks; - if (FAILED(compiland->findChildren(SymTagBlock, NULL, - nsNone, &blocks))) { - fprintf(stderr, "findChildren failed on a compiland\n"); - return false; - } - - CComPtr<IDiaSymbol> block; - while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) { - // find this block's lexical parent function - CComPtr<IDiaSymbol> parent; - DWORD tag; - if (SUCCEEDED(block->get_lexicalParent(&parent)) && - SUCCEEDED(parent->get_symTag(&tag)) && - tag == SymTagFunction) { - // now get the block's offset and the function's offset and size, - // and determine if the block is outside of the function - DWORD func_rva, block_rva; - ULONGLONG func_length; - if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) && - SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) && - SUCCEEDED(parent->get_length(&func_length))) { - if (block_rva < func_rva || block_rva > (func_rva + func_length)) { - if (!PrintFunction(parent, block)) { - return false; - } - } - } - } - parent.Release(); - block.Release(); - } - blocks.Release(); - compiland.Release(); - } - - global.Release(); - return true; -} - -#undef max - -bool PDBSourceLineWriter::PrintFrameDataUsingPDB() { - // It would be nice if it were possible to output frame data alongside the - // associated function, as is done with line numbers, but the DIA API - // doesn't make it possible to get the frame data in that way. - - CComPtr<IDiaEnumFrameData> frame_data_enum; - if (!FindTable(session_, &frame_data_enum)) - return false; - - DWORD last_type = std::numeric_limits<DWORD>::max(); - DWORD last_rva = std::numeric_limits<DWORD>::max(); - DWORD last_code_size = 0; - DWORD last_prolog_size = std::numeric_limits<DWORD>::max(); - - CComPtr<IDiaFrameData> frame_data; - ULONG count = 0; - while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) && - count == 1) { - DWORD type; - if (FAILED(frame_data->get_type(&type))) - return false; - - DWORD rva; - if (FAILED(frame_data->get_relativeVirtualAddress(&rva))) - return false; - - DWORD code_size; - if (FAILED(frame_data->get_lengthBlock(&code_size))) - return false; - - DWORD prolog_size; - if (FAILED(frame_data->get_lengthProlog(&prolog_size))) - return false; - - // parameter_size is the size of parameters passed on the stack. If any - // parameters are not passed on the stack (such as in registers), their - // sizes will not be included in parameter_size. - DWORD parameter_size; - if (FAILED(frame_data->get_lengthParams(¶meter_size))) - return false; - - DWORD saved_register_size; - if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size))) - return false; - - DWORD local_size; - if (FAILED(frame_data->get_lengthLocals(&local_size))) - return false; - - // get_maxStack can return S_FALSE, just use 0 in that case. - DWORD max_stack_size = 0; - if (FAILED(frame_data->get_maxStack(&max_stack_size))) - return false; - - // get_programString can return S_FALSE, indicating that there is no - // program string. In that case, check whether %ebp is used. - HRESULT program_string_result; - CComBSTR program_string; - if (FAILED(program_string_result = frame_data->get_program( - &program_string))) { - return false; - } - - // get_allocatesBasePointer can return S_FALSE, treat that as though - // %ebp is not used. - BOOL allocates_base_pointer = FALSE; - if (program_string_result != S_OK) { - if (FAILED(frame_data->get_allocatesBasePointer( - &allocates_base_pointer))) { - return false; - } - } - - // Only print out a line if type, rva, code_size, or prolog_size have - // changed from the last line. It is surprisingly common (especially in - // system library PDBs) for DIA to return a series of identical - // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86, - // this check reduces the size of the dumped symbol file by a third. - if (type != last_type || rva != last_rva || code_size != last_code_size || - prolog_size != last_prolog_size) { - // The prolog and the code portions of the frame have to be treated - // independently as they may have independently changed in size, or may - // even have been split. - // NOTE: If epilog size is ever non-zero, we have to do something - // similar with it. - - // Figure out where the prolog bytes have landed. - AddressRangeVector prolog_ranges; - if (prolog_size > 0) { - MapAddressRange(image_map_, AddressRange(rva, prolog_size), - &prolog_ranges); - } - - // And figure out where the code bytes have landed. - AddressRangeVector code_ranges; - MapAddressRange(image_map_, - AddressRange(rva + prolog_size, - code_size - prolog_size), - &code_ranges); - - struct FrameInfo { - DWORD rva; - DWORD code_size; - DWORD prolog_size; - }; - std::vector<FrameInfo> frame_infos; - - // Special case: The prolog and the code bytes remain contiguous. This is - // only done for compactness of the symbol file, and we could actually - // be outputting independent frame info for the prolog and code portions. - if (prolog_ranges.size() == 1 && code_ranges.size() == 1 && - prolog_ranges[0].end() == code_ranges[0].rva) { - FrameInfo fi = { prolog_ranges[0].rva, - prolog_ranges[0].length + code_ranges[0].length, - prolog_ranges[0].length }; - frame_infos.push_back(fi); - } else { - // Otherwise we output the prolog and code frame info independently. - for (size_t i = 0; i < prolog_ranges.size(); ++i) { - FrameInfo fi = { prolog_ranges[i].rva, - prolog_ranges[i].length, - prolog_ranges[i].length }; - frame_infos.push_back(fi); - } - for (size_t i = 0; i < code_ranges.size(); ++i) { - FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 }; - frame_infos.push_back(fi); - } - } - - for (size_t i = 0; i < frame_infos.size(); ++i) { - const FrameInfo& fi(frame_infos[i]); - fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ", - type, fi.rva, fi.code_size, fi.prolog_size, - 0 /* epilog_size */, parameter_size, saved_register_size, - local_size, max_stack_size, program_string_result == S_OK); - if (program_string_result == S_OK) { - fprintf(output_, "%ws\n", program_string.m_str); - } else { - fprintf(output_, "%d\n", allocates_base_pointer); - } - } - - last_type = type; - last_rva = rva; - last_code_size = code_size; - last_prolog_size = prolog_size; - } - - frame_data.Release(); - } - - return true; -} - -bool PDBSourceLineWriter::PrintFrameDataUsingEXE() { - if (code_file_.empty() && !FindPEFile()) { - fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); - return false; - } - - // Convert wchar to native charset because ImageLoad only takes - // a PSTR as input. - string code_file; - if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { - return false; - } - - AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); - if (!img) { - fprintf(stderr, "Failed to load %s\n", code_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(output_, "STACK CFI INIT %x %x .cfa: $rsp .ra: .cfa %d - ^\n", - funcs[i].BeginAddress, - funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset); - fprintf(output_, "STACK CFI %x .cfa: $rsp %d +\n", - funcs[i].BeginAddress, stack_size); - } - - return true; -} - -bool PDBSourceLineWriter::PrintFrameData() { - PDBModuleInfo info; - if (GetModuleInfo(&info) && info.cpu == L"x86_64") { - return PrintFrameDataUsingEXE(); - } else { - return PrintFrameDataUsingPDB(); - } - return false; -} - -bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) { - BOOL is_code; - if (FAILED(symbol->get_code(&is_code))) { - return false; - } - if (!is_code) { - return true; - } - - DWORD rva; - if (FAILED(symbol->get_relativeVirtualAddress(&rva))) { - return false; - } - - CComBSTR name; - int stack_param_size; - if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) { - return false; - } - - AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, 1), &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "PUBLIC %x %x %ws\n", ranges[i].rva, - stack_param_size > 0 ? stack_param_size : 0, - name.m_str); - } - return true; -} - -bool PDBSourceLineWriter::PrintPDBInfo() { - PDBModuleInfo info; - if (!GetModuleInfo(&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(output_, "MODULE windows %ws %ws %ws\n", - info.cpu.c_str(), info.debug_identifier.c_str(), - info.debug_file.c_str()); - - return true; -} - -bool PDBSourceLineWriter::PrintPEInfo() { - PEModuleInfo info; - if (!GetPEInfo(&info)) { - return false; - } - - fprintf(output_, "INFO CODE_ID %ws %ws\n", - info.code_identifier.c_str(), - info.code_file.c_str()); - return true; -} - -// wcstol_positive_strict is sort of like wcstol, but much stricter. string -// should be a buffer pointing to a null-terminated string containing only -// decimal digits. If the entire string can be converted to an integer -// without overflowing, and there are no non-digit characters before the -// result is set to the value and this function returns true. Otherwise, -// this function returns false. This is an alternative to the strtol, atoi, -// 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) { - int value = 0; - for (wchar_t *c = string; *c != '\0'; ++c) { - int last_value = value; - value *= 10; - // Detect overflow. - if (value / 10 != last_value || value < 0) { - return false; - } - if (*c < '0' || *c > '9') { - return false; - } - unsigned int c_value = *c - '0'; - last_value = value; - value += c_value; - // Detect overflow. - if (value < last_value) { - return false; - } - // Forbid leading zeroes unless the string is just "0". - if (value == 0 && *(c+1) != '\0') { - return false; - } - } - *result = value; - return true; -} - -bool PDBSourceLineWriter::FindPEFile() { - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) { - fprintf(stderr, "get_globalScope failed\n"); - return false; - } - - CComBSTR symbols_file; - if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) { - wstring file(symbols_file); - - // Look for an EXE or DLL file. - const wchar_t *extensions[] = { L"exe", L"dll" }; - for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) { - size_t dot_pos = file.find_last_of(L"."); - if (dot_pos != wstring::npos) { - file.replace(dot_pos + 1, wstring::npos, extensions[i]); - // Check if this file exists. - if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) { - code_file_ = file; - return true; - } - } - } - } - - return false; -} - -// static -bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, - BSTR *name, - 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_name(name) != S_OK) { - fprintf(stderr, "failed to get function name\n"); - return false; - } - - // It's possible for get_name to return an empty string, so - // special-case that. - if (wcscmp(*name, L"") == 0) { - SysFreeString(*name); - // dwarf_cu_to_module.cc uses "<name omitted>", so match that. - *name = SysAllocString(L"<name omitted>"); - return true; - } - - // If a name comes from get_name because no undecorated form existed, - // it's already formatted properly to be used as output. Don't do any - // additional processing. - // - // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's. - // This will result in calling get_name for some C++ symbols, so - // all of the parameter and return type information may not be included in - // the name string. - } else { - // 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 size_t replace_length = wcslen(replace_string); - const wchar_t *replacement_string = L"()"; - size_t length = wcslen(*name); - if (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); - length = wcslen(*name); - } - } - - // Undecorate names used for stdcall and fastcall. These names prefix - // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it - // with '@' followed by the number of bytes of parameters, in decimal. - // If such a name is found, take note of the size and undecorate it. - // Only do this for names that aren't C++, which is determined based on - // whether the undecorated name contains any ':' or '(' characters. - if (!wcschr(*name, ':') && !wcschr(*name, '(') && - (*name[0] == '_' || *name[0] == '@')) { - 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). - // We're only interested in the stack space used for parameters, so - // so subtract 8 and don't let the size go below 0. - if (*name[0] == '@') { - if (*stack_param_size > 8) { - *stack_param_size -= 8; - } else { - *stack_param_size = 0; - } - } - - // Undecorate the name by moving it one character to the left in its - // buffer, and terminating it where the last '@' had been. - WindowsStringUtils::safe_wcsncpy(*name, length, - *name + 1, last_at - *name - 1); - } else if (*name[0] == '_') { - // This symbol's name is encoded according to the cdecl rules. The - // name doesn't end in a '@' character followed by a decimal positive - // integer, so it's not a stdcall name. Strip off the leading - // underscore. - WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length); - } - } - } - - return true; -} - -// static -int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) { - // This implementation is highly x86-specific. - - // Gather the symbols corresponding to data. - CComPtr<IDiaEnumSymbols> data_children; - if (FAILED(function->findChildren(SymTagData, NULL, nsNone, - &data_children))) { - return 0; - } - - // lowest_base is the lowest %ebp-relative byte offset used for a parameter. - // highest_end is one greater than the highest offset (i.e. base + length). - // Stack parameters are assumed to be contiguous, because in reality, they - // are. - int lowest_base = INT_MAX; - int highest_end = INT_MIN; - - CComPtr<IDiaSymbol> child; - DWORD count; - while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) { - // If any operation fails at this point, just proceed to the next child. - // Use the next_child label instead of continue because child needs to - // be released before it's reused. Declare constructable/destructable - // types early to avoid gotos that cross initializations. - CComPtr<IDiaSymbol> child_type; - - // DataIsObjectPtr is only used for |this|. Because |this| can be passed - // as a stack parameter, look for it in addition to traditional - // parameters. - DWORD child_kind; - if (FAILED(child->get_dataKind(&child_kind)) || - (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) { - goto next_child; - } - - // Only concentrate on register-relative parameters. Parameters may also - // be enregistered (passed directly in a register), but those don't - // consume any stack space, so they're not of interest. - DWORD child_location_type; - if (FAILED(child->get_locationType(&child_location_type)) || - child_location_type != LocIsRegRel) { - goto next_child; - } - - // Of register-relative parameters, the only ones that make any sense are - // %ebp- or %esp-relative. Note that MSVC's debugging information always - // gives parameters as %ebp-relative even when a function doesn't use a - // traditional frame pointer and stack parameters are accessed relative to - // %esp, so just look for %ebp-relative parameters. If you wanted to - // access parameters, you'd probably want to treat these %ebp-relative - // offsets as if they were relative to %esp before a function's prolog - // executed. - DWORD child_register; - if (FAILED(child->get_registerId(&child_register)) || - child_register != CV_REG_EBP) { - goto next_child; - } - - LONG child_register_offset; - if (FAILED(child->get_offset(&child_register_offset))) { - goto next_child; - } - - // IDiaSymbol::get_type can succeed but still pass back a NULL value. - if (FAILED(child->get_type(&child_type)) || !child_type) { - goto next_child; - } - - ULONGLONG child_length; - if (FAILED(child_type->get_length(&child_length))) { - goto next_child; - } - - int child_end = child_register_offset + static_cast<ULONG>(child_length); - if (child_register_offset < lowest_base) { - lowest_base = child_register_offset; - } - if (child_end > highest_end) { - highest_end = child_end; - } - -next_child: - child.Release(); - } - - int param_size = 0; - // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest - // possible address to find a stack parameter before executing a function's - // prolog (see above). Some optimizations cause parameter offsets to be - // lower than 4, but we're not concerned with those because we're only - // looking for parameters contained in addresses higher than where the - // return address is stored. - if (lowest_base < 4) { - lowest_base = 4; - } - if (highest_end > lowest_base) { - // All stack parameters are pushed as at least 4-byte quantities. If the - // last type was narrower than 4 bytes, promote it. This assumes that all - // parameters' offsets are 4-byte-aligned, which is always the case. Only - // worry about the last type, because we're not summing the type sizes, - // just looking at the lowest and highest offsets. - int remainder = highest_end % 4; - if (remainder) { - highest_end += 4 - remainder; - } - - param_size = highest_end - lowest_base; - } - - return param_size; -} - -bool PDBSourceLineWriter::WriteMap(FILE *map_file) { - output_ = map_file; - - // Load the OMAP information, and disable auto-translation of addresses in - // preference of doing it ourselves. - OmapData omap_data; - if (!GetOmapDataAndDisableTranslation(session_, &omap_data)) - return false; - BuildImageMap(omap_data, &image_map_); - - bool ret = PrintPDBInfo(); - // This is not a critical piece of the symbol file. - PrintPEInfo(); - ret = ret && - PrintSourceFiles() && - PrintFunctions() && - PrintFrameData(); - - output_ = NULL; - return ret; -} - -void PDBSourceLineWriter::Close() { - session_.Release(); -} - -bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { - if (!info) { - return false; - } - - info->debug_file.clear(); - info->debug_identifier.clear(); - info->cpu.clear(); - - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) { - return false; - } - - DWORD machine_type; - // get_machineType can return S_FALSE. - if (global->get_machineType(&machine_type) == S_OK) { - // The documentation claims that get_machineType returns a value from - // the CV_CPU_TYPE_e enumeration, but that's not the case. - // Instead, it returns one of the IMAGE_FILE_MACHINE values as - // defined here: - // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx - switch (machine_type) { - case IMAGE_FILE_MACHINE_I386: - info->cpu = L"x86"; - break; - case IMAGE_FILE_MACHINE_AMD64: - info->cpu = L"x86_64"; - break; - default: - info->cpu = L"unknown"; - break; - } - } else { - // Unexpected, but handle gracefully. - info->cpu = L"unknown"; - } - - // DWORD* and int* are not compatible. This is clean and avoids a cast. - DWORD age; - if (FAILED(global->get_age(&age))) { - return false; - } - - bool uses_guid; - if (!UsesGUID(&uses_guid)) { - return false; - } - - if (uses_guid) { - GUID guid; - if (FAILED(global->get_guid(&guid))) { - return false; - } - - // 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'; - - info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid); - info->debug_identifier.append(age_string); - } else { - DWORD signature; - if (FAILED(global->get_signature(&signature))) { - return false; - } - - // 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'; - - info->debug_identifier = identifier_string; - } - - CComBSTR debug_file_string; - if (FAILED(global->get_symbolsFileName(&debug_file_string))) { - return false; - } - info->debug_file = - WindowsStringUtils::GetBaseName(wstring(debug_file_string)); - - return true; -} - -bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { - if (!info) { - return false; - } - - if (code_file_.empty() && !FindPEFile()) { - fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); - return false; - } - - // Convert wchar to native charset because ImageLoad only takes - // a PSTR as input. - string code_file; - if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { - return false; - } - - AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); - if (!img) { - fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str()); - return false; - } - - info->code_file = WindowsStringUtils::GetBaseName(code_file_); - - // The date and time that the file was created by the linker. - DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp; - // The size of the file in bytes, including all headers. - DWORD SizeOfImage = 0; - PIMAGE_OPTIONAL_HEADER64 opt = - &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader; - if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - // 64-bit PE file. - SizeOfImage = opt->SizeOfImage; - } else { - // 32-bit PE file. - SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage; - } - wchar_t code_identifier[32]; - swprintf(code_identifier, - sizeof(code_identifier) / sizeof(code_identifier[0]), - L"%08X%X", TimeDateStamp, SizeOfImage); - info->code_identifier = code_identifier; - - return true; -} - -bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { - if (!uses_guid) - return false; - - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) - return false; - - GUID guid; - if (FAILED(global->get_guid(&guid))) - return false; - - DWORD signature; - if (FAILED(global->get_signature(&signature))) - return false; - - // There are two possibilities for guid: either it's a real 128-bit GUID - // as identified in a code module by a new-style CodeView record, or it's - // a 32-bit signature (timestamp) as identified by an old-style record. - // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h. - // - // Because DIA doesn't provide a way to directly determine whether a module - // uses a GUID or a 32-bit signature, this code checks whether the first 32 - // bits of guid are the same as the signature, and if the rest of guid is - // zero. If so, then with a pretty high degree of certainty, there's an - // old-style CodeView record in use. This method will only falsely find an - // an old-style CodeView record if a real 128-bit GUID has its first 32 - // bits set the same as the module's signature (timestamp) and the rest of - // the GUID is set to 0. This is highly unlikely. - - GUID signature_guid = {signature}; // 0-initializes other members - *uses_guid = !IsEqualGUID(guid, signature_guid); - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h deleted file mode 100644 index e9e89bb27..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright (c) 2006, 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. - -// PDBSourceLineWriter uses a pdb file produced by Visual C++ to output -// a line/address map for use with BasicSourceLineResolver. - -#ifndef COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ -#define COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ - -#include <atlcomcli.h> - -#include <unordered_map> -#include <string> - -#include "common/windows/omap.h" - -struct IDiaEnumLineNumbers; -struct IDiaSession; -struct IDiaSymbol; - -namespace google_breakpad { - -using std::wstring; -using std::unordered_map; - -// A structure that carries information that identifies a pdb file. -struct PDBModuleInfo { - public: - // The basename of the pdb file from which information was loaded. - wstring debug_file; - - // The pdb's identifier. For recent pdb files, the identifier consists - // of the pdb's guid, in uppercase hexadecimal form without any dashes - // or separators, followed immediately by the pdb's age, also in - // uppercase hexadecimal form. For older pdb files which have no guid, - // the identifier is the pdb's 32-bit signature value, in zero-padded - // hexadecimal form, followed immediately by the pdb's age, in lowercase - // hexadecimal form. - wstring debug_identifier; - - // A string identifying the cpu that the 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; -}; - -class PDBSourceLineWriter { - public: - enum FileFormat { - PDB_FILE, // a .pdb file containing debug symbols - EXE_FILE, // a .exe or .dll file - ANY_FILE // try PDB_FILE and then EXE_FILE - }; - - explicit PDBSourceLineWriter(); - ~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); - - // Sets the code file full path. This is optional for 32-bit modules. It is - // also optional for 64-bit modules when there is an executable file stored - // in the same directory as the PDB file. It is only required for 64-bit - // modules when the executable file is not in the same location as the PDB - // 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); - - // Writes a map file from the current pdb file to the given file stream. - // Returns true on success. - bool WriteMap(FILE *map_file); - - // Closes the current pdb file and its associated resources. - void Close(); - - // Retrieves information about the module's debugging file. Returns - // true on success and false on failure. - bool GetModuleInfo(PDBModuleInfo *info); - - // Retrieves information about the module's PE file. Returns - // true on success and false on failure. - bool GetPEInfo(PEModuleInfo *info); - - // Sets uses_guid to true if the opened file uses a new-style CodeView - // record with a 128-bit GUID, or false if the opened file uses an old-style - // CodeView record. When no GUID is available, a 32-bit signature should be - // used to identify the module instead. If the information cannot be - // determined, this method returns false. - bool UsesGUID(bool *uses_guid); - - private: - // Outputs the line/address pairs for each line in the enumerator. - // Returns true on success. - bool PrintLines(IDiaEnumLineNumbers *lines); - - // 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 code block that is lexically part of this function, but - // resides at a separate address. - // Returns true on success. - bool PrintFunction(IDiaSymbol *function, IDiaSymbol *block); - - // Outputs all functions as described above. Returns true on success. - bool PrintFunctions(); - - // Outputs all of the source files in the session's pdb file. - // Returns true on success. - bool PrintSourceFiles(); - - // 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. - bool PrintFrameDataUsingPDB(); - - // Outputs all of the frame information necessary to construct stack - // backtraces in the absence of frame pointers. For x64 data stored in - // .exe, .dll files. Returns true on success. - bool PrintFrameDataUsingEXE(); - - // Outputs all of the frame information necessary to construct stack - // backtraces in the absence of frame pointers. Returns true on success. - bool PrintFrameData(); - - // Outputs a single public symbol address and name, if the symbol corresponds - // to a code address. Returns true on success. If symbol is does not - // correspond to code, returns true without outputting anything. - bool PrintCodePublicSymbol(IDiaSymbol *symbol); - - // Outputs a line identifying the PDB file that is being dumped, along with - // its uuid and age. - bool PrintPDBInfo(); - - // Outputs a line identifying the PE file corresponding to the PDB - // file that is being dumped, along with its code identifier, - // which consists of its timestamp and file size. - bool PrintPEInfo(); - - // Returns true if this filename has already been seen, - // and an ID is stored for it, or false if it has not. - bool FileIDIsCached(const wstring &file) { - return unique_files_.find(file) != unique_files_.end(); - } - - // Cache this filename and ID for later reuse. - 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) { - unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file); - if (iter != unique_files_.end()) { - // map this id to the previously seen one - file_ids_[id] = iter->second; - } - } - - // Given a file's unique ID, return the ID that should be used to - // 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); - if (iter == file_ids_.end()) - return id; - return iter->second; - } - - // Find the PE file corresponding to the loaded PDB file, and - // set the code_file_ member. Returns false on failure. - bool FindPEFile(); - - // Returns the function name for a symbol. If possible, the name is - // undecorated. If the symbol's decorated form indicates the size of - // parameters on the stack, this information is returned in stack_param_size. - // Returns true on success. If the symbol doesn't encode parameter size - // information, stack_param_size is set to -1. - static bool GetSymbolFunctionName(IDiaSymbol *function, BSTR *name, - int *stack_param_size); - - // Returns the number of bytes of stack space used for a function's - // parameters. function must have the tag SymTagFunction. In the event of - // a failure, returns 0, which is also a valid number of bytes. - static int GetFunctionStackParamSize(IDiaSymbol *function); - - // The filename of the PE file corresponding to the currently-open - // pdb file. - wstring code_file_; - - // The session for the currently-open pdb file. - CComPtr<IDiaSession> session_; - - // The current output file for this WriteMap invocation. - FILE *output_; - - // There may be many duplicate filenames with different IDs. - // This maps from the DIA "unique ID" to a single ID per unique - // filename. - unordered_map<DWORD, DWORD> file_ids_; - // This maps unique filenames to file IDs. - unordered_map<wstring, DWORD> unique_files_; - - // This is used for calculating post-transform symbol addresses and lengths. - ImageMap image_map_; - - // Disallow copy ctor and operator= - PDBSourceLineWriter(const PDBSourceLineWriter&); - void operator=(const PDBSourceLineWriter&); -}; - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h deleted file mode 100644 index 9b6360726..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2006, 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. - -// string_utils-inl.h: Safer string manipulation on Windows, supporting -// pre-MSVC8 environments. - -#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H_ -#define COMMON_WINDOWS_STRING_UTILS_INL_H_ - -#include <stdarg.h> -#include <wchar.h> - -#include <string> - -// The "ll" printf format size specifier corresponding to |long long| was -// intrudced in MSVC8. Earlier versions did not provide this size specifier, -// but "I64" can be used to print 64-bit types. Don't use "I64" where "ll" -// is available, in the event of oddball systems where |long long| is not -// 64 bits wide. -#if _MSC_VER >= 1400 // MSVC 2005/8 -#define WIN_STRING_FORMAT_LL "ll" -#else // MSC_VER >= 1400 -#define WIN_STRING_FORMAT_LL "I64" -#endif // MSC_VER >= 1400 - -// A nonconforming version of swprintf, without the length argument, was -// included with the CRT prior to MSVC8. Although a conforming version was -// also available via an overload, it is not reliably chosen. _snwprintf -// behaves as a standards-confirming swprintf should, so force the use of -// _snwprintf when using older CRTs. -#if _MSC_VER < 1400 // MSVC 2005/8 -#define swprintf _snwprintf -#else -// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently, -// it takes the same argument list as swprintf. -#define swprintf swprintf_s -#endif // MSC_VER < 1400 - -namespace google_breakpad { - -using std::string; -using std::wstring; - -class WindowsStringUtils { - public: - // 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); - - // 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); - - // 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); - - // The inverse of safe_mbstowcs. - static bool safe_wcstombs(const wstring &wcs, string *mbs); - - // Returns the base name of a file, e.g. strips off the path. - static wstring GetBaseName(const wstring &filename); - - private: - // Disallow instantiation and other object-based operations. - WindowsStringUtils(); - WindowsStringUtils(const WindowsStringUtils&); - ~WindowsStringUtils(); - void operator=(const WindowsStringUtils&); -}; - -// static -inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination, - size_t destination_size, - const wchar_t *source) { -#if _MSC_VER >= 1400 // MSVC 2005/8 - wcscpy_s(destination, destination_size, source); -#else // _MSC_VER >= 1400 - // Pre-MSVC 2005/8 doesn't have wcscpy_s. Simulate it with wcsncpy. - // wcsncpy doesn't 0-terminate the destination buffer if the source string - // is longer than size. Ensure that the destination is 0-terminated. - wcsncpy(destination, source, destination_size); - if (destination && destination_size) - destination[destination_size - 1] = 0; -#endif // _MSC_VER >= 1400 -} - -// static -inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination, - size_t destination_size, - const wchar_t *source, - size_t count) { -#if _MSC_VER >= 1400 // MSVC 2005/8 - wcsncpy_s(destination, destination_size, source, count); -#else // _MSC_VER >= 1400 - // Pre-MSVC 2005/8 doesn't have wcsncpy_s. Simulate it with wcsncpy. - // wcsncpy doesn't 0-terminate the destination buffer if the source string - // is longer than size. Ensure that the destination is 0-terminated. - if (destination_size < count) - count = destination_size; - - wcsncpy(destination, source, count); - if (destination && count) - destination[count - 1] = 0; -#endif // _MSC_VER >= 1400 -} - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_STRING_UTILS_INL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc deleted file mode 100644 index 272800035..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2006, 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 <cassert> -#include <vector> - -#include "common/windows/string_utils-inl.h" - -namespace google_breakpad { - -// static -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) { - base_name.erase(0, slash_pos + 1); - } - return base_name; -} - -// static -bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) { - assert(wcs); - - // First, determine the length of the destination buffer. - size_t wcs_length; - -#if _MSC_VER >= 1400 // MSVC 2005/8 - errno_t err; - if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) { - return false; - } - assert(wcs_length > 0); -#else // _MSC_VER >= 1400 - if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) == (size_t)-1) { - return false; - } - - // Leave space for the 0-terminator. - ++wcs_length; -#endif // _MSC_VER >= 1400 - - std::vector<wchar_t> wcs_v(wcs_length); - - // Now, convert. -#if _MSC_VER >= 1400 // MSVC 2005/8 - if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(), - _TRUNCATE)) != 0) { - return false; - } -#else // _MSC_VER >= 1400 - if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) == (size_t)-1) { - return false; - } - - // Ensure presence of 0-terminator. - wcs_v[wcs_length - 1] = '\0'; -#endif // _MSC_VER >= 1400 - - *wcs = &wcs_v[0]; - return true; -} - -// static -bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) { - assert(mbs); - - // First, determine the length of the destination buffer. - size_t mbs_length; - -#if _MSC_VER >= 1400 // MSVC 2005/8 - errno_t err; - if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) { - return false; - } - assert(mbs_length > 0); -#else // _MSC_VER >= 1400 - if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) == (size_t)-1) { - return false; - } - - // Leave space for the 0-terminator. - ++mbs_length; -#endif // _MSC_VER >= 1400 - - std::vector<char> mbs_v(mbs_length); - - // Now, convert. -#if _MSC_VER >= 1400 // MSVC 2005/8 - if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(), - _TRUNCATE)) != 0) { - return false; - } -#else // _MSC_VER >= 1400 - if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) == (size_t)-1) { - return false; - } - - // Ensure presence of 0-terminator. - mbs_v[mbs_length - 1] = '\0'; -#endif // _MSC_VER >= 1400 - - *mbs = &mbs_v[0]; - return true; -} - -} // namespace google_breakpad |