File: crash_helper.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 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 (136 lines) | stat: -rw-r--r-- 4,932 bytes parent folder | download | duplicates (6)
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
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/chrome_elf/crash/crash_helper.h"

#include <windows.h>

#include <assert.h>

#include <algorithm>
#include <string>
#include <vector>

#include "chrome/app/chrome_crash_reporter_client_win.h"
#include "components/crash/core/app/crashpad.h"
#include "components/crash/core/common/crash_keys.h"
#include "sandbox/policy/win/hook_util/hook_util.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h"

namespace {

// Crash handling from elf is only enabled for the chrome.exe process.
// Use this global to safely handle the rare case where elf may not be in that
// process (e.g. tests).
bool g_crash_helper_enabled = false;

// Global pointer to a vector of crash reports.
// This structure will be initialized in InitializeCrashReportingForProcess()
// and cleaned up in DllDetachCrashReportingCleanup().
std::vector<crash_reporter::Report>* g_crash_reports = nullptr;

// chrome_elf loads early in the process and initializes Crashpad. That in turn
// uses the SetUnhandledExceptionFilter API to set a top level exception
// handler for the process. When the process eventually initializes, CRT sets
// an exception handler which calls TerminateProcess which effectively bypasses
// us. Ideally we want to be at the top of the unhandled exception filter
// chain. However we don't have a good way of intercepting the
// SetUnhandledExceptionFilter API in the sandbox. EAT patching kernel32 or
// kernelbase should ideally work. However the kernel32 kernelbase dlls are
// prebound which causes EAT patching to not work. Sidestep works. However it
// is only supported for 32 bit. For now we use IAT patching for the
// executable.
// TODO(ananta).
// Check if it is possible to fix EAT patching or use sidestep patching for
// 32 bit and 64 bit for this purpose.
sandbox::policy::IATHook* g_set_unhandled_exception_filter = nullptr;

// Hook function, which ignores the request to set an unhandled-exception
// filter.
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
SetUnhandledExceptionFilterPatch(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
  // Don't set the exception filter. Please see above for comments.
  return nullptr;
}

}  // namespace

//------------------------------------------------------------------------------
// Public chrome_elf crash APIs
//------------------------------------------------------------------------------

namespace elf_crash {

// NOTE: This function will be called from DllMain during DLL_PROCESS_ATTACH
// (while we have the loader lock), so do not misbehave.
bool InitializeCrashReporting() {
  if (g_crash_helper_enabled)
    return true;

#if defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)
  assert(g_crash_reports == nullptr);
  assert(g_set_unhandled_exception_filter == nullptr);
#endif  // defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)

  // No global objects with destructors, so using global pointers.
  // DllMain on detach will clean these up.
  g_crash_reports = new std::vector<crash_reporter::Report>;
  g_set_unhandled_exception_filter = new sandbox::policy::IATHook();

  ChromeCrashReporterClient::InitializeCrashReportingForProcess();

  g_crash_helper_enabled = true;
  return true;
}

// NOTE: This function will be called from DllMain during DLL_PROCESS_DETACH
// (while we have the loader lock), so do not misbehave.
void ShutdownCrashReporting() {
  if (g_crash_reports) {
    g_crash_reports->clear();
    delete g_crash_reports;
  }
  if (g_set_unhandled_exception_filter) {
    delete g_set_unhandled_exception_filter;
  }
}

// Please refer to the comment on g_set_unhandled_exception_filter for more
// information about why we intercept the SetUnhandledExceptionFilter API.
void DisableSetUnhandledExceptionFilter() {
#if defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)
  // Should never patch SetUnhandledExceptionFilter before crashpad has called
  // it.
  assert(g_crash_helper_enabled);
#endif  // defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)
  if (g_set_unhandled_exception_filter->Hook(
          ::GetModuleHandle(nullptr), "kernel32.dll",
          "SetUnhandledExceptionFilter",
          reinterpret_cast<void*>(SetUnhandledExceptionFilterPatch)) !=
      NO_ERROR) {
#if defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)
    assert(false);
#endif  // defined(_DEBUG) || defined(DCHECK_ALWAYS_ON)
  }
}

int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers) {
  if (g_crash_helper_enabled)
    crashpad::CrashpadClient::DumpWithoutCrash(
        *(exception_pointers->ContextRecord));
  return EXCEPTION_CONTINUE_SEARCH;
}

void DumpWithoutCrashing() {
  crash_reporter::DumpWithoutCrashing();
}

void SetMetricsClientIdImpl(const char* client_id) {
  if (!g_crash_helper_enabled)
    return;
  if (client_id)
    crash_keys::SetMetricsClientIdFromGUID(client_id);
}

}  // namespace elf_crash