util: Add ec_parse_panicinfo tool to parse binary panicinfo
To be able to parse binary panicinfo from feedback reports, we need a host tool: - Move panicinfo generic parsing functions to a separate C file - Create a new host utility to parse panicinfo BRANCH=none BUG=chromium:643062 TEST=base64 -d | ec_parse_panicinfo Change-Id: Idd8560a2894f270d0ab3a9f654c333135759e57f Reviewed-on: https://chromium-review.googlesource.com/379639 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
parent
03a3f86479
commit
107cb0df63
|
@ -6,7 +6,8 @@
|
|||
# Host tools build
|
||||
#
|
||||
|
||||
host-util-bin=ectool lbplay stm32mon ec_sb_firmware_update lbcc
|
||||
host-util-bin=ectool lbplay stm32mon ec_sb_firmware_update lbcc \
|
||||
ec_parse_panicinfo
|
||||
build-util-bin=ec_uartd iteflash
|
||||
ifeq ($(CHIP),npcx)
|
||||
build-util-bin+=ecst
|
||||
|
@ -15,7 +16,9 @@ endif
|
|||
comm-objs=$(util-lock-objs:%=lock/%) comm-host.o comm-dev.o
|
||||
comm-objs+=comm-lpc.o comm-i2c.o misc_util.o
|
||||
|
||||
ectool-objs=ectool.o ectool_keyscan.o ec_flash.o $(comm-objs)
|
||||
ectool-objs=ectool.o ectool_keyscan.o ec_flash.o ec_panicinfo.o $(comm-objs)
|
||||
ec_sb_firmware_update-objs=ec_sb_firmware_update.o $(comm-objs) misc_util.o
|
||||
ec_sb_firmware_update-objs+=powerd_lock.o
|
||||
lbplay-objs=lbplay.o $(comm-objs)
|
||||
|
||||
ec_parse_panicinfo-objs=ec_parse_panicinfo.o ec_panicinfo.o
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "ec_panicinfo.h"
|
||||
|
||||
static void print_panic_reg(int regnum, const uint32_t *regs, int index)
|
||||
{
|
||||
static const char * const regname[] = {
|
||||
"r0 ", "r1 ", "r2 ", "r3 ", "r4 ",
|
||||
"r5 ", "r6 ", "r7 ", "r8 ", "r9 ",
|
||||
"r10", "r11", "r12", "sp ", "lr ",
|
||||
"pc "};
|
||||
|
||||
printf("%s:", regname[regnum]);
|
||||
if (regs)
|
||||
printf("%08x", regs[index]);
|
||||
else
|
||||
printf(" ");
|
||||
printf((regnum & 3) == 3 ? "\n" : " ");
|
||||
}
|
||||
|
||||
static int parse_panic_info_cm(const struct panic_data *pdata)
|
||||
{
|
||||
const uint32_t *lregs = pdata->cm.regs;
|
||||
const uint32_t *sregs = NULL;
|
||||
enum {
|
||||
ORIG_UNKNOWN = 0,
|
||||
ORIG_PROCESS,
|
||||
ORIG_HANDLER
|
||||
} origin = ORIG_UNKNOWN;
|
||||
int i;
|
||||
const char *panic_origins[3] = {"", "PROCESS", "HANDLER"};
|
||||
|
||||
printf("Saved panic data:%s\n",
|
||||
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
|
||||
|
||||
if (pdata->struct_version == 2)
|
||||
origin = ((lregs[11] & 0xf) == 1 || (lregs[11] & 0xf) == 9) ?
|
||||
ORIG_HANDLER : ORIG_PROCESS;
|
||||
|
||||
/*
|
||||
* In pdata struct, 'regs', which is allocated before 'frame', has
|
||||
* one less elements in version 1. Therefore, if the data is from
|
||||
* version 1, shift 'sregs' by one element to align with 'frame' in
|
||||
* version 1.
|
||||
*/
|
||||
if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID)
|
||||
sregs = pdata->cm.frame - (pdata->struct_version == 1 ? 1 : 0);
|
||||
|
||||
printf("=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n",
|
||||
panic_origins[origin],
|
||||
lregs[1] & 0xff, sregs ? sregs[7] : -1);
|
||||
for (i = 0; i < 4; ++i)
|
||||
print_panic_reg(i, sregs, i);
|
||||
for (i = 4; i < 10; ++i)
|
||||
print_panic_reg(i, lregs, i - 1);
|
||||
print_panic_reg(10, lregs, 9);
|
||||
print_panic_reg(11, lregs, 10);
|
||||
print_panic_reg(12, sregs, 4);
|
||||
print_panic_reg(13, lregs, origin == ORIG_HANDLER ? 2 : 0);
|
||||
print_panic_reg(14, sregs, 5);
|
||||
print_panic_reg(15, sregs, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_panic_info_nds32(const struct panic_data *pdata)
|
||||
{
|
||||
const uint32_t *regs = pdata->nds_n8.regs;
|
||||
uint32_t itype = pdata->nds_n8.itype;
|
||||
uint32_t ipc = pdata->nds_n8.ipc;
|
||||
uint32_t ipsw = pdata->nds_n8.ipsw;
|
||||
|
||||
printf("Saved panic data:%s\n",
|
||||
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
|
||||
|
||||
printf("=== EXCEP: ITYPE=%x ===\n", itype);
|
||||
printf("R0 %08x R1 %08x R2 %08x R3 %08x\n",
|
||||
regs[0], regs[1], regs[2], regs[3]);
|
||||
printf("R4 %08x R5 %08x R6 %08x R7 %08x\n",
|
||||
regs[4], regs[5], regs[6], regs[7]);
|
||||
printf("R8 %08x R9 %08x R10 %08x R15 %08x\n",
|
||||
regs[8], regs[9], regs[10], regs[11]);
|
||||
printf("FP %08x GP %08x LP %08x SP %08x\n",
|
||||
regs[12], regs[13], regs[14], regs[15]);
|
||||
printf("IPC %08x IPSW %05x\n", ipc, ipsw);
|
||||
printf("SWID of ITYPE: %x\n", ((itype >> 16) & 0x7fff));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_panic_info(const struct panic_data *pdata)
|
||||
{
|
||||
/*
|
||||
* We only understand panic data with version <= 2. Warn the user
|
||||
* of higher versions.
|
||||
*/
|
||||
if (pdata->struct_version > 2)
|
||||
fprintf(stderr,
|
||||
"Unknown panic data version (%d). "
|
||||
"Following data may be incorrect!\n",
|
||||
pdata->struct_version);
|
||||
|
||||
/* Validate magic number */
|
||||
if (pdata->magic != PANIC_DATA_MAGIC)
|
||||
fprintf(stderr,
|
||||
"Incorrect panic magic (%d). "
|
||||
"Following data may be incorrect!\n",
|
||||
pdata->magic);
|
||||
|
||||
switch (pdata->arch) {
|
||||
case PANIC_ARCH_CORTEX_M:
|
||||
return parse_panic_info_cm(pdata);
|
||||
case PANIC_ARCH_NDS32_N8:
|
||||
return parse_panic_info_nds32(pdata);
|
||||
default:
|
||||
fprintf(stderr, "Unknown architecture (%d).\n", pdata->arch);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef EC_PANICINFO_H
|
||||
#define EC_PANICINFO_H
|
||||
|
||||
#include "panic.h"
|
||||
|
||||
/**
|
||||
* Prints panic information to stdout.
|
||||
*
|
||||
* @param pdata Panic information to print
|
||||
* @return 0 if success or non-zero error code if error.
|
||||
*/
|
||||
int parse_panic_info(const struct panic_data *pdata);
|
||||
|
||||
#endif /* EC_PANICINFO_H */
|
|
@ -0,0 +1,22 @@
|
|||
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Standalone utility to parse EC panicinfo.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "ec_panicinfo.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct panic_data pdata;
|
||||
|
||||
if (fread(&pdata, sizeof(pdata), 1, stdin) != 1) {
|
||||
fprintf(stderr, "Error reading panicinfo from stdin.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parse_panic_info(&pdata) ? 1 : 0;
|
||||
}
|
110
util/ectool.c
110
util/ectool.c
|
@ -17,6 +17,7 @@
|
|||
#include "battery.h"
|
||||
#include "comm-host.h"
|
||||
#include "compile_time_macros.h"
|
||||
#include "ec_panicinfo.h"
|
||||
#include "ec_flash.h"
|
||||
#include "ectool.h"
|
||||
#include "lightbar.h"
|
||||
|
@ -4420,94 +4421,6 @@ int cmd_keyboard_factory_test(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void print_panic_reg(int regnum, const uint32_t *regs, int index)
|
||||
{
|
||||
static const char * const regname[] = {
|
||||
"r0 ", "r1 ", "r2 ", "r3 ", "r4 ",
|
||||
"r5 ", "r6 ", "r7 ", "r8 ", "r9 ",
|
||||
"r10", "r11", "r12", "sp ", "lr ",
|
||||
"pc "};
|
||||
|
||||
printf("%s:", regname[regnum]);
|
||||
if (regs)
|
||||
printf("%08x", regs[index]);
|
||||
else
|
||||
printf(" ");
|
||||
printf((regnum & 3) == 3 ? "\n" : " ");
|
||||
}
|
||||
|
||||
int cmd_panic_info_cm(int argc, char *argv[])
|
||||
{
|
||||
struct panic_data *pdata = (struct panic_data *)ec_inbuf;
|
||||
const uint32_t *lregs = pdata->cm.regs;
|
||||
const uint32_t *sregs = NULL;
|
||||
enum {
|
||||
ORIG_UNKNOWN = 0,
|
||||
ORIG_PROCESS,
|
||||
ORIG_HANDLER
|
||||
} origin = ORIG_UNKNOWN;
|
||||
int i;
|
||||
const char *panic_origins[3] = {"", "PROCESS", "HANDLER"};
|
||||
|
||||
printf("Saved panic data:%s\n",
|
||||
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
|
||||
|
||||
if (pdata->struct_version == 2)
|
||||
origin = ((lregs[11] & 0xf) == 1 || (lregs[11] & 0xf) == 9) ?
|
||||
ORIG_HANDLER : ORIG_PROCESS;
|
||||
|
||||
/*
|
||||
* In pdata struct, 'regs', which is allocated before 'frame', has
|
||||
* one less elements in version 1. Therefore, if the data is from
|
||||
* version 1, shift 'sregs' by one element to align with 'frame' in
|
||||
* version 1.
|
||||
*/
|
||||
if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID)
|
||||
sregs = pdata->cm.frame - (pdata->struct_version == 1 ? 1 : 0);
|
||||
|
||||
printf("=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n",
|
||||
panic_origins[origin],
|
||||
lregs[1] & 0xff, sregs ? sregs[7] : -1);
|
||||
for (i = 0; i < 4; ++i)
|
||||
print_panic_reg(i, sregs, i);
|
||||
for (i = 4; i < 10; ++i)
|
||||
print_panic_reg(i, lregs, i - 1);
|
||||
print_panic_reg(10, lregs, 9);
|
||||
print_panic_reg(11, lregs, 10);
|
||||
print_panic_reg(12, sregs, 4);
|
||||
print_panic_reg(13, lregs, origin == ORIG_HANDLER ? 2 : 0);
|
||||
print_panic_reg(14, sregs, 5);
|
||||
print_panic_reg(15, sregs, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_panic_info_nds32(int argc, char *argv[])
|
||||
{
|
||||
struct panic_data *pdata = (struct panic_data *)ec_inbuf;
|
||||
const uint32_t *regs = pdata->nds_n8.regs;
|
||||
uint32_t itype = pdata->nds_n8.itype;
|
||||
uint32_t ipc = pdata->nds_n8.ipc;
|
||||
uint32_t ipsw = pdata->nds_n8.ipsw;
|
||||
|
||||
printf("Saved panic data:%s\n",
|
||||
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
|
||||
|
||||
printf("=== EXCEP: ITYPE=%x ===\n", itype);
|
||||
printf("R0 %08x R1 %08x R2 %08x R3 %08x\n",
|
||||
regs[0], regs[1], regs[2], regs[3]);
|
||||
printf("R4 %08x R5 %08x R6 %08x R7 %08x\n",
|
||||
regs[4], regs[5], regs[6], regs[7]);
|
||||
printf("R8 %08x R9 %08x R10 %08x R15 %08x\n",
|
||||
regs[8], regs[9], regs[10], regs[11]);
|
||||
printf("FP %08x GP %08x LP %08x SP %08x\n",
|
||||
regs[12], regs[13], regs[14], regs[15]);
|
||||
printf("IPC %08x IPSW %05x\n", ipc, ipsw);
|
||||
printf("SWID of ITYPE: %x\n", ((itype >> 16) & 0x7fff));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_panic_info(int argc, char *argv[])
|
||||
{
|
||||
int rv;
|
||||
|
@ -4523,26 +4436,7 @@ int cmd_panic_info(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only understand panic data with version <= 2. Warn the user
|
||||
* of higher versions.
|
||||
*/
|
||||
if (pdata->struct_version > 2)
|
||||
fprintf(stderr,
|
||||
"Unknown panic data version (%d). "
|
||||
"Following data may be incorrect!\n",
|
||||
pdata->struct_version);
|
||||
|
||||
switch (pdata->arch) {
|
||||
case PANIC_ARCH_CORTEX_M:
|
||||
return cmd_panic_info_cm(argc, argv);
|
||||
case PANIC_ARCH_NDS32_N8:
|
||||
return cmd_panic_info_nds32(argc, argv);
|
||||
default:
|
||||
fprintf(stderr, "Unknown architecture (%d).\n", pdata->arch);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
return parse_panic_info(pdata);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue