當前位置:
首頁 > 知識 > Linux內核崩潰panic信息反向解析和保存在文件系統目錄

Linux內核崩潰panic信息反向解析和保存在文件系統目錄

環境

在linux-2.6版本中panic信息保存在crashlog buffer內存中,且沒有保存列印數據的屬性和額外信息,這樣在讀出crashlog buffer數據就與終端列印信息一致,但是在內核版本linux-4.1中有添加額外的列印屬性數據,導致讀出crashlog buffer數據顯示亂碼且多出很多數據;查看printk文件可知,高版本中添加了額外的列印屬性信息保存,所以要顯示或者保存的話需要反向解析並提出額外的屬性數據;

列印

亂碼顯示:

正常顯示:

代碼

printk列印後保存log_store函數

/* insert record into the buffer, discard old ones, update heads */

static int log_store(int facility, int level,

enum log_flags flags, u64 ts_nsec,

const char *dict, u16 dict_len,

const char *text, u16 text_len)

{

struct printk_log *msg;

u32 size, pad_len;

u16 trunc_msg_len = 0;

/* number of "" padding bytes to next message */

size = msg_used_size(text_len, dict_len, &pad_len);

if (log_make_free_space(size)) {

/* truncate the message if it is too long for empty buffer */

size = truncate_msg(&text_len, &trunc_msg_len,

&dict_len, &pad_len);

/* survive when the log buffer is too small for trunc_msg */

if (log_make_free_space(size))

return 0;

}

if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) {

/*

* This message + an additional empty header does not fit

* at the end of the buffer. Add an empty header with len == 0

* to signify a wrap around.

*/

memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));

log_next_idx = 0;

}

/* fill message 保存額外信息數據*/

msg = (struct printk_log *)(log_buf + log_next_idx);

memcpy(log_text(msg), text, text_len);

msg->text_len = text_len;

if (trunc_msg_len) {

memcpy(log_text(msg) + text_len, trunc_msg, trunc_msg_len);

msg->text_len += trunc_msg_len;

}

memcpy(log_dict(msg), dict, dict_len);

msg->dict_len = dict_len;

msg->facility = facility;

msg->level = level & 7;

msg->flags = flags & 0x1f;

if (ts_nsec > 0)

msg->ts_nsec = ts_nsec;

else

msg->ts_nsec = local_clock();

memset(log_dict(msg) + dict_len, 0, pad_len);

msg->len = size;

/* insert message */

log_next_idx += msg->len;

log_next_seq++;

return msg->text_len;

}

去掉額外數據解析代碼

msg=log_buf;

log_buf_tmp=log->buffer;

while(count < log_end)

{

msg_tmp = (struct printk_log *)msg;

memcpy(log_buf_tmp, log_text(msg), msg_tmp->text_len);

log_buf_tmp[msg_tmp->text_len] = "
";

log_buf_tmp+=(msg_tmp->text_len+1);

msg+=msg_tmp->len;

count+=msg_tmp->len;

}

完整代碼

#include <linux/slab.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/string.h>

#include <linux/mm.h>

#include <linux/syscalls.h>

#include <asm/unistd.h>

#include <asm/uaccess.h>

#define XD_CRASHLOG_FILE "/vdr/crashlog"

extern char *log_buf_addr_get(void);

extern unsigned int log_buf_len_get(void);

extern unsigned int log_next_idx_get(void);

struct logbuffer{

int buf_len;

char *buffer;

};

struct printk_log {

u64 ts_nsec; /* timestamp in nanoseconds */

u16 len; /* length of entire record */

u16 text_len; /* length of text buffer */

u16 dict_len; /* length of dictionary buffer */

u8 facility; /* syslog facility */

u8 flags:5; /* internal record flags */

u8 level:3; /* syslog level */

};

static char *log_text(char *msg)

{

return msg + sizeof(struct printk_log);

}

static int get_logbuffer(struct logbuffer *log)

{

char *log_buf;

char *log_buf_tmp;

unsigned int log_size;

unsigned int log_end;

char *msg;

struct printk_log *msg_tmp;

unsigned int count=0;

log_buf = (char *)log_buf_addr_get();

if(NULL == log_buf)

{

printk("ERROR:log_buf_addr_get is NULL, return -1
");

return -1;

}

log_size = log_buf_len_get();//Get syslog buffer cache, this system is 32k

log_end = log_next_idx_get();

log->buf_len = log_end; //We save all log

log->buffer = (char *)kzalloc(log->buf_len, GFP_KERNEL);

if(NULL == log->buffer){

printk("%s:Can"t kmalloc, fail
",__func__);

return -2;

}

msg=log_buf;

log_buf_tmp=log->buffer;

while(count < log_end)

{

msg_tmp = (struct printk_log *)msg;

memcpy(log_buf_tmp, log_text(msg), msg_tmp->text_len);

log_buf_tmp[msg_tmp->text_len] = "
";

log_buf_tmp+=(msg_tmp->text_len+1);

msg+=msg_tmp->len;

count+=msg_tmp->len;

}

return 0;

}

static void put_logbuffer(struct logbuffer *log)

{

kfree(log->buffer);

}

void xd_store_crash(void)

{

struct logbuffer log;

struct file *fp;

mm_segment_t fs;

loff_t pos;

int ret=-1;

if(get_logbuffer(&log) < 0)

{

printk("get_logbuffer failed!");

return;

}

fp = filp_open(XD_CRASHLOG_FILE, O_RDWR | O_CREAT, 0644);

if (IS_ERR(fp))

{

printk(KERN_ERR "open crashlog file error,return!
");

put_logbuffer(&log);

return;

}

fs = get_fs();

set_fs(KERNEL_DS);

pos = 0;

ret=vfs_write(fp, log.buffer, log.buf_len, &pos);

if(ret<0)

{

printk("xd_store_crash vfs_write failed,ret=%d
",ret);

}

vfs_fsync(fp, 0);

set_fs(fs);

filp_close(fp, NULL);

put_logbuffer(&log);

return;

}

EXPORT_SYMBOL(xd_store_crash);

MODULE_DESCRIPTION("CRASHLOG DRIVER");

MODULE_AUTHOR("xxx@qq.com");

手動觸發panic

echo c > /proc/sysrq-trigger,需要root許可權,參考鏈接:https://www.52os.net/articles/linux-force-kernel-panic-1.html

Linux內核崩潰panic信息反向解析和保存在文件系統目錄

打開今日頭條,查看更多精彩圖片
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

jsx遇到template-directive
Linux內存布局

TAG:程序員小新人學習 |