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, ×tamp, 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 ×tamp, 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