原创博客:欢迎转载,转载请注明出处 http://www.cnblogs.com/veryStrong/p/6218383.html

1、简介(基于s3c2440 linux)

在内核调试技术之中,最简单的就是printk的使用了,它的用法和C语言应用程序中的printf使用类似,在应用程序中依靠的是stdio.h中的库,而在linux内核中没有这个库,所以在linux内核中,使用这个printk就要对内核的实现有一定的了解。

printf和printk的区别:printk会在开头处加上"<N>"样式的字符,N的范围是0~7,表示这个信息的级别。

当printk("<n>"......);中的n < console_loglevel 时候,这个信息才能被打印出来。 

在内核文件中Printk.c (kernel) 中初始化这个console_loglevel 的级别为7.

/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ /* We show everything that is MORE important than this.. */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */int console_printk[] = {
DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
};

2、通过命令cat /proc/sys/kernel/printk查看等级配置:

# cat /proc/sys/kernel/printk
7 4 1 7

其中的 7 4 1 7,分别对应与:console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel

3、修改等级配置:

#echo "1 4 1 7">/proc/sys/kernel/printk 改变这四个值,当被console_loglevel设置为1的时候,所有的调试信息都会被打印出来。

4、printk函数记录的名称及使用

在内核文件:Kernel.h (include\linux) 定义了0~7这8个级别的名称

#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 */
#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])

使用printk:

① printk(KERN_WARNING"there is a warning here!\n");//注意,中间没有逗号间隔。

② printk(KERN_DEBUG"%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

在①和②中,我们需要查看缓冲区log_buf中的数据,才能看到打印出来的信息。需要使用命令 #dmesg

#
# dmesg
Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #19 Thu Dec 8 14:06:03 CST 2016
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
Machine: SMDK2440
Memory policy: ECC disabled, Data cache writeback
On node 0 totalpages: 16384
DMA zone: 128 pages used for memmap
DMA zone: 0 pages reserved
DMA zone: 16256 pages, LIFO batch:3
Normal zone: 0 pages used for memmap
CPU S3C2440A (id 0x32440001)
................................

还可以使用 cat /proc/kmsg& 后台运行,实时打印出调试信息。在②中,__FILE__, __FUNCTION__, __LINE__分别对应的是那个文件,那个函数,第几行。非常实用。

# cat /proc/kmsg&
# ./firstdrvtest on
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 23
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 25
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 27
# ./firstdrvtest off
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 23
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 25
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 27

  

 

5、串口与printk函数的关系:

printk
vprintk
vscnprintf //先把输出信息放入临时BUFFER
     // Copy the output into log_buf.
    // 把临时BUFFER里的数据稍作处理,再写入log_buf
    // 比如printk("abc")会得到"<4>abc", 再写入log_buf
    // 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息 // 调用硬件的write函数输出
release_console_sem
call_console_drivers
          //从log_buf得到数据,算出打印级别
_call_console_drivers
if ((msg_log_level < console_loglevel)//如果级别足够则打印
__call_console_drivers
con->write //con是console_drivers链表中的项,对用具体的输出函数 在drives/serial/s3c2410.c中查看

在该函数中注册一个console结构体

static void s3c24xx_serial_console_write(struct console *co, const char *s,
unsigned int count)
{
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}

串口输出函数,会调用s3c24xx_serial_console_putchar函数

static int s3c24xx_serial_initconsole(void)
{
...........................
register_console(&s3c24xx_serial_console);
return ;
}
static struct console s3c24xx_serial_console =
{
.name = S3C24XX_SERIAL_NAME,//这个宏被定义为:TTYSAC
.device = uart_console_device, //init进程,用户程序打开/dev/console的时候会调用
.flags = CON_PRINTBUFFER,//打印还没有初始化化console前保存在log_buf里面的数据
.index = -1,//选择那个串口,由uboot中的命令决定
.write = s3c24xx_serial_console_write,//控制台输出函数
.setup = s3c24xx_serial_console_setup //串口设置函数
};

这个函数和硬件相关,读取寄存器,看数据是否被发送完成,最后将数据一个字节一个字节的写入寄存器,s3c2440的串口控制器会自动把数据发送出去

static void s3c24xx_serial_console_putchar(struct uart_port *port, int ch)

{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch);
}

uboot的console=ttySAC0如果在linux中被识别出来是串口0的,在/kernel/printk.c中有一下代码,

__setup("console=", console_setup);

static int __init console_setup(char *str)
{
........
  add_preferred_console(name, idx, options);
}

内核开始执行时,会发现“console=...”的命令行参数时候,就会调用console_setup函数进行数据解析,对于命令行参数"console=ttySAC0",会解析出:设备名(name)为ttySAC,索引index为0,这些信息被保存在类型为console_cmdline、名称为console_cmdline的全局数组中(注意:数组名和数组的类型相同)

在后面的register_console(&s3c24xx_serial_console);的时候,会将s3c24xx_serial_console结构和console_cmdline数组中的设备进行比较。

①解析出来的name为S3C24XX_SERIAL_NAME 既“ttySAC”,而console_cmdline中的命令中的name也为“ttySAC”

②s3c24xx_serial_console结构体中的索引index为-1,表示使用命令行参数“console=ttySAC0”中的索引,index =  0

如果还想了解uboot的console=ttySAC0如果在linux中被识别出来是串口0的,可以看《嵌入式linux开发完全手册》Page 365

linux内核调试技术之printk的更多相关文章

  1. Linux内核调试技术——jprobe使用与实现

    前一篇博文介绍了kprobes的原理与kprobe的使用与实现方式,本文介绍kprobes中的另外一种探測技术jprobe.它基于kprobe实现,不能在函数的任何位置插入探測点,仅仅能在函数的入口处 ...

  2. linux内核调试技术之修改内核定时器来定位系统僵死问题

    1.简介 在内核调试中,会经常出现内核僵死的问题,也就是发生死循环,内核不能产生调度.导致内核失去响应.这种情况下我们可以采用修改系统内核中的系统时钟的中断来定位发生僵死的进程和函数名称.因为内核系统 ...

  3. linux内核调试技术之自构proc

    1.简介 在上一篇中,在内核中使用printk可以讲调试信息保存在log_buf缓冲区中,可以使用命令 #cat /proc/kmsg  将缓冲区的数区的数数据打印出来,今天我们就来研究一下,自己写k ...

  4. Linux内核调试的方式以及工具集锦【转】

    转自:https://blog.csdn.net/gatieme/article/details/68948080 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原 ...

  5. Linux内核调试的方式以及工具集锦

    原文:https://blog.csdn.net/gatieme/article/details/68948080 CSDN GitHubLinux内核调试的方式以及工具集锦 LDD-LinuxDev ...

  6. Linux kprobe调试技术使用

    kprobe调试技术是为了便于跟踪内核函数执行状态所设计的一种轻量级内核调试技术. 利用kprobe技术,可以在内核绝大多数函数中动态插入探测点,收集调试状态所需信息而基本不影响原有执行流程. kpr ...

  7. 嵌入式Linux的调试技术

    本节我们研究嵌入式Linux的调试技术,对于复杂的Linux驱动及HAL等程序库,需要使用各种方法对其进行调试.刚开始讲了打印内核调试信息:printk,这个函数的用法与printf函数类似,只不过p ...

  8. 第十章 嵌入式Linux的调试技术

    对调试工具进行简介.Linux中提供了一类工具,通过这些工具可以逐行跟踪程序的代码,用于测试用户空间程序的gdb.gdbserver和调试内核空间程序的kgdb. 用gdb调试用户空间程序:gdb可跟 ...

  9. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

随机推荐

  1. 论:开发者信仰之“天下IT是一家“(Java .NET篇)

    比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...

  2. PHP搭建大文件切割分块上传功能

    背景 在网站开发中,文件上传是很常见的一个功能.相信很多人都会遇到这种情况,想传一个文件上去,然后网页提示"该文件过大".因为一般情况下,我们都需要对上传的文件大小做限制,防止出现 ...

  3. Visaul Studio 常用快捷键的动画演示

    从本篇文章开始,我将会陆续介绍提高 VS 开发效率的文章,欢迎大家补充~ 在进行代码开发的时候,我们往往会频繁的使用键盘.鼠标进行协作,但是切换使用两种工具会影响到我们的开发速度,如果所有的操作都可以 ...

  4. C# 多种方式发送邮件(附帮助类)

    因项目业务需要,需要做一个发送邮件功能,查了下资料,整了整,汇总如下,亲测可用- QQ邮箱发送邮件 #region 发送邮箱 try { MailMessage mail = new MailMess ...

  5. Linux常用命令操作

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  6. CSharpGL(33)使用uniform块来优化对uniform变量的读写

    CSharpGL(33)使用uniform块来优化对uniform变量的读写 +BIT祝威+悄悄在此留下版了个权的信息说: Uniform块 如果shader程序变得比较复杂,那么其中用到的unifo ...

  7. 页面布局class常见命名规范

    头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left rig ...

  8. BPM生产安全管理解决方案分享

    一.方案概述生产安全管理是企业生产管理的重要组成部分,组织实施好企业安全管理规划.指导.检查和决策,保证生产处于最佳安全状态是安全管理的重要内容和职责.H3 BPM企业生产安全管理解决方案是一套专门为 ...

  9. android手机登录时遇到“QQ安全登录发现病毒”解决

    android手机作为开源系统非常容易感染病毒,有时候我们会经常遇到手机QQ登录时检测到app被感染,一般情况是由手机感染病毒所引起的,安装腾讯管家后只能检测病毒和卸载感染病毒的软件,不能清除病毒.解 ...

  10. 使用四元数解决万向节锁(Gimbal Lock)问题

    问题 使用四元数可以解决万向节锁的问题,但是我在实际使用中出现问题:我设计了一个程序,显示一个三维物体,用户可以输入绕zyx三个轴进行旋转的指令,物体进行相应的转动. 由于用户输入的是绕三个轴旋转的角 ...