环境
在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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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("[email protected]");
手动触发panic
echo c > /proc/sysrq-trigger,需要root权限,参考链接:https://www.52os.net/articles/linux-force-kernel-panic-1.html