150e299b00e803f085b34847dfe5232b471d84197mmentovai// Copyright (c) 2007, Google Inc.
250e299b00e803f085b34847dfe5232b471d84197mmentovai// All rights reserved.
350e299b00e803f085b34847dfe5232b471d84197mmentovai//
450e299b00e803f085b34847dfe5232b471d84197mmentovai// Redistribution and use in source and binary forms, with or without
550e299b00e803f085b34847dfe5232b471d84197mmentovai// modification, are permitted provided that the following conditions are
650e299b00e803f085b34847dfe5232b471d84197mmentovai// met:
750e299b00e803f085b34847dfe5232b471d84197mmentovai//
850e299b00e803f085b34847dfe5232b471d84197mmentovai//     * Redistributions of source code must retain the above copyright
950e299b00e803f085b34847dfe5232b471d84197mmentovai// notice, this list of conditions and the following disclaimer.
1050e299b00e803f085b34847dfe5232b471d84197mmentovai//     * Redistributions in binary form must reproduce the above
1150e299b00e803f085b34847dfe5232b471d84197mmentovai// copyright notice, this list of conditions and the following disclaimer
1250e299b00e803f085b34847dfe5232b471d84197mmentovai// in the documentation and/or other materials provided with the
1350e299b00e803f085b34847dfe5232b471d84197mmentovai// distribution.
1450e299b00e803f085b34847dfe5232b471d84197mmentovai//     * Neither the name of Google Inc. nor the names of its
1550e299b00e803f085b34847dfe5232b471d84197mmentovai// contributors may be used to endorse or promote products derived from
1650e299b00e803f085b34847dfe5232b471d84197mmentovai// this software without specific prior written permission.
1750e299b00e803f085b34847dfe5232b471d84197mmentovai//
1850e299b00e803f085b34847dfe5232b471d84197mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1950e299b00e803f085b34847dfe5232b471d84197mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2050e299b00e803f085b34847dfe5232b471d84197mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2150e299b00e803f085b34847dfe5232b471d84197mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2250e299b00e803f085b34847dfe5232b471d84197mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2350e299b00e803f085b34847dfe5232b471d84197mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2450e299b00e803f085b34847dfe5232b471d84197mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2550e299b00e803f085b34847dfe5232b471d84197mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2650e299b00e803f085b34847dfe5232b471d84197mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2750e299b00e803f085b34847dfe5232b471d84197mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2850e299b00e803f085b34847dfe5232b471d84197mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2950e299b00e803f085b34847dfe5232b471d84197mmentovai
3050e299b00e803f085b34847dfe5232b471d84197mmentovai// ms_symbol_server_converter.cc: Obtain symbol files from a Microsoft
31e5dc60822e5938fea2ae892ccddb906641ba174emmentovai// symbol server, and convert them to Breakpad's dumped format.
3250e299b00e803f085b34847dfe5232b471d84197mmentovai//
3350e299b00e803f085b34847dfe5232b471d84197mmentovai// See ms_symbol_server_converter.h for documentation.
3450e299b00e803f085b34847dfe5232b471d84197mmentovai//
3550e299b00e803f085b34847dfe5232b471d84197mmentovai// Author: Mark Mentovai
3650e299b00e803f085b34847dfe5232b471d84197mmentovai
37de9fe36b16a45972571b9d650633fe5cb156b536ted.mielczarek@gmail.com#include <windows.h>
38de9fe36b16a45972571b9d650633fe5cb156b536ted.mielczarek@gmail.com#include <dbghelp.h>
3950e299b00e803f085b34847dfe5232b471d84197mmentovai
4050e299b00e803f085b34847dfe5232b471d84197mmentovai#include <cassert>
4150e299b00e803f085b34847dfe5232b471d84197mmentovai#include <cstdio>
4250e299b00e803f085b34847dfe5232b471d84197mmentovai
4350e299b00e803f085b34847dfe5232b471d84197mmentovai#include "tools/windows/converter/ms_symbol_server_converter.h"
4450e299b00e803f085b34847dfe5232b471d84197mmentovai#include "common/windows/pdb_source_line_writer.h"
4550e299b00e803f085b34847dfe5232b471d84197mmentovai#include "common/windows/string_utils-inl.h"
4650e299b00e803f085b34847dfe5232b471d84197mmentovai
4750e299b00e803f085b34847dfe5232b471d84197mmentovai// SYMOPT_NO_PROMPTS is not defined in earlier platform SDKs.  Define it
4850e299b00e803f085b34847dfe5232b471d84197mmentovai// in that case, in the event that this code is used with a newer version
4950e299b00e803f085b34847dfe5232b471d84197mmentovai// of DbgHelp at runtime that recognizes the option.  The presence of this
5050e299b00e803f085b34847dfe5232b471d84197mmentovai// bit in the symbol options should not harm earlier versions of DbgHelp.
5150e299b00e803f085b34847dfe5232b471d84197mmentovai#ifndef SYMOPT_NO_PROMPTS
5250e299b00e803f085b34847dfe5232b471d84197mmentovai#define SYMOPT_NO_PROMPTS 0x00080000
5350e299b00e803f085b34847dfe5232b471d84197mmentovai#endif  // SYMOPT_NO_PROMPTS
5450e299b00e803f085b34847dfe5232b471d84197mmentovai
55e5dc60822e5938fea2ae892ccddb906641ba174emmentovainamespace google_breakpad {
5650e299b00e803f085b34847dfe5232b471d84197mmentovai
5750e299b00e803f085b34847dfe5232b471d84197mmentovai// Use sscanf_s if it is available, to quench the warning about scanf being
5850e299b00e803f085b34847dfe5232b471d84197mmentovai// deprecated.  Use scanf where sscanf_is not available.  Note that the
5950e299b00e803f085b34847dfe5232b471d84197mmentovai// parameters passed to sscanf and sscanf_s are only compatible as long as
6050e299b00e803f085b34847dfe5232b471d84197mmentovai// fields of type c, C, s, S, and [ are not used.
6150e299b00e803f085b34847dfe5232b471d84197mmentovai#if _MSC_VER >= 1400  // MSVC 2005/8
6250e299b00e803f085b34847dfe5232b471d84197mmentovai#define SSCANF sscanf_s
6350e299b00e803f085b34847dfe5232b471d84197mmentovai#else  // _MSC_VER >= 1400
6450e299b00e803f085b34847dfe5232b471d84197mmentovai#define SSCANF sscanf
6550e299b00e803f085b34847dfe5232b471d84197mmentovai#endif  // _MSC_VER >= 1400
6650e299b00e803f085b34847dfe5232b471d84197mmentovai
6750e299b00e803f085b34847dfe5232b471d84197mmentovaibool GUIDOrSignatureIdentifier::InitializeFromString(
6850e299b00e803f085b34847dfe5232b471d84197mmentovai    const string &identifier) {
6950e299b00e803f085b34847dfe5232b471d84197mmentovai  type_ = TYPE_NONE;
7050e299b00e803f085b34847dfe5232b471d84197mmentovai
7150e299b00e803f085b34847dfe5232b471d84197mmentovai  size_t length = identifier.length();
7250e299b00e803f085b34847dfe5232b471d84197mmentovai
7350e299b00e803f085b34847dfe5232b471d84197mmentovai  if (length > 32 && length <= 40) {
7450e299b00e803f085b34847dfe5232b471d84197mmentovai    // GUID
7550e299b00e803f085b34847dfe5232b471d84197mmentovai    if (SSCANF(identifier.c_str(),
7650e299b00e803f085b34847dfe5232b471d84197mmentovai               "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%X",
7750e299b00e803f085b34847dfe5232b471d84197mmentovai               &guid_.Data1, &guid_.Data2, &guid_.Data3,
7850e299b00e803f085b34847dfe5232b471d84197mmentovai               &guid_.Data4[0], &guid_.Data4[1],
7950e299b00e803f085b34847dfe5232b471d84197mmentovai               &guid_.Data4[2], &guid_.Data4[3],
8050e299b00e803f085b34847dfe5232b471d84197mmentovai               &guid_.Data4[4], &guid_.Data4[5],
8150e299b00e803f085b34847dfe5232b471d84197mmentovai               &guid_.Data4[6], &guid_.Data4[7],
8250e299b00e803f085b34847dfe5232b471d84197mmentovai               &age_) != 12) {
8350e299b00e803f085b34847dfe5232b471d84197mmentovai      return false;
8450e299b00e803f085b34847dfe5232b471d84197mmentovai    }
8550e299b00e803f085b34847dfe5232b471d84197mmentovai
8650e299b00e803f085b34847dfe5232b471d84197mmentovai    type_ = TYPE_GUID;
8750e299b00e803f085b34847dfe5232b471d84197mmentovai  } else if (length > 8 && length <= 15) {
8850e299b00e803f085b34847dfe5232b471d84197mmentovai    // Signature
8950e299b00e803f085b34847dfe5232b471d84197mmentovai    if (SSCANF(identifier.c_str(), "%08X%x", &signature_, &age_) != 2) {
9050e299b00e803f085b34847dfe5232b471d84197mmentovai      return false;
9150e299b00e803f085b34847dfe5232b471d84197mmentovai    }
9250e299b00e803f085b34847dfe5232b471d84197mmentovai
9350e299b00e803f085b34847dfe5232b471d84197mmentovai    type_ = TYPE_SIGNATURE;
9450e299b00e803f085b34847dfe5232b471d84197mmentovai  } else {
9550e299b00e803f085b34847dfe5232b471d84197mmentovai    return false;
9650e299b00e803f085b34847dfe5232b471d84197mmentovai  }
9750e299b00e803f085b34847dfe5232b471d84197mmentovai
9850e299b00e803f085b34847dfe5232b471d84197mmentovai  return true;
9950e299b00e803f085b34847dfe5232b471d84197mmentovai}
10050e299b00e803f085b34847dfe5232b471d84197mmentovai
10150e299b00e803f085b34847dfe5232b471d84197mmentovai#undef SSCANF
10250e299b00e803f085b34847dfe5232b471d84197mmentovai
10350e299b00e803f085b34847dfe5232b471d84197mmentovaiMSSymbolServerConverter::MSSymbolServerConverter(
10450e299b00e803f085b34847dfe5232b471d84197mmentovai    const string &local_cache, const vector<string> &symbol_servers)
10550e299b00e803f085b34847dfe5232b471d84197mmentovai    : symbol_path_(),
10650e299b00e803f085b34847dfe5232b471d84197mmentovai      fail_dns_(false),
10750e299b00e803f085b34847dfe5232b471d84197mmentovai      fail_timeout_(false),
10850e299b00e803f085b34847dfe5232b471d84197mmentovai      fail_not_found_(false) {
10950e299b00e803f085b34847dfe5232b471d84197mmentovai  // Setting local_cache can be done without verifying that it exists because
11050e299b00e803f085b34847dfe5232b471d84197mmentovai  // SymSrv will create it if it is missing - any creation failures will occur
11150e299b00e803f085b34847dfe5232b471d84197mmentovai  // at that time, so there's nothing to check here, making it safe to
11250e299b00e803f085b34847dfe5232b471d84197mmentovai  // assign this in the constructor.
11350e299b00e803f085b34847dfe5232b471d84197mmentovai
11450e299b00e803f085b34847dfe5232b471d84197mmentovai  assert(symbol_servers.size() > 0);
11550e299b00e803f085b34847dfe5232b471d84197mmentovai
1160a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com#if !defined(NDEBUG)
11750e299b00e803f085b34847dfe5232b471d84197mmentovai  // These are characters that are interpreted as having special meanings in
11850e299b00e803f085b34847dfe5232b471d84197mmentovai  // symbol_path_.
1190a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  const char kInvalidCharacters[] = "*;";
12050e299b00e803f085b34847dfe5232b471d84197mmentovai  assert(local_cache.find_first_of(kInvalidCharacters) == string::npos);
1210a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com#endif  // !defined(NDEBUG)
12250e299b00e803f085b34847dfe5232b471d84197mmentovai
12350e299b00e803f085b34847dfe5232b471d84197mmentovai  for (vector<string>::const_iterator symbol_server = symbol_servers.begin();
12450e299b00e803f085b34847dfe5232b471d84197mmentovai       symbol_server != symbol_servers.end();
12550e299b00e803f085b34847dfe5232b471d84197mmentovai       ++symbol_server) {
12650e299b00e803f085b34847dfe5232b471d84197mmentovai    // The symbol path format is explained by
12750e299b00e803f085b34847dfe5232b471d84197mmentovai    // http://msdn.microsoft.com/library/en-us/debug/base/using_symsrv.asp .
12850e299b00e803f085b34847dfe5232b471d84197mmentovai    // "srv*" is the same as "symsrv*symsrv.dll*", which means that
12950e299b00e803f085b34847dfe5232b471d84197mmentovai    // symsrv.dll is to be responsible for locating symbols.  symsrv.dll
13050e299b00e803f085b34847dfe5232b471d84197mmentovai    // interprets the rest of the string as a series of symbol stores separated
13150e299b00e803f085b34847dfe5232b471d84197mmentovai    // by '*'.  "srv*local_cache*symbol_server" means to check local_cache
13250e299b00e803f085b34847dfe5232b471d84197mmentovai    // first for the symbol file, and if it is not found there, to check
13350e299b00e803f085b34847dfe5232b471d84197mmentovai    // symbol_server.  Symbol files found on the symbol server will be placed
13450e299b00e803f085b34847dfe5232b471d84197mmentovai    // in the local cache, decompressed.
13550e299b00e803f085b34847dfe5232b471d84197mmentovai    //
13650e299b00e803f085b34847dfe5232b471d84197mmentovai    // Multiple specifications in this format may be presented, separated by
13750e299b00e803f085b34847dfe5232b471d84197mmentovai    // semicolons.
13850e299b00e803f085b34847dfe5232b471d84197mmentovai
13950e299b00e803f085b34847dfe5232b471d84197mmentovai    assert((*symbol_server).find_first_of(kInvalidCharacters) == string::npos);
14050e299b00e803f085b34847dfe5232b471d84197mmentovai    symbol_path_ += "srv*" + local_cache + "*" + *symbol_server + ";";
14150e299b00e803f085b34847dfe5232b471d84197mmentovai  }
14250e299b00e803f085b34847dfe5232b471d84197mmentovai
14350e299b00e803f085b34847dfe5232b471d84197mmentovai  // Strip the trailing semicolon.
14450e299b00e803f085b34847dfe5232b471d84197mmentovai  symbol_path_.erase(symbol_path_.length() - 1);
14550e299b00e803f085b34847dfe5232b471d84197mmentovai}
14650e299b00e803f085b34847dfe5232b471d84197mmentovai
14750e299b00e803f085b34847dfe5232b471d84197mmentovai// A stack-based class that manages SymInitialize and SymCleanup calls.
14850e299b00e803f085b34847dfe5232b471d84197mmentovaiclass AutoSymSrv {
14950e299b00e803f085b34847dfe5232b471d84197mmentovai public:
15050e299b00e803f085b34847dfe5232b471d84197mmentovai  AutoSymSrv() : initialized_(false) {}
15150e299b00e803f085b34847dfe5232b471d84197mmentovai
15250e299b00e803f085b34847dfe5232b471d84197mmentovai  ~AutoSymSrv() {
15350e299b00e803f085b34847dfe5232b471d84197mmentovai    if (!Cleanup()) {
15450e299b00e803f085b34847dfe5232b471d84197mmentovai      // Print the error message here, because destructors have no return
15550e299b00e803f085b34847dfe5232b471d84197mmentovai      // value.
15650e299b00e803f085b34847dfe5232b471d84197mmentovai      fprintf(stderr, "~AutoSymSrv: SymCleanup: error %d\n", GetLastError());
15750e299b00e803f085b34847dfe5232b471d84197mmentovai    }
15850e299b00e803f085b34847dfe5232b471d84197mmentovai  }
15950e299b00e803f085b34847dfe5232b471d84197mmentovai
16050e299b00e803f085b34847dfe5232b471d84197mmentovai  bool Initialize(HANDLE process, char *path, bool invade_process) {
16150e299b00e803f085b34847dfe5232b471d84197mmentovai    process_ = process;
16250e299b00e803f085b34847dfe5232b471d84197mmentovai    initialized_ = SymInitialize(process, path, invade_process) == TRUE;
16350e299b00e803f085b34847dfe5232b471d84197mmentovai    return initialized_;
16450e299b00e803f085b34847dfe5232b471d84197mmentovai  }
16550e299b00e803f085b34847dfe5232b471d84197mmentovai
16650e299b00e803f085b34847dfe5232b471d84197mmentovai  bool Cleanup() {
16750e299b00e803f085b34847dfe5232b471d84197mmentovai    if (initialized_) {
16850e299b00e803f085b34847dfe5232b471d84197mmentovai      if (SymCleanup(process_)) {
16950e299b00e803f085b34847dfe5232b471d84197mmentovai        initialized_ = false;
17050e299b00e803f085b34847dfe5232b471d84197mmentovai        return true;
17150e299b00e803f085b34847dfe5232b471d84197mmentovai      }
17250e299b00e803f085b34847dfe5232b471d84197mmentovai      return false;
17350e299b00e803f085b34847dfe5232b471d84197mmentovai    }
17450e299b00e803f085b34847dfe5232b471d84197mmentovai
17550e299b00e803f085b34847dfe5232b471d84197mmentovai    return true;
17650e299b00e803f085b34847dfe5232b471d84197mmentovai  }
17750e299b00e803f085b34847dfe5232b471d84197mmentovai
17850e299b00e803f085b34847dfe5232b471d84197mmentovai private:
17950e299b00e803f085b34847dfe5232b471d84197mmentovai  HANDLE process_;
18050e299b00e803f085b34847dfe5232b471d84197mmentovai  bool initialized_;
18150e299b00e803f085b34847dfe5232b471d84197mmentovai};
18250e299b00e803f085b34847dfe5232b471d84197mmentovai
18350e299b00e803f085b34847dfe5232b471d84197mmentovai// A stack-based class that "owns" a pathname and deletes it when destroyed,
18450e299b00e803f085b34847dfe5232b471d84197mmentovai// unless told not to by having its Release() method called.  Early deletions
18550e299b00e803f085b34847dfe5232b471d84197mmentovai// are supported by calling Delete().
18650e299b00e803f085b34847dfe5232b471d84197mmentovaiclass AutoDeleter {
18750e299b00e803f085b34847dfe5232b471d84197mmentovai public:
1880a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  explicit AutoDeleter(const string &path) : path_(path) {}
18950e299b00e803f085b34847dfe5232b471d84197mmentovai
19050e299b00e803f085b34847dfe5232b471d84197mmentovai  ~AutoDeleter() {
19150e299b00e803f085b34847dfe5232b471d84197mmentovai    int error;
19250e299b00e803f085b34847dfe5232b471d84197mmentovai    if ((error = Delete()) != 0) {
19350e299b00e803f085b34847dfe5232b471d84197mmentovai      // Print the error message here, because destructors have no return
19450e299b00e803f085b34847dfe5232b471d84197mmentovai      // value.
19550e299b00e803f085b34847dfe5232b471d84197mmentovai      fprintf(stderr, "~AutoDeleter: Delete: error %d for %s\n",
19650e299b00e803f085b34847dfe5232b471d84197mmentovai              error, path_.c_str());
19750e299b00e803f085b34847dfe5232b471d84197mmentovai    }
19850e299b00e803f085b34847dfe5232b471d84197mmentovai  }
19950e299b00e803f085b34847dfe5232b471d84197mmentovai
20050e299b00e803f085b34847dfe5232b471d84197mmentovai  int Delete() {
20150e299b00e803f085b34847dfe5232b471d84197mmentovai    if (path_.empty())
20250e299b00e803f085b34847dfe5232b471d84197mmentovai      return 0;
20350e299b00e803f085b34847dfe5232b471d84197mmentovai
20450e299b00e803f085b34847dfe5232b471d84197mmentovai    int error = remove(path_.c_str());
20550e299b00e803f085b34847dfe5232b471d84197mmentovai    Release();
20650e299b00e803f085b34847dfe5232b471d84197mmentovai    return error;
20750e299b00e803f085b34847dfe5232b471d84197mmentovai  }
20850e299b00e803f085b34847dfe5232b471d84197mmentovai
20950e299b00e803f085b34847dfe5232b471d84197mmentovai  void Release() {
21050e299b00e803f085b34847dfe5232b471d84197mmentovai    path_.clear();
21150e299b00e803f085b34847dfe5232b471d84197mmentovai  }
21250e299b00e803f085b34847dfe5232b471d84197mmentovai
21350e299b00e803f085b34847dfe5232b471d84197mmentovai private:
21450e299b00e803f085b34847dfe5232b471d84197mmentovai  string path_;
21550e299b00e803f085b34847dfe5232b471d84197mmentovai};
21650e299b00e803f085b34847dfe5232b471d84197mmentovai
21750e299b00e803f085b34847dfe5232b471d84197mmentovaiMSSymbolServerConverter::LocateResult
2180a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.comMSSymbolServerConverter::LocateFile(const string &debug_or_code_file,
2190a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                                    const string &debug_or_code_id,
2200a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                                    const string &version,
2210a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                                    string *file_name) {
2220a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  assert(file_name);
2230a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  file_name->clear();
22450e299b00e803f085b34847dfe5232b471d84197mmentovai
22550e299b00e803f085b34847dfe5232b471d84197mmentovai  GUIDOrSignatureIdentifier identifier;
2260a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (!identifier.InitializeFromString(debug_or_code_id)) {
22750e299b00e803f085b34847dfe5232b471d84197mmentovai    fprintf(stderr,
2280a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "LocateFile: Unparseable identifier for %s %s %s\n",
2290a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_file.c_str(),
2300a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_id.c_str(),
2310a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            version.c_str());
23250e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
23350e299b00e803f085b34847dfe5232b471d84197mmentovai  }
23450e299b00e803f085b34847dfe5232b471d84197mmentovai
23550e299b00e803f085b34847dfe5232b471d84197mmentovai  HANDLE process = GetCurrentProcess();  // CloseHandle is not needed.
23650e299b00e803f085b34847dfe5232b471d84197mmentovai  AutoSymSrv symsrv;
23750e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!symsrv.Initialize(process,
23850e299b00e803f085b34847dfe5232b471d84197mmentovai                         const_cast<char *>(symbol_path_.c_str()),
23950e299b00e803f085b34847dfe5232b471d84197mmentovai                         false)) {
2400a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr, "LocateFile: SymInitialize: error %d for %s %s %s\n",
24150e299b00e803f085b34847dfe5232b471d84197mmentovai            GetLastError(),
2420a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_file.c_str(),
2430a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_id.c_str(),
2440a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            version.c_str());
24550e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
24650e299b00e803f085b34847dfe5232b471d84197mmentovai  }
24750e299b00e803f085b34847dfe5232b471d84197mmentovai
24850e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!SymRegisterCallback64(process, SymCallback,
24950e299b00e803f085b34847dfe5232b471d84197mmentovai                             reinterpret_cast<ULONG64>(this))) {
25050e299b00e803f085b34847dfe5232b471d84197mmentovai    fprintf(stderr,
2510a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "LocateFile: SymRegisterCallback64: error %d for %s %s %s\n",
25250e299b00e803f085b34847dfe5232b471d84197mmentovai            GetLastError(),
2530a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_file.c_str(),
2540a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_id.c_str(),
2550a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            version.c_str());
25650e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
25750e299b00e803f085b34847dfe5232b471d84197mmentovai  }
25850e299b00e803f085b34847dfe5232b471d84197mmentovai
25950e299b00e803f085b34847dfe5232b471d84197mmentovai  // SYMOPT_DEBUG arranges for SymCallback to be called with additional
26050e299b00e803f085b34847dfe5232b471d84197mmentovai  // debugging information.  This is used to determine the nature of failures.
26150e299b00e803f085b34847dfe5232b471d84197mmentovai  DWORD options = SymGetOptions() | SYMOPT_DEBUG | SYMOPT_NO_PROMPTS |
26250e299b00e803f085b34847dfe5232b471d84197mmentovai                  SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_SECURE;
26350e299b00e803f085b34847dfe5232b471d84197mmentovai  SymSetOptions(options);
26450e299b00e803f085b34847dfe5232b471d84197mmentovai
26550e299b00e803f085b34847dfe5232b471d84197mmentovai  // SymCallback will set these as needed inisde the SymFindFileInPath call.
26650e299b00e803f085b34847dfe5232b471d84197mmentovai  fail_dns_ = false;
26750e299b00e803f085b34847dfe5232b471d84197mmentovai  fail_timeout_ = false;
26850e299b00e803f085b34847dfe5232b471d84197mmentovai  fail_not_found_ = false;
26950e299b00e803f085b34847dfe5232b471d84197mmentovai
27050e299b00e803f085b34847dfe5232b471d84197mmentovai  // Do the lookup.
27150e299b00e803f085b34847dfe5232b471d84197mmentovai  char path[MAX_PATH];
27250e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!SymFindFileInPath(
27350e299b00e803f085b34847dfe5232b471d84197mmentovai          process, NULL,
2740a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com          const_cast<char *>(debug_or_code_file.c_str()),
27550e299b00e803f085b34847dfe5232b471d84197mmentovai          const_cast<void *>(identifier.guid_or_signature_pointer()),
27650e299b00e803f085b34847dfe5232b471d84197mmentovai          identifier.age(), 0,
27750e299b00e803f085b34847dfe5232b471d84197mmentovai          identifier.type() == GUIDOrSignatureIdentifier::TYPE_GUID ?
27850e299b00e803f085b34847dfe5232b471d84197mmentovai              SSRVOPT_GUIDPTR : SSRVOPT_DWORDPTR,
27950e299b00e803f085b34847dfe5232b471d84197mmentovai          path, SymFindFileInPathCallback, this)) {
28050e299b00e803f085b34847dfe5232b471d84197mmentovai    DWORD error = GetLastError();
28150e299b00e803f085b34847dfe5232b471d84197mmentovai    if (error == ERROR_FILE_NOT_FOUND) {
28250e299b00e803f085b34847dfe5232b471d84197mmentovai      // This can be returned for a number of reasons.  Use the crumbs
28350e299b00e803f085b34847dfe5232b471d84197mmentovai      // collected by SymCallback to determine which one is relevant.
28450e299b00e803f085b34847dfe5232b471d84197mmentovai
28550e299b00e803f085b34847dfe5232b471d84197mmentovai      // These errors are possibly transient.
28650e299b00e803f085b34847dfe5232b471d84197mmentovai      if (fail_dns_ || fail_timeout_) {
28750e299b00e803f085b34847dfe5232b471d84197mmentovai        return LOCATE_RETRY;
28850e299b00e803f085b34847dfe5232b471d84197mmentovai      }
28950e299b00e803f085b34847dfe5232b471d84197mmentovai
29050e299b00e803f085b34847dfe5232b471d84197mmentovai      // This is an authoritiative file-not-found message.
29150e299b00e803f085b34847dfe5232b471d84197mmentovai      if (fail_not_found_) {
29211dc02869471b92f6e11023477e9cfed9ff11cd0doshimun        fprintf(stderr,
2930a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                "LocateFile: SymFindFileInPath: LOCATE_NOT_FOUND error "
29411dc02869471b92f6e11023477e9cfed9ff11cd0doshimun                "for %s %s %s\n",
2950a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                debug_or_code_file.c_str(),
2960a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                debug_or_code_id.c_str(),
2970a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                version.c_str());
29850e299b00e803f085b34847dfe5232b471d84197mmentovai        return LOCATE_NOT_FOUND;
29950e299b00e803f085b34847dfe5232b471d84197mmentovai      }
30050e299b00e803f085b34847dfe5232b471d84197mmentovai
30150e299b00e803f085b34847dfe5232b471d84197mmentovai      // If the error is FILE_NOT_FOUND but none of the known error
30250e299b00e803f085b34847dfe5232b471d84197mmentovai      // conditions are matched, fall through to LOCATE_FAILURE.
30350e299b00e803f085b34847dfe5232b471d84197mmentovai    }
30450e299b00e803f085b34847dfe5232b471d84197mmentovai
30550e299b00e803f085b34847dfe5232b471d84197mmentovai    fprintf(stderr,
3060a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "LocateFile: SymFindFileInPath: error %d for %s %s %s\n",
30750e299b00e803f085b34847dfe5232b471d84197mmentovai            error,
3080a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_file.c_str(),
3090a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_id.c_str(),
3100a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            version.c_str());
31150e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
31250e299b00e803f085b34847dfe5232b471d84197mmentovai  }
31350e299b00e803f085b34847dfe5232b471d84197mmentovai
3140a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // Making sure path is null-terminated.
3150a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  path[MAX_PATH - 1] = '\0';
3160a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
31750e299b00e803f085b34847dfe5232b471d84197mmentovai  // The AutoDeleter ensures that the file is only kept when returning
31850e299b00e803f085b34847dfe5232b471d84197mmentovai  // LOCATE_SUCCESS.
31950e299b00e803f085b34847dfe5232b471d84197mmentovai  AutoDeleter deleter(path);
32050e299b00e803f085b34847dfe5232b471d84197mmentovai
32150e299b00e803f085b34847dfe5232b471d84197mmentovai  // Do the cleanup here even though it will happen when symsrv goes out of
32250e299b00e803f085b34847dfe5232b471d84197mmentovai  // scope, to allow it to influence the return value.
32350e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!symsrv.Cleanup()) {
3240a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr, "LocateFile: SymCleanup: error %d for %s %s %s\n",
32550e299b00e803f085b34847dfe5232b471d84197mmentovai            GetLastError(),
3260a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_file.c_str(),
3270a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            debug_or_code_id.c_str(),
3280a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            version.c_str());
32950e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
33050e299b00e803f085b34847dfe5232b471d84197mmentovai  }
33150e299b00e803f085b34847dfe5232b471d84197mmentovai
33250e299b00e803f085b34847dfe5232b471d84197mmentovai  deleter.Release();
33350e299b00e803f085b34847dfe5232b471d84197mmentovai
3340a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  printf("Downloaded: %s\n", path);
3350a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  *file_name = path;
33650e299b00e803f085b34847dfe5232b471d84197mmentovai  return LOCATE_SUCCESS;
33750e299b00e803f085b34847dfe5232b471d84197mmentovai}
33850e299b00e803f085b34847dfe5232b471d84197mmentovai
3390a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
3400a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.comMSSymbolServerConverter::LocateResult
3410a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.comMSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo &missing,
3420a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                                      string *pe_file) {
3430a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  return LocateFile(missing.code_file, missing.code_identifier,
3440a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                    missing.version, pe_file);
3450a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com}
3460a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
3470a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.comMSSymbolServerConverter::LocateResult
3480a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.comMSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo &missing,
3490a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                                          string *symbol_file) {
3500a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  return LocateFile(missing.debug_file, missing.debug_identifier,
3510a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                    missing.version, symbol_file);
3520a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com}
3530a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
3540a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
35550e299b00e803f085b34847dfe5232b471d84197mmentovai// static
35650e299b00e803f085b34847dfe5232b471d84197mmentovaiBOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process,
35750e299b00e803f085b34847dfe5232b471d84197mmentovai                                                   ULONG action,
35850e299b00e803f085b34847dfe5232b471d84197mmentovai                                                   ULONG64 data,
35950e299b00e803f085b34847dfe5232b471d84197mmentovai                                                   ULONG64 context) {
36050e299b00e803f085b34847dfe5232b471d84197mmentovai  MSSymbolServerConverter *self =
36150e299b00e803f085b34847dfe5232b471d84197mmentovai      reinterpret_cast<MSSymbolServerConverter *>(context);
36250e299b00e803f085b34847dfe5232b471d84197mmentovai
36350e299b00e803f085b34847dfe5232b471d84197mmentovai  switch (action) {
36450e299b00e803f085b34847dfe5232b471d84197mmentovai    case CBA_EVENT: {
36550e299b00e803f085b34847dfe5232b471d84197mmentovai      IMAGEHLP_CBA_EVENT *cba_event =
36650e299b00e803f085b34847dfe5232b471d84197mmentovai          reinterpret_cast<IMAGEHLP_CBA_EVENT *>(data);
36750e299b00e803f085b34847dfe5232b471d84197mmentovai
3680a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com      // Put the string into a string object to be able to use string::find
36950e299b00e803f085b34847dfe5232b471d84197mmentovai      // for substring matching.  This is important because the not-found
37050e299b00e803f085b34847dfe5232b471d84197mmentovai      // message does not use the entire string but is appended to the URL
37150e299b00e803f085b34847dfe5232b471d84197mmentovai      // that SymSrv attempted to retrieve.
37250e299b00e803f085b34847dfe5232b471d84197mmentovai      string desc(cba_event->desc);
37350e299b00e803f085b34847dfe5232b471d84197mmentovai
37450e299b00e803f085b34847dfe5232b471d84197mmentovai      // desc_action maps strings (in desc) to boolean pointers that are to
37550e299b00e803f085b34847dfe5232b471d84197mmentovai      // be set to true if the string matches.
37650e299b00e803f085b34847dfe5232b471d84197mmentovai      struct desc_action {
37750e299b00e803f085b34847dfe5232b471d84197mmentovai        const char *desc;  // The substring to match.
37850e299b00e803f085b34847dfe5232b471d84197mmentovai        bool *action;      // On match, this pointer will be set to true.
37950e299b00e803f085b34847dfe5232b471d84197mmentovai      };
38050e299b00e803f085b34847dfe5232b471d84197mmentovai
38150e299b00e803f085b34847dfe5232b471d84197mmentovai      static const desc_action desc_actions[] = {
38250e299b00e803f085b34847dfe5232b471d84197mmentovai        // When a DNS error occurs, it could be indiciative of network
38350e299b00e803f085b34847dfe5232b471d84197mmentovai        // problems.
38450e299b00e803f085b34847dfe5232b471d84197mmentovai        { "SYMSRV:  The server name or address could not be resolved\n",
38550e299b00e803f085b34847dfe5232b471d84197mmentovai          &self->fail_dns_ },
38650e299b00e803f085b34847dfe5232b471d84197mmentovai
38750e299b00e803f085b34847dfe5232b471d84197mmentovai        // This message is produced if no connection is opened.
38850e299b00e803f085b34847dfe5232b471d84197mmentovai        { "SYMSRV:  A connection with the server could not be established\n",
38950e299b00e803f085b34847dfe5232b471d84197mmentovai          &self->fail_timeout_ },
39050e299b00e803f085b34847dfe5232b471d84197mmentovai
39150e299b00e803f085b34847dfe5232b471d84197mmentovai        // This message is produced if a connection is established but the
39250e299b00e803f085b34847dfe5232b471d84197mmentovai        // server fails to respond to the HTTP request.
39350e299b00e803f085b34847dfe5232b471d84197mmentovai        { "SYMSRV:  The operation timed out\n",
39450e299b00e803f085b34847dfe5232b471d84197mmentovai          &self->fail_timeout_ },
39550e299b00e803f085b34847dfe5232b471d84197mmentovai
39650e299b00e803f085b34847dfe5232b471d84197mmentovai        // This message is produced when the requested file is not found,
39750e299b00e803f085b34847dfe5232b471d84197mmentovai        // even if one or more of the above messages are also produced.
39850e299b00e803f085b34847dfe5232b471d84197mmentovai        // It's trapped to distinguish between not-found and unknown-failure
39950e299b00e803f085b34847dfe5232b471d84197mmentovai        // conditions.  Note that this message will not be produced if a
40050e299b00e803f085b34847dfe5232b471d84197mmentovai        // connection is established and the server begins to respond to the
40150e299b00e803f085b34847dfe5232b471d84197mmentovai        // HTTP request but does not finish transmitting the file.
40250e299b00e803f085b34847dfe5232b471d84197mmentovai        { " not found\n",
40350e299b00e803f085b34847dfe5232b471d84197mmentovai          &self->fail_not_found_ }
40450e299b00e803f085b34847dfe5232b471d84197mmentovai      };
40550e299b00e803f085b34847dfe5232b471d84197mmentovai
40650e299b00e803f085b34847dfe5232b471d84197mmentovai      for (int desc_action_index = 0;
40750e299b00e803f085b34847dfe5232b471d84197mmentovai           desc_action_index < sizeof(desc_actions) / sizeof(desc_action);
40850e299b00e803f085b34847dfe5232b471d84197mmentovai           ++desc_action_index) {
40950e299b00e803f085b34847dfe5232b471d84197mmentovai        if (desc.find(desc_actions[desc_action_index].desc) != string::npos) {
41050e299b00e803f085b34847dfe5232b471d84197mmentovai          *(desc_actions[desc_action_index].action) = true;
41150e299b00e803f085b34847dfe5232b471d84197mmentovai          break;
41250e299b00e803f085b34847dfe5232b471d84197mmentovai        }
41350e299b00e803f085b34847dfe5232b471d84197mmentovai      }
41450e299b00e803f085b34847dfe5232b471d84197mmentovai
41550e299b00e803f085b34847dfe5232b471d84197mmentovai      break;
41650e299b00e803f085b34847dfe5232b471d84197mmentovai    }
41750e299b00e803f085b34847dfe5232b471d84197mmentovai  }
41850e299b00e803f085b34847dfe5232b471d84197mmentovai
41950e299b00e803f085b34847dfe5232b471d84197mmentovai  // This function is a mere fly on the wall.  Treat everything as unhandled.
42050e299b00e803f085b34847dfe5232b471d84197mmentovai  return FALSE;
42150e299b00e803f085b34847dfe5232b471d84197mmentovai}
42250e299b00e803f085b34847dfe5232b471d84197mmentovai
42350e299b00e803f085b34847dfe5232b471d84197mmentovai// static
42450e299b00e803f085b34847dfe5232b471d84197mmentovaiBOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback(
4250a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    const char *filename, void *context) {
42650e299b00e803f085b34847dfe5232b471d84197mmentovai  // FALSE ends the search, indicating that the located symbol file is
42750e299b00e803f085b34847dfe5232b471d84197mmentovai  // satisfactory.
42850e299b00e803f085b34847dfe5232b471d84197mmentovai  return FALSE;
42950e299b00e803f085b34847dfe5232b471d84197mmentovai}
43050e299b00e803f085b34847dfe5232b471d84197mmentovai
43150e299b00e803f085b34847dfe5232b471d84197mmentovaiMSSymbolServerConverter::LocateResult
43250e299b00e803f085b34847dfe5232b471d84197mmentovaiMSSymbolServerConverter::LocateAndConvertSymbolFile(
43350e299b00e803f085b34847dfe5232b471d84197mmentovai    const MissingSymbolInfo &missing,
43450e299b00e803f085b34847dfe5232b471d84197mmentovai    bool keep_symbol_file,
4350a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    bool keep_pe_file,
43650e299b00e803f085b34847dfe5232b471d84197mmentovai    string *converted_symbol_file,
4370a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    string *symbol_file,
4380a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    string *out_pe_file) {
43950e299b00e803f085b34847dfe5232b471d84197mmentovai  assert(converted_symbol_file);
44050e299b00e803f085b34847dfe5232b471d84197mmentovai  converted_symbol_file->clear();
44150e299b00e803f085b34847dfe5232b471d84197mmentovai  if (symbol_file) {
44250e299b00e803f085b34847dfe5232b471d84197mmentovai    symbol_file->clear();
44350e299b00e803f085b34847dfe5232b471d84197mmentovai  }
44450e299b00e803f085b34847dfe5232b471d84197mmentovai
44550e299b00e803f085b34847dfe5232b471d84197mmentovai  string pdb_file;
44650e299b00e803f085b34847dfe5232b471d84197mmentovai  LocateResult result = LocateSymbolFile(missing, &pdb_file);
44750e299b00e803f085b34847dfe5232b471d84197mmentovai  if (result != LOCATE_SUCCESS) {
44850e299b00e803f085b34847dfe5232b471d84197mmentovai    return result;
44950e299b00e803f085b34847dfe5232b471d84197mmentovai  }
45050e299b00e803f085b34847dfe5232b471d84197mmentovai
45150e299b00e803f085b34847dfe5232b471d84197mmentovai  if (symbol_file && keep_symbol_file) {
45250e299b00e803f085b34847dfe5232b471d84197mmentovai    *symbol_file = pdb_file;
45350e299b00e803f085b34847dfe5232b471d84197mmentovai  }
45450e299b00e803f085b34847dfe5232b471d84197mmentovai
4550a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // The conversion of a symbol file for a Windows 64-bit module requires
4560a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // loading of the executable file.  If there is no executable file, convert
4570a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // using only the PDB file.  Without an executable file, the conversion will
4580a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  // fail for 64-bit modules but it should succeed for 32-bit modules.
4590a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  string pe_file;
4600a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  result = LocatePEFile(missing, &pe_file);
4610a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (result != LOCATE_SUCCESS) {
4620a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str());
4630a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  }
4640a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
4650a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (out_pe_file && keep_pe_file) {
4660a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    *out_pe_file = pe_file;
4670a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  }
4680a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
46950e299b00e803f085b34847dfe5232b471d84197mmentovai  // Conversion may fail because the file is corrupt.  If a broken file is
47050e299b00e803f085b34847dfe5232b471d84197mmentovai  // kept in the local cache, LocateSymbolFile will not hit the network again
47150e299b00e803f085b34847dfe5232b471d84197mmentovai  // to attempt to locate it.  To guard against problems like this, the
47250e299b00e803f085b34847dfe5232b471d84197mmentovai  // symbol file in the local cache will be removed if conversion fails.
47350e299b00e803f085b34847dfe5232b471d84197mmentovai  AutoDeleter pdb_deleter(pdb_file);
4740a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  AutoDeleter pe_deleter(pe_file);
47550e299b00e803f085b34847dfe5232b471d84197mmentovai
47650e299b00e803f085b34847dfe5232b471d84197mmentovai  // Be sure that it's a .pdb file, since we'll be replacing .pdb with .sym
47750e299b00e803f085b34847dfe5232b471d84197mmentovai  // for the converted file's name.
47850e299b00e803f085b34847dfe5232b471d84197mmentovai  string pdb_extension = pdb_file.substr(pdb_file.length() - 4);
47950e299b00e803f085b34847dfe5232b471d84197mmentovai  // strcasecmp is called _stricmp here.
48050e299b00e803f085b34847dfe5232b471d84197mmentovai  if (_stricmp(pdb_extension.c_str(), ".pdb") != 0) {
48150e299b00e803f085b34847dfe5232b471d84197mmentovai    fprintf(stderr, "LocateAndConvertSymbolFile: "
4820a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "no .pdb extension for %s %s %s %s\n",
48350e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.debug_file.c_str(),
48450e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.debug_identifier.c_str(),
48550e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.version.c_str(),
48650e299b00e803f085b34847dfe5232b471d84197mmentovai            pdb_file.c_str());
48750e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
48850e299b00e803f085b34847dfe5232b471d84197mmentovai  }
48950e299b00e803f085b34847dfe5232b471d84197mmentovai
4900a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  PDBSourceLineWriter writer;
4910a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  wstring pe_file_w;
4920a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) {
4930a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr,
4940a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "LocateAndConvertSymbolFile: "
4950a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                "WindowsStringUtils::safe_mbstowcs failed for %s\n",
4960a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            pe_file.c_str());
4970a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    return LOCATE_FAILURE;
4980a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  }
49950e299b00e803f085b34847dfe5232b471d84197mmentovai  wstring pdb_file_w;
50050e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!WindowsStringUtils::safe_mbstowcs(pdb_file, &pdb_file_w)) {
5010a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr,
5020a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "LocateAndConvertSymbolFile: "
5030a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com                "WindowsStringUtils::safe_mbstowcs failed for %s\n",
5040a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            pdb_file_w.c_str());
50550e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
50650e299b00e803f085b34847dfe5232b471d84197mmentovai  }
50750e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!writer.Open(pdb_file_w, PDBSourceLineWriter::PDB_FILE)) {
5080a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr,
5090a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "ERROR: PDBSourceLineWriter::Open failed for %s %s %s %ws\n",
5100a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            missing.debug_file.c_str(), missing.debug_identifier.c_str(),
5110a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            missing.version.c_str(), pdb_file_w.c_str());
5120a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    return LOCATE_FAILURE;
5130a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  }
5140a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (!writer.SetCodeFile(pe_file_w)) {
5150a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    fprintf(stderr,
5160a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            "ERROR: PDBSourceLineWriter::SetCodeFile failed for %s %s %s %ws\n",
5170a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            missing.debug_file.c_str(), missing.debug_identifier.c_str(),
5180a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com            missing.version.c_str(), pe_file_w.c_str());
51950e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
52050e299b00e803f085b34847dfe5232b471d84197mmentovai  }
52150e299b00e803f085b34847dfe5232b471d84197mmentovai
52250e299b00e803f085b34847dfe5232b471d84197mmentovai  *converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym";
52350e299b00e803f085b34847dfe5232b471d84197mmentovai
52450e299b00e803f085b34847dfe5232b471d84197mmentovai  FILE *converted_output = NULL;
52550e299b00e803f085b34847dfe5232b471d84197mmentovai#if _MSC_VER >= 1400  // MSVC 2005/8
52650e299b00e803f085b34847dfe5232b471d84197mmentovai  errno_t err;
52750e299b00e803f085b34847dfe5232b471d84197mmentovai  if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w"))
52850e299b00e803f085b34847dfe5232b471d84197mmentovai      != 0) {
52950e299b00e803f085b34847dfe5232b471d84197mmentovai#else  // _MSC_VER >= 1400
53050e299b00e803f085b34847dfe5232b471d84197mmentovai  // fopen_s and errno_t were introduced in MSVC8.  Use fopen for earlier
53150e299b00e803f085b34847dfe5232b471d84197mmentovai  // environments.  Don't use fopen with MSVC8 and later, because it's
53250e299b00e803f085b34847dfe5232b471d84197mmentovai  // deprecated.  fopen does not provide reliable error codes, so just use
53350e299b00e803f085b34847dfe5232b471d84197mmentovai  // -1 in the event of a failure.
53450e299b00e803f085b34847dfe5232b471d84197mmentovai  int err;
53550e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) {
53650e299b00e803f085b34847dfe5232b471d84197mmentovai    err = -1;
53750e299b00e803f085b34847dfe5232b471d84197mmentovai#endif  // _MSC_VER >= 1400
53850e299b00e803f085b34847dfe5232b471d84197mmentovai    fprintf(stderr, "LocateAndConvertSymbolFile: "
53950e299b00e803f085b34847dfe5232b471d84197mmentovai            "fopen_s: error %d for %s %s %s %s\n",
54050e299b00e803f085b34847dfe5232b471d84197mmentovai            err,
54150e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.debug_file.c_str(),
54250e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.debug_identifier.c_str(),
54350e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.version.c_str(),
54450e299b00e803f085b34847dfe5232b471d84197mmentovai            converted_symbol_file->c_str());
54550e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
54650e299b00e803f085b34847dfe5232b471d84197mmentovai  }
54750e299b00e803f085b34847dfe5232b471d84197mmentovai
54850e299b00e803f085b34847dfe5232b471d84197mmentovai  AutoDeleter sym_deleter(*converted_symbol_file);
54950e299b00e803f085b34847dfe5232b471d84197mmentovai
55050e299b00e803f085b34847dfe5232b471d84197mmentovai  bool success = writer.WriteMap(converted_output);
55150e299b00e803f085b34847dfe5232b471d84197mmentovai  fclose(converted_output);
55250e299b00e803f085b34847dfe5232b471d84197mmentovai
55350e299b00e803f085b34847dfe5232b471d84197mmentovai  if (!success) {
55450e299b00e803f085b34847dfe5232b471d84197mmentovai    fprintf(stderr, "LocateAndConvertSymbolFile: "
55550e299b00e803f085b34847dfe5232b471d84197mmentovai            "PDBSourceLineWriter::WriteMap failed for %s %s %s %s\n",
55650e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.debug_file.c_str(),
55750e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.debug_identifier.c_str(),
55850e299b00e803f085b34847dfe5232b471d84197mmentovai            missing.version.c_str(),
55950e299b00e803f085b34847dfe5232b471d84197mmentovai            pdb_file.c_str());
56050e299b00e803f085b34847dfe5232b471d84197mmentovai    return LOCATE_FAILURE;
56150e299b00e803f085b34847dfe5232b471d84197mmentovai  }
56250e299b00e803f085b34847dfe5232b471d84197mmentovai
56350e299b00e803f085b34847dfe5232b471d84197mmentovai  if (keep_symbol_file) {
56450e299b00e803f085b34847dfe5232b471d84197mmentovai    pdb_deleter.Release();
56550e299b00e803f085b34847dfe5232b471d84197mmentovai  }
56650e299b00e803f085b34847dfe5232b471d84197mmentovai
5670a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  if (keep_pe_file) {
5680a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com    pe_deleter.Release();
5690a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com  }
5700a35290a4ecafc23215c2df491f7093f18fcda97ivan.penkov@gmail.com
57150e299b00e803f085b34847dfe5232b471d84197mmentovai  sym_deleter.Release();
57250e299b00e803f085b34847dfe5232b471d84197mmentovai
57350e299b00e803f085b34847dfe5232b471d84197mmentovai  return LOCATE_SUCCESS;
57450e299b00e803f085b34847dfe5232b471d84197mmentovai}
57550e299b00e803f085b34847dfe5232b471d84197mmentovai
576e5dc60822e5938fea2ae892ccddb906641ba174emmentovai}  // namespace google_breakpad
577