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
73namespace google_breakpad {
74
75using std::string;
76using 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.
82struct MissingSymbolInfo {
83  string code_file;
84  string code_identifier;
85  string debug_file;
86  string debug_identifier;
87  string version;
88};
89
90class GUIDOrSignatureIdentifier {
91 public:
92  enum GUIDOrSignatureType {
93    TYPE_NONE = 0,
94    TYPE_GUID,
95    TYPE_SIGNATURE
96  };
97
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
106  GUIDOrSignatureType type() const { return type_; }
107  GUID guid() const { return guid_; }
108  DWORD signature() const { return signature_; }
109  int age() const { return age_; }
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
126class 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 private:
181  // Locates the PDB or PE file (DLL or EXE) specified by the identifying
182  // information in |debug_or_code_file| and |debug_or_code_id|, by checking
183  // the symbol stores identified when the object was created.  When
184  // returning LOCATE_SUCCESS, file_name is set to the pathname of the
185  // decompressed PDB or PE file file as it is stored in the local cache.
186  LocateResult LocateFile(const string &debug_or_code_file,
187                          const string &debug_or_code_id,
188                          const string &version, string *file_name);
189
190  // Called by various SymSrv functions to report status as progress is made
191  // and to allow the callback to influence processing.  Messages sent to this
192  // callback can be used to distinguish between the various failure modes
193  // that SymFindFileInPath might encounter.
194  static BOOL CALLBACK SymCallback(HANDLE process, ULONG action, ULONG64 data,
195                                   ULONG64 context);
196
197  // Called by SymFindFileInPath (in LocateSymbolFile) after a candidate
198  // symbol file is located, when it's present in the local cache.
199  // SymFindFileInPath actually seems to accept NULL for a callback function
200  // and behave properly for our needs in that case, but the documentation
201  // doesn't mention it, so this little callback is provided.
202  static BOOL CALLBACK SymFindFileInPathCallback(const char *filename,
203                                                 void *context);
204
205  // The search path used by SymSrv, built based on the arguments to the
206  // constructor.
207  string symbol_path_;
208
209  // SymCallback will set at least one of these failure variables if
210  // SymFindFileInPath fails for an expected reason.
211  bool fail_dns_;        // DNS failures (fail_not_found_ will also be set).
212  bool fail_timeout_;    // Timeouts (fail_not_found_ will also be set).
213  bool fail_not_found_;  // The file could not be found.  If this is the only
214                         // fail_* member set, then it is authoritative.
215};
216
217}  // namespace google_breakpad
218
219#endif  // TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_
220