Coverage for /Syzygy/agent/asan/syzyasan_rtl.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
85.0%961130.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    :  #include <windows.h>  // NOLINT
  16    :  #include <psapi.h>
  17    :  
  18    :  #include "base/at_exit.h"
  19    :  #include "base/atomicops.h"
  20    :  #include "base/command_line.h"
  21    :  #include "base/logging.h"
  22    :  #include "base/files/file_path.h"
  23    :  #include "base/win/pe_image.h"
  24    :  #include "syzygy/agent/asan/asan_rtl_impl.h"
  25    :  #include "syzygy/agent/asan/asan_runtime.h"
  26    :  #include "syzygy/agent/common/agent.h"
  27    :  #include "syzygy/common/com_utils.h"
  28    :  #include "syzygy/common/logging.h"
  29    :  
  30    :  // The linker satisfies this symbol. This gets us a pointer to our own module
  31    :  // when we're loaded.
  32    :  extern "C" IMAGE_DOS_HEADER __ImageBase;
  33    :  
  34    :  namespace {
  35    :  
  36    :  using agent::asan::AsanRuntime;
  37    :  
  38    :  // Our AtExit manager required by base.
  39    :  base::AtExitManager* at_exit = NULL;
  40    :  
  41    :  // The asan runtime manager.
  42    :  AsanRuntime* asan_runtime = NULL;
  43    :  
  44  E :  void SetUpAtExitManager() {
  45  E :    DCHECK(at_exit == NULL);
  46  E :    at_exit = new base::AtExitManager();
  47  E :    CHECK(at_exit != NULL);
  48  E :  }
  49    :  
  50    :  void TearDownAtExitManager() {
  51    :    DCHECK(at_exit != NULL);
  52    :    delete at_exit;
  53    :    at_exit = NULL;
  54    :  }
  55    :  
  56    :  // Returns the name of this module.
  57  E :  bool GetSelfPath(base::FilePath* self_path) {
  58  E :    DCHECK_NE(reinterpret_cast<base::FilePath*>(NULL), self_path);
  59    :  
  60  E :    HMODULE self = reinterpret_cast<HMODULE>(&__ImageBase);
  61    :  
  62  E :    std::vector<wchar_t> name(1024, 0);
  63  E :    while (true) {
  64  E :      size_t n = ::GetModuleFileNameW(self, name.data(), name.size());
  65  E :      if (n == 0) {
  66  i :        DWORD error = ::GetLastError();
  67  i :        LOG(ERROR) << "GetModuleFileNameW failed: "
  68    :                   << common::LogWe(error) << ".";
  69  i :        return false;
  70    :      }
  71    :  
  72    :      // If we read the whole thing we're done.
  73  E :      if (n < name.size())
  74  E :        break;
  75    :  
  76    :      // Otherwise resize the buffer and try again.
  77  i :      name.resize(2 * name.size(), 0);
  78  i :    }
  79    :  
  80  E :    *self_path = base::FilePath(name.data());
  81  E :    return true;
  82  E :  }
  83    :  
  84    :  // Used as user data by EnumImportChunksCallback. This is used to look for a
  85    :  // module matching |basename|. Success or failure is returned via |match|.
  86    :  struct EnumImportChunksCookie {
  87    :    const std::string* basename;
  88    :    bool match;
  89    :  };
  90    :  
  91    :  // Examines the imported |module|. If it matches the |basename| specified in
  92    :  // |cookie|, then aborts the search and indicates success via the |match|
  93    :  // parameter in |cookie|.
  94    :  bool EnumImportChunksCallback(const base::win::PEImage& image,
  95    :                                LPCSTR module,
  96    :                                PIMAGE_THUNK_DATA name_table,
  97    :                                PIMAGE_THUNK_DATA iat,
  98  E :                                PVOID cookie) {
  99  E :    DCHECK_NE(reinterpret_cast<LPCSTR>(NULL), module);
 100  E :    DCHECK_NE(reinterpret_cast<PVOID>(NULL), cookie);
 101    :  
 102    :    EnumImportChunksCookie* eicc =
 103  E :        reinterpret_cast<EnumImportChunksCookie*>(cookie);
 104  E :    if (::_stricmp(eicc->basename->c_str(), module) == 0) {
 105    :      // Indicate that the module was found.
 106  E :      eicc->match = true;
 107    :      // Stop the enumeration as we're done.
 108  E :      return false;
 109    :    }
 110    :  
 111    :    // Continue the iteration.
 112  E :    return true;
 113  E :  }
 114    :  
 115    :  // Inspects the given module for embedded Asan parameters. If they are found
 116    :  // sets a pointer to them in |asan_params|. Returns true on success, false
 117    :  // otherwise.
 118    :  bool InspectModuleForEmbeddedAsanParameters(
 119    :      const std::string& self_basename,
 120    :      HMODULE module,
 121  E :      const common::AsanParameters** asan_params) {
 122  E :    DCHECK_NE(reinterpret_cast<HMODULE>(NULL), module);
 123  E :    DCHECK_NE(reinterpret_cast<common::AsanParameters**>(NULL), asan_params);
 124    :  
 125  E :    *asan_params = NULL;
 126    :  
 127  E :    base::win::PEImage pe_image(module);
 128  E :    EnumImportChunksCookie eicc = { &self_basename, false };
 129  E :    pe_image.EnumImportChunks(&EnumImportChunksCallback, &eicc);
 130    :  
 131    :    // If there was no matching import then we can skip this module.
 132  E :    if (!eicc.match)
 133  E :      return true;
 134    :  
 135    :    // Look for the magic section containing the runtime parameters. If found
 136    :    // then set the pointer to the parameters.
 137    :    PIMAGE_SECTION_HEADER section = pe_image.GetImageSectionHeaderByName(
 138  E :        common::kAsanParametersSectionName);
 139  E :    if (section != NULL) {
 140  E :      const uint8* image_base = reinterpret_cast<const uint8*>(module);
 141    :      *asan_params = reinterpret_cast<const common::AsanParameters*>(
 142  E :          image_base + section->VirtualAddress);
 143    :    }
 144    :  
 145  E :    return true;
 146  E :  }
 147    :  
 148    :  // |asan_params| will be populated with a pointer to any found Asan parameters,
 149    :  // and will be set to NULL if none are found.
 150  E :  bool LookForEmbeddedAsanParameters(const common::AsanParameters** asan_params) {
 151  E :    DCHECK_NE(reinterpret_cast<common::AsanParameters**>(NULL), asan_params);
 152  E :    *asan_params = NULL;
 153    :  
 154    :    // Get the path of this module.
 155  E :    base::FilePath self_path;
 156  E :    if (!GetSelfPath(&self_path))
 157  i :      return false;
 158    :  
 159    :    // Get the base name of this module. We'll be looking for modules that import
 160    :    // it.
 161  E :    std::string self_basename = self_path.BaseName().AsUTF8Unsafe();
 162    :  
 163    :    // Determine how much space we need for the module list.
 164  E :    HANDLE process = ::GetCurrentProcess();
 165  E :    DWORD bytes_needed = 0;
 166  E :    if (!::EnumProcessModules(process, NULL, 0, &bytes_needed)) {
 167  i :      DWORD error = ::GetLastError();
 168  i :      LOG(ERROR) << "EnumProcessModules failed: "
 169    :                 << ::common::LogWe(error) << ".";
 170  i :      return false;
 171    :    }
 172    :  
 173    :    // Get the list of module handles.
 174  E :    std::vector<HMODULE> modules(bytes_needed / sizeof(HMODULE));
 175    :    if (!::EnumProcessModules(process, modules.data(), bytes_needed,
 176  E :                              &bytes_needed)) {
 177  i :      DWORD error = ::GetLastError();
 178  i :      LOG(ERROR) << "EnumProcessModules failed: "
 179    :                 << ::common::LogWe(error) << ".";
 180  i :      return false;
 181    :    }
 182    :  
 183    :    // Inspect each module to see if it contains Asan runtime parameters. The
 184    :    // first ones found will be used.
 185  E :    for (size_t i = 0; i < modules.size(); ++i) {
 186    :      if (!InspectModuleForEmbeddedAsanParameters(
 187  E :               self_basename, modules[i], asan_params)) {
 188  i :        return false;
 189    :      }
 190    :  
 191    :      // If this module contained parameters then we've finished our search.
 192  E :      if (*asan_params != NULL)
 193  E :        return true;
 194  E :    }
 195    :  
 196  E :    return true;
 197  E :  }
 198    :  
 199  E :  void SetUpAsanRuntime() {
 200  E :    DCHECK(asan_runtime == NULL);
 201  E :    asan_runtime = new AsanRuntime();
 202  E :    CHECK(asan_runtime != NULL);
 203    :  
 204    :    // Look for any parameters that have been embedded in instrumented modules.
 205  E :    const common::AsanParameters* asan_params = NULL;
 206  E :    if (!LookForEmbeddedAsanParameters(&asan_params )) {
 207  i :      LOG(ERROR) << "Error while trying to find embedded Asan parameters.";
 208    :    }
 209    :  
 210    :    // Inflate these and inject them into the runtime library. These will serve
 211    :    // as the baseline parameters that will then be potentially modified by any
 212    :    // parameters via the environment.
 213    :    if (asan_params != NULL &&
 214  E :        !common::InflateAsanParameters(asan_params, &asan_runtime->params())) {
 215  i :      LOG(ERROR) << "Failed to inflate embedded Asan parameters.";
 216    :    }
 217    :  
 218    :    // Get the flags string from the environment.
 219  E :    std::wstring asan_flags_str;
 220  E :    if (!AsanRuntime::GetAsanFlagsEnvVar(&asan_flags_str)) {
 221  i :      LOG(ERROR) << "Error while trying to read Asan command line.";
 222    :    }
 223    :  
 224    :    // Setup the runtime library with the given options.
 225  E :    asan_runtime->SetUp(asan_flags_str);
 226  E :    agent::asan::SetUpRtl(asan_runtime);
 227  E :  }
 228    :  
 229  E :  void TearDownAsanRuntime() {
 230  E :    DCHECK(asan_runtime != NULL);
 231  E :    asan_runtime->TearDown();
 232  E :    delete asan_runtime;
 233  E :    asan_runtime = NULL;
 234  E :  }
 235    :  
 236    :  }  // namespace
 237    :  
 238    :  extern "C" {
 239    :  
 240  E :  BOOL WINAPI DllMain(HMODULE instance, DWORD reason, LPVOID reserved) {
 241  E :    agent::common::InitializeCrt();
 242    :  
 243  E :    switch (reason) {
 244    :      case DLL_PROCESS_ATTACH: {
 245    :        // Create the At-Exit manager.
 246  E :        SetUpAtExitManager();
 247    :  
 248    :        // Disable logging. In the case of Chrome this is running in a sandboxed
 249    :        // process where logging to file doesn't help us any. In other cases the
 250    :        // log output will still go to console.
 251  E :        CommandLine::Init(0, NULL);
 252  E :        common::InitLoggingForDll(L"asan");
 253    :  
 254  E :        SetUpAsanRuntime();
 255  E :        break;
 256    :      }
 257    :  
 258    :      case DLL_THREAD_ATTACH: {
 259  E :        agent::asan::AsanRuntime* runtime = agent::asan::AsanRuntime::runtime();
 260  E :        DCHECK_NE(static_cast<agent::asan::AsanRuntime*>(nullptr), runtime);
 261  E :        runtime->AddThreadId(::GetCurrentThreadId());
 262  E :        break;
 263    :      }
 264    :  
 265    :      case DLL_THREAD_DETACH:
 266    :        // Nothing to do here.
 267  E :        break;
 268    :  
 269    :      case DLL_PROCESS_DETACH: {
 270  E :        CommandLine::Reset();
 271    :        // This should be the last thing called in the agent DLL before it
 272    :        // gets unloaded. Everything should otherwise have been initialized
 273    :        // and we're now just cleaning it up again.
 274  E :        agent::asan::TearDownRtl();
 275  E :        TearDownAsanRuntime();
 276  E :        break;
 277    :      }
 278    :  
 279    :      default:
 280  i :        NOTREACHED();
 281    :        break;
 282    :    }
 283    :  
 284  E :    return TRUE;
 285  E :  }
 286    :  
 287    :  }  // extern "C"

Coverage information generated Thu Mar 26 16:15:41 2015.