diff options
Diffstat (limited to 'util/ec_panicinfo.cc')
-rw-r--r-- | util/ec_panicinfo.cc | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/util/ec_panicinfo.cc b/util/ec_panicinfo.cc new file mode 100644 index 0000000000..308cd0e641 --- /dev/null +++ b/util/ec_panicinfo.cc @@ -0,0 +1,246 @@ +/* Copyright 2016 The ChromiumOS Authors + * 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 <string.h> + +#include <cstddef> + +/* Helpers from ec/include/compile_time_macros.h */ +#ifndef CONFIG_ZEPHYR +#define BIT(nr) (1U << (nr)) +#endif + +#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 void panic_show_extra_cm(const struct panic_data *pdata) +{ + enum { + CPU_NVIC_CFSR_BFARVALID = BIT(15), + CPU_NVIC_CFSR_MFARVALID = BIT(7), + }; + + printf("\n"); + if (pdata->cm.cfsr & CPU_NVIC_CFSR_BFARVALID) + printf("bfar=%08x, ", pdata->cm.bfar); + if (pdata->cm.cfsr & CPU_NVIC_CFSR_MFARVALID) + printf("mfar=%08x, ", pdata->cm.mfar); + printf("cfsr=%08x, ", pdata->cm.cfsr); + printf("shcsr=%08x, ", pdata->cm.shcsr); + printf("hfsr=%08x, ", pdata->cm.hfsr); + printf("dfsr=%08x, ", pdata->cm.dfsr); + printf("ipsr=%08x", pdata->cm.regs[CORTEX_PANIC_REGISTER_IPSR]); + printf("\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); + + panic_show_extra_cm(pdata); + + 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; +} + +static int parse_panic_info_rv32i(const struct panic_data *pdata) +{ + uint32_t *regs, mcause, mepc; + + regs = (uint32_t *)pdata->riscv.regs; + mcause = pdata->riscv.mcause; + mepc = pdata->riscv.mepc; + + printf("=== EXCEPTION: MCAUSE=%x ===\n", mcause); + printf("S11 %08x S10 %08x S9 %08x S8 %08x\n", regs[0], regs[1], + regs[2], regs[3]); + printf("S7 %08x S6 %08x S5 %08x S4 %08x\n", regs[4], regs[5], + regs[6], regs[7]); + printf("S3 %08x S2 %08x S1 %08x S0 %08x\n", regs[8], regs[9], + regs[10], regs[11]); + printf("T6 %08x T5 %08x T4 %08x T3 %08x\n", regs[12], regs[13], + regs[14], regs[15]); + printf("T2 %08x T1 %08x T0 %08x A7 %08x\n", regs[16], regs[17], + regs[18], regs[19]); + printf("A6 %08x A5 %08x A4 %08x A3 %08x\n", regs[20], regs[21], + regs[22], regs[23]); + printf("A2 %08x A1 %08x A0 %08x TP %08x\n", regs[24], regs[25], + regs[26], regs[27]); + printf("GP %08x RA %08x SP %08x MEPC %08x\n", regs[28], regs[29], + regs[30], mepc); + + return 0; +} + +int get_panic_input(char *data, size_t max_size) +{ + size_t size = 0; + size_t read; + + while (1) { + read = fread(&data[size], 1, max_size - size, stdin); + if (read < 0) { + fprintf(stderr, "Cannot read panicinfo from stdin.\n"); + return -1; + } + if (read == 0) + break; + + size += read; + if (size >= max_size) { + fprintf(stderr, "Too much panicinfo data in stdin.\n"); + return -1; + } + } + + return size; +} + +int parse_panic_info(const char *data, size_t size) +{ + /* Size of the panic information "header". */ + const size_t header_size = 4; + /* Size of the panic information "trailer" (struct_size and magic). */ + const size_t trailer_size = sizeof(struct panic_data) - + offsetof(struct panic_data, struct_size); + + struct panic_data pdata = { 0 }; + size_t copy_size; + + if (size < (header_size + trailer_size)) { + fprintf(stderr, "ERROR: Panic data too short (%zd).\n", size); + return -1; + } + + if (size > sizeof(pdata)) { + fprintf(stderr, + "WARNING: Panic data too large (%zd > %zd). " + "Following data may be incorrect!\n", + size, sizeof(pdata)); + copy_size = sizeof(pdata); + } else { + copy_size = size; + } + /* Copy the data into pdata, as the struct size may have changed. */ + memcpy(&pdata, data, copy_size); + /* Then copy the trailer in position. */ + memcpy((char *)&pdata + (sizeof(struct panic_data) - trailer_size), + data + (size - trailer_size), trailer_size); + + /* + * We only understand panic data with version <= 2. Warn the user + * of higher versions. + */ + if (pdata.struct_version > 2) + fprintf(stderr, + "WARNING: 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, + "WARNING: Incorrect panic magic (%d). " + "Following data may be incorrect!\n", + pdata.magic); + + if (pdata.struct_size != size) + fprintf(stderr, + "WARNING: Panic struct size inconsistent (%u vs %zd). " + "Following data may be incorrect!\n", + pdata.struct_size, size); + + 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); + case PANIC_ARCH_RISCV_RV32I: + return parse_panic_info_rv32i(&pdata); + default: + fprintf(stderr, "ERROR: Unknown architecture (%d).\n", + pdata.arch); + break; + } + return -1; +} |