Open Source im professionellen Einsatz
Linux-Magazin 01/2007
© pixelquelle.de

© pixelquelle.de

Mit dem Gnu-Debugger auf Inspektion in Perls Mechanik

Getriebeschaden

Dreht sich das Perl-Rad nur noch knirschend, sind vielleicht Fehler im Perl-Interpreter oder in Erweiterungsmodulen schuld. Der gute alte GDB inspiziert das Getriebe und kommt Problemstellen auf die Schliche.

640

Wer in Perl statt in C oder C++ programmiert, nimmt es oft als selbstverständlich hin, dass ihm viel unnütze Arbeit erspart bleibt: Speicher reservieren und freigeben, Referenzen zählen, auf wild gewordene Pointer aufpassen - derlei Sisyphusarbeit hält Perls virtuelle Maschine vom Programmierer fern, damit der sich auf das Implementieren konzentrieren kann.

Doch auch tief unten im Maschinenraum können Fehler auftreten. Es kommt zwar sehr selten vor, dass ein Bug in einer Perl-Release die in C implementierte virtuelle Maschine zum Absturz bringt. Häufiger aber können handgeschriebene Perl-Erweiterungen eines unachtsamen C/C++-Entwicklers dafür eine mögliche Ursache sein.

Nur in Ausnahmefällen stürzt der Perl-Interpreter »perl« so richtig ab, wenn es aber doch passiert, hilft auch der Perl-Debugger [2] nicht mehr weiter. Das Skript in Listing 1 führt zum Beispiel mit Hilfe einer C-Erweiterung bewusst einen Absturz des Interpreters mit einem Segmentation Fault herbei.

Listing 1:
»crash«

01 #!/usr/bin/perl -w
02 use strict;
03 use Inline "C";
04 use Inline Config =>
05    CLEAN_AFTER_BUILD => 0;
06 
07 c_crash(43);
08 
09 __END__
10 __C__
11 int c_crash( int num ) {
12  char *cp = 0xcba00000;
13  strcpy(cp, "Ouch!");
14 }

Linux zieht den Teppich weg

Das Beispiel bedient sich hierzu des CPAN-Moduls Inline, das angehängten C-Code kompiliert und dynamisch in das Skript einbindet. Der C-Code nach der »__END__«-Markierung setzt einen Pointer auf die Adresse »0xcba00000« und lässt dann die C-Funktion »strcpy« rücksichtslos an dieser, zumindest in der 32-Bit-x86-Architektur geschützten Kerneladresse schreiben. Der Prozessor merkt das, löst einen Interrupt aus und der Linux-Kernel zieht daraufhin dem schuldigen Programm den Teppich unter den Füßen weg.

Abbildung 1 zeigt, wie das Perl-Skript für die Reproduktion des Fehlers im Gnu-Debugger »gdb« aufzurufen ist. Das ausführende Binärprogramm ist der Perl-Interpreter, also startet der Debugger mit »gdb perl«. Um dann das Perl-Skript »crash« vom Interpreter abarbeiten zu lassen, ruft man im Debugger das Kommando »run crash« auf. Nach dem Absturz liefert »gdb« nicht nur den C-Code jener Zeile, die den Crash auslöste. Das Debugger-Kommando »bt« (für Backtrace, alternativ funktioniert auch »where«) zeigt zusätzlich die aufrufende C-Funktionshierarchie im so genannten Stacktrace an.

Abbildung 1: Eine »gdb«-Session analysiert den Stacktrace des Perl-Skripts.

Damit der Debugger ausgeführte Funktionen den Zeilennummern im C-Sourcecode zuordnen kann, muss der Fehlersucher sein Perl zuvor mit dem Compiler-Flag »-g« kompiliert haben. Auf die Frage des Konfigurationsskripts: »What optimizer/debugger flag should be used?« sollte er dazu »-g« antworten oder das Skript gleich mit »./Configure -D optimize=-g -d« aufrufen.

Versäumt er dies, ist die Analyse mangels Referenzen zum C-Sourcecode schwieriger, und wenn das Executable auch noch gestrippt ist, sieht es ganz düster aus, denn disassemblierten Assemblercode verstehen bleibt langbärtigen Gurus vorbehalten. Aber auch aus einem normal kompilierten »perl« lassen sich Informationen herausholen. Die Autopsie gestaltet sich dann zwar schwieriger, doch ein Trick, dessen Erklärung weiter unten folgt, hilft dabei, exzessives Jonglieren mit Hex-Zahlen zu vermeiden.

Obduktion der Skriptleiche

Kommt es in einem laufenden Programm zum Crash, erzeugt der Linux-Kernel normalerweise eine Core-Datei. Ist dies nicht der Fall, unterdrückt die Bash wahrscheinlich die Core-Produktion mit der Standardeinstellung »ulimit -c 0«. Lautet die Einstellung hingegen »ulimit -c unlimited«, dann entsteht eine Core-Datei (»core« oder auch »core.PID« mit angehängter Prozess-ID):

$ ./crash
Segmentation fault (core dumped)
$ ls -l core.*
-rw------- 1 mschilli mschilli 1658880 Nov 3 21:30 core.1234


Der so genannte Core-Dump liegt normalerweise in dem aufrufenden Verzeichnis, es sei denn, in »/proc/sys/kernel/core_pattern« ist etwas anderes definiert. Wer herausfinden will, was den Crash ausgelöst hat, ruft den Debugger post mortem mit dem ausführenden Programm und dem Core-File auf (beispielsweise »gdb perl core.1234«). Er erhält eine ähnliche Debugger-Session, wie sie in Abbildung 1 zu sehen ist. Aus ihr lässt sich ebenfalls der Stacktrace kurz vor dem Absturz ermitteln. Zu starten ist ein solcher Speicher-Schnappschuss allerdings nicht mehr.

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Neues Perl Major Release

    Nach einem Jahr Entwicklungszeit ist jetzt das nächste Major Release von Perl 5 erscheinen. Perl 5.16 enthält im Verleich zum Vorgänger 5.14 rund 590.000 Änderungen in 2500 Files, die 139 Autoren beisteuerten.

  • Humpeln zur Diagnose

    Viele verdammen Debugger als Teufelszeug. Oft erweisen sie sich aber als letzte Rettung. Perl hat einen sogar eingebaut. Mit ihm beschäftigt sich dieser Snapshot - passend zum Schwerpunkt des Hefts.

  • Tux liest

    Das Linux-Magazin stellt zwei englischsprachige Bücher über unterschiedliche Aspekte der Software-Entwicklung vor: "Perl Hacks" erforscht obskure Winkel der vielseitigen Skriptsprache, "Designing Interfaces" widmet sich ganz der Gestaltung von Benutzeroberflächen.

  • Perl-Snapshot Linux-Magazin 2011/06

    "Perlmeister" Michael Schilli hat seinen Snapshot aus dem Magazin 2011/06 als Screencast verarbeitet.

  • Bitparade

    Für Perl-Entwickler gibt es ausgefeilte Plugins für Texteditoren, aber auch für ausgewachsene IDEs. Ob der Einsatz solcher Plugins oder Anwendungen tatsächlich beim Skripte-Programmieren hilft, lotet die aktuelle Bitparade anhand des Editors Vim, der Perl-IDE Padre sowie des Eclipse-Plugins Epic aus.

comments powered by Disqus

Ausgabe 07/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.