blob: 400f9488d67ea46eee277377e2fcb250ffe8289c [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
35## Getting Started with a Single Key-Value Pair
36
37Imagine you are investigating a crash, and you want to know the value of some
38variable when the crash occurs; the crash key logging system enables you to do
39just that.
40
41#### 1. Declare the Crash Key
42
43A crash key must be allocated using static storage duration, so that there is
44space for the value to be set. This can be done as a static variable in the
45global or function scope, or in an anonymous namespace:
46
47 static crash_reporter::CrashKeyString<32> crash_key_one("one");
48
49 namespace {
50 crash_reporter::CrashKeyString<64> crash_key_two("two");
51 }
52
53 void DoSomething(const std::string& arg) {
54 static crash_reporter::CrashKeyString<8> three("three");
55 crash_key_two.Set(arg);
56 three.Set("true");
57 }
58
59The template argument specifies the maximum length a value can be, and it
60should include space for a trailing NUL byte. Values must be C-strings and
61cannot have embedded NULs. The constructor argument is the name of the
62crash key, and it is what you will use to identify your data in uploaded
63crash reports.
64
65If you need to declare an array of crash keys (e.g., for recording N values
66of an array), you can use a constructor tag to avoid warnings about `explicit`:
67
68 static ArrayItemKey = crash_reporter::CrashKeyString<32>;
69 static ArrayItemKey crash_keys[] = {
70 {"array-item-1", ArrayItemKey::Tag::kArray},
71 {"array-item-2", ArrayItemKey::Tag::kArray},
72 {"array-item-3", ArrayItemKey::Tag::kArray},
73 {"array-item-4", ArrayItemKey::Tag::kArray},
74 };
75
76The crash key system will require your target to have a dependency on
77`//components/crash/core/common:crash_key`. If you encounter link errors for
78unresolved symbols to `crashpad::Annotation::SetSize(unsigned int)`, adding
79the dependency will resolve them.
80
81#### 2. Set the Crash Key
82
83After a key has been allocated, its `Set(base::StringPiece)` and
84`Clear()` methods can be used to record and clear a value. In addition,
85crash_key.h provides a `ScopedCrashKeyString` class to set the value for the
86duration of a scope and clear it upon exiting.
87
88#### 3. Seeing the Data
89
90Using <http://go/crash> (internal only), find the crash report signature related
91to your bug, and click on the "N of M" reports link to drill down to
92report-specific information. From there, select a report and go to the
93"Product Data" section to view all the crash key-value pairs.
94
95## Dealing with DEPS
96
97Not all targets in the Chromium source tree are permitted to depend on the
98`//components/crash/core/common:crash_key` target due to DEPS file
99`include_rules`.
100
101If the crash key being added is only a temporary debugging aid to track down a
102crash, consider adding the dependency temporarily and removing it when done.
103A specific include rule can be added for crash_key.h:
104
105 # DEPS
106 include_rules = [
107 '+components/crash/core/common/crash_key.h',
108 ]
109
110Then simply remove it (and the BUILD.gn dependency) once the crash is resolved
111and the crash key deleted.
112
113If this crash key is more permanent, then there is an alternate API in //base
114that can be used. This API is used by the //content module to set its permanent
115crash key information. Note however that the base-level API is more limited in
116terms of features and flexibility. See the header documentation in
117[//base/debug/crash_logging.h](https://cs.chromium.org/chromium/src/base/debug/crash_logging.h)
118for usage examples.
119
120## Advanced Topics: Stack Traces
121
122Now imagine a scenario where you have a use-after-free. The crash reports coming
123in do not indicate where the object being used was initially freed, however,
124just where it is later being dereferenced. To make debugging easier, it would be
125nice to have the stack trace of the destructor, and the crash key system works
126for that, too.
127
128#### 1. Declare the Crash Key
129
130Declaring the crash key is no different than written above, though special
131attention should be paid to the maximum size argument, which will affect the
132number of stack frames that are recorded. Typically a value of _1024_ is
133recommended.
134
135#### 2. Set the Crash Key
136
137To set a stack trace to a crash key, use the `SetCrashKeyStringToStackTrace()`
138function in crash_logging.h:
139
140 Usemeafterfree::~Usemeafterfree() {
141 static crash_reporter::CrashKeyString<1024> trace_key("uaf-dtor-trace");
142 crash_reporter::SetCrashKeyStringToStackTrace(&trace_key,
143                                        base::debug::StackTrace());
144 }
145
146#### 3. Seeing the Data
147
148Unlike with the previous example, a stack trace will just be a string of
149hexadecimal addresses. To turn the addresses back into symbols use,
150<http://go/crsym> (internal instance of <https://github.com/chromium/crsym/>).
151Using the **Crash Key** input type, give it a crash report ID and the name of
152your crash key. Crsym will then fetch the symbol data from the internal crash
153processing backends and return a formatted, symbolized stack trace.