1#!/usr/bin/env python3 2# 3# Copyright (c) 2020 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import logging 8import struct 9 10 11# Note: keep sync with C code 12COREDUMP_HDR_ID = b'ZE' 13COREDUMP_HDR_VER = 1 14LOG_HDR_STRUCT = "<ccHHBBI" 15LOG_HDR_SIZE = struct.calcsize(LOG_HDR_STRUCT) 16 17COREDUMP_ARCH_HDR_ID = b'A' 18LOG_ARCH_HDR_STRUCT = "<cHH" 19LOG_ARCH_HDR_SIZE = struct.calcsize(LOG_ARCH_HDR_STRUCT) 20 21COREDUMP_MEM_HDR_ID = b'M' 22COREDUMP_MEM_HDR_VER = 1 23LOG_MEM_HDR_STRUCT = "<cH" 24LOG_MEM_HDR_SIZE = struct.calcsize(LOG_MEM_HDR_STRUCT) 25 26 27logger = logging.getLogger("parser") 28 29 30def reason_string(reason): 31 # Keep sync with "enum k_fatal_error_reason" 32 ret = "(Unknown)" 33 34 if reason == 0: 35 ret = "K_ERR_CPU_EXCEPTION" 36 elif reason == 1: 37 ret = "K_ERR_SPURIOUS_IRQ" 38 elif reason == 2: 39 ret = "K_ERR_STACK_CHK_FAIL" 40 elif reason == 3: 41 ret = "K_ERR_KERNEL_OOPS" 42 elif reason == 4: 43 ret = "K_ERR_KERNEL_PANIC" 44 45 return ret 46 47 48class CoredumpLogFile: 49 """ 50 Process the binary coredump file for register block 51 and memory blocks. 52 """ 53 54 def __init__(self, logfile): 55 self.logfile = logfile 56 self.fd = None 57 58 self.log_hdr = None 59 self.arch_data = list() 60 self.memory_regions = list() 61 62 def open(self): 63 self.fd = open(self.logfile, "rb") 64 65 def close(self): 66 self.fd.close() 67 68 def get_arch_data(self): 69 return self.arch_data 70 71 def get_memory_regions(self): 72 return self.memory_regions 73 74 def parse_arch_section(self): 75 hdr = self.fd.read(LOG_ARCH_HDR_SIZE) 76 _, hdr_ver, num_bytes = struct.unpack(LOG_ARCH_HDR_STRUCT, hdr) 77 78 arch_data = self.fd.read(num_bytes) 79 80 self.arch_data = {"hdr_ver" : hdr_ver, "data" : arch_data} 81 82 return True 83 84 def parse_memory_section(self): 85 hdr = self.fd.read(LOG_MEM_HDR_SIZE) 86 _, hdr_ver = struct.unpack(LOG_MEM_HDR_STRUCT, hdr) 87 88 if hdr_ver != COREDUMP_MEM_HDR_VER: 89 logger.error(f"Memory block version: {hdr_ver}, expected {COREDUMP_MEM_HDR_VER}!") 90 return False 91 92 # Figure out how to read the start and end addresses 93 ptr_fmt = None 94 if self.log_hdr["ptr_size"] == 64: 95 ptr_fmt = "QQ" 96 elif self.log_hdr["ptr_size"] == 32: 97 ptr_fmt = "II" 98 else: 99 return False 100 101 data = self.fd.read(struct.calcsize(ptr_fmt)) 102 saddr, eaddr = struct.unpack(ptr_fmt, data) 103 104 size = eaddr - saddr 105 106 data = self.fd.read(size) 107 108 mem = {"start": saddr, "end": eaddr, "data": data} 109 self.memory_regions.append(mem) 110 111 logger.info("Memory: 0x%x to 0x%x of size %d" % 112 (saddr, eaddr, size)) 113 114 return True 115 116 def parse(self): 117 if self.fd is None: 118 self.open() 119 120 hdr = self.fd.read(LOG_HDR_SIZE) 121 id1, id2, hdr_ver, tgt_code, ptr_size, flags, reason = struct.unpack(LOG_HDR_STRUCT, hdr) 122 123 if (id1 + id2) != COREDUMP_HDR_ID: 124 # ID in header does not match 125 logger.error("Log header ID not found...") 126 return False 127 128 if hdr_ver != COREDUMP_HDR_VER: 129 logger.error(f"Log version: {hdr_ver}, expected: {COREDUMP_HDR_VER}!") 130 return False 131 132 ptr_size = 2 ** ptr_size 133 134 self.log_hdr = { 135 "hdr_version": hdr_ver, 136 "tgt_code": tgt_code, 137 "ptr_size": ptr_size, 138 "flags": flags, 139 "reason": reason, 140 } 141 142 logger.info("Reason: {0}".format(reason_string(reason))) 143 logger.info(f"Pointer size {ptr_size}") 144 145 del id1, id2, hdr_ver, tgt_code, ptr_size, flags, reason 146 147 while True: 148 section_id = self.fd.read(1) 149 if not section_id: 150 # no more data to read 151 break 152 153 self.fd.seek(-1, 1) # go back 1 byte 154 if section_id == COREDUMP_ARCH_HDR_ID: 155 if not self.parse_arch_section(): 156 logger.error("Cannot parse architecture section") 157 return False 158 elif section_id == COREDUMP_MEM_HDR_ID: 159 if not self.parse_memory_section(): 160 logger.error("Cannot parse memory section") 161 return False 162 else: 163 # Unknown section in log file 164 logger.error(f"Unknown section in log file with ID {section_id}") 165 return False 166 167 return True 168