blob: aded7b6ee2093fc8a34c4506c8007309ae46e48c [file] [log] [blame] [view]
Robert Sesek21f5a442018-01-05 19:29:071# Debugging with Crash Keys
2
3Chrome is client-side software, which means that sometimes there are bugs that
4can occur only on users' machines ("in production") that cannot be reproduced by
5test or software engineering. When this happens, it's often helpful to gather bug-
6specific data from production to help pinpoint the cause of the crash. The crash
7key logging system is a generic method to help do that.
8
9[TOC]
10
11## High-Level Overview
12
13The core of the crash key logging system is in [//components/crash/core/common/crash_key.h](https://cs.chromium.org/chromium/src/components/crash/core/common/crash_key.h),
14which declares a `crash_reporter::CrashKeyString` class. Every crash key has
15an associated value maximum length and a string name to identify it. The maximum
16length is specified as a template parameter in order to allocate that amount of
17space for the value up-front. When a process is crashing, memory corruption can
18make it unsafe to call into the system allocator, so pre-allocating space for
19the value defends against that.
20
21When a crash key is set, the specified value is copied to its internal storage.
22And if the process subsequently crashes, the name-value tuple is uploaded as
23POST form-multipart data when the crash report minidump is uploaded to the
24Google crash reporting system. (The data therefore are only accessible to those
25with access to crash reports internally at Google). For platforms that use
26[Crashpad](https://crashpad.chromium.org) as the crash reporting platform, the
27crash keys are also stored in the minidump file itself. For platforms that use
28Breakpad, the keys are only available at upload.
29
30The crash key system is used to report some common pieces of data, not just
31things that happen in exceptional cases: the URL of the webpage, command line
32switches, active extension IDs, GPU vendor information, experiment/variations
33information, etc.
34
Fergal Daly3f51b302020-03-04 16:05:3135## Redaction
36
Nate Fischer80c1af7df2024-01-31 01:29:4037Beware that certain on certain platforms (e.g. Android WebView) we
Fergal Daly3f51b302020-03-04 16:05:3138[sanitize the stack in the dump](https://cs.chromium.org/chromium/src/third_party/crashpad/crashpad/snapshot/sanitized/memory_snapshot_sanitized.h)
Oksana Zhuravlova04b1bd412021-03-18 21:30:2739and only crash keys on an
40[allowlist](https://cs.chromium.org/chromium/src/android_webview/common/crash_reporter/crash_keys.cc)
Fergal Daly3f51b302020-03-04 16:05:3141will be captured.
42
Robert Sesek21f5a442018-01-05 19:29:0743## Getting Started with a Single Key-Value Pair
44
45Imagine you are investigating a crash, and you want to know the value of some
46variable when the crash occurs; the crash key logging system enables you to do
47just that.
48
49#### 1. Declare the Crash Key
50
51A crash key must be allocated using static storage duration, so that there is
52space for the value to be set. This can be done as a static variable in the
53global or function scope, or in an anonymous namespace:
54
55 static crash_reporter::CrashKeyString<32> crash_key_one("one");
56
57 namespace {
58 crash_reporter::CrashKeyString<64> crash_key_two("two");
59 }
60
61 void DoSomething(const std::string& arg) {
62 static crash_reporter::CrashKeyString<8> three("three");
63 crash_key_two.Set(arg);
64 three.Set("true");
65 }
66
67The template argument specifies the maximum length a value can be, and it
68should include space for a trailing NUL byte. Values must be C-strings and
69cannot have embedded NULs. The constructor argument is the name of the
70crash key, and it is what you will use to identify your data in uploaded
71crash reports.
72
Caleb Raittoa5a95f92022-06-16 16:10:5373Note that crash key names are global and must not conflict with the
74name of any other crash key in Chrome.
75
Robert Sesek21f5a442018-01-05 19:29:0776If you need to declare an array of crash keys (e.g., for recording N values
77of an array), you can use a constructor tag to avoid warnings about `explicit`:
78
79 static ArrayItemKey = crash_reporter::CrashKeyString<32>;
80 static ArrayItemKey crash_keys[] = {
81 {"array-item-1", ArrayItemKey::Tag::kArray},
82 {"array-item-2", ArrayItemKey::Tag::kArray},
83 {"array-item-3", ArrayItemKey::Tag::kArray},
84 {"array-item-4", ArrayItemKey::Tag::kArray},
85 };
86
87The crash key system will require your target to have a dependency on
88`//components/crash/core/common:crash_key`. If you encounter link errors for
89unresolved symbols to `crashpad::Annotation::SetSize(unsigned int)`, adding
90the dependency will resolve them.
91
92#### 2. Set the Crash Key
93
94After a key has been allocated, its `Set(base::StringPiece)` and
95`Clear()` methods can be used to record and clear a value. In addition,
96crash_key.h provides a `ScopedCrashKeyString` class to set the value for the
97duration of a scope and clear it upon exiting.
98
99#### 3. Seeing the Data
100
101Using <http://go/crash> (internal only), find the crash report signature related
102to your bug, and click on the "N of M" reports link to drill down to
103report-specific information. From there, select a report and go to the
104"Product Data" section to view all the crash key-value pairs.
105
106## Dealing with DEPS
107
108Not all targets in the Chromium source tree are permitted to depend on the
109`//components/crash/core/common:crash_key` target due to DEPS file
110`include_rules`.
111
112If the crash key being added is only a temporary debugging aid to track down a
113crash, consider adding the dependency temporarily and removing it when done.
114A specific include rule can be added for crash_key.h:
115
116 # DEPS
117 include_rules = [
118 '+components/crash/core/common/crash_key.h',
119 ]
120
121Then simply remove it (and the BUILD.gn dependency) once the crash is resolved
122and the crash key deleted.
123
124If this crash key is more permanent, then there is an alternate API in //base
125that can be used. This API is used by the //content module to set its permanent
126crash key information. Note however that the base-level API is more limited in
127terms of features and flexibility. See the header documentation in
128[//base/debug/crash_logging.h](https://cs.chromium.org/chromium/src/base/debug/crash_logging.h)
129for usage examples.
130
131## Advanced Topics: Stack Traces
132
133Now imagine a scenario where you have a use-after-free. The crash reports coming
134in do not indicate where the object being used was initially freed, however,
135just where it is later being dereferenced. To make debugging easier, it would be
136nice to have the stack trace of the destructor, and the crash key system works
137for that, too.
138
139#### 1. Declare the Crash Key
140
141Declaring the crash key is no different than written above, though special
142attention should be paid to the maximum size argument, which will affect the
143number of stack frames that are recorded. Typically a value of _1024_ is
144recommended.
145
146#### 2. Set the Crash Key
147
148To set a stack trace to a crash key, use the `SetCrashKeyStringToStackTrace()`
149function in crash_logging.h:
150
151 Usemeafterfree::~Usemeafterfree() {
Caleb Raittoa5a95f92022-06-16 16:10:53152 static crash_reporter::CrashKeyString<1024> trace_key(
153 "useme-after-free-uaf-dtor-trace");
Robert Sesek21f5a442018-01-05 19:29:07154 crash_reporter::SetCrashKeyStringToStackTrace(&trace_key,
155                                        base::debug::StackTrace());
156 }
157
158#### 3. Seeing the Data
159
160Unlike with the previous example, a stack trace will just be a string of
161hexadecimal addresses. To turn the addresses back into symbols use,
162<http://go/crsym> (internal instance of <https://github.com/chromium/crsym/>).
163Using the **Crash Key** input type, give it a crash report ID and the name of
164your crash key. Crsym will then fetch the symbol data from the internal crash
165processing backends and return a formatted, symbolized stack trace.