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()

 

posted @ 2020-12-25 13:37  smilingsusu  阅读(984)  评论(0编辑  收藏  举报