Add ARM support
Adds support for scanning ARM backtraces so that kernel crash reporting can work on ARM. BUG=chromium-os:12454 TEST=cat /sys/kernel/debug/preserved/kcrash > x crash_reporter -generate_kernel_signature x Verify that it finds a backtrace properly. FEATURES=test emerge-x86-mario crash-reporter - check all tests pass (this will run both ARM and X86 tests) Change-Id: I4dc6d7a2bae53d05883da9425ec8e9ac4a5c2bba Review URL: http://codereview.chromium.org/6599022
This commit is contained in:
parent
c7dcf3f52c
commit
d74cc09bbd
3 changed files with 180 additions and 36 deletions
|
|
@ -24,9 +24,31 @@ static const int kSignatureTimestampWindow = 2;
|
|||
// Kernel log timestamp regular expression.
|
||||
static const std::string kTimestampRegex("^<.*>\\[\\s*(\\d+\\.\\d+)\\]");
|
||||
|
||||
/*
|
||||
* These regular expressions enable to us capture the PC in a backtrace.
|
||||
* The backtrace is obtained through dmesg or the kernel's preserved/kcrashmem
|
||||
* feature.
|
||||
*
|
||||
* For ARM we see:
|
||||
* "<5>[ 39.458982] PC is at write_breakme+0xd0/0x1b4"
|
||||
* For x86:
|
||||
* "<0>[ 37.474699] EIP: [<790ed488>] write_breakme+0x80/0x108 \
|
||||
* SS:ESP 0068:e9dd3efc
|
||||
*/
|
||||
static const char *s_pc_regex[] = {
|
||||
0,
|
||||
" PC is at ([^\\+ ]+).*",
|
||||
" EIP: \\[<.*>\\] ([^\\+ ]+).*", // X86 uses EIP for the program counter
|
||||
};
|
||||
|
||||
COMPILE_ASSERT(arraysize(s_pc_regex) == KernelCollector::archCount,
|
||||
missing_arch_pc_regexp);
|
||||
|
||||
KernelCollector::KernelCollector()
|
||||
: is_enabled_(false),
|
||||
preserved_dump_path_(kPreservedDumpPath) {
|
||||
// We expect crash dumps in the format of the architecture we are built for.
|
||||
arch_ = GetCompilerArch();
|
||||
}
|
||||
|
||||
KernelCollector::~KernelCollector() {
|
||||
|
|
@ -47,7 +69,12 @@ bool KernelCollector::LoadPreservedDump(std::string *contents) {
|
|||
}
|
||||
|
||||
bool KernelCollector::Enable() {
|
||||
if (!file_util::PathExists(preserved_dump_path_)) {
|
||||
if (arch_ == archUnknown || arch_ >= archCount ||
|
||||
s_pc_regex[arch_] == NULL) {
|
||||
LOG(WARNING) << "KernelCollector does not understand this architecture";
|
||||
return false;
|
||||
}
|
||||
else if (!file_util::PathExists(preserved_dump_path_)) {
|
||||
LOG(WARNING) << "Kernel does not support crash dumping";
|
||||
return false;
|
||||
}
|
||||
|
|
@ -90,11 +117,21 @@ void KernelCollector::ProcessStackTrace(
|
|||
unsigned *hash,
|
||||
float *last_stack_timestamp) {
|
||||
pcrecpp::RE line_re("(.+)", pcrecpp::MULTILINE());
|
||||
pcrecpp::RE stack_trace_start_re(kTimestampRegex + " Call Trace:$");
|
||||
pcrecpp::RE stack_trace_start_re(kTimestampRegex +
|
||||
" (Call Trace|Backtrace):$");
|
||||
|
||||
// For ARM:
|
||||
// <4>[ 3498.731164] [<c0057220>] (__bug+0x20/0x2c) from [<c018062c>]
|
||||
// (write_breakme+0xdc/0x1bc)
|
||||
//
|
||||
// For X86:
|
||||
// Match lines such as the following and grab out "error_code".
|
||||
// <4>[ 6066.849504] [<7937bcee>] error_code+0x66/0x6c
|
||||
// <4>[ 6066.849504] [<7937bcee>] ? error_code+0x66/0x6c
|
||||
// The ? may or may not be present
|
||||
pcrecpp::RE stack_entry_re(kTimestampRegex +
|
||||
" \\[<.*>\\]([\\s\\?]+)([^\\+ ]+)");
|
||||
"\\s+\\[<[[:xdigit:]]+>\\]" // Matches " [<7937bcee>]"
|
||||
"([\\s\\?(]+)" // Matches " ? (" (ARM) or " ? " (X86)
|
||||
"([^\\+ )]+)"); // Matches until delimiter reached
|
||||
std::string line;
|
||||
std::string hashable;
|
||||
|
||||
|
|
@ -137,14 +174,33 @@ void KernelCollector::ProcessStackTrace(
|
|||
}
|
||||
}
|
||||
|
||||
enum KernelCollector::ArchKind KernelCollector::GetCompilerArch(void)
|
||||
{
|
||||
#if defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
|
||||
return archArm;
|
||||
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
|
||||
return archX86;
|
||||
#else
|
||||
return archUnknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
void KernelCollector::SetArch(enum ArchKind arch)
|
||||
{
|
||||
arch_ = arch;
|
||||
}
|
||||
|
||||
bool KernelCollector::FindCrashingFunction(
|
||||
pcrecpp::StringPiece kernel_dump,
|
||||
bool print_diagnostics,
|
||||
float stack_trace_timestamp,
|
||||
std::string *crashing_function) {
|
||||
pcrecpp::RE eip_re(kTimestampRegex + " EIP: \\[<.*>\\] ([^\\+ ]+).*",
|
||||
pcrecpp::MULTILINE());
|
||||
pcrecpp::StringPiece kernel_dump,
|
||||
bool print_diagnostics,
|
||||
float stack_trace_timestamp,
|
||||
std::string *crashing_function) {
|
||||
float timestamp = 0;
|
||||
|
||||
// Use the correct regex for this architecture.
|
||||
pcrecpp::RE eip_re(kTimestampRegex + s_pc_regex[arch_],
|
||||
pcrecpp::MULTILINE());
|
||||
|
||||
while (eip_re.FindAndConsume(&kernel_dump, ×tamp, crashing_function)) {
|
||||
if (print_diagnostics) {
|
||||
printf("@%f: found crashing function %s\n",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,15 @@ class FilePath;
|
|||
// Kernel crash collector.
|
||||
class KernelCollector : public CrashCollector {
|
||||
public:
|
||||
// Enumeration to specify architecture type.
|
||||
enum ArchKind {
|
||||
archUnknown,
|
||||
archArm,
|
||||
archX86,
|
||||
|
||||
archCount // Number of architectures.
|
||||
};
|
||||
|
||||
KernelCollector();
|
||||
|
||||
virtual ~KernelCollector();
|
||||
|
|
@ -41,6 +50,10 @@ class KernelCollector : public CrashCollector {
|
|||
std::string *kernel_signature,
|
||||
bool print_diagnostics);
|
||||
|
||||
// Set the architecture of the crash dumps we are looking at.
|
||||
void SetArch(enum ArchKind arch);
|
||||
enum ArchKind GetArch() { return arch_; }
|
||||
|
||||
private:
|
||||
friend class KernelCollectorTest;
|
||||
FRIEND_TEST(KernelCollectorTest, ClearPreservedDump);
|
||||
|
|
@ -62,9 +75,15 @@ class KernelCollector : public CrashCollector {
|
|||
bool print_diagnostics,
|
||||
std::string *panic_message);
|
||||
|
||||
// Returns the architecture kind for which we are built - enum ArchKind.
|
||||
enum ArchKind GetCompilerArch(void);
|
||||
|
||||
bool is_enabled_;
|
||||
FilePath preserved_dump_path_;
|
||||
static const char kClearingSequence[];
|
||||
|
||||
// The architecture of kernel dump strings we are working with.
|
||||
enum ArchKind arch_;
|
||||
};
|
||||
|
||||
#endif // _CRASH_REPORTER_KERNEL_COLLECTOR_H_
|
||||
|
|
|
|||
|
|
@ -50,11 +50,17 @@ class KernelCollectorTest : public ::testing::Test {
|
|||
|
||||
void SetUpSuccessfulCollect();
|
||||
void CheckPreservedDumpClear();
|
||||
void ComputeKernelStackSignatureCommon();
|
||||
|
||||
KernelCollector collector_;
|
||||
FilePath test_kcrash_;
|
||||
};
|
||||
|
||||
TEST_F(KernelCollectorTest, ComputeKernelStackSignatureBase) {
|
||||
// Make sure the normal build architecture is detected
|
||||
EXPECT_TRUE(collector_.GetArch() != KernelCollector::archUnknown);
|
||||
}
|
||||
|
||||
TEST_F(KernelCollectorTest, LoadPreservedDump) {
|
||||
ASSERT_FALSE(file_util::PathExists(test_kcrash_));
|
||||
std::string dump;
|
||||
|
|
@ -162,7 +168,92 @@ TEST_F(KernelCollectorTest, CollectOK) {
|
|||
CheckPreservedDumpClear();
|
||||
}
|
||||
|
||||
TEST_F(KernelCollectorTest, ComputeKernelStackSignature) {
|
||||
// Perform tests which are common across architectures
|
||||
void KernelCollectorTest::ComputeKernelStackSignatureCommon() {
|
||||
std::string signature;
|
||||
|
||||
const char kStackButNoPC[] =
|
||||
"<4>[ 6066.829029] [<790340af>] __do_softirq+0xa6/0x143\n";
|
||||
EXPECT_TRUE(
|
||||
collector_.ComputeKernelStackSignature(kStackButNoPC, &signature, false));
|
||||
EXPECT_EQ("kernel--83615F0A", signature);
|
||||
|
||||
const char kMissingEverything[] =
|
||||
"<4>[ 6066.829029] [<790340af>] ? __do_softirq+0xa6/0x143\n";
|
||||
EXPECT_FALSE(
|
||||
collector_.ComputeKernelStackSignature(kMissingEverything,
|
||||
&signature,
|
||||
false));
|
||||
|
||||
// Long message.
|
||||
const char kTruncatedMessage[] =
|
||||
"<0>[ 87.485611] Kernel panic - not syncing: 01234567890123456789"
|
||||
"01234567890123456789X\n";
|
||||
EXPECT_TRUE(
|
||||
collector_.ComputeKernelStackSignature(kTruncatedMessage,
|
||||
&signature,
|
||||
false));
|
||||
EXPECT_EQ("kernel-0123456789012345678901234567890123456789-00000000",
|
||||
signature);
|
||||
}
|
||||
|
||||
TEST_F(KernelCollectorTest, ComputeKernelStackSignatureARM) {
|
||||
const char kBugToPanic[] =
|
||||
"<5>[ 123.412524] Modules linked in:\n"
|
||||
"<5>[ 123.412534] CPU: 0 Tainted: G W "
|
||||
"(2.6.37-01030-g51cee64 #153)\n"
|
||||
"<5>[ 123.412552] PC is at write_breakme+0xd0/0x1b4\n"
|
||||
"<5>[ 123.412560] LR is at write_breakme+0xc8/0x1b4\n"
|
||||
"<5>[ 123.412569] pc : [<c0058220>] lr : [<c005821c>] "
|
||||
"psr: 60000013\n"
|
||||
"<5>[ 123.412574] sp : f4e0ded8 ip : c04d104c fp : 000e45e0\n"
|
||||
"<5>[ 123.412581] r10: 400ff000 r9 : f4e0c000 r8 : 00000004\n"
|
||||
"<5>[ 123.412589] r7 : f4e0df80 r6 : f4820c80 r5 : 00000004 "
|
||||
"r4 : f4e0dee8\n"
|
||||
"<5>[ 123.412598] r3 : 00000000 r2 : f4e0decc r1 : c05f88a9 "
|
||||
"r0 : 00000039\n"
|
||||
"<5>[ 123.412608] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA "
|
||||
"ARM Segment user\n"
|
||||
"<5>[ 123.412617] Control: 10c53c7d Table: 34dcc04a DAC: 00000015\n"
|
||||
"<0>[ 123.412626] Process bash (pid: 1014, stack limit = 0xf4e0c2f8)\n"
|
||||
"<0>[ 123.412634] Stack: (0xf4e0ded8 to 0xf4e0e000)\n"
|
||||
"<0>[ 123.412641] dec0: "
|
||||
" f4e0dee8 c0183678\n"
|
||||
"<0>[ 123.412654] dee0: 00000000 00000000 00677562 0000081f c06a6a78 "
|
||||
"400ff000 f4e0dfb0 00000000\n"
|
||||
"<0>[ 123.412666] df00: bec7ab44 000b1719 bec7ab0c c004f498 bec7a314 "
|
||||
"c024acc8 00000001 c018359c\n"
|
||||
"<0>[ 123.412679] df20: f4e0df34 c04d10fc f5803c80 271beb39 000e45e0 "
|
||||
"f5803c80 c018359c c017bfe0\n"
|
||||
"<0>[ 123.412691] df40: 00000004 f4820c80 400ff000 f4e0df80 00000004 "
|
||||
"f4e0c000 00000000 c01383e4\n"
|
||||
"<0>[ 123.412703] df60: f4820c80 400ff000 f4820c80 400ff000 00000000 "
|
||||
"00000000 00000004 c0138578\n"
|
||||
"<0>[ 123.412715] df80: 00000000 00000000 00000004 00000000 00000004 "
|
||||
"402f95d0 00000004 00000004\n"
|
||||
"<0>[ 123.412727] dfa0: c0054984 c00547c0 00000004 402f95d0 00000001 "
|
||||
"400ff000 00000004 00000000\n"
|
||||
"<0>[ 123.412739] dfc0: 00000004 402f95d0 00000004 00000004 400ff000 "
|
||||
"000c194c bec7ab58 000e45e0\n"
|
||||
"<0>[ 123.412751] dfe0: 00000000 bec7aad8 40232520 40284e9c 60000010 "
|
||||
"00000001 00000000 00000000\n"
|
||||
"<5>[ 39.496577] Backtrace:\n"
|
||||
"<5>[ 123.412782] [<c0058220>] (__bug+0x20/0x2c) from [<c0183678>] "
|
||||
"(write_breakme+0xdc/0x1bc)\n"
|
||||
"<5>[ 123.412798] [<c0183678>] (write_breakme+0xdc/0x1bc) from "
|
||||
"[<c017bfe0>] (proc_reg_write+0x88/0x9c)\n";
|
||||
std::string signature;
|
||||
|
||||
collector_.SetArch(KernelCollector::archArm);
|
||||
EXPECT_TRUE(
|
||||
collector_.ComputeKernelStackSignature(kBugToPanic, &signature, false));
|
||||
EXPECT_EQ("kernel-write_breakme-97D3E92F", signature);
|
||||
|
||||
ComputeKernelStackSignatureCommon();
|
||||
}
|
||||
|
||||
|
||||
TEST_F(KernelCollectorTest, ComputeKernelStackSignatureX86) {
|
||||
const char kBugToPanic[] =
|
||||
"<4>[ 6066.829029] [<79039d16>] ? run_timer_softirq+0x165/0x1e6\n"
|
||||
"<4>[ 6066.829029] [<790340af>] ignore_old_stack+0xa6/0x143\n"
|
||||
|
|
@ -178,6 +269,8 @@ TEST_F(KernelCollectorTest, ComputeKernelStackSignature) {
|
|||
"<4>[ 6066.949971] [<7937c5c5>] oops_end+0x73/0x81\n"
|
||||
"<4>[ 6066.950208] [<7901b260>] no_context+0x10d/0x117\n";
|
||||
std::string signature;
|
||||
|
||||
collector_.SetArch(KernelCollector::archX86);
|
||||
EXPECT_TRUE(
|
||||
collector_.ComputeKernelStackSignature(kBugToPanic, &signature, false));
|
||||
EXPECT_EQ("kernel-ieee80211_stop_tx_ba_session-DE253569", signature);
|
||||
|
|
@ -188,19 +281,6 @@ TEST_F(KernelCollectorTest, ComputeKernelStackSignature) {
|
|||
collector_.ComputeKernelStackSignature(kPCButNoStack, &signature, false));
|
||||
EXPECT_EQ("kernel-ieee80211_stop_tx_ba_session-00000000", signature);
|
||||
|
||||
const char kStackButNoPC[] =
|
||||
"<4>[ 6066.829029] [<790340af>] __do_softirq+0xa6/0x143\n";
|
||||
EXPECT_TRUE(
|
||||
collector_.ComputeKernelStackSignature(kStackButNoPC, &signature, false));
|
||||
EXPECT_EQ("kernel--83615F0A", signature);
|
||||
|
||||
const char kMissingEverything[] =
|
||||
"<4>[ 6066.829029] [<790340af>] ? __do_softirq+0xa6/0x143\n";
|
||||
EXPECT_FALSE(
|
||||
collector_.ComputeKernelStackSignature(kMissingEverything,
|
||||
&signature,
|
||||
false));
|
||||
|
||||
const char kBreakmeBug[] =
|
||||
"<4>[ 180.492137] [<790970c6>] ? handle_mm_fault+0x67f/0x96d\n"
|
||||
"<4>[ 180.492137] [<790dcdfe>] ? proc_reg_write+0x5f/0x73\n"
|
||||
|
|
@ -255,18 +335,7 @@ TEST_F(KernelCollectorTest, ComputeKernelStackSignature) {
|
|||
&signature,
|
||||
false));
|
||||
EXPECT_EQ("kernel-Testing panic-E0FC3552", signature);
|
||||
|
||||
// Long message.
|
||||
const char kTruncatedMessage[] =
|
||||
"<0>[ 87.485611] Kernel panic - not syncing: 01234567890123456789"
|
||||
"01234567890123456789X\n";
|
||||
EXPECT_TRUE(
|
||||
collector_.ComputeKernelStackSignature(kTruncatedMessage,
|
||||
&signature,
|
||||
false));
|
||||
EXPECT_EQ("kernel-0123456789012345678901234567890123456789-00000000",
|
||||
signature);
|
||||
|
||||
ComputeKernelStackSignatureCommon();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue