android_webview
apps
ash
base
build
build_overrides
buildtools
cc
chrome
chromecast
chromeos
clank
codelabs
components
content
courgette
crypto
dbus
device
docs
accessibility
autofill
chromeos
design
enterprise
experiments
fuchsia
gpu
images
infra
intl
ios
lacros
linux
login
mac
media
memory
memory-infra
patterns
privacy
privacy_budget
process
security
speed
speed_metrics
standards
telemetry_extension
testing
transcripts
ui
updater
webapps
website
workflow
DIR_METADATA
OWNERS
README.md
accessibility.md
ad_tagging.md
adding_to_third_party.md
android_accessing_cpp_enums_in_java.md
android_accessing_cpp_features_in_java.md
android_accessing_cpp_switches_in_java.md
android_build_instructions.md
android_cast_build_instructions.md
android_debugging_instructions.md
android_dynamic_feature_modules.md
android_emulator.md
android_isolated_splits.md
android_jni_ownership_best_practices.md
android_logging.md
android_native_libraries.md
android_studio.md
angle_in_chromium.md
api_keys.md
asan.md
atom.md
benchmark_performance_regressions.md
bitmap_pipeline.md
branch_gardener.md
building_old_revisions.md
callback.md
ccache_mac.md
chrome_os_logging.md
chrome_settings.md
chrome_untrusted.md
chromedriver_status.md
chromeos_build_instructions.md
chromeos_glossary.md
chromium_browser_vs_google_chrome.md
cipd_and_3pp.md
cl_respect.md
cl_tips.md
clang.md
clang_code_coverage_wrapper.md
clang_format.md
clang_gardening.md
clang_sheriffing.md
clang_static_analyzer.md
clang_tidy.md
clang_tool_refactoring.md
clangd.md
clion.md
closure_compilation.md
cocoa_tips_and_tricks.md
code_review_owners.md
code_reviews.md
commit_checklist.md
component_build.md
configuration.md
contributing.md
cq_fault_attribution.md
cr_respect.md
cr_user_manual.md
cross_platform_ui.md
cygwin_dll_remapping_failure.md
dangling_ptr.md
dangling_ptr_guide.md
dbus_mojo_connection_service.md
debugging_with_crash_keys.md
dependencies.md
deterministic_builds.md
disassemble_code.md
documentation_best_practices.md
documentation_guidelines.md
early-hints.md
eclipse.md
emacs.md
erc_irc.md
flag_expiry.md
flag_guarding_guidelines.md
flag_ownership.md
frame_trees.md
gardener.md
gdbinit.md
get_the_code.md
git_cookbook.md
git_submodules.md
git_tips.md
google_chrome_branded_builds.md
google_play_services.md
graphical_debugging_aid_chromium_views.md
gwp_asan.md
history_manipulation_intervention.md
how_cc_works.md
how_to_add_your_feature_flag.md
how_to_extend_web_test_framework.md
idn.md
initialize_blink_features.md
inlined_stack_traces.md
installation_at_vmware.md
ios_build_instructions.md
ios_infra.md
ios_voiceover.md
kiosk_mode.md
lacros.md
life_of_a_frame.md
lldbinit.md
mac_arm64.md
mac_build_instructions.md
mac_lld.md
modifying_session_history_serialization.md
mojo_and_services.md
mojo_ipc_conversion.md
mojo_testing.md
native_relocations.md
navbar.md
navigation-request-navigation-state.gv
navigation-request-navigation-state.png
navigation.md
navigation_concepts.md
network_traffic_annotations.md
no_sources_assignment_filter.md
optimizing_web_uis.md
origin_trials_integration.md
ozone_overview.md
parsing_test_results.md
pgo.md
piranha_plant.md
process_model_and_site_isolation.md
profiling.md
profiling_content_shell_on_android.md
proxy_auto_config.md
qtcreator.md
release_branch_guidance.md
render-frame-host-lifecycle-state.gv
render-frame-host-lifecycle-state.png
render_document.md
rust.md
seccomp_sandbox_crash_dumping.md
servicification.md
session_history.md
sheriff.md
shutdown.md
special_case_urls.md
static_initializers.md
sublime_ide.md
system_hardening_features.md
tab_helpers.md
testing_webui.md
threading_and_tasks.md
threading_and_tasks_faq.md
threading_and_tasks_testing.md
toolchain_support.md
tour_of_luci_ui.md
tpm_quick_ref.md
translation_screenshots.md
trusted_types_on_webui.md
unretained_dangling_ptr_guide.md
unsafe_buffers.md
updating_clang.md
updating_clang_format_binaries.md
use_counter_wiki.md
useful_urls.md
user_data_dir.md
user_data_storage.md
user_handle_mapping.md
vanilla_msysgit_workflow.md
vscode.md
vscode_python.md
webui_build_configuration.md
webui_explainer.md
webui_in_chrome.md
webui_in_components.md
webview_policies.md
win_cross.md
win_order_files.md
windows_build_instructions.md
windows_native_window_occlusion_tracking.md
windows_pwa_integration.md
windows_shortcut_and_taskbar_handling.md
windows_split_dll.md
windows_virtual_desktop_handling.md
wmax_tokens.md
working_remotely_with_android.md
writing_clang_plugins.md
extensions
fuchsia_web
gin
google_apis
google_update
gpu
headless
infra
internal
ios
ios_internal
ipc
media
mojo
native_client
native_client_sdk
net
pdf
ppapi
printing
remoting
rlz
sandbox
services
signing_keys
skia
sql
storage
styleguide
testing
third_party
tools
ui
url
v8
webkit
.clang-format
.clang-tidy
.clangd
.eslintrc.js
.git-blame-ignore-revs
.gitallowed
.gitattributes
.gitignore
.gitmodules
.gn
.mailmap
.rustfmt.toml
.vpython3
.yapfignore
ATL_OWNERS
AUTHORS
BUILD.gn
CODE_OF_CONDUCT.md
DEPS
DIR_METADATA
LICENSE
LICENSE.chromium_os
OWNERS
PRESUBMIT.py
PRESUBMIT_test.py
PRESUBMIT_test_mocks.py
README.md
WATCHLISTS
codereview.settings

No change to content. This only changes the capitalization of "Webview" to "WebView" to match the spelling we use in other documentation. Change-Id: I417fd5b8ecc036ed19918ff2f12da883599a6a57 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5251796 Reviewed-by: Adam Walls <avvall@chromium.org> Commit-Queue: Adam Walls <avvall@chromium.org> Commit-Queue: Nate Fischer <ntfschr@chromium.org> Auto-Submit: Nate Fischer <ntfschr@chromium.org> Cr-Commit-Position: refs/heads/main@{#1254305}
166 lines
7.2 KiB
Markdown
166 lines
7.2 KiB
Markdown
# Debugging with Crash Keys
|
||
|
||
Chrome is client-side software, which means that sometimes there are bugs that
|
||
can occur only on users' machines ("in production") that cannot be reproduced by
|
||
test or software engineering. When this happens, it's often helpful to gather bug-
|
||
specific data from production to help pinpoint the cause of the crash. The crash
|
||
key logging system is a generic method to help do that.
|
||
|
||
[TOC]
|
||
|
||
## High-Level Overview
|
||
|
||
The 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),
|
||
which declares a `crash_reporter::CrashKeyString` class. Every crash key has
|
||
an associated value maximum length and a string name to identify it. The maximum
|
||
length is specified as a template parameter in order to allocate that amount of
|
||
space for the value up-front. When a process is crashing, memory corruption can
|
||
make it unsafe to call into the system allocator, so pre-allocating space for
|
||
the value defends against that.
|
||
|
||
When a crash key is set, the specified value is copied to its internal storage.
|
||
And if the process subsequently crashes, the name-value tuple is uploaded as
|
||
POST form-multipart data when the crash report minidump is uploaded to the
|
||
Google crash reporting system. (The data therefore are only accessible to those
|
||
with access to crash reports internally at Google). For platforms that use
|
||
[Crashpad](https://crashpad.chromium.org) as the crash reporting platform, the
|
||
crash keys are also stored in the minidump file itself. For platforms that use
|
||
Breakpad, the keys are only available at upload.
|
||
|
||
The crash key system is used to report some common pieces of data, not just
|
||
things that happen in exceptional cases: the URL of the webpage, command line
|
||
switches, active extension IDs, GPU vendor information, experiment/variations
|
||
information, etc.
|
||
|
||
## Redaction
|
||
|
||
Beware that certain on certain platforms (e.g. Android WebView) we
|
||
[sanitize the stack in the dump](https://cs.chromium.org/chromium/src/third_party/crashpad/crashpad/snapshot/sanitized/memory_snapshot_sanitized.h)
|
||
and only crash keys on an
|
||
[allowlist](https://cs.chromium.org/chromium/src/android_webview/common/crash_reporter/crash_keys.cc)
|
||
will be captured.
|
||
|
||
## Getting Started with a Single Key-Value Pair
|
||
|
||
Imagine you are investigating a crash, and you want to know the value of some
|
||
variable when the crash occurs; the crash key logging system enables you to do
|
||
just that.
|
||
|
||
#### 1. Declare the Crash Key
|
||
|
||
A crash key must be allocated using static storage duration, so that there is
|
||
space for the value to be set. This can be done as a static variable in the
|
||
global or function scope, or in an anonymous namespace:
|
||
|
||
static crash_reporter::CrashKeyString<32> crash_key_one("one");
|
||
|
||
namespace {
|
||
crash_reporter::CrashKeyString<64> crash_key_two("two");
|
||
}
|
||
|
||
void DoSomething(const std::string& arg) {
|
||
static crash_reporter::CrashKeyString<8> three("three");
|
||
crash_key_two.Set(arg);
|
||
three.Set("true");
|
||
}
|
||
|
||
The template argument specifies the maximum length a value can be, and it
|
||
should include space for a trailing NUL byte. Values must be C-strings and
|
||
cannot have embedded NULs. The constructor argument is the name of the
|
||
crash key, and it is what you will use to identify your data in uploaded
|
||
crash reports.
|
||
|
||
Note that crash key names are global and must not conflict with the
|
||
name of any other crash key in Chrome.
|
||
|
||
If you need to declare an array of crash keys (e.g., for recording N values
|
||
of an array), you can use a constructor tag to avoid warnings about `explicit`:
|
||
|
||
static ArrayItemKey = crash_reporter::CrashKeyString<32>;
|
||
static ArrayItemKey crash_keys[] = {
|
||
{"array-item-1", ArrayItemKey::Tag::kArray},
|
||
{"array-item-2", ArrayItemKey::Tag::kArray},
|
||
{"array-item-3", ArrayItemKey::Tag::kArray},
|
||
{"array-item-4", ArrayItemKey::Tag::kArray},
|
||
};
|
||
|
||
The crash key system will require your target to have a dependency on
|
||
`//components/crash/core/common:crash_key`. If you encounter link errors for
|
||
unresolved symbols to `crashpad::Annotation::SetSize(unsigned int)`, adding
|
||
the dependency will resolve them.
|
||
|
||
#### 2. Set the Crash Key
|
||
|
||
After a key has been allocated, its `Set(base::StringPiece)` and
|
||
`Clear()` methods can be used to record and clear a value. In addition,
|
||
crash_key.h provides a `ScopedCrashKeyString` class to set the value for the
|
||
duration of a scope and clear it upon exiting.
|
||
|
||
#### 3. Seeing the Data
|
||
|
||
Using <http://go/crash> (internal only), find the crash report signature related
|
||
to your bug, and click on the "N of M" reports link to drill down to
|
||
report-specific information. From there, select a report and go to the
|
||
"Product Data" section to view all the crash key-value pairs.
|
||
|
||
## Dealing with DEPS
|
||
|
||
Not all targets in the Chromium source tree are permitted to depend on the
|
||
`//components/crash/core/common:crash_key` target due to DEPS file
|
||
`include_rules`.
|
||
|
||
If the crash key being added is only a temporary debugging aid to track down a
|
||
crash, consider adding the dependency temporarily and removing it when done.
|
||
A specific include rule can be added for crash_key.h:
|
||
|
||
# DEPS
|
||
include_rules = [
|
||
'+components/crash/core/common/crash_key.h',
|
||
]
|
||
|
||
Then simply remove it (and the BUILD.gn dependency) once the crash is resolved
|
||
and the crash key deleted.
|
||
|
||
If this crash key is more permanent, then there is an alternate API in //base
|
||
that can be used. This API is used by the //content module to set its permanent
|
||
crash key information. Note however that the base-level API is more limited in
|
||
terms of features and flexibility. See the header documentation in
|
||
[//base/debug/crash_logging.h](https://cs.chromium.org/chromium/src/base/debug/crash_logging.h)
|
||
for usage examples.
|
||
|
||
## Advanced Topics: Stack Traces
|
||
|
||
Now imagine a scenario where you have a use-after-free. The crash reports coming
|
||
in do not indicate where the object being used was initially freed, however,
|
||
just where it is later being dereferenced. To make debugging easier, it would be
|
||
nice to have the stack trace of the destructor, and the crash key system works
|
||
for that, too.
|
||
|
||
#### 1. Declare the Crash Key
|
||
|
||
Declaring the crash key is no different than written above, though special
|
||
attention should be paid to the maximum size argument, which will affect the
|
||
number of stack frames that are recorded. Typically a value of _1024_ is
|
||
recommended.
|
||
|
||
#### 2. Set the Crash Key
|
||
|
||
To set a stack trace to a crash key, use the `SetCrashKeyStringToStackTrace()`
|
||
function in crash_logging.h:
|
||
|
||
Usemeafterfree::~Usemeafterfree() {
|
||
static crash_reporter::CrashKeyString<1024> trace_key(
|
||
"useme-after-free-uaf-dtor-trace");
|
||
crash_reporter::SetCrashKeyStringToStackTrace(&trace_key,
|
||
base::debug::StackTrace());
|
||
}
|
||
|
||
#### 3. Seeing the Data
|
||
|
||
Unlike with the previous example, a stack trace will just be a string of
|
||
hexadecimal addresses. To turn the addresses back into symbols use,
|
||
<http://go/crsym> (internal instance of <https://github.com/chromium/crsym/>).
|
||
Using the **Crash Key** input type, give it a crash report ID and the name of
|
||
your crash key. Crsym will then fetch the symbol data from the internal crash
|
||
processing backends and return a formatted, symbolized stack trace.
|