1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/crash/core/app/fallback_crash_handler_win.h"
#include <dbghelp.h>
#include <psapi.h>
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_handle_util.h"
#include "build/build_config.h"
#include "components/crash/core/app/minidump_with_crashpad_info.h"
namespace crash_reporter {
namespace {
void AcquireMemoryMetrics(const base::Process& process,
StringStringMap* crash_keys) {
// Grab the process private memory.
// This is best effort, though really shouldn't ever fail.
PROCESS_MEMORY_COUNTERS_EX process_memory = {sizeof(process_memory)};
if (GetProcessMemoryInfo(
process.Handle(),
reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&process_memory),
sizeof(process_memory))) {
// This is in units of bytes, re-scale to pages for consistency with
// system metrics.
const uint64_t kPageSize = 4096;
crash_keys->insert(std::make_pair(
"ProcessPrivateUsage",
base::NumberToString(process_memory.PrivateUsage / kPageSize)));
crash_keys->insert(std::make_pair(
"ProcessPeakWorkingSetSize",
base::NumberToString(process_memory.PeakWorkingSetSize / kPageSize)));
crash_keys->insert(std::make_pair(
"ProcessPeakPagefileUsage",
base::NumberToString(process_memory.PeakPagefileUsage / kPageSize)));
}
// Grab system commit memory. Also best effort.
PERFORMANCE_INFORMATION perf_info = {sizeof(perf_info)};
if (GetPerformanceInfo(&perf_info, sizeof(perf_info))) {
// Record the remaining committable memory and the limit. This is in units
// of system pages.
crash_keys->insert(std::make_pair(
"SystemCommitRemaining",
base::NumberToString(perf_info.CommitLimit - perf_info.CommitTotal)));
crash_keys->insert(std::make_pair(
"SystemCommitLimit", base::NumberToString(perf_info.CommitLimit)));
}
}
} // namespace
FallbackCrashHandler::FallbackCrashHandler()
: thread_id_(base::kInvalidThreadId), exception_ptrs_(0UL) {}
FallbackCrashHandler::~FallbackCrashHandler() = default;
bool FallbackCrashHandler::ParseCommandLine(const base::CommandLine& cmd_line) {
// Retrieve the handle to the process to dump.
unsigned int uint_process;
if (!base::StringToUint(cmd_line.GetSwitchValueASCII("process"),
&uint_process)) {
return false;
}
// Before taking ownership of the supposed handle, see whether it's really
// a process handle.
base::ProcessHandle process_handle = base::win::Uint32ToHandle(uint_process);
if (base::GetProcId(process_handle) == base::kNullProcessId)
return false;
// Retrieve the thread id argument.
unsigned int thread_id = 0;
if (!base::StringToUint(cmd_line.GetSwitchValueASCII("thread"), &thread_id)) {
return false;
}
thread_id_ = base::PlatformThreadId(
static_cast<base::PlatformThreadId::UnderlyingType>(thread_id));
// Retrieve the "exception-pointers" argument.
uint64_t uint_exc_ptrs = 0;
if (!base::StringToUint64(cmd_line.GetSwitchValueASCII("exception-pointers"),
&uint_exc_ptrs)) {
return false;
}
exception_ptrs_ = static_cast<uintptr_t>(uint_exc_ptrs);
// Retrieve the "database" argument.
database_dir_ = cmd_line.GetSwitchValuePath("database");
if (database_dir_.empty())
return false;
// Everything checks out, take ownership of the process handle.
process_ = base::Process(process_handle);
return true;
}
bool FallbackCrashHandler::GenerateCrashDump(const std::string& product,
const std::string& version,
const std::string& channel,
const std::string& process_type) {
MINIDUMP_EXCEPTION_INFORMATION exc_info = {};
exc_info.ThreadId = thread_id_.raw();
exc_info.ExceptionPointers =
reinterpret_cast<EXCEPTION_POINTERS*>(exception_ptrs_);
exc_info.ClientPointers = TRUE; // ExceptionPointers in client.
// Mandatory crash keys. These will be read by Crashpad and used as
// http request parameters for the upload. Keys and values need to match
// server side configuration.
#if defined(ARCH_CPU_64_BITS)
const char* platform = "Win64";
#else
const char* platform = "Win32";
#endif
std::map<std::string, std::string> crash_keys = {{"prod", product},
{"ver", version},
{"channel", channel},
{"plat", platform},
{"ptype", process_type}};
// Add memory metrics relating to system-wide and target process memory usage.
AcquireMemoryMetrics(process_, &crash_keys);
uint32_t minidump_type = MiniDumpWithUnloadedModules |
MiniDumpWithProcessThreadData |
MiniDumpWithFullMemoryInfo |
MiniDumpWithThreadInfo;
// Capture more detail for canary and dev channels. The prefix search caters
// for the legacy "-m" suffixed multi-install channels.
if (channel.find("canary") == 0 || channel.find("dev") == 0)
minidump_type |= MiniDumpWithIndirectlyReferencedMemory;
return DumpAndReportProcess(process_, minidump_type, &exc_info, crash_keys,
database_dir_);
}
} // namespace crash_reporter
|