Skip to content

Commit

Permalink
Include string annotation objects when uploading crash reports.
Browse files Browse the repository at this point in the history
This extracts string annotation objects from the minidumps and includes
them as form POST key-value pairs.

This change also starts building a crashpad_handler_test binary on Mac.

Bug: crashpad:192
Change-Id: I68cbf6fda6f1e57c1e621d5e3de8717cfaea65bf
Reviewed-on: https://chromium-review.googlesource.com/749793
Commit-Queue: Robert Sesek <[email protected]>
Reviewed-by: Mark Mentovai <[email protected]>
  • Loading branch information
rsesek authored and Commit Bot committed Nov 2, 2017
1 parent 4d7d4dd commit 79e2dd8
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 89 deletions.
5 changes: 1 addition & 4 deletions build/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,13 @@ def main(args):

tests = [
'crashpad_client_test',
'crashpad_handler_test',
'crashpad_minidump_test',
'crashpad_snapshot_test',
'crashpad_test_test',
'crashpad_util_test',
]

if sys.platform == 'win32':
tests.append('crashpad_handler_test')
tests = sorted(tests)

for test in tests:
print '-' * 80
print test
Expand Down
69 changes: 6 additions & 63 deletions handler/crash_report_upload_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "client/settings.h"
#include "handler/minidump_to_upload_parameters.h"
#include "snapshot/minidump/process_snapshot_minidump.h"
#include "snapshot/module_snapshot.h"
#include "util/file/file_reader.h"
Expand All @@ -46,68 +47,6 @@ namespace crashpad {

namespace {

void InsertOrReplaceMapEntry(std::map<std::string, std::string>* map,
const std::string& key,
const std::string& value) {
std::string old_value;
if (!MapInsertOrReplace(map, key, value, &old_value)) {
LOG(WARNING) << "duplicate key " << key << ", discarding value "
<< old_value;
}
}

// Given a minidump file readable by |minidump_file_reader|, returns a map of
// key-value pairs to use as HTTP form parameters for upload to a Breakpad
// server. The map is built by combining the process simple annotations map with
// each module’s simple annotations map. In the case of duplicate keys, the map
// will retain the first value found for any key, and will log a warning about
// discarded values. Each module’s annotations vector is also examined and built
// into a single string value, with distinct elements separated by newlines, and
// stored at the key named “list_annotations”, which supersedes any other key
// found by that name. The client ID stored in the minidump is converted to
// a string and stored at the key named “guid”, which supersedes any other key
// found by that name.
//
// In the event of an error reading the minidump file, a message will be logged.
std::map<std::string, std::string> BreakpadHTTPFormParametersFromMinidump(
FileReaderInterface* minidump_file_reader) {
ProcessSnapshotMinidump minidump_process_snapshot;
if (!minidump_process_snapshot.Initialize(minidump_file_reader)) {
return std::map<std::string, std::string>();
}

std::map<std::string, std::string> parameters =
minidump_process_snapshot.AnnotationsSimpleMap();

std::string list_annotations;
for (const ModuleSnapshot* module : minidump_process_snapshot.Modules()) {
for (const auto& kv : module->AnnotationsSimpleMap()) {
if (!parameters.insert(kv).second) {
LOG(WARNING) << "duplicate key " << kv.first << ", discarding value "
<< kv.second;
}
}

for (std::string annotation : module->AnnotationsVector()) {
list_annotations.append(annotation);
list_annotations.append("\n");
}
}

if (!list_annotations.empty()) {
// Remove the final newline character.
list_annotations.resize(list_annotations.size() - 1);

InsertOrReplaceMapEntry(&parameters, "list_annotations", list_annotations);
}

UUID client_id;
minidump_process_snapshot.ClientID(&client_id);
InsertOrReplaceMapEntry(&parameters, "guid", client_id.ToString());

return parameters;
}

// Calls CrashReportDatabase::RecordUploadAttempt() with |successful| set to
// false upon destruction unless disarmed by calling Fire() or Disarm(). Fire()
// triggers an immediate call. Armed upon construction.
Expand Down Expand Up @@ -359,7 +298,11 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport(
// minidump file. This may result in its being uploaded with few or no
// parameters, but as long as there’s a dump file, the server can decide what
// to do with it.
parameters = BreakpadHTTPFormParametersFromMinidump(&minidump_file_reader);
ProcessSnapshotMinidump minidump_process_snapshot;
if (minidump_process_snapshot.Initialize(&minidump_file_reader)) {
parameters =
BreakpadHTTPFormParametersFromMinidump(&minidump_process_snapshot);
}

if (!minidump_file_reader.SeekSet(start_offset)) {
return UploadResult::kPermanentFailure;
Expand Down
2 changes: 2 additions & 0 deletions handler/handler.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
'mac/exception_handler_server.h',
'mac/file_limit_annotation.cc',
'mac/file_limit_annotation.h',
'minidump_to_upload_parameters.cc',
'minidump_to_upload_parameters.h',
'prune_crash_reports_thread.cc',
'prune_crash_reports_thread.h',
'user_stream_data_source.cc',
Expand Down
56 changes: 34 additions & 22 deletions handler/handler_test.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,40 @@
'../build/crashpad.gypi',
],
'targets': [
{
'target_name': 'crashpad_handler_test',
'type': 'executable',
'dependencies': [
'crashpad_handler_test_extended_handler',
'handler.gyp:crashpad_handler_lib',
'../client/client.gyp:crashpad_client',
'../compat/compat.gyp:crashpad_compat',
'../snapshot/snapshot.gyp:crashpad_snapshot',
'../snapshot/snapshot_test.gyp:crashpad_snapshot_test_lib',
'../test/test.gyp:crashpad_gtest_main',
'../test/test.gyp:crashpad_test',
'../third_party/gtest/gtest.gyp:gtest',
'../third_party/mini_chromium/mini_chromium.gyp:base',
'../util/util.gyp:crashpad_util',
],
'include_dirs': [
'..',
],
'sources': [
'crashpad_handler_test.cc',
'minidump_to_upload_parameters_test.cc',
],
'conditions': [
['OS!="win"', {
'dependencies!': [
'crashpad_handler_test_extended_handler',
],
'sources!': [
'crashpad_handler_test.cc',
],
}],
],
},
{
'target_name': 'crashpad_handler_test_extended_handler',
'type': 'executable',
Expand Down Expand Up @@ -52,28 +86,6 @@
'win/crash_other_program.cc',
],
},
{
# The handler is only tested on Windows for now.
'target_name': 'crashpad_handler_test',
'type': 'executable',
'dependencies': [
'crashpad_handler_test_extended_handler',
'handler.gyp:crashpad_handler_lib',
'../client/client.gyp:crashpad_client',
'../compat/compat.gyp:crashpad_compat',
'../test/test.gyp:crashpad_gtest_main',
'../test/test.gyp:crashpad_test',
'../third_party/gtest/gtest.gyp:gtest',
'../third_party/mini_chromium/mini_chromium.gyp:base',
'../util/util.gyp:crashpad_util',
],
'include_dirs': [
'..',
],
'sources': [
'crashpad_handler_test.cc',
],
},
{
'target_name': 'crashy_program',
'type': 'executable',
Expand Down
86 changes: 86 additions & 0 deletions handler/minidump_to_upload_parameters.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "handler/minidump_to_upload_parameters.h"

#include "base/logging.h"
#include "client/annotation.h"
#include "snapshot/module_snapshot.h"
#include "util/stdlib/map_insert.h"

namespace crashpad {

namespace {

void InsertOrReplaceMapEntry(std::map<std::string, std::string>* map,
const std::string& key,
const std::string& value) {
std::string old_value;
if (!MapInsertOrReplace(map, key, value, &old_value)) {
LOG(WARNING) << "duplicate key " << key << ", discarding value "
<< old_value;
}
}

} // namespace

std::map<std::string, std::string> BreakpadHTTPFormParametersFromMinidump(
const ProcessSnapshot* process_snapshot) {
std::map<std::string, std::string> parameters =
process_snapshot->AnnotationsSimpleMap();

std::string list_annotations;
for (const ModuleSnapshot* module : process_snapshot->Modules()) {
for (const auto& kv : module->AnnotationsSimpleMap()) {
if (!parameters.insert(kv).second) {
LOG(WARNING) << "duplicate key " << kv.first << ", discarding value "
<< kv.second;
}
}

for (std::string annotation : module->AnnotationsVector()) {
list_annotations.append(annotation);
list_annotations.append("\n");
}

for (const AnnotationSnapshot& annotation : module->AnnotationObjects()) {
if (annotation.type != static_cast<uint16_t>(Annotation::Type::kString)) {
continue;
}

std::string value(reinterpret_cast<const char*>(annotation.value.data()),
annotation.value.size());
std::pair<std::string, std::string> entry(annotation.name, value);
if (!parameters.insert(entry).second) {
LOG(WARNING) << "duplicate annotation name " << annotation.name
<< ", discarding value " << value;
}
}
}

if (!list_annotations.empty()) {
// Remove the final newline character.
list_annotations.resize(list_annotations.size() - 1);

InsertOrReplaceMapEntry(&parameters, "list_annotations", list_annotations);
}

UUID client_id;
process_snapshot->ClientID(&client_id);
InsertOrReplaceMapEntry(&parameters, "guid", client_id.ToString());

return parameters;
}

} // namespace crashpad
61 changes: 61 additions & 0 deletions handler/minidump_to_upload_parameters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HANDLER_MINIDUMP_TO_UPLOAD_PARAMETERS_H_
#define HANDLER_MINIDUMP_TO_UPLOAD_PARAMETERS_H_

#include <map>
#include <string>

#include "snapshot/process_snapshot.h"

namespace crashpad {

//! \brief Given a ProcessSnapshot, returns a map of key-value pairs to use as
//! HTTP form parameters for upload to a Breakpad crash report colleciton
//! server.
//!
//! The map is built by combining the process simple annotations map with
//! each module’s simple annotations map and annotation objects.
//!
//! In the case of duplicate simple map keys or annotation names, the map will
//! retain the first value found for any key, and will log a warning about
//! discarded values. The precedence rules for annotation names are: the two
//! reserved keys discussed below, process simple annotations, module simple
//! annotations, and module annotation objects.
//!
//! For annotation objects, only ones of that are Annotation::Type::kString are
//! included.
//!
//! Each module’s annotations vector is also examined and built into a single
//! string value, with distinct elements separated by newlines, and stored at
//! the key named “list_annotations”, which supersedes any other key found by
//! that name.
//!
//! The client ID stored in the minidump is converted to a string and stored at
//! the key named “guid”, which supersedes any other key found by that name.
//!
//! In the event of an error reading the minidump file, a message will be
//! logged.
//!
//! \param[in] process_snapshot The process snapshot from which annotations
//! will be extracted.
//!
//! \returns A string map of the annotations.
std::map<std::string, std::string> BreakpadHTTPFormParametersFromMinidump(
const ProcessSnapshot* process_snapshot);

} // namespace crashpad

#endif // HANDLER_MINIDUMP_TO_UPLOAD_PARAMETERS_H_
Loading

0 comments on commit 79e2dd8

Please sign in to comment.