Heim  >  Artikel  >  System-Tutorial  >  Debug-Ausgabefunktion im Linux-Kernel: Ausführliche Erklärung von printk

Debug-Ausgabefunktion im Linux-Kernel: Ausführliche Erklärung von printk

PHPz
PHPznach vorne
2024-02-14 20:33:141238Durchsuche

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.

Debug-Ausgabefunktion im Linux-Kernel: Ausführliche Erklärung von printk

1. Einführung (basierend auf s3c2440 Linux)

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 */
};

2. Überprüfen Sie die Levelkonfiguration mit dem Befehl cat /proc/sys/kernel/printk:

# 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

3. Ebenenkonfiguration ändern:

#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.

4. Der Name und die Verwendung von printk-Funktionsdatensätzen

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

5. Die Beziehung zwischen der seriellen Schnittstelle und der Druckfunktion:

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);
}

uboot’s console=ttySAC0, wenn es unter Linux als serieller Port 0 erkannt wird, gibt es den folgenden Code in /kernel/printk.c,

__setup("console=", console_setup);

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

Wenn der Kernel mit der Ausführung beginnt und der Befehlszeilenparameter „console=…“ gefunden wird, wird die Funktion console_setup zur Datenanalyse aufgerufen. Für den Befehlszeilenparameter „console=ttySAC0“ wird Folgendes analysiert: Der Gerätename (Name) ist ttySAC, der Indexindex ist 0 und diese Informationen werden in einem globalen Array vom Typ console_cmdline und dem Namen console_cmdline gespeichert (Hinweis: Der Array-Name und der Typ des Arrays sind identisch)

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen