blob: 68f2d9e8a5ebb3b0471685b3358e30108860a5f2 [file] [log] [blame]
Steve Fung6c34c252015-08-20 00:27:30 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Ken Mixter03403162010-08-18 15:23:16 -070016
Steve Fung129bea52015-07-23 13:11:15 -070017#include "kernel_collector.h"
Ken Mixter03403162010-08-18 15:23:16 -070018
Ben Chan7e776902014-06-18 13:19:51 -070019#include <map>
Mike Frysinger6f891c52014-09-24 15:42:11 -040020#include <sys/stat.h>
Ben Chan7e776902014-06-18 13:19:51 -070021
Ben Chanab6cc902014-09-05 08:21:06 -070022#include <base/files/file_util.h>
Ben Chan7e776902014-06-18 13:19:51 -070023#include <base/logging.h>
24#include <base/strings/string_util.h>
25#include <base/strings/stringprintf.h>
Ken Mixter03403162010-08-18 15:23:16 -070026
Ben Chan3c6b82c2014-07-23 14:52:14 -070027using base::FilePath;
28using base::StringPrintf;
29
30namespace {
31
32const char kDefaultKernelStackSignature[] = "kernel-UnspecifiedStackSignature";
Steve Fung2bedc742016-02-02 16:11:43 -080033const char kDumpParentPath[] = "/sys/fs";
34const char kDumpPath[] = "/sys/fs/pstore";
Ben Chan3c6b82c2014-07-23 14:52:14 -070035const char kDumpFormat[] = "dmesg-ramoops-%zu";
36const char kKernelExecName[] = "kernel";
Kees Cookce9556e2011-11-04 20:49:09 +000037// Maximum number of records to examine in the kDumpPath.
Ben Chan3c6b82c2014-07-23 14:52:14 -070038const size_t kMaxDumpRecords = 100;
Ken Mixterafcf8082010-10-26 14:45:01 -070039const pid_t kKernelPid = 0;
Ben Chan3c6b82c2014-07-23 14:52:14 -070040const char kKernelSignatureKey[] = "sig";
Ken Mixterafcf8082010-10-26 14:45:01 -070041// Byte length of maximum human readable portion of a kernel crash signature.
Ben Chan3c6b82c2014-07-23 14:52:14 -070042const int kMaxHumanStringLength = 40;
Ken Mixterafcf8082010-10-26 14:45:01 -070043const uid_t kRootUid = 0;
44// Time in seconds from the final kernel log message for a call stack
45// to count towards the signature of the kcrash.
Ben Chan3c6b82c2014-07-23 14:52:14 -070046const int kSignatureTimestampWindow = 2;
Ken Mixterafcf8082010-10-26 14:45:01 -070047// Kernel log timestamp regular expression.
Ben Chan3c6b82c2014-07-23 14:52:14 -070048const char kTimestampRegex[] = "^<.*>\\[\\s*(\\d+\\.\\d+)\\]";
Ken Mixter03403162010-08-18 15:23:16 -070049
Ben Chan7e776902014-06-18 13:19:51 -070050//
51// These regular expressions enable to us capture the PC in a backtrace.
52// The backtrace is obtained through dmesg or the kernel's preserved/kcrashmem
53// feature.
54//
55// For ARM we see:
56// "<5>[ 39.458982] PC is at write_breakme+0xd0/0x1b4"
Ben Chan120c6752014-07-22 21:06:09 -070057// For MIPS we see:
58// "<5>[ 3378.552000] epc : 804010f0 lkdtm_do_action+0x68/0x3f8"
Ben Chan7e776902014-06-18 13:19:51 -070059// For x86:
60// "<0>[ 37.474699] EIP: [<790ed488>] write_breakme+0x80/0x108
61// SS:ESP 0068:e9dd3efc"
62//
Ben Chan3c6b82c2014-07-23 14:52:14 -070063const char* const kPCRegex[] = {
Simon Glassd74cc092011-04-06 10:47:01 -070064 0,
65 " PC is at ([^\\+ ]+).*",
Ben Chan120c6752014-07-22 21:06:09 -070066 " epc\\s+:\\s+\\S+\\s+([^\\+ ]+).*", // MIPS has an exception program counter
Simon Glassd74cc092011-04-06 10:47:01 -070067 " EIP: \\[<.*>\\] ([^\\+ ]+).*", // X86 uses EIP for the program counter
Bryan Freedb8737592012-04-02 17:05:48 -070068 " RIP \\[<.*>\\] ([^\\+ ]+).*", // X86_64 uses RIP for the program counter
Simon Glassd74cc092011-04-06 10:47:01 -070069};
70
Alex Vakulenkoea05ff92016-01-20 07:53:57 -080071static_assert(arraysize(kPCRegex) == KernelCollector::kArchCount,
72 "Missing Arch PC regexp");
Simon Glassd74cc092011-04-06 10:47:01 -070073
Ben Chan3c6b82c2014-07-23 14:52:14 -070074} // namespace
75
Ken Mixter03403162010-08-18 15:23:16 -070076KernelCollector::KernelCollector()
77 : is_enabled_(false),
Ben Chan2076b902012-02-29 22:26:54 -080078 ramoops_dump_path_(kDumpPath),
Ben Chan3c6b82c2014-07-23 14:52:14 -070079 records_(0),
80 // We expect crash dumps in the format of architecture we are built for.
81 arch_(GetCompilerArch()) {
Ken Mixter03403162010-08-18 15:23:16 -070082}
83
84KernelCollector::~KernelCollector() {
85}
86
87void KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) {
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -070088 ramoops_dump_path_ = file_path;
89}
90
91bool KernelCollector::ReadRecordToString(std::string *contents,
Kees Cookce9556e2011-11-04 20:49:09 +000092 size_t current_record,
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -070093 bool *record_found) {
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -070094 // A record is a ramoops dump. It has an associated size of "record_size".
95 std::string record;
96 std::string captured;
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -070097
98 // Ramoops appends a header to a crash which contains ==== followed by a
99 // timestamp. Ignore the header.
Ben Chan3c6b82c2014-07-23 14:52:14 -0700100 pcrecpp::RE record_re(
101 "====\\d+\\.\\d+\n(.*)",
102 pcrecpp::RE_Options().set_multiline(true).set_dotall(true));
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700103
Ben Zhang1c5533d2015-01-20 17:26:31 -0800104 pcrecpp::RE sanity_check_re("\n<\\d+>\\[\\s*(\\d+\\.\\d+)\\]");
105
Kees Cookce9556e2011-11-04 20:49:09 +0000106 FilePath ramoops_record;
107 GetRamoopsRecordPath(&ramoops_record, current_record);
Mike Frysingera557c112014-02-05 22:55:39 -0500108 if (!base::ReadFileToString(ramoops_record, &record)) {
Kees Cookce9556e2011-11-04 20:49:09 +0000109 LOG(ERROR) << "Unable to open " << ramoops_record.value();
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700110 return false;
111 }
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700112
Ben Zhang1c5533d2015-01-20 17:26:31 -0800113 *record_found = false;
Ben Chan7e776902014-06-18 13:19:51 -0700114 if (record_re.FullMatch(record, &captured)) {
Ben Zhang1c5533d2015-01-20 17:26:31 -0800115 // Found a ramoops header, so strip the header and append the rest.
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700116 contents->append(captured);
Ben Zhang1c5533d2015-01-20 17:26:31 -0800117 *record_found = true;
118 } else if (sanity_check_re.PartialMatch(record.substr(0, 1024))) {
Ben Zhang8e5340a2014-07-07 17:39:47 -0700119 // pstore compression has been added since kernel 3.12. In order to
120 // decompress dmesg correctly, ramoops driver has to strip the header
121 // before handing over the record to the pstore driver, so we don't
Ben Zhang1c5533d2015-01-20 17:26:31 -0800122 // need to do it here anymore. However, the sanity check is needed because
123 // sometimes a pstore record is just a chunk of uninitialized memory which
124 // is not the result of a kernel crash. See crbug.com/443764
Ben Zhang8e5340a2014-07-07 17:39:47 -0700125 contents->append(record);
Ben Zhang1c5533d2015-01-20 17:26:31 -0800126 *record_found = true;
127 } else {
128 LOG(WARNING) << "Found invalid record at " << ramoops_record.value();
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700129 }
Ben Zhang1c5533d2015-01-20 17:26:31 -0800130
131 // Remove the record from pstore after it's found.
132 if (*record_found)
133 base::DeleteFile(ramoops_record, false);
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700134
135 return true;
136}
137
Kees Cookce9556e2011-11-04 20:49:09 +0000138void KernelCollector::GetRamoopsRecordPath(FilePath *path,
139 size_t record) {
Michael Krebs1e09a842012-04-18 12:34:13 -0700140 // Disable error "format not a string literal, argument types not checked"
141 // because this is valid, but GNU apparently doesn't bother checking a const
142 // format string.
143 #pragma GCC diagnostic push
144 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
Kees Cookce9556e2011-11-04 20:49:09 +0000145 *path = ramoops_dump_path_.Append(StringPrintf(kDumpFormat, record));
Michael Krebs1e09a842012-04-18 12:34:13 -0700146 #pragma GCC diagnostic pop
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700147}
148
149bool KernelCollector::LoadParameters() {
Kees Cookce9556e2011-11-04 20:49:09 +0000150 // Discover how many ramoops records are being exported by the driver.
151 size_t count;
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700152
Kees Cookce9556e2011-11-04 20:49:09 +0000153 for (count = 0; count < kMaxDumpRecords; ++count) {
154 FilePath ramoops_record;
155 GetRamoopsRecordPath(&ramoops_record, count);
156
Mike Frysingera557c112014-02-05 22:55:39 -0500157 if (!base::PathExists(ramoops_record))
Kees Cookce9556e2011-11-04 20:49:09 +0000158 break;
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700159 }
160
Kees Cookce9556e2011-11-04 20:49:09 +0000161 records_ = count;
162 return (records_ > 0);
Ken Mixter03403162010-08-18 15:23:16 -0700163}
164
165bool KernelCollector::LoadPreservedDump(std::string *contents) {
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700166 // Load dumps from the preserved memory and save them in contents.
167 // Since the system is set to restart on oops we won't actually ever have
168 // multiple records (only 0 or 1), but check in case we don't restart on
169 // oops in the future.
170 bool any_records_found = false;
171 bool record_found = false;
Ken Mixter03403162010-08-18 15:23:16 -0700172 // clear contents since ReadFileToString actually appends to the string.
173 contents->clear();
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700174
Kees Cookce9556e2011-11-04 20:49:09 +0000175 for (size_t i = 0; i < records_; ++i) {
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700176 if (!ReadRecordToString(contents, i, &record_found)) {
177 break;
178 }
179 if (record_found) {
180 any_records_found = true;
181 }
182 }
183
184 if (!any_records_found) {
185 LOG(ERROR) << "No valid records found in " << ramoops_dump_path_.value();
Ken Mixter03403162010-08-18 15:23:16 -0700186 return false;
187 }
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700188
Ken Mixter03403162010-08-18 15:23:16 -0700189 return true;
190}
191
Doug Anderson1e6b8bd2011-04-07 09:40:05 -0700192void KernelCollector::StripSensitiveData(std::string *kernel_dump) {
193 // Strip any data that the user might not want sent up to the crash servers.
194 // We'll read in from kernel_dump and also place our output there.
195 //
196 // At the moment, the only sensitive data we strip is MAC addresses.
197
198 // Get rid of things that look like MAC addresses, since they could possibly
199 // give information about where someone has been. This is strings that look
200 // like this: 11:22:33:44:55:66
201 // Complications:
202 // - Within a given kernel_dump, want to be able to tell when the same MAC
203 // was used more than once. Thus, we'll consistently replace the first
204 // MAC found with 00:00:00:00:00:01, the second with ...:02, etc.
205 // - ACPI commands look like MAC addresses. We'll specifically avoid getting
206 // rid of those.
207 std::ostringstream result;
208 std::string pre_mac_str;
209 std::string mac_str;
210 std::map<std::string, std::string> mac_map;
211 pcrecpp::StringPiece input(*kernel_dump);
212
213 // This RE will find the next MAC address and can return us the data preceding
214 // the MAC and the MAC itself.
215 pcrecpp::RE mac_re("(.*?)("
216 "[0-9a-fA-F][0-9a-fA-F]:"
217 "[0-9a-fA-F][0-9a-fA-F]:"
218 "[0-9a-fA-F][0-9a-fA-F]:"
219 "[0-9a-fA-F][0-9a-fA-F]:"
220 "[0-9a-fA-F][0-9a-fA-F]:"
221 "[0-9a-fA-F][0-9a-fA-F])",
222 pcrecpp::RE_Options()
223 .set_multiline(true)
224 .set_dotall(true));
225
226 // This RE will identify when the 'pre_mac_str' shows that the MAC address
227 // was really an ACPI cmd. The full string looks like this:
228 // ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
229 pcrecpp::RE acpi_re("ACPI cmd ef/$",
230 pcrecpp::RE_Options()
231 .set_multiline(true)
232 .set_dotall(true));
233
234 // Keep consuming, building up a result string as we go.
235 while (mac_re.Consume(&input, &pre_mac_str, &mac_str)) {
236 if (acpi_re.PartialMatch(pre_mac_str)) {
237 // We really saw an ACPI command; add to result w/ no stripping.
238 result << pre_mac_str << mac_str;
239 } else {
240 // Found a MAC address; look up in our hash for the mapping.
241 std::string replacement_mac = mac_map[mac_str];
242 if (replacement_mac == "") {
243 // It wasn't present, so build up a replacement string.
244 int mac_id = mac_map.size();
245
246 // Handle up to 2^32 unique MAC address; overkill, but doesn't hurt.
247 replacement_mac = StringPrintf("00:00:%02x:%02x:%02x:%02x",
248 (mac_id & 0xff000000) >> 24,
249 (mac_id & 0x00ff0000) >> 16,
250 (mac_id & 0x0000ff00) >> 8,
251 (mac_id & 0x000000ff));
252 mac_map[mac_str] = replacement_mac;
253 }
254
255 // Dump the string before the MAC and the fake MAC address into result.
256 result << pre_mac_str << replacement_mac;
257 }
258 }
259
260 // One last bit of data might still be in the input.
261 result << input;
262
263 // We'll just assign right back to kernel_dump.
264 *kernel_dump = result.str();
265}
266
Mike Frysinger6f891c52014-09-24 15:42:11 -0400267bool KernelCollector::DumpDirMounted() {
268 struct stat st_parent;
269 if (stat(kDumpParentPath, &st_parent)) {
270 PLOG(WARNING) << "Could not stat " << kDumpParentPath;
271 return false;
272 }
273
274 struct stat st_dump;
275 if (stat(kDumpPath, &st_dump)) {
276 PLOG(WARNING) << "Could not stat " << kDumpPath;
277 return false;
278 }
279
280 if (st_parent.st_dev == st_dump.st_dev) {
281 LOG(WARNING) << "Dump dir " << kDumpPath << " not mounted";
282 return false;
283 }
284
285 return true;
286}
287
Ken Mixter03403162010-08-18 15:23:16 -0700288bool KernelCollector::Enable() {
Ben Chan262d7982014-09-18 08:05:20 -0700289 if (arch_ == kArchUnknown || arch_ >= kArchCount ||
290 kPCRegex[arch_] == nullptr) {
Simon Glassd74cc092011-04-06 10:47:01 -0700291 LOG(WARNING) << "KernelCollector does not understand this architecture";
292 return false;
Ben Chan3c6b82c2014-07-23 14:52:14 -0700293 }
294
Mike Frysinger6f891c52014-09-24 15:42:11 -0400295 if (!DumpDirMounted()) {
Ben Chan3c6b82c2014-07-23 14:52:14 -0700296 LOG(WARNING) << "Kernel does not support crash dumping";
297 return false;
Ken Mixter03403162010-08-18 15:23:16 -0700298 }
299
300 // To enable crashes, we will eventually need to set
301 // the chnv bit in BIOS, but it does not yet work.
Ken Mixtera3249322011-03-03 08:47:38 -0800302 LOG(INFO) << "Enabling kernel crash handling";
Ken Mixter03403162010-08-18 15:23:16 -0700303 is_enabled_ = true;
304 return true;
305}
306
Ken Mixterafcf8082010-10-26 14:45:01 -0700307// Hash a string to a number. We define our own hash function to not
308// be dependent on a C++ library that might change. This function
309// uses basically the same approach as tr1/functional_hash.h but with
310// a larger prime number (16127 vs 131).
311static unsigned HashString(const std::string &input) {
312 unsigned hash = 0;
313 for (size_t i = 0; i < input.length(); ++i)
314 hash = hash * 16127 + input[i];
315 return hash;
316}
317
318void KernelCollector::ProcessStackTrace(
319 pcrecpp::StringPiece kernel_dump,
320 bool print_diagnostics,
321 unsigned *hash,
Luigi Semenzatof6400992011-12-29 13:18:35 -0800322 float *last_stack_timestamp,
323 bool *is_watchdog_crash) {
Ken Mixterafcf8082010-10-26 14:45:01 -0700324 pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE());
Ben Chan3c6b82c2014-07-23 14:52:14 -0700325 pcrecpp::RE stack_trace_start_re(std::string(kTimestampRegex) +
Simon Glassd74cc092011-04-06 10:47:01 -0700326 " (Call Trace|Backtrace):$");
327
Luigi Semenzatof6400992011-12-29 13:18:35 -0800328 // Match lines such as the following and grab out "function_name".
329 // The ? may or may not be present.
330 //
Simon Glassd74cc092011-04-06 10:47:01 -0700331 // For ARM:
Luigi Semenzatof6400992011-12-29 13:18:35 -0800332 // <4>[ 3498.731164] [<c0057220>] ? (function_name+0x20/0x2c) from
333 // [<c018062c>] (foo_bar+0xdc/0x1bc)
Simon Glassd74cc092011-04-06 10:47:01 -0700334 //
Ben Chan120c6752014-07-22 21:06:09 -0700335 // For MIPS:
336 // <5>[ 3378.656000] [<804010f0>] lkdtm_do_action+0x68/0x3f8
337 //
Simon Glassd74cc092011-04-06 10:47:01 -0700338 // For X86:
Luigi Semenzatof6400992011-12-29 13:18:35 -0800339 // <4>[ 6066.849504] [<7937bcee>] ? function_name+0x66/0x6c
340 //
Ben Chan3c6b82c2014-07-23 14:52:14 -0700341 pcrecpp::RE stack_entry_re(std::string(kTimestampRegex) +
Simon Glassd74cc092011-04-06 10:47:01 -0700342 "\\s+\\[<[[:xdigit:]]+>\\]" // Matches " [<7937bcee>]"
343 "([\\s\\?(]+)" // Matches " ? (" (ARM) or " ? " (X86)
344 "([^\\+ )]+)"); // Matches until delimiter reached
Ken Mixterafcf8082010-10-26 14:45:01 -0700345 std::string line;
346 std::string hashable;
Luigi Semenzatof6400992011-12-29 13:18:35 -0800347 std::string previous_hashable;
348 bool is_watchdog = false;
Ken Mixterafcf8082010-10-26 14:45:01 -0700349
350 *hash = 0;
351 *last_stack_timestamp = 0;
352
Luigi Semenzatof6400992011-12-29 13:18:35 -0800353 // Find the last and second-to-last stack traces. The latter is used when
354 // the panic is from a watchdog timeout.
Ken Mixterafcf8082010-10-26 14:45:01 -0700355 while (line_re.FindAndConsume(&kernel_dump, &line)) {
356 std::string certainty;
357 std::string function_name;
358 if (stack_trace_start_re.PartialMatch(line, last_stack_timestamp)) {
359 if (print_diagnostics) {
Luigi Semenzatof6400992011-12-29 13:18:35 -0800360 printf("Stack trace starting.%s\n",
361 hashable.empty() ? "" : " Saving prior trace.");
Ken Mixterafcf8082010-10-26 14:45:01 -0700362 }
Luigi Semenzatof6400992011-12-29 13:18:35 -0800363 previous_hashable = hashable;
Ken Mixterafcf8082010-10-26 14:45:01 -0700364 hashable.clear();
Luigi Semenzatof6400992011-12-29 13:18:35 -0800365 is_watchdog = false;
Ken Mixterafcf8082010-10-26 14:45:01 -0700366 } else if (stack_entry_re.PartialMatch(line,
367 last_stack_timestamp,
368 &certainty,
369 &function_name)) {
370 bool is_certain = certainty.find('?') == std::string::npos;
371 if (print_diagnostics) {
372 printf("@%f: stack entry for %s (%s)\n",
373 *last_stack_timestamp,
374 function_name.c_str(),
375 is_certain ? "certain" : "uncertain");
376 }
377 // Do not include any uncertain (prefixed by '?') frames in our hash.
378 if (!is_certain)
379 continue;
380 if (!hashable.empty())
381 hashable.append("|");
Luigi Semenzatof6400992011-12-29 13:18:35 -0800382 if (function_name == "watchdog_timer_fn" ||
383 function_name == "watchdog") {
384 is_watchdog = true;
385 }
Ken Mixterafcf8082010-10-26 14:45:01 -0700386 hashable.append(function_name);
387 }
388 }
389
Luigi Semenzatof6400992011-12-29 13:18:35 -0800390 // If the last stack trace contains a watchdog function we assume the panic
391 // is from the watchdog timer, and we hash the previous stack trace rather
392 // than the last one, assuming that the previous stack is that of the hung
393 // thread.
394 //
395 // In addition, if the hashable is empty (meaning all frames are uncertain,
396 // for whatever reason) also use the previous frame, as it cannot be any
397 // worse.
398 if (is_watchdog || hashable.empty()) {
399 hashable = previous_hashable;
400 }
401
Ken Mixterafcf8082010-10-26 14:45:01 -0700402 *hash = HashString(hashable);
Luigi Semenzatof6400992011-12-29 13:18:35 -0800403 *is_watchdog_crash = is_watchdog;
Ken Mixterafcf8082010-10-26 14:45:01 -0700404
405 if (print_diagnostics) {
406 printf("Hash based on stack trace: \"%s\" at %f.\n",
407 hashable.c_str(), *last_stack_timestamp);
408 }
409}
410
Ben Chan3c6b82c2014-07-23 14:52:14 -0700411// static
412KernelCollector::ArchKind KernelCollector::GetCompilerArch() {
Simon Glassd74cc092011-04-06 10:47:01 -0700413#if defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
Ben Chan3c6b82c2014-07-23 14:52:14 -0700414 return kArchArm;
Ben Chan120c6752014-07-22 21:06:09 -0700415#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
Ben Chan3c6b82c2014-07-23 14:52:14 -0700416 return kArchMips;
Bryan Freedb8737592012-04-02 17:05:48 -0700417#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_64)
Ben Chan3c6b82c2014-07-23 14:52:14 -0700418 return kArchX86_64;
Simon Glassd74cc092011-04-06 10:47:01 -0700419#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
Ben Chan3c6b82c2014-07-23 14:52:14 -0700420 return kArchX86;
Simon Glassd74cc092011-04-06 10:47:01 -0700421#else
Ben Chan3c6b82c2014-07-23 14:52:14 -0700422 return kArchUnknown;
Simon Glassd74cc092011-04-06 10:47:01 -0700423#endif
424}
425
Ken Mixterafcf8082010-10-26 14:45:01 -0700426bool KernelCollector::FindCrashingFunction(
Simon Glassd74cc092011-04-06 10:47:01 -0700427 pcrecpp::StringPiece kernel_dump,
428 bool print_diagnostics,
429 float stack_trace_timestamp,
430 std::string *crashing_function) {
Ken Mixterafcf8082010-10-26 14:45:01 -0700431 float timestamp = 0;
Simon Glassd74cc092011-04-06 10:47:01 -0700432
433 // Use the correct regex for this architecture.
Ben Chan3c6b82c2014-07-23 14:52:14 -0700434 pcrecpp::RE eip_re(std::string(kTimestampRegex) + kPCRegex[arch_],
Simon Glassd74cc092011-04-06 10:47:01 -0700435 pcrecpp::MULTILINE());
436
Ken Mixterafcf8082010-10-26 14:45:01 -0700437 while (eip_re.FindAndConsume(&kernel_dump, &timestamp, crashing_function)) {
438 if (print_diagnostics) {
439 printf("@%f: found crashing function %s\n",
440 timestamp,
441 crashing_function->c_str());
442 }
443 }
444 if (timestamp == 0) {
445 if (print_diagnostics) {
446 printf("Found no crashing function.\n");
447 }
448 return false;
449 }
450 if (stack_trace_timestamp != 0 &&
Yunlian Jiang9f520402014-02-27 14:26:15 -0800451 abs(static_cast<int>(stack_trace_timestamp - timestamp))
452 > kSignatureTimestampWindow) {
Ken Mixterafcf8082010-10-26 14:45:01 -0700453 if (print_diagnostics) {
454 printf("Found crashing function but not within window.\n");
455 }
456 return false;
457 }
458 if (print_diagnostics) {
459 printf("Found crashing function %s\n", crashing_function->c_str());
460 }
461 return true;
462}
463
464bool KernelCollector::FindPanicMessage(pcrecpp::StringPiece kernel_dump,
465 bool print_diagnostics,
466 std::string *panic_message) {
467 // Match lines such as the following and grab out "Fatal exception"
468 // <0>[ 342.841135] Kernel panic - not syncing: Fatal exception
Ben Chan3c6b82c2014-07-23 14:52:14 -0700469 pcrecpp::RE kernel_panic_re(std::string(kTimestampRegex) +
Ken Mixterafcf8082010-10-26 14:45:01 -0700470 " Kernel panic[^\\:]*\\:\\s*(.*)",
471 pcrecpp::MULTILINE());
472 float timestamp = 0;
473 while (kernel_panic_re.FindAndConsume(&kernel_dump,
474 &timestamp,
475 panic_message)) {
476 if (print_diagnostics) {
477 printf("@%f: panic message %s\n",
478 timestamp,
479 panic_message->c_str());
480 }
481 }
482 if (timestamp == 0) {
483 if (print_diagnostics) {
484 printf("Found no panic message.\n");
485 }
486 return false;
487 }
488 return true;
489}
490
491bool KernelCollector::ComputeKernelStackSignature(
492 const std::string &kernel_dump,
493 std::string *kernel_signature,
494 bool print_diagnostics) {
495 unsigned stack_hash = 0;
496 float last_stack_timestamp = 0;
497 std::string human_string;
Luigi Semenzatof6400992011-12-29 13:18:35 -0800498 bool is_watchdog_crash;
Ken Mixterafcf8082010-10-26 14:45:01 -0700499
500 ProcessStackTrace(kernel_dump,
501 print_diagnostics,
502 &stack_hash,
Luigi Semenzatof6400992011-12-29 13:18:35 -0800503 &last_stack_timestamp,
504 &is_watchdog_crash);
Ken Mixterafcf8082010-10-26 14:45:01 -0700505
506 if (!FindCrashingFunction(kernel_dump,
507 print_diagnostics,
508 last_stack_timestamp,
509 &human_string)) {
510 if (!FindPanicMessage(kernel_dump, print_diagnostics, &human_string)) {
511 if (print_diagnostics) {
512 printf("Found no human readable string, using empty string.\n");
513 }
514 human_string.clear();
515 }
516 }
517
518 if (human_string.empty() && stack_hash == 0) {
519 if (print_diagnostics) {
520 printf("Found neither a stack nor a human readable string, failing.\n");
521 }
522 return false;
523 }
524
525 human_string = human_string.substr(0, kMaxHumanStringLength);
Luigi Semenzatof6400992011-12-29 13:18:35 -0800526 *kernel_signature = StringPrintf("%s-%s%s-%08X",
Ken Mixterafcf8082010-10-26 14:45:01 -0700527 kKernelExecName,
Luigi Semenzatof6400992011-12-29 13:18:35 -0800528 (is_watchdog_crash ? "(HANG)-" : ""),
Ken Mixterafcf8082010-10-26 14:45:01 -0700529 human_string.c_str(),
530 stack_hash);
531 return true;
532}
533
Ken Mixter03403162010-08-18 15:23:16 -0700534bool KernelCollector::Collect() {
535 std::string kernel_dump;
536 FilePath root_crash_directory;
Sergiu Iordache1ea8abe2011-08-03 16:11:36 -0700537
538 if (!LoadParameters()) {
539 return false;
540 }
Ken Mixter03403162010-08-18 15:23:16 -0700541 if (!LoadPreservedDump(&kernel_dump)) {
542 return false;
543 }
Doug Anderson1e6b8bd2011-04-07 09:40:05 -0700544 StripSensitiveData(&kernel_dump);
Ken Mixter03403162010-08-18 15:23:16 -0700545 if (kernel_dump.empty()) {
546 return false;
547 }
Ken Mixterafcf8082010-10-26 14:45:01 -0700548 std::string signature;
549 if (!ComputeKernelStackSignature(kernel_dump, &signature, false)) {
550 signature = kDefaultKernelStackSignature;
551 }
Ken Mixteree849c52010-09-30 15:30:10 -0700552
Ken Mixter9ee1f5f2011-10-25 02:15:05 +0000553 std::string reason = "handling";
554 bool feedback = true;
555 if (IsDeveloperImage()) {
556 reason = "developer build - always dumping";
557 feedback = true;
558 } else if (!is_feedback_allowed_function_()) {
559 reason = "ignoring - no consent";
560 feedback = false;
561 }
Ken Mixterafcf8082010-10-26 14:45:01 -0700562
Ken Mixtera3249322011-03-03 08:47:38 -0800563 LOG(INFO) << "Received prior crash notification from "
Ken Mixter9ee1f5f2011-10-25 02:15:05 +0000564 << "kernel (signature " << signature << ") (" << reason << ")";
Ken Mixterafcf8082010-10-26 14:45:01 -0700565
566 if (feedback) {
Ken Mixter03403162010-08-18 15:23:16 -0700567 count_crash_function_();
568
569 if (!GetCreatedCrashDirectoryByEuid(kRootUid,
Ken Mixter207694d2010-10-28 15:42:37 -0700570 &root_crash_directory,
Ben Chan262d7982014-09-18 08:05:20 -0700571 nullptr)) {
Ken Mixter03403162010-08-18 15:23:16 -0700572 return true;
573 }
574
Ken Mixteree849c52010-09-30 15:30:10 -0700575 std::string dump_basename =
Ben Chan262d7982014-09-18 08:05:20 -0700576 FormatDumpBasename(kKernelExecName, time(nullptr), kKernelPid);
Ken Mixteree849c52010-09-30 15:30:10 -0700577 FilePath kernel_crash_path = root_crash_directory.Append(
578 StringPrintf("%s.kcrash", dump_basename.c_str()));
579
Ben Chanf30c6412014-05-22 23:09:01 -0700580 // We must use WriteNewFile instead of base::WriteFile as we
Ken Mixter9b346472010-11-07 13:45:45 -0800581 // do not want to write with root access to a symlink that an attacker
582 // might have created.
583 if (WriteNewFile(kernel_crash_path,
584 kernel_dump.data(),
585 kernel_dump.length()) !=
Ken Mixter03403162010-08-18 15:23:16 -0700586 static_cast<int>(kernel_dump.length())) {
Ken Mixtera3249322011-03-03 08:47:38 -0800587 LOG(INFO) << "Failed to write kernel dump to "
588 << kernel_crash_path.value().c_str();
Ken Mixter03403162010-08-18 15:23:16 -0700589 return true;
590 }
591
Ken Mixterafcf8082010-10-26 14:45:01 -0700592 AddCrashMetaData(kKernelSignatureKey, signature);
Ken Mixteree849c52010-09-30 15:30:10 -0700593 WriteCrashMetaData(
594 root_crash_directory.Append(
595 StringPrintf("%s.meta", dump_basename.c_str())),
Ken Mixterc909b692010-10-18 12:26:05 -0700596 kKernelExecName,
597 kernel_crash_path.value());
Ken Mixteree849c52010-09-30 15:30:10 -0700598
Ken Mixtera3249322011-03-03 08:47:38 -0800599 LOG(INFO) << "Stored kcrash to " << kernel_crash_path.value();
Ken Mixter03403162010-08-18 15:23:16 -0700600 }
Ken Mixter03403162010-08-18 15:23:16 -0700601
602 return true;
603}