1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,225 @@ 1.4 +// Copyright (c) 2006, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// Tool to upload an exe/dll and its associated symbols to an HTTP server. 1.34 +// The PDB file is located automatically, using the path embedded in the 1.35 +// executable. The upload is sent as a multipart/form-data POST request, 1.36 +// with the following parameters: 1.37 +// code_file: the basename of the module, e.g. "app.exe" 1.38 +// debug_file: the basename of the debugging file, e.g. "app.pdb" 1.39 +// debug_identifier: the debug file's identifier, usually consisting of 1.40 +// the guid and age embedded in the pdb, e.g. 1.41 +// "11111111BBBB3333DDDD555555555555F" 1.42 +// version: the file version of the module, e.g. "1.2.3.4" 1.43 +// os: the operating system that the module was built for, always 1.44 +// "windows" in this implementation. 1.45 +// cpu: the CPU that the module was built for, typically "x86". 1.46 +// symbol_file: the contents of the breakpad-format symbol file 1.47 + 1.48 +#include <Windows.h> 1.49 +#include <DbgHelp.h> 1.50 +#include <WinInet.h> 1.51 + 1.52 +#include <cstdio> 1.53 +#include <map> 1.54 +#include <string> 1.55 +#include <vector> 1.56 + 1.57 +#include "common/windows/string_utils-inl.h" 1.58 + 1.59 +#include "common/windows/http_upload.h" 1.60 +#include "common/windows/pdb_source_line_writer.h" 1.61 + 1.62 +using std::string; 1.63 +using std::wstring; 1.64 +using std::vector; 1.65 +using std::map; 1.66 +using google_breakpad::HTTPUpload; 1.67 +using google_breakpad::PDBModuleInfo; 1.68 +using google_breakpad::PDBSourceLineWriter; 1.69 +using google_breakpad::WindowsStringUtils; 1.70 + 1.71 +// Extracts the file version information for the given filename, 1.72 +// as a string, for example, "1.2.3.4". Returns true on success. 1.73 +static bool GetFileVersionString(const wchar_t *filename, wstring *version) { 1.74 + DWORD handle; 1.75 + DWORD version_size = GetFileVersionInfoSize(filename, &handle); 1.76 + if (version_size < sizeof(VS_FIXEDFILEINFO)) { 1.77 + return false; 1.78 + } 1.79 + 1.80 + vector<char> version_info(version_size); 1.81 + if (!GetFileVersionInfo(filename, handle, version_size, &version_info[0])) { 1.82 + return false; 1.83 + } 1.84 + 1.85 + void *file_info_buffer = NULL; 1.86 + unsigned int file_info_length; 1.87 + if (!VerQueryValue(&version_info[0], L"\\", 1.88 + &file_info_buffer, &file_info_length)) { 1.89 + return false; 1.90 + } 1.91 + 1.92 + // The maximum value of each version component is 65535 (0xffff), 1.93 + // so the max length is 24, including the terminating null. 1.94 + wchar_t ver_string[24]; 1.95 + VS_FIXEDFILEINFO *file_info = 1.96 + reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer); 1.97 + swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]), 1.98 + L"%d.%d.%d.%d", 1.99 + file_info->dwFileVersionMS >> 16, 1.100 + file_info->dwFileVersionMS & 0xffff, 1.101 + file_info->dwFileVersionLS >> 16, 1.102 + file_info->dwFileVersionLS & 0xffff); 1.103 + 1.104 + // remove when VC++7.1 is no longer supported 1.105 + ver_string[sizeof(ver_string) / sizeof(ver_string[0]) - 1] = L'\0'; 1.106 + 1.107 + *version = ver_string; 1.108 + return true; 1.109 +} 1.110 + 1.111 +// Creates a new temporary file and writes the symbol data from the given 1.112 +// exe/dll file to it. Returns the path to the temp file in temp_file_path 1.113 +// and information about the pdb in pdb_info. 1.114 +static bool DumpSymbolsToTempFile(const wchar_t *file, 1.115 + wstring *temp_file_path, 1.116 + PDBModuleInfo *pdb_info) { 1.117 + google_breakpad::PDBSourceLineWriter writer; 1.118 + // Use EXE_FILE to get information out of the exe/dll in addition to the 1.119 + // pdb. The name and version number of the exe/dll are of value, and 1.120 + // there's no way to locate an exe/dll given a pdb. 1.121 + if (!writer.Open(file, PDBSourceLineWriter::EXE_FILE)) { 1.122 + return false; 1.123 + } 1.124 + 1.125 + wchar_t temp_path[_MAX_PATH]; 1.126 + if (GetTempPath(_MAX_PATH, temp_path) == 0) { 1.127 + return false; 1.128 + } 1.129 + 1.130 + wchar_t temp_filename[_MAX_PATH]; 1.131 + if (GetTempFileName(temp_path, L"sym", 0, temp_filename) == 0) { 1.132 + return false; 1.133 + } 1.134 + 1.135 + FILE *temp_file = NULL; 1.136 +#if _MSC_VER >= 1400 // MSVC 2005/8 1.137 + if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) 1.138 +#else // _MSC_VER >= 1400 1.139 + // _wfopen_s was introduced in MSVC8. Use _wfopen for earlier environments. 1.140 + // Don't use it with MSVC8 and later, because it's deprecated. 1.141 + if (!(temp_file = _wfopen(temp_filename, L"w"))) 1.142 +#endif // _MSC_VER >= 1400 1.143 + { 1.144 + return false; 1.145 + } 1.146 + 1.147 + bool success = writer.WriteMap(temp_file); 1.148 + fclose(temp_file); 1.149 + if (!success) { 1.150 + _wunlink(temp_filename); 1.151 + return false; 1.152 + } 1.153 + 1.154 + *temp_file_path = temp_filename; 1.155 + 1.156 + return writer.GetModuleInfo(pdb_info); 1.157 +} 1.158 + 1.159 +void printUsageAndExit() { 1.160 + wprintf(L"Usage: symupload [--timeout NN] <file.exe|file.dll> <symbol upload URL>\n\n"); 1.161 + wprintf(L"Timeout is in milliseconds, or can be 0 to be unlimited\n\n"); 1.162 + wprintf(L"Example:\n\n\tsymupload.exe --timeout 0 chrome.dll http://no.free.symbol.server.for.you\n"); 1.163 + exit(0); 1.164 +} 1.165 +int wmain(int argc, wchar_t *argv[]) { 1.166 + if ((argc != 3) && 1.167 + (argc != 5)) { 1.168 + printUsageAndExit(); 1.169 + } 1.170 + 1.171 + const wchar_t *module, *url; 1.172 + int timeout = -1; 1.173 + if (argc == 3) { 1.174 + module = argv[1]; 1.175 + url = argv[2]; 1.176 + } else { 1.177 + // check for timeout flag 1.178 + if (!wcscmp(L"--timeout", argv[1])) { 1.179 + timeout = _wtoi(argv[2]); 1.180 + module = argv[3]; 1.181 + url = argv[4]; 1.182 + } else { 1.183 + printUsageAndExit(); 1.184 + } 1.185 + } 1.186 + 1.187 + wstring symbol_file; 1.188 + PDBModuleInfo pdb_info; 1.189 + if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info)) { 1.190 + fwprintf(stderr, L"Could not get symbol data from %s\n", module); 1.191 + return 1; 1.192 + } 1.193 + 1.194 + wstring code_file = WindowsStringUtils::GetBaseName(wstring(module)); 1.195 + 1.196 + map<wstring, wstring> parameters; 1.197 + parameters[L"code_file"] = code_file; 1.198 + parameters[L"debug_file"] = pdb_info.debug_file; 1.199 + parameters[L"debug_identifier"] = pdb_info.debug_identifier; 1.200 + parameters[L"os"] = L"windows"; // This version of symupload is Windows-only 1.201 + parameters[L"cpu"] = pdb_info.cpu; 1.202 + 1.203 + // Don't make a missing version a hard error. Issue a warning, and let the 1.204 + // server decide whether to reject files without versions. 1.205 + wstring file_version; 1.206 + if (GetFileVersionString(module, &file_version)) { 1.207 + parameters[L"version"] = file_version; 1.208 + } else { 1.209 + fwprintf(stderr, L"Warning: Could not get file version for %s\n", module); 1.210 + } 1.211 + 1.212 + bool success = HTTPUpload::SendRequest(url, parameters, 1.213 + symbol_file, L"symbol_file", 1.214 + timeout == -1 ? NULL : &timeout, 1.215 + NULL, NULL); 1.216 + _wunlink(symbol_file.c_str()); 1.217 + 1.218 + if (!success) { 1.219 + fwprintf(stderr, L"Symbol file upload failed\n"); 1.220 + return 1; 1.221 + } 1.222 + 1.223 + wprintf(L"Uploaded symbols for windows-%s/%s/%s (%s %s)\n", 1.224 + pdb_info.cpu.c_str(), pdb_info.debug_file.c_str(), 1.225 + pdb_info.debug_identifier.c_str(), code_file.c_str(), 1.226 + file_version.c_str()); 1.227 + return 0; 1.228 +}