printk ist eine der am häufigsten verwendeten Debugging-Funktionen im Linux-Kernel. Sie wird verwendet, um Debugging-Informationen an den Kernel-Puffer oder die Konsole auszugeben, z. B. den Wert von Variablen, den Ausführungsfluss von Funktionen, die Fehlerursache usw. Der Vorteil von printk besteht darin, dass es einfach und benutzerfreundlich ist und keine zusätzliche Ausrüstung oder Treiber erfordert. Die Implementierung von printk umfasst Konzepte wie Kernel-Puffer, Protokollebenen und formatierte Zeichenfolgen. In diesem Artikel stellen wir die Prinzipien und Methoden von printk, einer Linux-Kernel-Debugging-Technologie, vor und veranschaulichen deren Verwendung und Vorsichtsmaßnahmen anhand von Beispielen.
Unter den Kernel-Debugging-Technologien ist die Verwendung von printk die einfachste. Die Verwendung ähnelt der Verwendung von printf in C-Sprachanwendungen. In der Anwendung ist sie auf die Bibliothek in stdio.h angewiesen Da es keine solche Bibliothek gibt, erfordert die Verwendung dieses printk im Linux-Kernel ein gewisses Verständnis der Kernel-Implementierung.
Der Unterschied zwischen printf und printk: printk fügt am Anfang Zeichen im Stil „“ hinzu. Der Bereich von N liegt zwischen 0 und 7 und gibt die Ebene dieser Informationen an.
Wenn n in printk(""......);
Initialisieren Sie die Konsolenprotokollebene auf 7 in der Kerneldatei Printk.c (Kernel).
/* 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 */ };
# cat /proc/sys/kernel/printk
7 4 1 7
7 4 1 7 darunter entsprechen: console_loglevel, default_message_loglevel, Minimum_console_loglevel, default_console_loglevel
#echo „1 4 1 7“>/proc/sys/kernel/printk Ändern Sie diese vier Werte. Wenn console_loglevel auf 1 gesetzt ist, werden alle Debugging-Informationen gedruckt.
In der Kernel-Datei: Kernel.h (includelinux) sind 8 Namensebenen von 0 bis 7 definiert
#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])
Verwenden Sie printk:
① printk(KERN_WARNING"there is a warning here!\n");//注意,中间没有逗号间隔。 ② printk(KERN_DEBUG"%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
In ① und ② müssen wir die Daten im Puffer log_buf anzeigen, um die gedruckten Informationen zu sehen. Sie müssen den Befehl #dmesg
verwenden#``# 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)................................
Sie können cat /proc/kmsg& auch verwenden, um im Hintergrund zu laufen und Debugging-Informationen in Echtzeit auszudrucken. In ② entsprechen __FILE__, FUNCTION und __LINE__ jeweils dieser Datei, dieser Funktion und welcher Zeile. Sehr praktisch.
# 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
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); }
Die Ausgabefunktion der seriellen Schnittstelle ruft die Funktion s3c24xx_serial_console_putchar auf
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 //串口设置函数 };
Diese Funktion hängt mit der Hardware zusammen, um zu sehen, ob die Daten Byte für Byte gesendet wurden. Der s3c2440-Controller sendet die Daten automatisch
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); }
__setup("console=", console_setup); static int __init console_setup(char *str) { ........ add_preferred_console(name, idx, options); }
Im folgenden register_console(&s3c24xx_serial_console); wird die Struktur s3c24xx_serial_console mit den Geräten im Array console_cmdline verglichen.
①Der geparste Name ist S3C24XX_SERIAL_NAME, also „ttySAC“, und der Name im Befehl in console_cmdline ist ebenfalls „ttySAC“
②Der Indexindex in der Struktur s3c24xx_serial_console ist -1, was bedeutet, dass der Index im Befehlszeilenparameter „console=ttySAC0“ verwendet wird, Index = 0
Durch diesen Artikel haben wir die Prinzipien und Methoden von printk kennengelernt, einer Linux-Kernel-Debugging-Technologie, die zum Debuggen und Ausgeben des Kernels verwendet werden kann. Wir sollten die geeignete Methode basierend auf den tatsächlichen Anforderungen auswählen und einige Grundprinzipien befolgen, z. B. die Verwendung der richtigen Protokollebene, die Verwendung der richtigen Formatzeichenfolge, die Verwendung der richtigen Ausgabefunktion usw. Printk ist eine der einfachsten und effektivsten Debugging-Funktionen im Linux-Kernel. Sie kann Feedback und Überwachung des Kernels realisieren und auch die Wartbarkeit und Skalierbarkeit des Kernels verbessern. Ich hoffe, dass dieser Artikel für Sie hilfreich und inspirierend sein kann.
Das obige ist der detaillierte Inhalt vonDebug-Ausgabefunktion im Linux-Kernel: Ausführliche Erklärung von printk. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!