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 '\0' 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] = '\n';
		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\n");
		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\n",__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] = '\n';
		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!\n"); 
		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\n",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

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值