简介(基于 linux)

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

嵌入式进阶教程分门别类整理好了,看的时候十分方便,由于内容较多,这里就截取一部分图吧。

printk格式_printk_printk查看

需要的朋友私信【内核】即可领取。

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

当(“”……);中的n < 时候,这个信息才能被打印出来。

1、在内核文件中.c () 中初始化这个 的级别为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[4] = { 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//查看等级配置:

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

其中的 7 4 1 7,分别对应与:、evel、evel、evel

3、修改等级配置:

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

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

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

#define   KERN_EMERG   "" /* system is unusable */
#define KERN_ALERT "" /* acTIon must be taken immediately */
#define KERN_CRIT "" /* criTIcal condiTIons */
#define KERN_ERR "" /* error condiTIons */
#define KERN_WARNING "" /* warning conditions */
#define KERN_NOTICE "" /* normal but significant condition*/
#define KERN_INFO "" /* informational*/
#define KERN_DEBUG "" /* 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])

使用:

① (“there is a here!n”);//注意,中间没有逗号间隔。

② (“%s %s %dn”, , , );

在①和②中,我们需要查看缓冲区中的数据,才能看到打印出来的信息。需要使用命令 #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& 后台运行,实时打印出调试信息。在②中,, , 分别对应的是那个文件,那个函数,第几行。非常实用。

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

5、串口与函数的关系:

printk vprintk vscnprintf //先把输出信息放入临时BUFFER     
 Copy the output into log_buf. // 把临时BUFFER里的数据稍作处理,再写入log_buf     
 // 比如printk("abc")会得到"abc", 再写入log_buf     
 // 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息
 // 调用硬件的write函数输出 release_console_sem call_console_drivers          
 //从log_buf得到数据,算出打印级别 _call_console_drivers if ((msg_log_level 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);}

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

static int s3c24xx_serial_initconsole(void){ 
                  register_console(&s3c24xx_serial_console); 
return 0;
}
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 //串口设置函数
};

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

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的=如果在linux中被识别出来是串口0的,在//.c中有一下代码,

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

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

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

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

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

———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666

声明:1、本内容转载于网络,版权归原作者所有!2、本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。3、本内容若侵犯到你的版权利益,请联系我们,会尽快给予删除处理!