GNU/Linux >> Linux Esercitazione >  >> Linux

Traccia dello stack del kernel alle righe del codice sorgente

Soluzione 1:

Non ho un ~=RHEL5 a portata di mano, quindi l'output mostrato è di Fedora 20, anche se il processo dovrebbe essere sostanzialmente lo stesso (il nome della funzione è cambiato).

Dovresti installare il kernel-debug-debuginfo appropriato pacchetto per il tuo kernel (assumendo RHEL o una distribuzione derivata). Questo pacchetto fornisce un vmlinux image (una versione non compressa del kernel):

# rpm -ql kernel-debug-debuginfo | grep vmlinux
/usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux

quell'immagine può essere utilizzata direttamente con gdb

# gdb /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux
GNU gdb (GDB) Fedora 7.7.1-13.fc20
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...
Reading symbols from /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux...done.
(gdb) disassemble link_path_walk
Dump of assembler code for function link_path_walk:
   0xffffffff81243d50 <+0>:     callq  0xffffffff817ea840 <__fentry__>
   0xffffffff81243d55 <+5>:     push   %rbp
   0xffffffff81243d56 <+6>:     mov    %rsp,%rbp
   0xffffffff81243d59 <+9>:     push   %r15
   0xffffffff81243d5b <+11>:    mov    %rsi,%r15
   0xffffffff81243d5e <+14>:    push   %r14
   0xffffffff81243d60 <+16>:    push   %r13
   0xffffffff81243d62 <+18>:    push   %r12
   0xffffffff81243d64 <+20>:    push   %rbx
   0xffffffff81243d65 <+21>:    mov    %rdi,%rbx
   0xffffffff81243d68 <+24>:    sub    $0x78,%rsp
   0xffffffff81243d6c <+28>:    mov    %gs:0x28,%rax
   0xffffffff81243d75 <+37>:    mov    %rax,0x70(%rsp)
   0xffffffff81243d7a <+42>:    xor    %eax,%eax
   0xffffffff81243d7c <+44>:    movzbl (%rdi),%eax
   0xffffffff81243d7f <+47>:    cmp    $0x2f,%al
   ....

Puoi anche usare objdump(1) sul vmlinux immagine:

# objdump -rDlS /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux > vmlinux.out

I flag sono:

   -D
   --disassemble-all
       Like -d, but disassemble the contents of all sections, not just those expected to contain instructions.
   -r
   --reloc
       Print the relocation entries of the file.  If used with -d or -D, the relocations are printed interspersed with the
       disassembly.
   -S
   --source
       Display source code intermixed with disassembly, if possible.  Implies -d.
   -l
   --line-numbers
       Label the display (using debugging information) with the filename and source line numbers corresponding to the object
       code or relocs shown.  Only useful with -d, -D, or -r.

Puoi cercare la funzione qui:

ffffffff81243d50 <link_path_walk>:
link_path_walk():
/usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1729
 *
 * Returns 0 and nd will have valid dentry and mnt on success.
 * Returns error and drops reference to input namei data on failure.
 */
static int link_path_walk(const char *name, struct nameidata *nd)
{
ffffffff81243d50:       e8 eb 6a 5a 00          callq  ffffffff817ea840 <__entry_text_start>
ffffffff81243d55:       55                      push   %rbp
ffffffff81243d56:       48 89 e5                mov    %rsp,%rbp
ffffffff81243d59:       41 57                   push   %r15
ffffffff81243d5b:       49 89 f7                mov    %rsi,%r15
ffffffff81243d5e:       41 56                   push   %r14
ffffffff81243d60:       41 55                   push   %r13
ffffffff81243d62:       41 54                   push   %r12
ffffffff81243d64:       53                      push   %rbx
ffffffff81243d65:       48 89 fb                mov    %rdi,%rbx
ffffffff81243d68:       48 83 ec 78             sub    $0x78,%rsp
ffffffff81243d6c:       65 48 8b 04 25 28 00    mov    %gs:0x28,%rax
ffffffff81243d73:       00 00
ffffffff81243d75:       48 89 44 24 70          mov    %rax,0x70(%rsp)
ffffffff81243d7a:       31 c0                   xor    %eax,%eax
/usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1733
        struct path next;
        int err;

        while (*name=='/')
ffffffff81243d7c:       0f b6 07                movzbl (%rdi),%eax
ffffffff81243d7f:       3c 2f                   cmp    $0x2f,%al
ffffffff81243d81:       75 10                   jne    ffffffff81243d93 <link_path_walk+0x43>
ffffffff81243d83:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1734
                name++;
ffffffff81243d88:       48 83 c3 01             add    $0x1,%rbx
/usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1733
static int link_path_walk(const char *name, struct nameidata *nd)
{
        struct path next;
        int err;

        while (*name=='/')
....

e far corrispondere l'offset alla riga di codice effettiva.

Soluzione 2:

Dato un vmlinux non strippato con i simboli di debug (tipicamente inclusi nei pacchetti "linux-devel" o "linux-headers" che corrispondono alla tua versione del kernel), puoi usare il addr2line programma incluso con binutils per tradurre gli indirizzi in righe nei file sorgente.

Considera questa traccia delle chiamate:

Call Trace:
 [<ffffffff8107bf5d>] ? finish_task_switch+0x3d/0x120
 [<ffffffff815f3130>] __schedule+0x3b0/0x9d0
 [<ffffffff815f3779>] schedule+0x29/0x70
 [<ffffffff815f2ccc>] schedule_hrtimeout_range_clock.part.24+0xdc/0xf0
 [<ffffffff81076440>] ? hrtimer_get_res+0x50/0x50
 [<ffffffff815f2c6f>] ? schedule_hrtimeout_range_clock.part.24+0x7f/0xf0
 [<ffffffff815f2cf9>] schedule_hrtimeout_range_clock+0x19/0x60
 [<ffffffff815f2d53>] schedule_hrtimeout_range+0x13/0x20
 [<ffffffff811a8aa9>] poll_schedule_timeout+0x49/0x70
 [<ffffffff811aa203>] do_sys_poll+0x423/0x550
 [<ffffffff814eaf8c>] ? sock_recvmsg+0x9c/0xd0
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
 [<ffffffff811aa3fe>] SyS_poll+0x5e/0x100
 [<ffffffff816015d2>] system_call_fastpath+0x16/0x1b

Quindi l'indirizzo del chiamante in poll_select_copy_remaining può essere trovato con:

$ addr2line -e /tmp/vmlinux ffffffff811a8c50
/tmp/linux-3.15-rc8/fs/select.c:209

Soluzione 3:

  1. Installa kernel-debuginfo

  2. Scarica decode_stacktrace.sh che si trova nell'albero dei sorgenti del kernel.

  3. Rendi di nuovo utile l'output dello stack dump.

     # ./decode_stacktrace.sh /usr/lib/debug/lib/modules/`uname -r`/vmlinux /usr/lib/debug/lib/modules/4.1.12-112.14.14.el7uek.x86_64/ < ./trace > out
     # cat out
     [102820.087367] Call Trace:
     [102820.087371] dump_stack (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/lib/dump_stack.c:53)
     [102820.087375] warn_slowpath_common (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/kernel/panic.c:499)
     [102820.087378] warn_slowpath_null (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/kernel/panic.c:533)
     [102820.087380] af_alg_accept (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/include/net/sock.h:1689 /usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/crypto/af_alg.c:287)
     [102820.087382] alg_accept (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/crypto/af_alg.c:326)
     [102820.087385] SYSC_accept4 (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/net/socket.c:1485)
     [102820.087388] ? release_sock (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/net/core/sock.c:2415)
     [102820.087390] ? alg_setsockopt (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/crypto/af_alg.c:264)
     [102820.087393] SyS_accept (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/net/socket.c:1515)
     [102820.087395] system_call_fastpath (/usr/src/debug////////kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/arch/x86/kernel/entry_64.S:277)
     [102820.087397] ---[ end trace 1315ff0b8d6ff7d8 ]---
    
  4. Per una manciata di offset di funzioni, prova faddr2line che si trova anche nei sorgenti del kernel.

     $ wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/faddr2line
     $ bash faddr2line /usr/lib/debug/lib/modules/`uname -r`/vmlinux __do_softirq+0x92/0x320
     __do_softirq+0x92/0x320:
     ffs at arch/x86/include/asm/bitops.h:410
     (inlined by) __do_softirq at kernel/softirq.c:261
    

Linux
  1. Trova il numero di righe di codice dal repository GitHub

  2. Linux:dove scaricare il codice sorgente del kernel Linux di una versione specifica?

  3. Ottieni il codice sorgente per qualsiasi comando Linux

  4. Come leggo il codice sorgente dei comandi della shell?

  5. Qual è l'attuale sorgente del kernel Linux?

Introduzione a differenze e patch

Nozioni di base sulla compilazione di software dal codice sorgente in Linux

Cloc:conta le righe del codice sorgente in molti linguaggi di programmazione

Rimuovere il codice sorgente Ppa?

Numeri di riga di origine nel grafico delle chiamate perf?

Aggiornamenti del kernel senza riavviare