16c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung/*
26c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * Copyright (C) 2012 The Android Open Source Project
36c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung *
46c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * Licensed under the Apache License, Version 2.0 (the "License");
56c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * you may not use this file except in compliance with the License.
66c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * You may obtain a copy of the License at
76c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung *
86c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung *      http://www.apache.org/licenses/LICENSE-2.0
96c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung *
106c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * Unless required by applicable law or agreed to in writing, software
116c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * distributed under the License is distributed on an "AS IS" BASIS,
126c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * See the License for the specific language governing permissions and
146c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung * limitations under the License.
156c34c2576eb241f134431b2cc847a6c7d70ef012Steve Fung */
160340316050044e0995b98fea87ed41ea77abb28bKen Mixter
17129bea543b7572bfdf09c6a7b3cebbe3b57ce723Steve Fung#include "kernel_collector.h"
180340316050044e0995b98fea87ed41ea77abb28bKen Mixter
197e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <map>
206f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger#include <sys/stat.h>
217e77690375bc8a896a8de318d69d515e67c7aefeBen Chan
22ab6cc90503ca2db976a3cb9c9382a9da85c4b5a2Ben Chan#include <base/files/file_util.h>
237e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/logging.h>
247e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/string_util.h>
257e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/stringprintf.h>
260340316050044e0995b98fea87ed41ea77abb28bKen Mixter
273c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanusing base::FilePath;
283c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanusing base::StringPrintf;
293c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan
303c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Channamespace {
313c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan
323c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst char kDefaultKernelStackSignature[] = "kernel-UnspecifiedStackSignature";
332bedc7455318e35b2a6ac77031b673d59893877dSteve Fungconst char kDumpParentPath[] = "/sys/fs";
342bedc7455318e35b2a6ac77031b673d59893877dSteve Fungconst char kDumpPath[] = "/sys/fs/pstore";
353c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst char kDumpFormat[] = "dmesg-ramoops-%zu";
363c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst char kKernelExecName[] = "kernel";
37ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook// Maximum number of records to examine in the kDumpPath.
383c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst size_t kMaxDumpRecords = 100;
390340316050044e0995b98fea87ed41ea77abb28bKen Mixterconst pid_t kKernelPid = 0;
403c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst char kKernelSignatureKey[] = "sig";
41afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// Byte length of maximum human readable portion of a kernel crash signature.
423c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst int kMaxHumanStringLength = 40;
430340316050044e0995b98fea87ed41ea77abb28bKen Mixterconst uid_t kRootUid = 0;
44afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// Time in seconds from the final kernel log message for a call stack
45afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// to count towards the signature of the kcrash.
463c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst int kSignatureTimestampWindow = 2;
47afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// Kernel log timestamp regular expression.
483c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst char kTimestampRegex[] = "^<.*>\\[\\s*(\\d+\\.\\d+)\\]";
490340316050044e0995b98fea87ed41ea77abb28bKen Mixter
507e77690375bc8a896a8de318d69d515e67c7aefeBen Chan//
517e77690375bc8a896a8de318d69d515e67c7aefeBen Chan// These regular expressions enable to us capture the PC in a backtrace.
527e77690375bc8a896a8de318d69d515e67c7aefeBen Chan// The backtrace is obtained through dmesg or the kernel's preserved/kcrashmem
537e77690375bc8a896a8de318d69d515e67c7aefeBen Chan// feature.
547e77690375bc8a896a8de318d69d515e67c7aefeBen Chan//
557e77690375bc8a896a8de318d69d515e67c7aefeBen Chan// For ARM we see:
567e77690375bc8a896a8de318d69d515e67c7aefeBen Chan//   "<5>[   39.458982] PC is at write_breakme+0xd0/0x1b4"
57120c675df0836290d629764d06f1eb4ba49d7740Ben Chan// For MIPS we see:
58120c675df0836290d629764d06f1eb4ba49d7740Ben Chan//   "<5>[ 3378.552000] epc   : 804010f0 lkdtm_do_action+0x68/0x3f8"
597e77690375bc8a896a8de318d69d515e67c7aefeBen Chan// For x86:
607e77690375bc8a896a8de318d69d515e67c7aefeBen Chan//   "<0>[   37.474699] EIP: [<790ed488>] write_breakme+0x80/0x108
617e77690375bc8a896a8de318d69d515e67c7aefeBen Chan//    SS:ESP 0068:e9dd3efc"
627e77690375bc8a896a8de318d69d515e67c7aefeBen Chan//
633c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chanconst char* const kPCRegex[] = {
64d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  0,
65d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  " PC is at ([^\\+ ]+).*",
66120c675df0836290d629764d06f1eb4ba49d7740Ben Chan  " epc\\s+:\\s+\\S+\\s+([^\\+ ]+).*",  // MIPS has an exception program counter
67d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  " EIP: \\[<.*>\\] ([^\\+ ]+).*",  // X86 uses EIP for the program counter
68b87375957eb9e07c929a84683460e9e7f87985c1Bryan Freed  " RIP  \\[<.*>\\] ([^\\+ ]+).*",  // X86_64 uses RIP for the program counter
69d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass};
70d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass
71ea05ff9229163e6aacfb7f7dffdd76bff559673cAlex Vakulenkostatic_assert(arraysize(kPCRegex) == KernelCollector::kArchCount,
72ea05ff9229163e6aacfb7f7dffdd76bff559673cAlex Vakulenko              "Missing Arch PC regexp");
73d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass
743c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan}  // namespace
753c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan
760340316050044e0995b98fea87ed41ea77abb28bKen MixterKernelCollector::KernelCollector()
770340316050044e0995b98fea87ed41ea77abb28bKen Mixter    : is_enabled_(false),
782076b9011d0f217d2c308d28ba13af84cf2e4b17Ben Chan      ramoops_dump_path_(kDumpPath),
793c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan      records_(0),
803c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan      // We expect crash dumps in the format of architecture we are built for.
813c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan      arch_(GetCompilerArch()) {
820340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
830340316050044e0995b98fea87ed41ea77abb28bKen Mixter
840340316050044e0995b98fea87ed41ea77abb28bKen MixterKernelCollector::~KernelCollector() {
850340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
860340316050044e0995b98fea87ed41ea77abb28bKen Mixter
870340316050044e0995b98fea87ed41ea77abb28bKen Mixtervoid KernelCollector::OverridePreservedDumpPath(const FilePath &file_path) {
881ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  ramoops_dump_path_ = file_path;
891ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache}
901ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
911ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordachebool KernelCollector::ReadRecordToString(std::string *contents,
92ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook                                         size_t current_record,
931ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache                                         bool *record_found) {
941ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // A record is a ramoops dump. It has an associated size of "record_size".
951ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  std::string record;
961ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  std::string captured;
971ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
981ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // Ramoops appends a header to a crash which contains ==== followed by a
991ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // timestamp. Ignore the header.
1003c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  pcrecpp::RE record_re(
1013c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan      "====\\d+\\.\\d+\n(.*)",
1023c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan      pcrecpp::RE_Options().set_multiline(true).set_dotall(true));
1031ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
1041c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang  pcrecpp::RE sanity_check_re("\n<\\d+>\\[\\s*(\\d+\\.\\d+)\\]");
1051c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang
106ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  FilePath ramoops_record;
107ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  GetRamoopsRecordPath(&ramoops_record, current_record);
108a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger  if (!base::ReadFileToString(ramoops_record, &record)) {
109ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook    LOG(ERROR) << "Unable to open " << ramoops_record.value();
1101ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    return false;
1111ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  }
1121ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
1131c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang  *record_found = false;
1147e77690375bc8a896a8de318d69d515e67c7aefeBen Chan  if (record_re.FullMatch(record, &captured)) {
1151c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    // Found a ramoops header, so strip the header and append the rest.
1161ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    contents->append(captured);
1171c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    *record_found = true;
1181c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang  } else if (sanity_check_re.PartialMatch(record.substr(0, 1024))) {
1198e5340a1d8a552a30dbf31acc3e885ded48d42a9Ben Zhang    // pstore compression has been added since kernel 3.12. In order to
1208e5340a1d8a552a30dbf31acc3e885ded48d42a9Ben Zhang    // decompress dmesg correctly, ramoops driver has to strip the header
1218e5340a1d8a552a30dbf31acc3e885ded48d42a9Ben Zhang    // before handing over the record to the pstore driver, so we don't
1221c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    // need to do it here anymore. However, the sanity check is needed because
1231c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    // sometimes a pstore record is just a chunk of uninitialized memory which
1241c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    // is not the result of a kernel crash. See crbug.com/443764
1258e5340a1d8a552a30dbf31acc3e885ded48d42a9Ben Zhang    contents->append(record);
1261c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    *record_found = true;
1271c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang  } else {
1281c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    LOG(WARNING) << "Found invalid record at " << ramoops_record.value();
1291ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  }
1301c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang
1311c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang  // Remove the record from pstore after it's found.
1321c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang  if (*record_found)
1331c5533d4cd99f19ec8a37aaa841caeba76f7005cBen Zhang    base::DeleteFile(ramoops_record, false);
1341ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
1351ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  return true;
1361ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache}
1371ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
138ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cookvoid KernelCollector::GetRamoopsRecordPath(FilePath *path,
139ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook                                           size_t record) {
1401e09a84aafcadfcc6dc453f0a4791e50317e569aMichael Krebs  // Disable error "format not a string literal, argument types not checked"
1411e09a84aafcadfcc6dc453f0a4791e50317e569aMichael Krebs  // because this is valid, but GNU apparently doesn't bother checking a const
1421e09a84aafcadfcc6dc453f0a4791e50317e569aMichael Krebs  // format string.
1431e09a84aafcadfcc6dc453f0a4791e50317e569aMichael Krebs  #pragma GCC diagnostic push
1441e09a84aafcadfcc6dc453f0a4791e50317e569aMichael Krebs  #pragma GCC diagnostic ignored "-Wformat-nonliteral"
145ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  *path = ramoops_dump_path_.Append(StringPrintf(kDumpFormat, record));
1461e09a84aafcadfcc6dc453f0a4791e50317e569aMichael Krebs  #pragma GCC diagnostic pop
1471ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache}
1481ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
1491ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordachebool KernelCollector::LoadParameters() {
150ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  // Discover how many ramoops records are being exported by the driver.
151ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  size_t count;
1521ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
153ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  for (count = 0; count < kMaxDumpRecords; ++count) {
154ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook    FilePath ramoops_record;
155ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook    GetRamoopsRecordPath(&ramoops_record, count);
1561ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
157a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger    if (!base::PathExists(ramoops_record))
158ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook      break;
159ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  }
1601ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
161ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  records_ = count;
162ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  return (records_ > 0);
1630340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1640340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1650340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool KernelCollector::LoadPreservedDump(std::string *contents) {
1661ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // Load dumps from the preserved memory and save them in contents.
1671ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // Since the system is set to restart on oops we won't actually ever have
1681ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // multiple records (only 0 or 1), but check in case we don't restart on
1691ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  // oops in the future.
1701ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  bool any_records_found = false;
1711ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  bool record_found = false;
1720340316050044e0995b98fea87ed41ea77abb28bKen Mixter  // clear contents since ReadFileToString actually appends to the string.
1730340316050044e0995b98fea87ed41ea77abb28bKen Mixter  contents->clear();
1741ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
175ce9556e1c490113bf66eaf5bb3f2d9241e209474Kees Cook  for (size_t i = 0; i < records_; ++i) {
1761ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    if (!ReadRecordToString(contents, i, &record_found)) {
1771ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache      break;
1781ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    }
1791ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    if (record_found) {
1801ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache      any_records_found = true;
1811ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    }
1821ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  }
1831ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
1841ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  if (!any_records_found) {
1851ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    LOG(ERROR) << "No valid records found in " << ramoops_dump_path_.value();
1860340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
1870340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
1881ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
1890340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
1900340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1910340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1921e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Andersonvoid KernelCollector::StripSensitiveData(std::string *kernel_dump) {
1931e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // Strip any data that the user might not want sent up to the crash servers.
1941e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // We'll read in from kernel_dump and also place our output there.
1951e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  //
1961e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // At the moment, the only sensitive data we strip is MAC addresses.
1971e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
1981e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // Get rid of things that look like MAC addresses, since they could possibly
1991e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // give information about where someone has been.  This is strings that look
2001e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // like this: 11:22:33:44:55:66
2011e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // Complications:
2021e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // - Within a given kernel_dump, want to be able to tell when the same MAC
2031e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  //   was used more than once.  Thus, we'll consistently replace the first
2041e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  //   MAC found with 00:00:00:00:00:01, the second with ...:02, etc.
2051e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // - ACPI commands look like MAC addresses.  We'll specifically avoid getting
2061e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  //   rid of those.
2071e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  std::ostringstream result;
2081e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  std::string pre_mac_str;
2091e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  std::string mac_str;
2101e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  std::map<std::string, std::string> mac_map;
2111e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  pcrecpp::StringPiece input(*kernel_dump);
2121e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2131e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // This RE will find the next MAC address and can return us the data preceding
2141e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // the MAC and the MAC itself.
2151e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  pcrecpp::RE mac_re("(.*?)("
2161e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     "[0-9a-fA-F][0-9a-fA-F]:"
2171e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     "[0-9a-fA-F][0-9a-fA-F]:"
2181e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     "[0-9a-fA-F][0-9a-fA-F]:"
2191e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     "[0-9a-fA-F][0-9a-fA-F]:"
2201e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     "[0-9a-fA-F][0-9a-fA-F]:"
2211e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     "[0-9a-fA-F][0-9a-fA-F])",
2221e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                     pcrecpp::RE_Options()
2231e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                       .set_multiline(true)
2241e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                       .set_dotall(true));
2251e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2261e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // This RE will identify when the 'pre_mac_str' shows that the MAC address
2271e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // was really an ACPI cmd.  The full string looks like this:
2281e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  //   ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out
2291e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  pcrecpp::RE acpi_re("ACPI cmd ef/$",
2301e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                      pcrecpp::RE_Options()
2311e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                        .set_multiline(true)
2321e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                        .set_dotall(true));
2331e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2341e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // Keep consuming, building up a result string as we go.
2351e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  while (mac_re.Consume(&input, &pre_mac_str, &mac_str)) {
2361e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson    if (acpi_re.PartialMatch(pre_mac_str)) {
2371e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      // We really saw an ACPI command; add to result w/ no stripping.
2381e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      result << pre_mac_str << mac_str;
2391e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson    } else {
2401e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      // Found a MAC address; look up in our hash for the mapping.
2411e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      std::string replacement_mac = mac_map[mac_str];
2421e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      if (replacement_mac == "") {
2431e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson        // It wasn't present, so build up a replacement string.
2441e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson        int mac_id = mac_map.size();
2451e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2461e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson        // Handle up to 2^32 unique MAC address; overkill, but doesn't hurt.
2471e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson        replacement_mac = StringPrintf("00:00:%02x:%02x:%02x:%02x",
2481e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                                       (mac_id & 0xff000000) >> 24,
2491e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                                       (mac_id & 0x00ff0000) >> 16,
2501e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                                       (mac_id & 0x0000ff00) >> 8,
2511e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson                                       (mac_id & 0x000000ff));
2521e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson        mac_map[mac_str] = replacement_mac;
2531e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      }
2541e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2551e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      // Dump the string before the MAC and the fake MAC address into result.
2561e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson      result << pre_mac_str << replacement_mac;
2571e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson    }
2581e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  }
2591e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2601e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // One last bit of data might still be in the input.
2611e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  result << input;
2621e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2631e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  // We'll just assign right back to kernel_dump.
2641e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  *kernel_dump = result.str();
2651e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson}
2661e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson
2676f891c5b3fa232dee58339612184387f1eb583a5Mike Frysingerbool KernelCollector::DumpDirMounted() {
2686f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  struct stat st_parent;
2696f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  if (stat(kDumpParentPath, &st_parent)) {
2706f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger    PLOG(WARNING) << "Could not stat " << kDumpParentPath;
2716f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger    return false;
2726f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  }
2736f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger
2746f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  struct stat st_dump;
2756f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  if (stat(kDumpPath, &st_dump)) {
2766f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger    PLOG(WARNING) << "Could not stat " << kDumpPath;
2776f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger    return false;
2786f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  }
2796f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger
2806f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  if (st_parent.st_dev == st_dump.st_dev) {
2816f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger    LOG(WARNING) << "Dump dir " << kDumpPath << " not mounted";
2826f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger    return false;
2836f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  }
2846f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger
2856f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  return true;
2866f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger}
2876f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger
2880340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool KernelCollector::Enable() {
289262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  if (arch_ == kArchUnknown || arch_ >= kArchCount ||
290262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan      kPCRegex[arch_] == nullptr) {
291d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass    LOG(WARNING) << "KernelCollector does not understand this architecture";
292d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass    return false;
2933c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  }
2943c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan
2956f891c5b3fa232dee58339612184387f1eb583a5Mike Frysinger  if (!DumpDirMounted()) {
2963c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan    LOG(WARNING) << "Kernel does not support crash dumping";
2973c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan    return false;
2980340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2990340316050044e0995b98fea87ed41ea77abb28bKen Mixter
3000340316050044e0995b98fea87ed41ea77abb28bKen Mixter  // To enable crashes, we will eventually need to set
3010340316050044e0995b98fea87ed41ea77abb28bKen Mixter  // the chnv bit in BIOS, but it does not yet work.
302a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  LOG(INFO) << "Enabling kernel crash handling";
3030340316050044e0995b98fea87ed41ea77abb28bKen Mixter  is_enabled_ = true;
3040340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
3050340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
3060340316050044e0995b98fea87ed41ea77abb28bKen Mixter
307afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// Hash a string to a number.  We define our own hash function to not
308afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// be dependent on a C++ library that might change.  This function
309afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// uses basically the same approach as tr1/functional_hash.h but with
310afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter// a larger prime number (16127 vs 131).
311afcf80821c57a189b53b7a66f76d13855d63821eKen Mixterstatic unsigned HashString(const std::string &input) {
312afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  unsigned hash = 0;
313afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  for (size_t i = 0; i < input.length(); ++i)
314afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    hash = hash * 16127 + input[i];
315afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  return hash;
316afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
317afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
318afcf80821c57a189b53b7a66f76d13855d63821eKen Mixtervoid KernelCollector::ProcessStackTrace(
319afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    pcrecpp::StringPiece kernel_dump,
320afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    bool print_diagnostics,
321afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    unsigned *hash,
322f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato    float *last_stack_timestamp,
323f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato    bool *is_watchdog_crash) {
324afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE());
3253c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  pcrecpp::RE stack_trace_start_re(std::string(kTimestampRegex) +
326d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass        " (Call Trace|Backtrace):$");
327d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass
328f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // Match lines such as the following and grab out "function_name".
329f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // The ? may or may not be present.
330f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  //
331d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  // For ARM:
332f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // <4>[ 3498.731164] [<c0057220>] ? (function_name+0x20/0x2c) from
333f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // [<c018062c>] (foo_bar+0xdc/0x1bc)
334d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  //
335120c675df0836290d629764d06f1eb4ba49d7740Ben Chan  // For MIPS:
336120c675df0836290d629764d06f1eb4ba49d7740Ben Chan  // <5>[ 3378.656000] [<804010f0>] lkdtm_do_action+0x68/0x3f8
337120c675df0836290d629764d06f1eb4ba49d7740Ben Chan  //
338d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  // For X86:
339f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // <4>[ 6066.849504]  [<7937bcee>] ? function_name+0x66/0x6c
340f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  //
3413c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  pcrecpp::RE stack_entry_re(std::string(kTimestampRegex) +
342d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass    "\\s+\\[<[[:xdigit:]]+>\\]"      // Matches "  [<7937bcee>]"
343d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass    "([\\s\\?(]+)"                   // Matches " ? (" (ARM) or " ? " (X86)
344d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass    "([^\\+ )]+)");                  // Matches until delimiter reached
345afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string line;
346afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string hashable;
347f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  std::string previous_hashable;
348f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  bool is_watchdog = false;
349afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
350afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  *hash = 0;
351afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  *last_stack_timestamp = 0;
352afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
353f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // Find the last and second-to-last stack traces.  The latter is used when
354f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // the panic is from a watchdog timeout.
355afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  while (line_re.FindAndConsume(&kernel_dump, &line)) {
356afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    std::string certainty;
357afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    std::string function_name;
358afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (stack_trace_start_re.PartialMatch(line, last_stack_timestamp)) {
359afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      if (print_diagnostics) {
360f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato        printf("Stack trace starting.%s\n",
361f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato               hashable.empty() ? "" : "  Saving prior trace.");
362afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      }
363f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato      previous_hashable = hashable;
364afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      hashable.clear();
365f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato      is_watchdog = false;
366afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    } else if (stack_entry_re.PartialMatch(line,
367afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                           last_stack_timestamp,
368afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                           &certainty,
369afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                           &function_name)) {
370afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      bool is_certain = certainty.find('?') == std::string::npos;
371afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      if (print_diagnostics) {
372afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter        printf("@%f: stack entry for %s (%s)\n",
373afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter               *last_stack_timestamp,
374afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter               function_name.c_str(),
375afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter               is_certain ? "certain" : "uncertain");
376afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      }
377afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      // Do not include any uncertain (prefixed by '?') frames in our hash.
378afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      if (!is_certain)
379afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter        continue;
380afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      if (!hashable.empty())
381afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter        hashable.append("|");
382f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato      if (function_name == "watchdog_timer_fn" ||
383f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato          function_name == "watchdog") {
384f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato        is_watchdog = true;
385f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato      }
386afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      hashable.append(function_name);
387afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
388afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
389afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
390f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // If the last stack trace contains a watchdog function we assume the panic
391f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // is from the watchdog timer, and we hash the previous stack trace rather
392f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // than the last one, assuming that the previous stack is that of the hung
393f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // thread.
394f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  //
395f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // In addition, if the hashable is empty (meaning all frames are uncertain,
396f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // for whatever reason) also use the previous frame, as it cannot be any
397f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  // worse.
398f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  if (is_watchdog || hashable.empty()) {
399f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato    hashable = previous_hashable;
400f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  }
401f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato
402afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  *hash = HashString(hashable);
403f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  *is_watchdog_crash = is_watchdog;
404afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
405afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (print_diagnostics) {
406afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    printf("Hash based on stack trace: \"%s\" at %f.\n",
407afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter           hashable.c_str(), *last_stack_timestamp);
408afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
409afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
410afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
4113c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan// static
4123c6b82c4c73f9ac39a71809f01af6f3b75339606Ben ChanKernelCollector::ArchKind KernelCollector::GetCompilerArch() {
413d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass#if defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
4143c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  return kArchArm;
415120c675df0836290d629764d06f1eb4ba49d7740Ben Chan#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
4163c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  return kArchMips;
417b87375957eb9e07c929a84683460e9e7f87985c1Bryan Freed#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_64)
4183c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  return kArchX86_64;
419d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
4203c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  return kArchX86;
421d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass#else
4223c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  return kArchUnknown;
423d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass#endif
424d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass}
425d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass
426afcf80821c57a189b53b7a66f76d13855d63821eKen Mixterbool KernelCollector::FindCrashingFunction(
427d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  pcrecpp::StringPiece kernel_dump,
428d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  bool print_diagnostics,
429d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  float stack_trace_timestamp,
430d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  std::string *crashing_function) {
431afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  float timestamp = 0;
432d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass
433d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass  // Use the correct regex for this architecture.
4343c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  pcrecpp::RE eip_re(std::string(kTimestampRegex) + kPCRegex[arch_],
435d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass                     pcrecpp::MULTILINE());
436d74cc09bbd6829535e1ce0b29bf2ef7de9fd8468Simon Glass
437afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  while (eip_re.FindAndConsume(&kernel_dump, &timestamp, crashing_function)) {
438afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (print_diagnostics) {
439afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      printf("@%f: found crashing function %s\n",
440afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter             timestamp,
441afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter             crashing_function->c_str());
442afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
443afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
444afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (timestamp == 0) {
445afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (print_diagnostics) {
446afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      printf("Found no crashing function.\n");
447afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
448afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    return false;
449afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
450afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (stack_trace_timestamp != 0 &&
4519f52040ac95fe6180b6c1a95835eb15c439c5381Yunlian Jiang      abs(static_cast<int>(stack_trace_timestamp - timestamp))
4529f52040ac95fe6180b6c1a95835eb15c439c5381Yunlian Jiang        > kSignatureTimestampWindow) {
453afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (print_diagnostics) {
454afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      printf("Found crashing function but not within window.\n");
455afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
456afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    return false;
457afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
458afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (print_diagnostics) {
459afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    printf("Found crashing function %s\n", crashing_function->c_str());
460afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
461afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  return true;
462afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
463afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
464afcf80821c57a189b53b7a66f76d13855d63821eKen Mixterbool KernelCollector::FindPanicMessage(pcrecpp::StringPiece kernel_dump,
465afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                       bool print_diagnostics,
466afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                       std::string *panic_message) {
467afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  // Match lines such as the following and grab out "Fatal exception"
468afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  // <0>[  342.841135] Kernel panic - not syncing: Fatal exception
4693c6b82c4c73f9ac39a71809f01af6f3b75339606Ben Chan  pcrecpp::RE kernel_panic_re(std::string(kTimestampRegex) +
470afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                              " Kernel panic[^\\:]*\\:\\s*(.*)",
471afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                              pcrecpp::MULTILINE());
472afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  float timestamp = 0;
473afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  while (kernel_panic_re.FindAndConsume(&kernel_dump,
474afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                        &timestamp,
475afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                        panic_message)) {
476afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (print_diagnostics) {
477afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      printf("@%f: panic message %s\n",
478afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter             timestamp,
479afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter             panic_message->c_str());
480afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
481afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
482afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (timestamp == 0) {
483afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (print_diagnostics) {
484afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      printf("Found no panic message.\n");
485afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
486afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    return false;
487afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
488afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  return true;
489afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
490afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
491afcf80821c57a189b53b7a66f76d13855d63821eKen Mixterbool KernelCollector::ComputeKernelStackSignature(
492afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    const std::string &kernel_dump,
493afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    std::string *kernel_signature,
494afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    bool print_diagnostics) {
495afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  unsigned stack_hash = 0;
496afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  float last_stack_timestamp = 0;
497afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string human_string;
498f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  bool is_watchdog_crash;
499afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
500afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  ProcessStackTrace(kernel_dump,
501afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                    print_diagnostics,
502afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                    &stack_hash,
503f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato                    &last_stack_timestamp,
504f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato                    &is_watchdog_crash);
505afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
506afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (!FindCrashingFunction(kernel_dump,
507afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                            print_diagnostics,
508afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                            last_stack_timestamp,
509afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                            &human_string)) {
510afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (!FindPanicMessage(kernel_dump, print_diagnostics, &human_string)) {
511afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      if (print_diagnostics) {
512afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter        printf("Found no human readable string, using empty string.\n");
513afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      }
514afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      human_string.clear();
515afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
516afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
517afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
518afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (human_string.empty() && stack_hash == 0) {
519afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    if (print_diagnostics) {
520afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      printf("Found neither a stack nor a human readable string, failing.\n");
521afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    }
522afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    return false;
523afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
524afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
525afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  human_string = human_string.substr(0, kMaxHumanStringLength);
526f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato  *kernel_signature = StringPrintf("%s-%s%s-%08X",
527afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                   kKernelExecName,
528f640099ceb6e945136110a6d41d3af66786a5d0dLuigi Semenzato                                   (is_watchdog_crash ? "(HANG)-" : ""),
529afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                   human_string.c_str(),
530afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                   stack_hash);
531afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  return true;
532afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
533afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
5340340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool KernelCollector::Collect() {
5350340316050044e0995b98fea87ed41ea77abb28bKen Mixter  std::string kernel_dump;
5360340316050044e0995b98fea87ed41ea77abb28bKen Mixter  FilePath root_crash_directory;
5371ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache
5381ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  if (!LoadParameters()) {
5391ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache    return false;
5401ea8abecd38a71a98c89e556d5a7fc5e9692577eSergiu Iordache  }
5410340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!LoadPreservedDump(&kernel_dump)) {
5420340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
5430340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
5441e6b8bdbba944299b31b977297b3ce1aeb2fee7dDoug Anderson  StripSensitiveData(&kernel_dump);
5450340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (kernel_dump.empty()) {
5460340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
5470340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
548afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string signature;
549afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (!ComputeKernelStackSignature(kernel_dump, &signature, false)) {
550afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    signature = kDefaultKernelStackSignature;
551afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  }
552afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
5539ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter  std::string reason = "handling";
5549ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter  bool feedback = true;
5559ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter  if (IsDeveloperImage()) {
5569ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter    reason = "developer build - always dumping";
5579ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter    feedback = true;
5589ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter  } else if (!is_feedback_allowed_function_()) {
5599ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter    reason = "ignoring - no consent";
5609ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter    feedback = false;
5619ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter  }
562afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
563a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  LOG(INFO) << "Received prior crash notification from "
5649ee1f5f034e44dd20b3cb229db601eeb1098a3d6Ken Mixter            << "kernel (signature " << signature << ") (" << reason << ")";
565ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
566afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (feedback) {
5670340316050044e0995b98fea87ed41ea77abb28bKen Mixter    count_crash_function_();
5680340316050044e0995b98fea87ed41ea77abb28bKen Mixter
5690340316050044e0995b98fea87ed41ea77abb28bKen Mixter    if (!GetCreatedCrashDirectoryByEuid(kRootUid,
570207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                        &root_crash_directory,
571262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan                                        nullptr)) {
5720340316050044e0995b98fea87ed41ea77abb28bKen Mixter      return true;
5730340316050044e0995b98fea87ed41ea77abb28bKen Mixter    }
5740340316050044e0995b98fea87ed41ea77abb28bKen Mixter
575ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string dump_basename =
576262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan        FormatDumpBasename(kKernelExecName, time(nullptr), kKernelPid);
577ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    FilePath kernel_crash_path = root_crash_directory.Append(
578ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter        StringPrintf("%s.kcrash", dump_basename.c_str()));
579ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
580f30c641225e55055641ffe3fd679a96e44f34af6Ben Chan    // We must use WriteNewFile instead of base::WriteFile as we
5819b346474538a255bc7144ae358bb0ee129163d58Ken Mixter    // do not want to write with root access to a symlink that an attacker
5829b346474538a255bc7144ae358bb0ee129163d58Ken Mixter    // might have created.
5839b346474538a255bc7144ae358bb0ee129163d58Ken Mixter    if (WriteNewFile(kernel_crash_path,
5849b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                     kernel_dump.data(),
5859b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                     kernel_dump.length()) !=
5860340316050044e0995b98fea87ed41ea77abb28bKen Mixter        static_cast<int>(kernel_dump.length())) {
587a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(INFO) << "Failed to write kernel dump to "
588a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                << kernel_crash_path.value().c_str();
5890340316050044e0995b98fea87ed41ea77abb28bKen Mixter      return true;
5900340316050044e0995b98fea87ed41ea77abb28bKen Mixter    }
5910340316050044e0995b98fea87ed41ea77abb28bKen Mixter
592afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    AddCrashMetaData(kKernelSignatureKey, signature);
593ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    WriteCrashMetaData(
594ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter        root_crash_directory.Append(
595ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter            StringPrintf("%s.meta", dump_basename.c_str())),
596c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter        kKernelExecName,
597c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter        kernel_crash_path.value());
598ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
599a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(INFO) << "Stored kcrash to " << kernel_crash_path.value();
6000340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
6010340316050044e0995b98fea87ed41ea77abb28bKen Mixter
6020340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
6030340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
604