Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crash-reporter/kernel_collector.h" | 5 #include "crash-reporter/kernel_collector.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 | 10 |
| 11 const char KernelCollector::kClearingSequence[] = " "; | 11 const char KernelCollector::kClearingSequence[] = " "; |
| 12 static const char kDefaultKernelStackSignature[] = | 12 static const char kDefaultKernelStackSignature[] = |
| 13 "kernel-UnspecifiedStackSignature"; | 13 "kernel-UnspecifiedStackSignature"; |
| 14 static const char kKernelExecName[] = "kernel"; | 14 static const char kKernelExecName[] = "kernel"; |
| 15 const pid_t kKernelPid = 0; | 15 const pid_t kKernelPid = 0; |
| 16 static const char kKernelSignatureKey[] = "sig"; | 16 static const char kKernelSignatureKey[] = "sig"; |
| 17 // Byte length of maximum human readable portion of a kernel crash signature. | 17 // Byte length of maximum human readable portion of a kernel crash signature. |
| 18 static const int kMaxHumanStringLength = 40; | 18 static const int kMaxHumanStringLength = 40; |
| 19 static const char kPreservedDumpPath[] = "/sys/kernel/debug/preserved/kcrash"; | 19 static const char kPreservedDumpPath[] = "/sys/kernel/debug/preserved/kcrash"; |
| 20 const uid_t kRootUid = 0; | 20 const uid_t kRootUid = 0; |
| 21 // Time in seconds from the final kernel log message for a call stack | 21 // Time in seconds from the final kernel log message for a call stack |
| 22 // to count towards the signature of the kcrash. | 22 // to count towards the signature of the kcrash. |
| 23 static const int kSignatureTimestampWindow = 2; | 23 static const int kSignatureTimestampWindow = 2; |
| 24 // Kernel log timestamp regular expression. | 24 // Kernel log timestamp regular expression. |
| 25 static const std::string kTimestampRegex("^<.*>\\[\\s*(\\d+\\.\\d+)\\]"); | 25 static const std::string kTimestampRegex("^<.*>\\[\\s*(\\d+\\.\\d+)\\]"); |
| 26 | 26 |
| 27 /* | |
| 28 * For ARM we see: | |
|
kmixter1
2011/04/05 00:09:26
Could you change the comment to be more descriptiv
sjg
2011/04/05 17:45:04
done
| |
| 29 * "<5>[ 39.458982] PC is at write_breakme+0xd0/0x1b4" | |
| 30 * For x86: | |
| 31 * "<0>[ 37.474699] EIP: [<790ed488>] write_breakme+0x80/0x108 \ | |
| 32 * SS:ESP 0068:e9dd3efc | |
| 33 */ | |
| 34 static const std::string pcRegex[KernelCollector::archCount] = { | |
|
kmixter1
2011/04/05 00:09:26
I suspect that if archCount is greater than the nu
sjg
2011/04/05 17:45:04
OK have changed the varname and added a check in c
| |
| 35 " PC is at ([^\\+ ]+).*", | |
| 36 " EIP: \\[<.*>\\] ([^\\+ ]+).*", // X86 uses EIP for the program counter | |
| 37 " Unsupported architecture" | |
| 38 }; | |
| 39 | |
| 27 KernelCollector::KernelCollector() | 40 KernelCollector::KernelCollector() |
| 28 : is_enabled_(false), | 41 : is_enabled_(false), |
| 29 preserved_dump_path_(kPreservedDumpPath) { | 42 preserved_dump_path_(kPreservedDumpPath) { |
| 43 // We expect crash dumps in the format of the architecture we are built for. | |
| 44 arch_ = GetCompilerArch(); | |
| 45 if (arch_ == archUnknown) | |
| 46 LOG(WARNING) << "KernelCollector does not understand this architecture"; | |
| 30 } | 47 } |
| 31 | 48 |
| 32 KernelCollector::~KernelCollector() { | 49 KernelCollector::~KernelCollector() { |
| 33 } | 50 } |
| 34 | 51 |
| 35 void KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) { | 52 void KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) { |
| 36 preserved_dump_path_ = file_path; | 53 preserved_dump_path_ = file_path; |
| 37 } | 54 } |
| 38 | 55 |
| 39 bool KernelCollector::LoadPreservedDump(std::string *contents) { | 56 bool KernelCollector::LoadPreservedDump(std::string *contents) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 hash = hash * 16127 + input[i]; | 100 hash = hash * 16127 + input[i]; |
| 84 return hash; | 101 return hash; |
| 85 } | 102 } |
| 86 | 103 |
| 87 void KernelCollector::ProcessStackTrace( | 104 void KernelCollector::ProcessStackTrace( |
| 88 pcrecpp::StringPiece kernel_dump, | 105 pcrecpp::StringPiece kernel_dump, |
| 89 bool print_diagnostics, | 106 bool print_diagnostics, |
| 90 unsigned *hash, | 107 unsigned *hash, |
| 91 float *last_stack_timestamp) { | 108 float *last_stack_timestamp) { |
| 92 pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE()); | 109 pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE()); |
| 93 pcrecpp::RE stack_trace_start_re(kTimestampRegex + " Call Trace:$"); | 110 pcrecpp::RE stack_trace_start_re(kTimestampRegex + |
| 111 " (Call Trace|Backtrace):$"); | |
| 94 // Match lines such as the following and grab out "error_code". | 112 // Match lines such as the following and grab out "error_code". |
| 95 // <4>[ 6066.849504] [<7937bcee>] error_code+0x66/0x6c | 113 // <4>[ 6066.849504] [<7937bcee>] ? error_code+0x66/0x6c |
| 114 // The ? may or may not be present | |
| 115 | |
| 116 // For ARM: | |
|
kmixter1
2011/04/05 00:09:26
Could you add the x86 example? It may be easier t
sjg
2011/04/05 17:45:04
It is above - I have changed it around to be more
| |
| 117 // <4>[ 3498.731164] [<c0057220>] (__bug+0x20/0x2c) from [<c018062c>] | |
| 118 // (write_breakme+0xdc/0x1bc) | |
| 96 pcrecpp::RE stack_entry_re(kTimestampRegex + | 119 pcrecpp::RE stack_entry_re(kTimestampRegex + |
| 97 " \\[<.*>\\]([\\s\\?]+)([^\\+ ]+)"); | 120 "\\s+\\[<[[:xdigit:]]+>\\]" // Matches " [<7937bcee>]" |
| 121 "([\\s\\?(]+)" // Matches " ? (" | |
|
kmixter1
2011/04/05 00:09:26
Matches " ? (" (ARM) or " ? " (x86).
sjg
2011/04/05 17:45:04
done
| |
| 122 "([^\\+ )]+)"); // Matches until \ + space ) | |
|
kmixter1
2011/04/05 00:09:26
nit: it took me a while to parse this comment. Ma
sjg
2011/04/05 17:45:04
done
| |
| 98 std::string line; | 123 std::string line; |
| 99 std::string hashable; | 124 std::string hashable; |
| 100 | 125 |
| 101 *hash = 0; | 126 *hash = 0; |
| 102 *last_stack_timestamp = 0; | 127 *last_stack_timestamp = 0; |
| 103 | 128 |
| 104 while (line_re.FindAndConsume(&kernel_dump, &line)) { | 129 while (line_re.FindAndConsume(&kernel_dump, &line)) { |
| 105 std::string certainty; | 130 std::string certainty; |
| 106 std::string function_name; | 131 std::string function_name; |
| 107 if (stack_trace_start_re.PartialMatch(line, last_stack_timestamp)) { | 132 if (stack_trace_start_re.PartialMatch(line, last_stack_timestamp)) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 130 } | 155 } |
| 131 | 156 |
| 132 *hash = HashString(hashable); | 157 *hash = HashString(hashable); |
| 133 | 158 |
| 134 if (print_diagnostics) { | 159 if (print_diagnostics) { |
| 135 printf("Hash based on stack trace: \"%s\" at %f.\n", | 160 printf("Hash based on stack trace: \"%s\" at %f.\n", |
| 136 hashable.c_str(), *last_stack_timestamp); | 161 hashable.c_str(), *last_stack_timestamp); |
| 137 } | 162 } |
| 138 } | 163 } |
| 139 | 164 |
| 165 enum KernelCollector::ArchKind KernelCollector::GetCompilerArch(void) | |
| 166 { | |
| 167 #if defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY) | |
| 168 return archArm; | |
| 169 #elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) | |
| 170 return archX86; | |
| 171 #else | |
| 172 return archUnknown; | |
| 173 #endif | |
| 174 } | |
| 175 | |
| 176 void KernelCollector::SetArch(enum ArchKind arch) | |
| 177 { | |
| 178 arch_ = arch; | |
| 179 } | |
| 180 | |
| 140 bool KernelCollector::FindCrashingFunction( | 181 bool KernelCollector::FindCrashingFunction( |
| 141 pcrecpp::StringPiece kernel_dump, | 182 pcrecpp::StringPiece kernel_dump, |
| 142 bool print_diagnostics, | 183 bool print_diagnostics, |
| 143 float stack_trace_timestamp, | 184 float stack_trace_timestamp, |
| 144 std::string *crashing_function) { | 185 std::string *crashing_function) { |
| 145 pcrecpp::RE eip_re(kTimestampRegex + " EIP: \\[<.*>\\] ([^\\+ ]+).*", | 186 float timestamp = 0; |
| 187 | |
| 188 // Use the correct regex for this architecture. | |
| 189 pcrecpp::RE eip_re(kTimestampRegex + pcRegex[arch_], | |
| 146 pcrecpp::MULTILINE()); | 190 pcrecpp::MULTILINE()); |
| 147 float timestamp = 0; | 191 |
| 148 while (eip_re.FindAndConsume(&kernel_dump, ×tamp, crashing_function)) { | 192 while (eip_re.FindAndConsume(&kernel_dump, ×tamp, crashing_function)) { |
| 149 if (print_diagnostics) { | 193 if (print_diagnostics) { |
| 150 printf("@%f: found crashing function %s\n", | 194 printf("@%f: found crashing function %s\n", |
| 151 timestamp, | 195 timestamp, |
| 152 crashing_function->c_str()); | 196 crashing_function->c_str()); |
| 153 } | 197 } |
| 154 } | 198 } |
| 155 if (timestamp == 0) { | 199 if (timestamp == 0) { |
| 156 if (print_diagnostics) { | 200 if (print_diagnostics) { |
| 157 printf("Found no crashing function.\n"); | 201 printf("Found no crashing function.\n"); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 294 kernel_crash_path.value()); | 338 kernel_crash_path.value()); |
| 295 | 339 |
| 296 LOG(INFO) << "Stored kcrash to " << kernel_crash_path.value(); | 340 LOG(INFO) << "Stored kcrash to " << kernel_crash_path.value(); |
| 297 } | 341 } |
| 298 if (!ClearPreservedDump()) { | 342 if (!ClearPreservedDump()) { |
| 299 return false; | 343 return false; |
| 300 } | 344 } |
| 301 | 345 |
| 302 return true; | 346 return true; |
| 303 } | 347 } |
| OLD | NEW |