Coverage for /Syzygy/pe/find.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
82.6%951150.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // Implementation of utility functions for module/PDB search and discovery.
  16    :  // Leverages the debughlp back-end so that behaviour is consistent with those
  17    :  // tools.
  18    :  
  19    :  #include "syzygy/pe/find.h"
  20    :  
  21    :  #include <dbghelp.h>
  22    :  #include <winnt.h>
  23    :  
  24    :  #include "base/environment.h"
  25    :  #include "base/file_util.h"
  26    :  #include "base/logging.h"
  27    :  #include "base/string_split.h"
  28    :  #include "base/utf_string_conversions.h"
  29    :  #include "sawbuck/common/com_utils.h"
  30    :  #include "syzygy/pdb/pdb_util.h"
  31    :  #include "syzygy/pe/pdb_info.h"
  32    :  #include "syzygy/pe/pe_data.h"
  33    :  #include "syzygy/pe/pe_file.h"
  34    :  
  35    :  namespace pe {
  36    :  
  37    :  namespace {
  38    :  
  39  E :  bool GetEnvVar(const char* name, std::wstring* value) {
  40  E :    DCHECK(name != NULL);
  41  E :    DCHECK(value != NULL);
  42  E :    value->clear();
  43    :  
  44  E :    scoped_ptr<base::Environment> env(base::Environment::Create());
  45  E :    if (env.get() == NULL) {
  46  i :      LOG(ERROR) << "base::Environment::Create returned NULL.";
  47  i :      return false;
  48    :    }
  49    :  
  50    :    // If this fails, the environment variable simply does not exist.
  51  E :    std::string var;
  52  E :    if (!env->GetVar(name, &var))
  53  E :      return true;
  54    :  
  55    :    if (!UTF8ToWide(var.c_str(),
  56    :                    var.size(),
  57  E :                    value)) {
  58  i :      LOG(ERROR) << "UTF8ToWide(\"" << var << "\" failed.";
  59  i :      return false;
  60    :    }
  61    :  
  62  E :    return true;
  63  E :  }
  64    :  
  65    :  // Return TRUE to continue searching, FALSE if we want the search to stop.
  66  E :  BOOL CALLBACK FindPdbFileCallback(PCTSTR path, PVOID context) {
  67  E :    DCHECK(path != NULL);
  68  E :    DCHECK(context != NULL);
  69    :  
  70  E :    FilePath pdb_path(path);
  71  E :    const PdbInfo* pdb_info = static_cast<PdbInfo*>(context);
  72    :  
  73    :    pdb::PdbInfoHeader70 pdb_header;
  74  E :    if (!pdb::ReadPdbHeader(pdb_path, &pdb_header))
  75  i :      return TRUE;
  76  E :    if (!pdb_info->IsConsistent(pdb_header))
  77  i :      return TRUE;
  78    :  
  79  E :    return FALSE;
  80  E :  }
  81    :  
  82    :  // Return TRUE to continue searching, FALSE if we want the search to stop.
  83  E :  BOOL CALLBACK FindPeFileCallback(PCTSTR path, PVOID context) {
  84  E :    DCHECK(path != NULL);
  85  E :    DCHECK(context != NULL);
  86    :  
  87  E :    FilePath pe_path(path);
  88  E :    const PEFile::Signature* pe_info = static_cast<PEFile::Signature*>(context);
  89    :  
  90  E :    PEFile pe_file;
  91  E :    if (!pe_file.Init(pe_path))
  92  i :      return TRUE;
  93  E :    PEFile::Signature pe_sig;
  94  E :    pe_file.GetSignature(&pe_sig);
  95    :  
  96    :    // We don't care about the base address or the path.
  97    :    if (pe_sig.module_checksum != pe_info->module_checksum ||
  98    :        pe_sig.module_size != pe_info->module_size ||
  99  E :        pe_sig.module_time_date_stamp != pe_info->module_time_date_stamp) {
 100  i :      return TRUE;
 101    :    }
 102    :  
 103  E :    return FALSE;
 104  E :  }
 105    :  
 106    :  bool FindFile(const FilePath& file_path,
 107    :                const wchar_t* search_paths,
 108    :                const void* id,
 109    :                uint32 data,
 110    :                uint32 flags,
 111    :                PFINDFILEINPATHCALLBACKW callback,
 112    :                void* callback_context,
 113  E :                FilePath* found_file) {
 114  E :    DCHECK(search_paths != NULL);
 115  E :    DCHECK(found_file != NULL);
 116    :  
 117  E :    found_file->clear();
 118    :  
 119  E :    HANDLE handle = ::GetCurrentProcess();
 120    :  
 121  E :    BOOL result = ::SymInitialize(handle, NULL, FALSE);
 122  E :    if (result == FALSE) {
 123  i :      DWORD error = ::GetLastError();
 124  i :      LOG(ERROR) << "SymInitialize failed: " << com::LogWe(error);
 125  i :      return false;
 126    :    }
 127    :  
 128  E :    FilePath dir = file_path.DirName();
 129  E :    std::wstring basename = file_path.BaseName().value();
 130    :  
 131    :    // Augment the search paths with the directory of file_path and the
 132    :    // current working directory.
 133  E :    std::wstring paths;
 134  E :    if (file_util::PathExists(dir)) {
 135  E :      paths.append(dir.value());
 136  E :      paths.push_back(L';');
 137    :    }
 138  E :    paths.append(L".;");
 139  E :    paths.append(search_paths);
 140    :  
 141    :    // Search for the file.
 142    :    wchar_t buffer[MAX_PATH];
 143    :    result = ::SymFindFileInPathW(handle,
 144    :                                  paths.c_str(),
 145    :                                  basename.c_str(),
 146    :                                  const_cast<void*>(id),
 147    :                                  data,
 148    :                                  0,
 149    :                                  flags,
 150    :                                  &buffer[0],
 151    :                                  callback,
 152  E :                                  callback_context);
 153  E :    if (::SymCleanup(handle) == FALSE) {
 154  i :      DWORD error = ::GetLastError();
 155  i :      LOG(ERROR) << "SymCleanup failed: " << com::LogWe(error);
 156  i :      return false;
 157    :    }
 158  E :    if (!result) {
 159    :      // If there is a zero error code, this simply means that the search failed
 160    :      // to find anything, which is not an error.
 161  E :      DWORD error = ::GetLastError();
 162  E :      if (error == 0)
 163  E :        return true;
 164    :  
 165  i :      LOG(ERROR) << "SymFindFileInPath(\"" << file_path.value() << "\") failed: "
 166    :                 << com::LogWe(error);
 167  i :      return false;
 168    :    }
 169    :  
 170  E :    *found_file = FilePath(buffer);
 171    :  
 172  E :    return true;
 173  E :  }
 174    :  
 175    :  }  // namespace
 176    :  
 177  E :  bool PeAndPdbAreMatched(const FilePath& pe_path, const FilePath& pdb_path) {
 178  E :    pe::PdbInfo pe_pdb_info;
 179  E :    if (!pe_pdb_info.Init(pe_path))
 180  E :      return false;
 181    :    pdb::PdbInfoHeader70 pdb_info;
 182  E :    if (!pdb::ReadPdbHeader(pdb_path, &pdb_info))
 183  i :      return false;
 184  E :    if (!pe_pdb_info.IsConsistent(pdb_info))
 185  E :      return false;
 186  E :    return true;
 187  E :  }
 188    :  
 189    :  bool FindModuleBySignature(const PEFile::Signature& module_signature,
 190    :                             const wchar_t* search_paths,
 191  E :                             FilePath* module_path) {
 192  E :    DCHECK(search_paths != NULL);
 193  E :    DCHECK(module_path != NULL);
 194    :  
 195  E :    FilePath path(module_signature.path);
 196    :    const void* id =
 197  E :        reinterpret_cast<void*>(module_signature.module_time_date_stamp);
 198    :    return FindFile(path,
 199    :                    search_paths,
 200    :                    id,
 201    :                    module_signature.module_size,
 202    :                    SSRVOPT_DWORD,
 203    :                    FindPeFileCallback,
 204    :                    const_cast<PEFile::Signature*>(&module_signature),
 205  E :                    module_path);
 206  E :  }
 207    :  
 208    :  bool FindModuleBySignature(const PEFile::Signature& module_signature,
 209  E :                             FilePath* module_path) {
 210  E :    DCHECK(module_path != NULL);
 211    :  
 212  E :    std::wstring search_paths;
 213  E :    if (!GetEnvVar("PATH", &search_paths))
 214  i :      return false;
 215    :  
 216    :    return FindModuleBySignature(module_signature,
 217    :                                 search_paths.c_str(),
 218  E :                                 module_path);
 219  E :  }
 220    :  
 221    :  bool FindPdbForModule(const FilePath& module_path,
 222    :                        const wchar_t* search_paths,
 223  E :                        FilePath* pdb_path) {
 224  E :    DCHECK(search_paths != NULL);
 225  E :    DCHECK(pdb_path != NULL);
 226    :  
 227  E :    PdbInfo pdb_info;
 228  E :    if (!pdb_info.Init(module_path))
 229  i :      return false;
 230    :  
 231    :    // Prepend the module path to the symbol path.
 232  E :    std::wstring search_path(module_path.DirName().value());
 233  E :    search_path.append(L";");
 234  E :    search_path.append(search_paths);
 235    :  
 236    :    return FindFile(pdb_info.pdb_file_name(),
 237    :                    search_path.c_str(),
 238    :                    &pdb_info.signature(),
 239    :                    pdb_info.pdb_age(),
 240    :                    SSRVOPT_GUIDPTR,
 241    :                    FindPdbFileCallback,
 242    :                    &pdb_info,
 243  E :                    pdb_path);
 244  E :  }
 245    :  
 246    :  bool FindPdbForModule(const FilePath& module_path,
 247  E :                        FilePath* pdb_path) {
 248  E :    DCHECK(pdb_path != NULL);
 249    :  
 250  E :    std::wstring search_paths;
 251  E :    if (!GetEnvVar("_NT_SYMBOL_PATH", &search_paths))
 252  i :      return false;
 253    :  
 254    :    return FindPdbForModule(module_path,
 255    :                            search_paths.c_str(),
 256  E :                            pdb_path);
 257  E :  }
 258    :  
 259    :  }  // namespace pe

Coverage information generated Thu Sep 06 11:30:46 2012.