Coverage for /Syzygy/pe/find.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
83.7%1131350.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   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/utf_string_conversions.h"
  28    :  #include "base/strings/string_split.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 :    base::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  E :      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 :    base::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 base::FilePath& file_path,
 107    :                const base::StringPiece16& search_paths,
 108    :                const void* id,
 109    :                uint32 data,
 110    :                uint32 flags,
 111    :                PFINDFILEINPATHCALLBACKW callback,
 112    :                void* callback_context,
 113  E :                base::FilePath* found_file) {
 114  E :    DCHECK(found_file != NULL);
 115    :  
 116  E :    found_file->clear();
 117    :  
 118  E :    HANDLE handle = ::GetCurrentProcess();
 119    :  
 120  E :    BOOL result = ::SymInitialize(handle, NULL, FALSE);
 121  E :    if (result == FALSE) {
 122  i :      DWORD error = ::GetLastError();
 123  i :      LOG(ERROR) << "SymInitialize failed: " << com::LogWe(error);
 124  i :      return false;
 125    :    }
 126    :  
 127  E :    base::FilePath dir = file_path.DirName();
 128  E :    std::wstring basename = file_path.BaseName().value();
 129    :  
 130    :    // Augment the search paths with the directory of file_path and the
 131    :    // current working directory.
 132  E :    std::wstring paths;
 133  E :    if (file_util::PathExists(dir)) {
 134  E :      paths.append(dir.value());
 135  E :      paths.push_back(L';');
 136    :    }
 137  E :    paths.append(L".;");
 138  E :    paths.append(search_paths.begin(), search_paths.end());
 139    :  
 140    :    // Search for the file.
 141    :    wchar_t buffer[MAX_PATH];
 142    :    result = ::SymFindFileInPathW(handle,
 143    :                                  paths.c_str(),
 144    :                                  basename.c_str(),
 145    :                                  const_cast<void*>(id),
 146    :                                  data,
 147    :                                  0,
 148    :                                  flags,
 149    :                                  &buffer[0],
 150    :                                  callback,
 151  E :                                  callback_context);
 152  E :    if (::SymCleanup(handle) == FALSE) {
 153  i :      DWORD error = ::GetLastError();
 154  i :      LOG(ERROR) << "SymCleanup failed: " << com::LogWe(error);
 155  i :      return false;
 156    :    }
 157  E :    if (!result) {
 158    :      // If there is a zero error code, this simply means that the search failed
 159    :      // to find anything, which is not an error.
 160  E :      DWORD error = ::GetLastError();
 161  E :      if (error == 0)
 162  E :        return true;
 163    :  
 164  i :      LOG(ERROR) << "SymFindFileInPath(\"" << file_path.value() << "\") failed: "
 165    :                 << com::LogWe(error);
 166  i :      return false;
 167    :    }
 168    :  
 169  E :    *found_file = base::FilePath(buffer);
 170    :  
 171  E :    return true;
 172  E :  }
 173    :  
 174    :  }  // namespace
 175    :  
 176    :  bool PeAndPdbAreMatched(const base::FilePath& pe_path,
 177  E :                          const base::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  E :      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 base::StringPiece16& search_paths,
 191  E :                             base::FilePath* module_path) {
 192  E :    DCHECK(module_path != NULL);
 193    :  
 194  E :    std::vector<base::FilePath> candidate_paths;
 195  E :    if (!module_path->empty())
 196  E :      candidate_paths.push_back(*module_path);
 197  E :    candidate_paths.push_back(base::FilePath(module_signature.path));
 198    :  
 199    :    const void* id =
 200  E :        reinterpret_cast<void*>(module_signature.module_time_date_stamp);
 201    :  
 202    :    // Try a search based on each of the candidate paths.
 203  E :    for (size_t i = 0; i < candidate_paths.size(); ++i) {
 204  E :      const base::FilePath& path = candidate_paths[i];
 205    :  
 206    :      if (!FindFile(path,
 207    :                    search_paths,
 208    :                    id,
 209    :                    module_signature.module_size,
 210    :                    SSRVOPT_DWORD,
 211    :                    FindPeFileCallback,
 212    :                    const_cast<PEFile::Signature*>(&module_signature),
 213  E :                    module_path)) {
 214  i :        return false;
 215    :      }
 216    :  
 217    :      // If the search was successful we can terminate early.
 218  E :      if (!module_path->empty())
 219  E :        return true;
 220  i :    }
 221  i :    DCHECK(module_path->empty());
 222    :  
 223  i :    return true;
 224  E :  }
 225    :  
 226    :  bool FindModuleBySignature(const PEFile::Signature& module_signature,
 227  E :                             base::FilePath* module_path) {
 228  E :    DCHECK(module_path != NULL);
 229    :  
 230  E :    std::wstring search_paths;
 231  E :    if (!GetEnvVar("PATH", &search_paths))
 232  i :      return false;
 233    :  
 234    :    return FindModuleBySignature(module_signature,
 235    :                                 search_paths.c_str(),
 236  E :                                 module_path);
 237  E :  }
 238    :  
 239    :  bool FindPdbForModule(const base::FilePath& module_path,
 240    :                        const base::StringPiece16& search_paths,
 241  E :                        base::FilePath* pdb_path) {
 242  E :    DCHECK(pdb_path != NULL);
 243    :  
 244  E :    std::vector<base::FilePath> candidate_paths;
 245  E :    if (!pdb_path->empty())
 246  E :      candidate_paths.push_back(*pdb_path);
 247    :  
 248  E :    PdbInfo pdb_info;
 249  E :    if (!pdb_info.Init(module_path))
 250  E :      return false;
 251  E :    candidate_paths.push_back(pdb_info.pdb_file_name());
 252    :  
 253    :    // Prepend the module path to the symbol path.
 254  E :    std::wstring search_path(module_path.DirName().value());
 255  E :    search_path.append(L";");
 256  E :    search_path.append(search_paths.begin(), search_paths.end());
 257    :  
 258  E :    for (size_t i = 0; i < candidate_paths.size(); ++i) {
 259  E :      const base::FilePath& path = candidate_paths[i];
 260    :  
 261    :      if (!FindFile(path,
 262    :                    search_path.c_str(),
 263    :                    &pdb_info.signature(),
 264    :                    pdb_info.pdb_age(),
 265    :                    SSRVOPT_GUIDPTR,
 266    :                    FindPdbFileCallback,
 267    :                    &pdb_info,
 268  E :                    pdb_path)) {
 269  i :        return false;
 270    :      }
 271    :  
 272    :      // If the search was successful we can terminate early.
 273  E :      if (!pdb_path->empty())
 274  E :        return true;
 275  E :    }
 276  E :    DCHECK(pdb_path->empty());
 277    :  
 278  E :    return true;
 279  E :  }
 280    :  
 281    :  bool FindPdbForModule(const base::FilePath& module_path,
 282  E :                        base::FilePath* pdb_path) {
 283  E :    DCHECK(pdb_path != NULL);
 284    :  
 285  E :    std::wstring search_paths;
 286  E :    if (!GetEnvVar("_NT_SYMBOL_PATH", &search_paths))
 287  i :      return false;
 288    :  
 289    :    return FindPdbForModule(module_path,
 290    :                            search_paths.c_str(),
 291  E :                            pdb_path);
 292  E :  }
 293    :  
 294    :  }  // namespace pe

Coverage information generated Thu Jul 04 09:34:53 2013.