File: fallback_crash_handler_win.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (156 lines) | stat: -rw-r--r-- 5,875 bytes parent folder | download | duplicates (5)
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