1 // Copyright (c) 2007, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 // ms_symbol_server_converter.h: Obtain symbol files from a Microsoft 31 // symbol server, and convert them to Breakpad's dumped format. 32 // 33 // At runtime, MSSymbolServerConverter and code that it calls depend on being 34 // able to locate suitable versions of dbghelp.dll and symsrv.dll. For best 35 // results, place these files in the same directory as the executable. 36 // dbghelp.dll and symsrv.dll as supplied with Debugging Tools for Windows are 37 // both redistributable, as indicated by the package's redist.txt file. 38 // 39 // When connecting to Microsoft's symbol server at 40 // http://msdl.microsoft.com/download/symbols/, which provides access to 41 // symbols for the operating system itself, symsrv.dll requires agreement to 42 // Microsoft's "Terms of Use for Microsoft Symbols and Binaries." Because this 43 // library places the symbol engine into a promptless mode, the dialog with the 44 // terms will not appear, and use of Microsoft's symbol server will not be 45 // possible. To indicate agreement to the terms, create a file called 46 // symsrv.yes in the same directory as symsrv.dll. (Note that symsrv.dll will 47 // also recognize a symsrv.no file as indicating that you do not accept the 48 // terms; the .yes file takes priority over the .no file.) The terms of use 49 // are contained within symsrv.dll; they were formerly available online at 50 // http://www.microsoft.com/whdc/devtools/debugging/symsrvTOU2.mspx , but 51 // do not appear to be available online any longer as of January, 2007. It is 52 // possible to view the terms from within WinDbg (Debugging Tools for Windows) 53 // by removing any symsrv.yes and symsrv.no files from WinDbg's directory, 54 // setting the symbol path to include Microsoft's symbol server (.sympath), and 55 // attempting to load symbols from their server (.reload). 56 // 57 // This code has been tested with dbghelp.dll 6.5.3.7 and symsrv.dll 6.5.3.8, 58 // included with Microsoft Visual Studio 8 in Common7/IDE. This has also been 59 // tested with dbghelp.dll and symsrv.dll versions 6.6.7.5 and 6.12.2.633, 60 // included with the same versions of Debugging Tools for Windows, available at 61 // http://www.microsoft.com/whdc/devtools/debugging/ . 62 // 63 // Author: Mark Mentovai 64 65 #ifndef TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ 66 #define TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ 67 68 #include <windows.h> 69 70 #include <string> 71 #include <vector> 72 73 namespace google_breakpad { 74 75 using std::string; 76 using std::vector; 77 78 // MissingSymbolInfo contains the subset of the information in the processor's 79 // CodeModule structure relevant to obtaining a missing symbol file. Only 80 // debug_file and debug_identifier are relevant in actually obtaining the 81 // missing file; the other fields are for convenience. 82 struct MissingSymbolInfo { 83 string code_file; 84 string code_identifier; 85 string debug_file; 86 string debug_identifier; 87 string version; 88 }; 89 90 class GUIDOrSignatureIdentifier { 91 public: 92 enum GUIDOrSignatureType { 93 TYPE_NONE = 0, 94 TYPE_GUID, 95 TYPE_SIGNATURE 96 }; 97 GUIDOrSignatureIdentifier()98 GUIDOrSignatureIdentifier() : type_(TYPE_NONE) {} 99 100 // Converts |identifier|, a debug_identifier-formatted string, into its 101 // component fields: either a GUID and age, or signature and age. If 102 // successful, sets the relevant fields in the object, including the type 103 // field, and returns true. On error, returns false. 104 bool InitializeFromString(const string &identifier); 105 type()106 GUIDOrSignatureType type() const { return type_; } guid()107 GUID guid() const { return guid_; } signature()108 DWORD signature() const { return signature_; } age()109 int age() const { return age_; } guid_or_signature_pointer()110 const void *guid_or_signature_pointer() const { return &guid_; } 111 112 private: 113 GUIDOrSignatureType type_; 114 115 // An identifier contains either a 128-bit uuid or a 32-bit signature. 116 union { 117 GUID guid_; 118 DWORD signature_; 119 }; 120 121 // All identifiers used here have age fields, which indicate a specific 122 // revision given a uuid or signature. 123 int age_; 124 }; 125 126 class MSSymbolServerConverter { 127 public: 128 enum LocateResult { 129 LOCATE_FAILURE = 0, 130 LOCATE_NOT_FOUND, // Authoritative: the file is not present. 131 LOCATE_RETRY, // Transient (network?) error, try again later. 132 LOCATE_SUCCESS 133 }; 134 135 // Create a new object. local_cache is the location (pathname) of a local 136 // symbol store used to hold downloaded and converted symbol files. This 137 // directory will be created by LocateSymbolFile when it successfully 138 // retrieves a symbol file. symbol_servers contains a list of locations (URLs 139 // or pathnames) of the upstream symbol server stores, given in order of 140 // preference, with the first string in the vector identifying the first 141 // store to try. The vector must contain at least one string. None of the 142 // strings passed to this constructor may contain asterisk ('*') or semicolon 143 // (';') characters, as the symbol engine uses these characters as separators. 144 MSSymbolServerConverter(const string &local_cache, 145 const vector<string> &symbol_servers); 146 147 // Locates the PE file (DLL or EXE) specified by the identifying information 148 // in |missing|, by checking the symbol stores identified when the object 149 // was created. When returning LOCATE_SUCCESS, pe_file is set to 150 // the pathname of the decompressed PE file as it is stored in the 151 // local cache. 152 LocateResult LocatePEFile(const MissingSymbolInfo &missing, string *pe_file); 153 154 // Locates the symbol file specified by the identifying information in 155 // |missing|, by checking the symbol stores identified when the object 156 // was created. When returning LOCATE_SUCCESS, symbol_file is set to 157 // the pathname of the decompressed symbol file as it is stored in the 158 // local cache. 159 LocateResult LocateSymbolFile(const MissingSymbolInfo &missing, 160 string *symbol_file); 161 162 // Calls LocateSymbolFile and converts the returned symbol file to the 163 // dumped-symbol format, storing it adjacent to the symbol file. The 164 // only conversion supported is from pdb files. Returns the return 165 // value of LocateSymbolFile, or if LocateSymbolFile succeeds but 166 // conversion fails, returns LOCATE_FAILURE. The pathname to the 167 // pdb file and to the converted symbol file are returned in 168 // |converted_symbol_file|, |symbol_file|, and |pe_file|. |symbol_file| and 169 // |pe_file| are optional and may be NULL. If only the converted symbol file 170 // is desired, set |keep_symbol_file| and |keep_pe_file| to false to indicate 171 // that the original symbol file (pdb) and executable file (exe, dll) should 172 // be deleted after conversion. 173 LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo &missing, 174 bool keep_symbol_file, 175 bool keep_pe_file, 176 string *converted_symbol_file, 177 string *symbol_file, 178 string *pe_file); 179 180 // Calls LocatePEFile and converts the returned PE file to the 181 // dumped-symbol format, storing it adjacent to the PE file. The 182 // only conversion supported is from PE files. Returns the return 183 // value of LocatePEFile, or if LocatePEFile succeeds but 184 // conversion fails, returns LOCATE_FAILURE. The pathname to the 185 // PE file and to the converted symbol file are returned in 186 // |converted_symbol_file| and |pe_file|. |pe_file| is optional and may be 187 // NULL. If only the converted symbol file is desired, set |keep_pe_file| 188 // to false to indicate that the executable file (exe, dll) should be deleted 189 // after conversion. 190 // NOTE: Currrently only supports x64 PEs. 191 LocateResult LocateAndConvertPEFile(const MissingSymbolInfo &missing, 192 bool keep_pe_file, 193 string *converted_symbol_file, 194 string *pe_file); 195 196 private: 197 // Locates the PDB or PE file (DLL or EXE) specified by the identifying 198 // information in |debug_or_code_file| and |debug_or_code_id|, by checking 199 // the symbol stores identified when the object was created. When 200 // returning LOCATE_SUCCESS, file_name is set to the pathname of the 201 // decompressed PDB or PE file file as it is stored in the local cache. 202 LocateResult LocateFile(const string &debug_or_code_file, 203 const string &debug_or_code_id, 204 const string &version, string *file_name); 205 206 // Called by various SymSrv functions to report status as progress is made 207 // and to allow the callback to influence processing. Messages sent to this 208 // callback can be used to distinguish between the various failure modes 209 // that SymFindFileInPath might encounter. 210 static BOOL CALLBACK SymCallback(HANDLE process, ULONG action, ULONG64 data, 211 ULONG64 context); 212 213 // Called by SymFindFileInPath (in LocateSymbolFile) after a candidate 214 // symbol file is located, when it's present in the local cache. 215 // SymFindFileInPath actually seems to accept NULL for a callback function 216 // and behave properly for our needs in that case, but the documentation 217 // doesn't mention it, so this little callback is provided. 218 static BOOL CALLBACK SymFindFileInPathCallback(const char *filename, 219 void *context); 220 221 // The search path used by SymSrv, built based on the arguments to the 222 // constructor. 223 string symbol_path_; 224 225 // SymCallback will set at least one of these failure variables if 226 // SymFindFileInPath fails for an expected reason. 227 bool fail_dns_; // DNS failures (fail_not_found_ will also be set). 228 bool fail_timeout_; // Timeouts (fail_not_found_ will also be set). 229 bool fail_not_found_; // The file could not be found. If this is the only 230 // fail_* member set, then it is authoritative. 231 }; 232 233 } // namespace google_breakpad 234 235 #endif // TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ 236