Coverage for /Syzygy/agent/asan/reporters/kasko_reporter.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
81.5%66810.C++source

Line-by-line coverage:

   1    :  // Copyright 2016 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 "syzygy/agent/asan/reporters/kasko_reporter.h"
  16    :  
  17    :  #include "base/file_version_info.h"
  18    :  #include "base/path_service.h"
  19    :  #include "base/version.h"
  20    :  #include "base/files/file_path.h"
  21    :  #include "base/strings/string_util.h"
  22    :  #include "base/strings/utf_string_conversions.h"
  23    :  #include "syzygy/kasko/api/client.h"
  24    :  
  25    :  namespace agent {
  26    :  namespace asan {
  27    :  
  28    :  static_assert(kasko::api::kProtobufStreamType ==
  29    :      ReporterInterface::kCrashdataProtobufStreamType,
  30    :      "protobuf stream type id mismatch");
  31    :  
  32    :  // Define required export names.
  33    :  const char* reporters::KaskoReporter::ReportCrashWithProtobuf::name_ =
  34    :      "ReportCrashWithProtobuf";
  35    :  const char* reporters::KaskoReporter::
  36    :      ReportCrashWithProtobufAndMemoryRanges::name_ =
  37    :          "ReportCrashWithProtobufAndMemoryRanges";
  38    :  const char* reporters::KaskoReporter:: SetCrashKeyValueImpl::name_ =
  39    :      "SetCrashKeyValueImpl";
  40    :  
  41    :  namespace reporters {
  42    :  
  43    :  // static
  44  E :  std::unique_ptr<KaskoReporter> KaskoReporter::Create() {
  45    :    // Initialize the required reporter functions
  46  E :    KaskoFunctions kasko_functions;
  47  E :    kasko_functions.set_crash_key_value_impl.Lookup();
  48  E :    kasko_functions.report_crash_with_protobuf.Lookup();
  49  E :    kasko_functions.report_crash_with_protobuf_and_memory_ranges.Lookup();
  50  E :    if (!AreValid(kasko_functions))
  51  E :      return nullptr;
  52    :  
  53  E :    return std::unique_ptr<KaskoReporter>(new KaskoReporter(kasko_functions));
  54  E :  }
  55    :  
  56    :  // static
  57  E :  bool KaskoReporter::AreValid(const KaskoFunctions& kasko_functions) {
  58    :    // The crash key function and at least one reporting function must be
  59    :    // present.
  60  E :    if (!kasko_functions.set_crash_key_value_impl.IsValid())
  61  E :      return false;
  62  E :    return (kasko_functions.report_crash_with_protobuf.IsValid() ||
  63    :        kasko_functions.report_crash_with_protobuf_and_memory_ranges.IsValid());
  64  E :  }
  65    :  
  66  E :  const char* KaskoReporter::GetName() const {
  67  E :    return "KaskoReporter";
  68  E :  }
  69    :  
  70  E :  uint32_t KaskoReporter::GetFeatures() const {
  71  E :    uint32_t features = FEATURE_CRASH_KEYS | FEATURE_CUSTOM_STREAMS;
  72  E :    if (kasko_functions_.report_crash_with_protobuf_and_memory_ranges.IsValid())
  73  E :      features |= FEATURE_MEMORY_RANGES;
  74  E :    if (SupportsEarlyCrashKeys())
  75  i :      features |= FEATURE_EARLY_CRASH_KEYS;
  76  E :    return features;
  77  E :  }
  78    :  
  79    :  bool KaskoReporter::SetCrashKey(base::StringPiece key,
  80  E :                                  base::StringPiece value) {
  81  E :    DCHECK(kasko_functions_.set_crash_key_value_impl.IsValid());
  82    :  
  83  E :    std::wstring wkey = base::UTF8ToWide(key);
  84  E :    std::wstring wvalue = base::UTF8ToWide(value);
  85  E :    kasko_functions_.set_crash_key_value_impl.Run(wkey.c_str(), wvalue.c_str());
  86  E :    return true;
  87  E :  }
  88    :  
  89  E :  bool KaskoReporter::SetMemoryRanges(const MemoryRanges& memory_ranges) {
  90    :    // This is only supported if the appropriate reporting function was found.
  91  E :    if (!kasko_functions_.report_crash_with_protobuf_and_memory_ranges.IsValid())
  92  E :      return false;
  93    :  
  94    :    // Convert the memory ranges to the null terminated format Kasko expects.
  95  E :    range_bases_.resize(memory_ranges.size() + 1);
  96  E :    range_lengths_.resize(memory_ranges.size() + 1);
  97  E :    for (size_t i = 0; i < memory_ranges.size(); ++i) {
  98  E :      range_bases_[i] = memory_ranges[i].first;
  99  E :      range_lengths_[i] = memory_ranges[i].second;
 100  E :    }
 101  E :    range_bases_.back() = nullptr;
 102  E :    range_lengths_.back() = 0;
 103  E :    return true;
 104  E :  }
 105    :  
 106    :  bool KaskoReporter::SetCustomStream(uint32_t stream_type,
 107    :                                      const uint8_t* stream_data,
 108  E :                                      size_t stream_length) {
 109    :    // Only support setting the Kasko stream type.
 110  E :    if (stream_type != kCrashdataProtobufStreamType)
 111  E :      return false;
 112  E :    protobuf_.assign(reinterpret_cast<const char*>(stream_data), stream_length);
 113  E :    return true;
 114  E :  }
 115    :  
 116    :  // Crashes the running process and sends a crash report.
 117  E :  void KaskoReporter::DumpAndCrash(EXCEPTION_POINTERS* exception_pointers) {
 118    :    // Prefer to use the memory ranges version.
 119  E :    if (kasko_functions_.report_crash_with_protobuf_and_memory_ranges.IsValid()) {
 120  E :        kasko_functions_.report_crash_with_protobuf_and_memory_ranges.Run(
 121    :            exception_pointers, protobuf_.c_str(), protobuf_.size(),
 122    :            range_bases_.data(), range_lengths_.data());
 123  E :    } else {
 124  E :      DCHECK(kasko_functions_.report_crash_with_protobuf.IsValid());
 125  E :      kasko_functions_.report_crash_with_protobuf.Run(
 126    :          exception_pointers, protobuf_.c_str(), protobuf_.size());
 127    :    }
 128    :  
 129    :    // The crash function shouldn't return, but putting a NOTREACHED here makes
 130    :    // this function difficult to test.
 131  E :  }
 132    :  
 133  E :  bool KaskoReporter::DumpWithoutCrash(const CONTEXT& context) {
 134    :    // This functionality is not supported in Kasko.
 135  E :    return false;
 136  E :  }
 137    :  
 138    :  // static
 139  E :  bool KaskoReporter::SupportsEarlyCrashKeys() {
 140    :    // Whether or not this is safe to do is really dependent on the crash key
 141    :    // system as implemented in a given binary. Kasko doesn't provide its own,
 142    :    // but rather relies on that provided by the instrumented binary itself.
 143    :    // Binaries need to be evaluated individually and added to this whitelist
 144    :    // explicitly if early crash key support is required.
 145    :    //
 146    :    // This whole thing becomes a moot point when using Crashpad, as it provides
 147    :    // a uniform and safe early crash key mechanism. Moving forward, all Chromium
 148    :    // projects will be using it.
 149    :  
 150    :    // The process needs to be an instance of "chrome.exe".
 151  E :    base::FilePath path;
 152  E :    if (!PathService::Get(base::FILE_EXE, &path))
 153  i :      return false;
 154  E :    if (!base::EqualsCaseInsensitiveASCII(path.BaseName().value(),
 155    :                                          L"chrome.exe")) {
 156  E :      return false;
 157    :    }
 158    :  
 159  i :    std::unique_ptr<FileVersionInfo> version_info(
 160    :        FileVersionInfo::CreateFileVersionInfo(path));
 161  i :    if (!version_info.get())
 162  i :      return false;
 163    :  
 164    :    // The version string may have the format "0.1.2.3 (baadf00d)". The
 165    :    // revision hash must be stripped in order to use base::Version.
 166  i :    std::string v = base::WideToUTF8(version_info->product_version());
 167  i :    size_t offset = v.find_first_not_of("0123456789.");
 168  i :    if (offset != v.npos)
 169  i :      v.resize(offset);
 170    :  
 171    :    // Ensure the version is sufficiently new. Prior to M36 the crashkey
 172    :    // implementation used a structure that wasn't ready or safe to use before
 173    :    // all initializers had run. Afterwards it uses a global static structure so
 174    :    // crash key writing early on is safe.
 175  i :    base::Version version(v);
 176  i :    if (!version.IsValid())
 177  i :      return false;
 178  i :    if (version < base::Version("36.0.0.0"))
 179  i :      return false;
 180    :  
 181  i :    return true;
 182  E :  }
 183    :  
 184    :  }  // namespace reporters
 185    :  }  // namespace asan
 186    :  }  // namespace agent

Coverage information generated Fri Jul 29 11:00:21 2016.