Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1493)

Unified Diff: kernel_collector.cc

Issue 4018008: crash-reporter: Generate kernel crash signatures for server-side grouping of similar crashes (Closed) Base URL: http://git.chromium.org/git/crash-reporter.git
Patch Set: Respond to petkov review Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « kernel_collector.h ('k') | kernel_collector_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: kernel_collector.cc
diff --git a/kernel_collector.cc b/kernel_collector.cc
index c6bb33fca4d3c664edfd1e688e3a851466d29a5b..a95d757dbbaffe2ba423fcd0ac796a4c10e0a876 100644
--- a/kernel_collector.cc
+++ b/kernel_collector.cc
@@ -9,12 +9,21 @@
#include "base/string_util.h"
#include "crash-reporter/system_logging.h"
+const char KernelCollector::kClearingSequence[] = " ";
+static const char kDefaultKernelStackSignature[] =
+ "kernel-UnspecifiedStackSignature";
static const char kKernelExecName[] = "kernel";
-static const char kPreservedDumpPath[] = "/sys/kernel/debug/preserved/kcrash";
const pid_t kKernelPid = 0;
+static const char kKernelSignatureKey[] = "sig";
+// Byte length of maximum human readable portion of a kernel crash signature.
+static const int kMaxHumanStringLength = 40;
+static const char kPreservedDumpPath[] = "/sys/kernel/debug/preserved/kcrash";
const uid_t kRootUid = 0;
-
-const char KernelCollector::kClearingSequence[] = " ";
+// Time in seconds from the final kernel log message for a call stack
+// to count towards the signature of the kcrash.
+static const int kSignatureTimestampWindow = 2;
+// Kernel log timestamp regular expression.
+static const std::string kTimestampRegex("^<.*>\\[\\s*(\\d+\\.\\d+)\\]");
KernelCollector::KernelCollector()
: is_enabled_(false),
@@ -66,6 +75,171 @@ bool KernelCollector::ClearPreservedDump() {
return true;
}
+// Hash a string to a number. We define our own hash function to not
+// be dependent on a C++ library that might change. This function
+// uses basically the same approach as tr1/functional_hash.h but with
+// a larger prime number (16127 vs 131).
+static unsigned HashString(const std::string &input) {
+ unsigned hash = 0;
+ for (size_t i = 0; i < input.length(); ++i)
+ hash = hash * 16127 + input[i];
+ return hash;
+}
+
+void KernelCollector::ProcessStackTrace(
+ pcrecpp::StringPiece kernel_dump,
+ bool print_diagnostics,
+ unsigned *hash,
+ float *last_stack_timestamp) {
+ pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE());
+ pcrecpp::RE stack_trace_start_re(kTimestampRegex + " Call Trace:$");
+ // Match lines such as the following and grab out "error_code".
+ // <4>[ 6066.849504] [<7937bcee>] error_code+0x66/0x6c
+ pcrecpp::RE stack_entry_re(kTimestampRegex +
+ " \\[<.*>\\]([\\s\\?]+)([^\\+ ]+)");
+ std::string line;
+ std::string hashable;
+
+ *hash = 0;
+ *last_stack_timestamp = 0;
+
+ while (line_re.FindAndConsume(&kernel_dump, &line)) {
+ std::string certainty;
+ std::string function_name;
+ if (stack_trace_start_re.PartialMatch(line, last_stack_timestamp)) {
+ if (print_diagnostics) {
+ printf("Stack trace starting. Clearing any prior traces.\n");
+ }
+ hashable.clear();
+ } else if (stack_entry_re.PartialMatch(line,
+ last_stack_timestamp,
+ &certainty,
+ &function_name)) {
+ bool is_certain = certainty.find('?') == std::string::npos;
+ if (print_diagnostics) {
+ printf("@%f: stack entry for %s (%s)\n",
+ *last_stack_timestamp,
+ function_name.c_str(),
+ is_certain ? "certain" : "uncertain");
+ }
+ // Do not include any uncertain (prefixed by '?') frames in our hash.
+ if (!is_certain)
+ continue;
+ if (!hashable.empty())
+ hashable.append("|");
+ hashable.append(function_name);
+ }
+ }
+
+ *hash = HashString(hashable);
+
+ if (print_diagnostics) {
+ printf("Hash based on stack trace: \"%s\" at %f.\n",
+ hashable.c_str(), *last_stack_timestamp);
+ }
+}
+
+bool KernelCollector::FindCrashingFunction(
+ pcrecpp::StringPiece kernel_dump,
+ bool print_diagnostics,
+ float stack_trace_timestamp,
+ std::string *crashing_function) {
+ pcrecpp::RE eip_re(kTimestampRegex + " EIP: \\[<.*>\\] ([^\\+ ]+).*",
+ pcrecpp::MULTILINE());
+ float timestamp = 0;
+ while (eip_re.FindAndConsume(&kernel_dump, &timestamp, crashing_function)) {
+ if (print_diagnostics) {
+ printf("@%f: found crashing function %s\n",
+ timestamp,
+ crashing_function->c_str());
+ }
+ }
+ if (timestamp == 0) {
+ if (print_diagnostics) {
+ printf("Found no crashing function.\n");
+ }
+ return false;
+ }
+ if (stack_trace_timestamp != 0 &&
+ abs(stack_trace_timestamp - timestamp) > kSignatureTimestampWindow) {
+ if (print_diagnostics) {
+ printf("Found crashing function but not within window.\n");
+ }
+ return false;
+ }
+ if (print_diagnostics) {
+ printf("Found crashing function %s\n", crashing_function->c_str());
+ }
+ return true;
+}
+
+bool KernelCollector::FindPanicMessage(pcrecpp::StringPiece kernel_dump,
+ bool print_diagnostics,
+ std::string *panic_message) {
+ // Match lines such as the following and grab out "Fatal exception"
+ // <0>[ 342.841135] Kernel panic - not syncing: Fatal exception
+ pcrecpp::RE kernel_panic_re(kTimestampRegex +
+ " Kernel panic[^\\:]*\\:\\s*(.*)",
+ pcrecpp::MULTILINE());
+ float timestamp = 0;
+ while (kernel_panic_re.FindAndConsume(&kernel_dump,
+ &timestamp,
+ panic_message)) {
+ if (print_diagnostics) {
+ printf("@%f: panic message %s\n",
+ timestamp,
+ panic_message->c_str());
+ }
+ }
+ if (timestamp == 0) {
+ if (print_diagnostics) {
+ printf("Found no panic message.\n");
+ }
+ return false;
+ }
+ return true;
+}
+
+bool KernelCollector::ComputeKernelStackSignature(
+ const std::string &kernel_dump,
+ std::string *kernel_signature,
+ bool print_diagnostics) {
+ unsigned stack_hash = 0;
+ float last_stack_timestamp = 0;
+ std::string human_string;
+
+ ProcessStackTrace(kernel_dump,
+ print_diagnostics,
+ &stack_hash,
+ &last_stack_timestamp);
+
+ if (!FindCrashingFunction(kernel_dump,
+ print_diagnostics,
+ last_stack_timestamp,
+ &human_string)) {
+ if (!FindPanicMessage(kernel_dump, print_diagnostics, &human_string)) {
+ if (print_diagnostics) {
+ printf("Found no human readable string, using empty string.\n");
+ }
+ human_string.clear();
+ }
+ }
+
+ if (human_string.empty() && stack_hash == 0) {
+ if (print_diagnostics) {
+ printf("Found neither a stack nor a human readable string, failing.\n");
+ }
+ return false;
+ }
+
+ human_string = human_string.substr(0, kMaxHumanStringLength);
+ *kernel_signature = StringPrintf("%s-%s-%08X",
+ kKernelExecName,
+ human_string.c_str(),
+ stack_hash);
+ return true;
+}
+
bool KernelCollector::Collect() {
std::string kernel_dump;
FilePath root_crash_directory;
@@ -75,9 +249,19 @@ bool KernelCollector::Collect() {
if (kernel_dump.empty()) {
return false;
}
- logger_->LogInfo("Received prior crash notification from kernel");
+ std::string signature;
+ if (!ComputeKernelStackSignature(kernel_dump, &signature, false)) {
+ signature = kDefaultKernelStackSignature;
+ }
+
+ bool feedback = is_feedback_allowed_function_();
+
+ logger_->LogInfo("Received prior crash notification from "
+ "kernel (signature %s) (%s)",
+ signature.c_str(),
+ feedback ? "handling" : "ignoring");
- if (is_feedback_allowed_function_()) {
+ if (feedback) {
count_crash_function_();
if (!GetCreatedCrashDirectoryByEuid(kRootUid,
@@ -101,16 +285,15 @@ bool KernelCollector::Collect() {
return true;
}
+ AddCrashMetaData(kKernelSignatureKey, signature);
WriteCrashMetaData(
root_crash_directory.Append(
StringPrintf("%s.meta", dump_basename.c_str())),
kKernelExecName,
kernel_crash_path.value());
- logger_->LogInfo("Collected kernel crash diagnostics into %s",
+ logger_->LogInfo("Stored kcrash to %s",
kernel_crash_path.value().c_str());
- } else {
- logger_->LogInfo("Crash not saved since metrics disabled");
}
if (!ClearPreservedDump()) {
return false;
« no previous file with comments | « kernel_collector.h ('k') | kernel_collector_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698