Wie lesen Sie eine Segfault-Kernel-Protokollnachricht?

Lesezeit: 7 Minuten

Benutzeravatar von Sullenx
Sullenx

Dies kann eine sehr einfache Frage sein. Ich versuche, eine Anwendung zu debuggen, die den folgenden Segfault-Fehler in der generiert kern.log

kernel: myapp[15514]: segfault at 794ef0 ip 080513b sp 794ef0 error 6 in myapp[8048000+24000]

Hier sind meine Fragen:

  1. Gibt es eine Dokumentation darüber, was die Diff-Fehlernummern auf segfault sind, in diesem Fall ist es Fehler 6, aber ich habe Fehler 4, 5 gesehen

  2. Welche Bedeutung haben die Informationen at bf794ef0 ip 0805130b sp bf794ef0 and myapp[8048000+24000]?

Bisher konnte ich mit Symbolen kompilieren, und wenn ich a x 0x8048000+24000 es gibt ein Symbol zurück, ist das der richtige Weg? Meine Vermutungen sind bisher folgende:

  • sp = Stapelzeiger?
  • ip = Befehlszeiger
  • bei = ????
  • meine App[8048000+24000] = Adresse des Symbols?

  • Hinzugefügt [unix] [segmentation-fault] [syslog] Stichworte.

    – Emil Cormier

    1. Februar 2010 um 19:41 Uhr


  • Hallo, haben Sie nützliche Informationen gefunden? Ich stecke fest.

    – Baroudi Safwen

    11. Januar 2018 um 18:22 Uhr

Benutzeravatar von Charles Duffy
Charles Duffy

Wenn der Bericht auf ein Programm verweist, nicht auf eine gemeinsam genutzte Bibliothek

Laufen addr2line -e myapp 080513b (und wiederholen Sie dies für die anderen angegebenen Anweisungszeigerwerte), um zu sehen, wo der Fehler auftritt. Holen Sie sich besser einen debug-instrumentierten Build und reproduzieren Sie das Problem mit einem Debugger wie gdb.

Wenn es sich um eine gemeinsam genutzte Bibliothek handelt

In dem libfoo.so[NNNNNN+YYYY] Teil, der NNNNNN wo die Bibliothek geladen wurde. Subtrahieren Sie dies vom Befehlszeiger (ip) und Sie erhalten den Offset in die .so der anstößigen Belehrung. Dann können Sie verwenden objdump -DCgl libfoo.so und suche nach der Anweisung an diesem Offset. Sie sollten anhand der asm-Labels leicht erkennen können, um welche Funktion es sich handelt. Wenn die .so hat keine Optimierungen, die Sie auch ausprobieren können addr2line -e libfoo.so <offset>.

Was der Fehler bedeutet

Hier die Aufteilung der Felder:

  • address – der Ort im Speicher, auf den der Code zuzugreifen versucht (es ist wahrscheinlich das 10 und 11 sind Offsets von einem Zeiger, von dem wir erwarten, dass er auf einen gültigen Wert gesetzt wird, der aber stattdessen zeigt 0)
  • ip – Anweisungszeiger, dh. wo der Code lebt, der dies versucht
  • sp – Stapelzeiger
  • error – Architekturspezifische Flags; sehen arch/*/mm/fault.c für Ihre Plattform.

  • Event für eine Shared Lib, das “[8048000+24000]” Teil sollte einen Hinweis geben, wo das abstürzende Segment der Bibliothek im Speicher abgebildet wurde. “readelf –segments mylib.so” listet diese Segmente auf, und dann können Sie den EIP-Offset in das abstürzende Segment berechnen und an addr2line (oder Betrachten Sie es in “objdump -dgS”).

    – oliver

    13. Juni 2013 um 17:18 Uhr

  • Ich glaube, 0x8048000 ist (wahrscheinlich) die Adresse, an der das Textsegment abgebildet wurde, also sollten Sie weitergeben -j .text zum objdump Befehl. (Zumindest brauchte ich das, als ich gerade eines davon diagnostizierte.)

    – Nemo

    5. Juni 2014 um 16:30 Uhr

  • @Charles Duffy Wenn ich dich jemals sehe, werde ich dich umarmen, wie ich noch nie eine lebende Seele umarmt habe.

    – Baroudi Safwen

    11. Januar 2018 um 18:47 Uhr

  • Auf einem 64-Bit-Debian-System habe ich trap divide error ip:55fc4735e6d8 sp:7fa4d77fcd80 error:0 in myapp[55fc472d4000+ed000]aber addr2line -e myapp 55fc4735e6d8 kehrt einfach zurück ??:0. Die App ist ein Debug-Build ohne aktivierte Optimierungen. Irgendein Rat?

    – emkey08

    26. November 2020 um 7:23 Uhr


  • Hinweis: Ich habe es auch versucht addr2line -e myapp 8a6d8 (seit 55fc4735e6d8 – 55fc472d4000 = 8a6d8), was tatsächlich eine Quellzeile findet, aber offensichtlich eine falsche, da dort überhaupt keine Division stattfindet. (Ich habe einen Trap-Division-Fehler.)

    – emkey08

    26. November 2020 um 7:42 Uhr

Benutzeravatar von jschmier
jschmier

Nach meinem begrenzten Wissen sind Ihre Annahmen richtig.

  • sp = Stapelzeiger
  • ip = Anweisungszeiger
  • myapp[8048000+24000] = Adresse

Wenn ich das Problem debuggen würde, würde ich den Code ändern, um einen Core-Dump zu erzeugen oder einen Stack-Backtrace für den Absturz zu protokollieren. Sie können das Programm auch unter GDB ausführen (oder anhängen).

Der Fehlercode ist nur der architektonische Fehlercode für Seitenfehler und scheint architekturspezifisch zu sein. Sie sind oft dokumentiert in arch/*/mm/fault.c in der Kernelquelle. Meine Kopie von Linux/arch/i386/mm/fault.c hat die folgende Definition für error_code:

  • Bit 0 == 0 bedeutet keine Seite gefunden, 1 bedeutet Schutzfehler
  • Bit 1 == 0 bedeutet lesen, 1 bedeutet schreiben
  • Bit 2 == 0 bedeutet Kernel, 1 bedeutet Benutzermodus

Meine Kopie von Linux/arch/x86_64/mm/fault.c fügt folgendes hinzu:

  • Bit 3 == 1 bedeutet, dass der Fehler ein Befehlsabruf war

  • Das Problem, das ich habe, ist Folgendes: 1) Die Anwendung segfaulting in einer Produktionsumgebung, in der Symbole entfernt werden, alles, was ich habe, sind nur die Protokolle. 2) Ich versuche, diesen Speicherort in der Entwicklungsumgebung zu finden, also zumindest i kann sehen, wo es abstürzt.

    – Sullenx

    1. Februar 2010 um 19:42 Uhr

  • Wenn Sie die vorab gestrippte Binärdatei haben, versuchen Sie, sie durch nm oder objdump laufen zu lassen.

    – jschmier

    1. Februar 2010 um 19:52 Uhr


  • nm ist ziemlich hilfreich, zumindest habe ich eine Idee, wo der Absturz passiert ist. Eine letzte Sache, was ist ein Fehler 6? … gibt es da draußen einen Tisch?

    – Sullenx

    1. Februar 2010 um 20:07 Uhr

  • Segfault bei 794ef0 … sp 794ef0 – Stapel ist offensichtlich beschädigt.

    – Nikolai Fetissov

    1. Februar 2010 um 20:54 Uhr

  • Danke, das ist sehr hilfreich

    – Sullenx

    1. Februar 2010 um 20:56 Uhr

Wenn es sich um eine gemeinsam genutzte Bibliothek handelt

Du bist leider abgespritzt; Es ist nicht möglich, im Nachhinein zu wissen, wo die Bibliotheken vom dynamischen Linker im Speicher platziert wurden.

Nun, es gibt immer noch eine Möglichkeit, die Informationen nicht aus der Binärdatei, sondern aus dem Objekt abzurufen. Sie benötigen jedoch die Basisadresse des Objekts. Und diese Informationen befinden sich immer noch im Coredump in der link_map-Struktur.

Zuerst wollen Sie also die Struktur link_map in GDB importieren. Kompilieren Sie also ein Programm damit mit dem Debug-Symbol und fügen Sie es der GDB hinzu.

link.c

#include <link.h>
toto(){struct link_map * s = 0x400;}

get_baseaddr_from_coredump.sh

#!/bin/bash

BINARY=$(which myapplication)

IsBinPIE ()
{
    readelf -h $1|grep 'Type' |grep "EXEC">/dev/null || return 0
    return 1
}

Hex2Decimal ()
{
    export number="`echo "$1" | sed -e 's:^0[xX]::' | tr '[a-f]' '[A-F]'`"
    export number=`echo "ibase=16; $number" | bc`
}

GetBinaryLength ()
{
    if [ $# != 1 ]; then
    echo "Error, no argument provided"
    fi
    IsBinPIE $1 || (echo "ET_EXEC file, need a base_address"; exit 0)
    export totalsize=0
    # Get PT_LOAD's size segment out of Program Header Table (ELF format)
    export sizes="$(readelf -l $1 |grep LOAD |awk '{print $6}'|tr '\n' ' ')"
    for size in $sizes
    do Hex2Decimal "$size"; export totalsize=$(expr $number + $totalsize); export totalsize=$(expr $number + $totalsize)
    done
    return $totalsize
}

if [ $# = 1 ]; then
    echo "Using binary $1"
    IsBinPIE $1 && (echo "NOT ET_EXEC, need a base_address..."; exit 0)
    BINARY=$1
fi

gcc -g3 -fPIC -shared link.c -o link.so

GOTADDR=$(readelf -S $BINARY|grep -E '\.got.plt[ \t]'|awk '{print $4}')

echo "First do the following command :"
echo file $BINARY
echo add-symbol-file ./link.so 0x0
read
echo "Now copy/paste the following into your gdb session with attached coredump"
cat <<EOF
set \$linkmapaddr = *(0x$GOTADDR + 4)
set \$mylinkmap = (struct link_map *) \$linkmapaddr
while (\$mylinkmap != 0)
if (\$mylinkmap->l_addr)
printf "add-symbol-file .%s %#.08x\n", \$mylinkmap->l_name, \$mylinkmap->l_addr
end
set \$mylinkmap = \$mylinkmap->l_next
end

Es wird Ihnen den gesamten link_map-Inhalt innerhalb eines Satzes von GDB-Befehlen drucken.

Es selbst mag unnötig erscheinen, aber mit der base_addr des gemeinsamen Objekts, um das es uns geht, können Sie möglicherweise mehr Informationen aus einer Adresse erhalten, indem Sie das betroffene gemeinsame Objekt direkt in einer anderen GDB-Instanz debuggen. Behalten Sie die erste gdb, um eine Vorstellung von dem Symbol zu haben.

HINWEIS: Das Skript ist ziemlich unvollständig, ich vermute, Sie können es hinzufügen Zum zweiten Parameter von add-symbol-file wurde die Summe mit diesem Wert gedruckt:

readelf -S $SO_PATH|grep -E '\.text[ \t]'|awk '{print $5}'

wobei $SO_PATH die ist Erste Argument der Add-Symbol-Datei

Ich hoffe es hilft

  • Wie kompilieren Sie link.c ?

    – Tectrendz

    23. April 2014 um 18:57 Uhr

1416620cookie-checkWie lesen Sie eine Segfault-Kernel-Protokollnachricht?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy