blob: eeb6f20d0703d01652600d3b91760f6be37856f4 [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
37Beware that certain on certain platforms (e.g. Android Webview) we
38[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
73If you need to declare an array of crash keys (e.g., for recording N values
74of an array), you can use a constructor tag to avoid warnings about `explicit`:
75
76 static ArrayItemKey = crash_reporter::CrashKeyString<32>;
77 static ArrayItemKey crash_keys[] = {
78 {"array-item-1", ArrayItemKey::Tag::kArray},
79 {"array-item-2", ArrayItemKey::Tag::kArray},
80 {"array-item-3", ArrayItemKey::Tag::kArray},
81 {"array-item-4", ArrayItemKey::Tag::kArray},
82 };
83
84The crash key system will require your target to have a dependency on
85`//components/crash/core/common:crash_key`. If you encounter link errors for
86unresolved symbols to `crashpad::Annotation::SetSize(unsigned int)`, adding
87the dependency will resolve them.
88
89#### 2. Set the Crash Key
90
91After a key has been allocated, its `Set(base::StringPiece)` and
92`Clear()` methods can be used to record and clear a value. In addition,
93crash_key.h provides a `ScopedCrashKeyString` class to set the value for the
94duration of a scope and clear it upon exiting.
95
96#### 3. Seeing the Data
97
98Using <http://go/crash> (internal only), find the crash report signature related
99to your bug, and click on the "N of M" reports link to drill down to
100report-specific information. From there, select a report and go to the
101"Product Data" section to view all the crash key-value pairs.
102
103## Dealing with DEPS
104
105Not all targets in the Chromium source tree are permitted to depend on the
106`//components/crash/core/common:crash_key` target due to DEPS file
107`include_rules`.
108
109If the crash key being added is only a temporary debugging aid to track down a
110crash, consider adding the dependency temporarily and removing it when done.
111A specific include rule can be added for crash_key.h:
112
113 # DEPS
114 include_rules = [
115 '+components/crash/core/common/crash_key.h',
116 ]
117
118Then simply remove it (and the BUILD.gn dependency) once the crash is resolved
119and the crash key deleted.
120
121If this crash key is more permanent, then there is an alternate API in //base
122that can be used. This API is used by the //content module to set its permanent
123crash key information. Note however that the base-level API is more limited in
124terms of features and flexibility. See the header documentation in
125[//base/debug/crash_logging.h](https://cs.chromium.org/chromium/src/base/debug/crash_logging.h)
126for usage examples.
127
128## Advanced Topics: Stack Traces
129
130Now imagine a scenario where you have a use-after-free. The crash reports coming
131in do not indicate where the object being used was initially freed, however,
132just where it is later being dereferenced. To make debugging easier, it would be
133nice to have the stack trace of the destructor, and the crash key system works
134for that, too.
135
136#### 1. Declare the Crash Key
137
138Declaring the crash key is no different than written above, though special
139attention should be paid to the maximum size argument, which will affect the
140number of stack frames that are recorded. Typically a value of _1024_ is
141recommended.
142
143#### 2. Set the Crash Key
144
145To set a stack trace to a crash key, use the `SetCrashKeyStringToStackTrace()`
146function in crash_logging.h:
147
148 Usemeafterfree::~Usemeafterfree() {
149 static crash_reporter::CrashKeyString<1024> trace_key("uaf-dtor-trace");
150 crash_reporter::SetCrashKeyStringToStackTrace(&trace_key,
151                                        base::debug::StackTrace());
152 }
153
154#### 3. Seeing the Data
155
156Unlike with the previous example, a stack trace will just be a string of
157hexadecimal addresses. To turn the addresses back into symbols use,
158<http://go/crsym> (internal instance of <https://github.com/chromium/crsym/>).
159Using the **Crash Key** input type, give it a crash report ID and the name of
160your crash key. Crsym will then fetch the symbol data from the internal crash
161processing backends and return a formatted, symbolized stack trace.