调试技术

Klogd&&Syslogd

1>  所有系统信息是输出到ring buffer中去的.dmesg所显示的内容也是从ring buffer中读取的.

2> LINUX系统中/etc/init.d/sysklogd会启动2个守护进程:Klogd&&Syslogd

3> klogd是负责读取内核信息的,有2种方式:

            syslog()系统调用

            直接的对/proc/kmsg进行读取(再这提一下,/proc/kmsg是专门输出内核信息的地方)

4>   Klogd的输出结果会传送给syslogd进行处理,syslogd会根据/etc/syslog.conf的配置把log 信息输出到/var/log/下的不同文件中.

printk

日志级别字符串:KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG. printk默认级别是DEFAULT_MESSAGE_LOGLEVEL(在kernel/printk.c中定义)。当优先级小于console_loglevel消息才会显示出来。

宏定义中##和#的作用

 ##是一个连接符号,用于把参数连在一起,例如: 
            > #define  FOO(arg)   my##arg 
            > FOO(abc)         相当于   myabc      

 #是“字符串化”的意思。出现在宏定义中的#是把跟在后面的参数转换成一个字符串,例如: 
            > #define STRCPY(dst, src)   strcpy(dst, #src)         则 
            > STRCPY(buff, abc)         相当于   strcpy(buff, "abc") 

#undef PDEBUG             /* undef it, just in case */
#ifdef SCULLC_DEBUG
#  ifdef __KERNEL__
     /* This one if debugging is on, and kernel space */
#    define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullc: " fmt, ## args)
#  else
     /* This one for user space */
#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#  endif
#else
#  define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif

Makefie

ifeq ($(DEBUG),y)
  DEBFLAGS = -O -g -DSCULLC_DEBUG # "-O" is needed to expand inlines, -D can remove space
else
  DEBFLAGS = -O2
endif

CFLAGS += $(DEBFLAGS) -I$(LDDINC)

有些进程在遇到失败后会不停的重试,这样会造成巨量输出,并可能在控制台设备较慢时独占CPU。printk_ratelimit可以控制一定间隔打印。 

if(printk_ratelimit())
    printk(KERN_NOTICE "The printer is still on fire\n");

//打印设备编号,下面两个函数都可以
int print_dev_t(char *buffer, dev_t dev);
char *format_dev_t(char *buffer, dev_t dev);

使用/proc文件系统

/proc是由软件创建的文件系统,/proc下面每个文件都绑定一个内核函数,用户读取其中文件时,该函数动态的生成文件的内容。创建一个只读文件时,驱动程序需要实现一个函数,用于读取文件时生成数据。当进程读取 这个文件时,读取请求会通过函数发送到驱动程序模块。当进程读取/proc文件时,内核会分配一个内存页,驱动程序可以通过其将数据返回给用空间。写好read_proc函数就要把它和/proc入口连接起来,通过create_proc_read_entry实现。卸载模块通过remove_proc_entry实现。

注意:删除调用可能在文件正在使用时发生,因为/proc入口项不存在关联的使用者,因此对这些文件的使用不会作用到模块的引用计数上。

int (*read_proc)(char *page, char **start, off_t offset, int count, int *eof, void *data);
//在scull中就是scullc_read_procmem, start返回实际数据写到内存页哪个位置。
//第一个参数是创建的文件名称,第三个是该文件所在目录,NULL表示在/proc根目录下
//第5个参数为void *data 是传给第四个参数执行的函数
create_proc_read_entry("scullcmem", 0 /*mode, 0表示系统默认权限*/, NULL, scullc_read_procmem, NULL);
remove_proc_entry("scullmen", NULL /*parent dir*/);
int scullc_read_procmem(char *buf, char **start, off_t offset,
                   int count, int *eof, void *data)
{
	int i, j, quantum, qset, len = 0;
	int limit = count - 80; /* Don't print more than this */
	struct scullc_dev *d;

	*start = buf;
	for(i = 0; i < scullc_devs; i++) {
		d = &scullc_devices[i];
		if (down_interruptible (&d->sem))
			return -ERESTARTSYS;
		qset = d->qset;  /* retrieve the features of each device */
		quantum=d->quantum;
		len += sprintf(buf+len,"\nDevice %i: qset %i, quantum %i, sz %li\n",
				i, qset, quantum, (long)(d->size));
		for (; d; d = d->next) { /* scan the list */
			len += sprintf(buf+len,"  item at %p, qset at %p\n",d,d->data);
			scullc_proc_offset (buf, start, &offset, &len);
			if (len > limit)
				goto out;
			if (d->data && !d->next) /* dump only the last item - save space */
				for (j = 0; j < qset; j++) {
					if (d->data[j])
						len += sprintf(buf+len,"    % 4i:%8p\n",j,d->data[j]);
					scullc_proc_offset (buf, start, &offset, &len);
					if (len > limit)
						goto out;
				}
		}
	  out:
		up (&scullc_devices[i].sem);
		if (len > limit)
			break;
	}
	*eof = 1;
	return len;
}

猜你喜欢

转载自blog.csdn.net/qq_23084801/article/details/81455308
今日推荐