DUMP kernel log_buf以及解析log_buf字符的办法。
多数情况下,Linux出问题时都可以打印出错误log,但是有些情形却又不能,这时就要自己来dump出还没来得及打印的log了。
1. dump log_buf
a. 需要找到 _text字段的虚拟地址,可以 nm vmlinux | grep _text
b. 需要找到 _log_buf字段的虚拟地址,可以 nm vmlinux | grep _log_buf
c. 需要找到kernel在内存的起始位置 PA。
找到以上部分,那么可以算出_log_buf在物理内存中的地址了。
PA_log_buf = _log_buf - _text + PA
一般来说,_text会有0x8000/0x80000的偏移,如果要算上的话,PA也会有这个偏移,要一同算上比如:
c0dd480c b __log_buf
PA_log_buf = c0dd480c - c0008000 + 20208000
还有另外一种情况就是,我们在bootargs中添加了log_buf_len,这时会使用新的地址,_log_buf就可能不适用了。
这时需要找到 log_buf 的地址,然后看这个地址上的值是多少,新的log_buf会保存在这里。
2.解析dump出来的数据。
#! /usr/bin/python import sys import os from ctypes import * # struct printk_log { # u64 ts_nsec; # u16 len; # u16 text_len; # u16 dict_len; # u8 facility; # u8 flags:5; # u8 level:3; # } class PHEAD(LittleEndianStructure): _pack_ = 1 _fields_ = [ ('ts_nsec', c_uint64), ('len', c_uint16), ('text_len',c_uint16), ('dict_len',c_uint16), ('facility',c_uint8), ('flags', c_uint8,5), ('level', c_uint8,3), ] def encode(self): return string_at(addressof(self), sizeof(self)) def decode(self, data): memmove(addressof(self), data, sizeof(self)) return len(data) headsize = 16 if __name__ == "__main__": fd = open(sys.argv[1], "rb") line = fd.read(headsize) while line: ss = PHEAD() ss.decode(line) if (ss.level > 7 or ss.len > 1024 or ss.text_len > ss.len or ss.len == 0 or ss.text_len == 0): fd.seek(-15, 1) line = fd.read(headsize) if (len(line) != headsize): break continue tel = fd.tell() stream = fd.read(ss.text_len) check_byte = True for i in range(ss.text_len): if (ord(stream[i]) > 0x7f or ord(stream[i]) < 0x10): fd.seek(tel, 0) fd.seek(-15, 1) line = fd.read(headsize) check_byte = False break print ("[ %05d.%06d ] ")%(ss.ts_nsec/1000000000,(ss.ts_nsec%1000000000)/1000), print stream if (check_byte == False): continue offset = 4 - ss.len%4 if (offset >= 4): offset = 0 offset += ss.len - ss.text_len - headsize if (offset < 0 ): offset = 0 fd.seek(offset, 1) line = fd.read(headsize) fd.close()