学习链接:https://xuesong.blog.csdn.net/article/details/109522945?spm=1001.2014.3001.5502
1. printk
printk简介
内核中的打印函数printk(), 通过 printk 可以打印变量或者寄存器的地址和值,printk函数中可以附加不同的日志级别或消息优先级
搜索函数,搜到以后,看函数原形
printk(打印级别 "内容")
printk(KERN_ERR "Fail%d",a);
printk(KERN_ERR "%s:%s:%d\n",__FILE__,__func__,__LINE__);
驱动在哪一个文件,哪一个函数,哪一行
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
查看内核打印级别 vi -t KERN_ERR
include/linux/printk.h
#define KERN_EMERG "<0>" /* system is unusable */(系统不用)
#define KERN_ALERT "<1>" /* action must be taken immediately */(被立即处理)
#define KERN_CRIT "<2>" /* critical conditions */(临界条件,临界资源)
#define KERN_ERR "<3>" /* error conditions */(出错)
#define KERN_WARNING "<4>" /* warning conditions */(警告)
#define KERN_NOTICE "<5>" /* normal but significant condition */(提示)
#define KERN_INFO "<6>" /* informational */(打印信息时候的级别)
#define KERN_DEBUG "<7>" /* debug-level messages */ (调试级别)
0 ------ 7
最高的 最低的
linux@ubuntu:~$ cat /proc/sys/kernel/printk 4 4 1 7
终端的级别 消息的默认级别 终端的最大级别 终端的最小级别
#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])
注意:只有当消息的级别大于终端级别,消息才会被显示
修改系统默认的级别
su root
echo 4 3 1 7 > /proc/sys/kernel/printk
虚拟机的默认情况
板子的默认情况:
修改开发板对应的打印级别
vi rootfs/etc/init.d/rcS
echo 4 3 1 7 > /proc/sys/kernel/printk
在rootfs/etc/init.d/rcS里面添加上以后再起板子,板子的级别就为如下:
安装驱动和卸载驱动时,消息会打印。
2.dump_stack
dump_stack() ,相信从事 Linux 内核或者驱动相关开发的同行对于此函数肯定不陌生。我们经常会用到此函数来对自己的代码进行 debug,可以快速帮助开发者理清函数调用流程,有些时候,只需要在终端上打印一下栈的回溯信息来帮助调试。 dump_stack() 这个函数只在终端上打印寄存器上下文和函数的跟踪线索。
if (!debug_check) {
printk(KERN_DEBUG “provide some information…/n”);
dump_stack();
}
printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
log_lvl, raw_smp_processor_id(), current->pid, current->comm,
print_tainted(), init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version); 以及
printk("[<%p>] %pS\n", (void *) ip, (void *) ip);
3.oops
oops是指Linux内核中的错误报告机制,全称为“Out of memory (OOM) killer Process Stopped(内存不足杀掉进程)”。当内核检测到意外的错误时,它会自动解锁已经持有的互斥锁,并打印一条错误消息,然后导致系统宕机。 使用oops的步骤如下: 1.设置内核参数,使它在oops发生时自动记录到系统日志中。可以通过设置/sys/module/kernel /parameters/panic_on_oops参数来实现,将其设置为1。 2. 当oops发生时,Linux内核会记录错误信息,并将它们写入到系统日志中。可以通过使用dmesg命令来查看最近的错误消息,或者通过查看/var/log/messages文件来查看完整信息。 3. 使用oops解码和分析工具,如crash或者ksymoops来处理错误信息,并诊断和修复问题。 4. 如果需要更详细的信息来了解系统的状态和内核操作,可以使用Kdump来收集内存转储,并进行off-line分析。 总之,oops是一种非常重要的工具,可以帮助开发人员和系统管理员快速诊断和修复故障,提高系统的可靠性和稳定性。
36 ssize_t faulty_read(struct file *filp, char __user *buf,
37 size_t count, loff_t *pos)
38 {
39 int ret;
40 char stack_buf[4];
41
42 /* Let’s try a buffer overflow */
43 memset(stack_buf, 0xff, 20); //出错
44 if (count > 4)
45 count = 4; /* copy 4 bytes to the user */
46 ret = copy_to_user(buf, stack_buf, count);
47 if (!ret)
48 return count;
49 return ret;
50 }
/
00000000 <faulty_read>:
0: e1a0c00d mov ip, sp
4: e92dd870 stmdb sp!, {r4, r5, r6, fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4 ; 0×4
c: e24dd004 sub sp, sp, #4 ; 0×4,这里为stack_buf[]在栈上分配1个字的空间,局部变量ret使用寄存器存储,因此就不在栈上分配空间了
10: e24b501c sub r5, fp, #28 ; 0x1c
14: e1a04001 mov r4, r1
18: e1a06002 mov r6, r2
1c: e3a010ff mov r1, #255 ; 0xff
20: e3a02014 mov r2, #20 ; 0×14
24: e1a00005 mov r0, r5
28: ebfffffe bl 28 <faulty_read+0×28> //这里在调用memset
78: e89da878 ldmia sp, {r3, r4, r5, r6, fp, sp, pc}