mit gdb aktuelle Zeile in hängendem Shell Skript ermitteln

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
SubOptimal
Beiträge: 1709
Registriert: 10.01.2005 23:25:46
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: bei Frankfurt

mit gdb aktuelle Zeile in hängendem Shell Skript ermitteln

Beitrag von SubOptimal » 19.10.2011 00:14:17

Hi,

habe folgendes Problem. Ein Korn Shell Skript hängt fest und ich wollte herausfinden an welcher Zeile er hängt, da in der dazugehörigen Logdatei kein Fehler aufgetaucht ist, lässt er sich auch nicht einkreisen.

Folgendes hab ich schon versucht.
- im gdb mittels »where« geschaut wo der Prozess hängt, er hängt bei einem waitpid() Aufruf
- ps liefert zum hängenden Prozess allerdings keinen zugehörigen Childprozess, was eventuell erklärt warum der Prozess nun endlos wartet

Wegen dem waitpid() denke ich, es müsste im Skript ein Aufruf von dieser Art sein

Code: Alles auswählen

rc=`foo bar`
Davon gibt es im Skript allerdings mehrere.

Der Fehler ist in 2 Monaten nun genau 2x aufgetreten. Dazwischen ist das Skript (läuft als Daemon 24/7) fehlerfrei ausgeführt worden.

Leider besteht keine Möglichkeit (ist ein Zeit Problem) den Prozess auf gut Glück mit mehr Loginformationen nochmal zu starten und auf das nächste Festhängen zu warten.

Gibt es eine relativ einfache Möglichkeit mittels gdb das zuletzt ausgeführte Kommando im Korn Shell Skript zu ermitteln?

Hier noch ein paar zusätzliche Infos.
- Korn Shell ist die ksh93, ohne Debuginformationen kompiliert und gestrippt

Da dieses Shell Skript auch eher suboptimal geschrieben ist, werd ich wohl schon mal anfangen und den Code aufräumen.
Allerdings würde mich eine Lösung des Problems trotzdem interessieren. Ein core dump, für spätere Versuche, wurde schon erstellt.

SubOptimal

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: mit gdb aktuelle Zeile in hängendem Shell Skript ermitte

Beitrag von Meillo » 19.10.2011 12:18:49

Die Vorraussetzungen zum Debuggen hoeren sich nicht toll an.

Fragen, Klarstellungen und Anmerkungen:

- Es geht um ein ksh-Script.
- Du wendest gdb auf die ksh selbst an, oder?
- Haengt ein Programm das vom Script gestartet wird oder haengt die ksh?
- Wieso kannst du das Shellscript nicht um Debuggingzeug erweitern?
- Kannst du eine Testversion des Scripts separat starten?
- Die meisten ksh-Scripte lassen sich auch mit der bash oder zsh ausfuehren.
- Kannst du Code hier zeigen?

In jedem Fall musst du versuchen das Problem reproduzierbar zu machen. Sonst kannst du alle Debuggingbemuehungen vergessen.
Use ed once in a while!

Benutzeravatar
SubOptimal
Beiträge: 1709
Registriert: 10.01.2005 23:25:46
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: bei Frankfurt

Re: mit gdb aktuelle Zeile in hängendem Shell Skript ermitte

Beitrag von SubOptimal » 21.10.2011 01:49:19

Hi Meillo,
Die Vorraussetzungen zum Debuggen hoeren sich nicht toll an.
Dem stimme ich zu.
- Es geht um ein ksh-Script.
ja
- Du wendest gdb auf die ksh selbst an, oder?
ja
- Haengt ein Programm das vom Script gestartet wird oder haengt die ksh?
Der ksh Prozess steckt laut gdb bei einem waitpid() fest und verbraucht keine CPU Zeit. Zum ksh gibt es wie gesagt keinen Childprozess.
- Wieso kannst du das Shellscript nicht um Debuggingzeug erweitern?
Weil dann u.U. wieder 2 Monate oder mehr bis zum nächsten festhängen vergehen könnten.
- Kannst du eine Testversion des Scripts separat starten?
Hab ich schon gemacht und bisher ist der Fehler nicht wieder aufgetreten. Ist halt einer von der sporadischen Art. ;-)
- Die meisten ksh-Scripte lassen sich auch mit der bash oder zsh ausfuehren.
Ich weiß. Sollte aber nicht das Problem sein. Immerhin läuft das Skript ja sonst auch problemlos 24/7 durch. Läuft in einer Endlosschleife und tut alle 60 Sekunden was.
- Kannst du Code hier zeigen?
Nein (Firmenkram und speziell diesen _willst_ Du nicht sehen, der wurde hinter der rechten Tür entwickelt [1] ;-) ).
In jedem Fall musst du versuchen das Problem reproduzierbar zu machen. Sonst kannst du alle Debuggingbemuehungen vergessen.
Genau das, mit dem reproduzierbar machen, ist das Problem. Deshalb dachte ich evtl. per gdb die Zeile "herauskitzeln" zu können.

Hab mich aber heute mal hingehockt und den Gilb der letzten Jahre (inkl. der sichtbaren Fehler) entfernt. Wenn es nun fehlschlägt, dann sieht man im Log zumindest wo. ;-)

Meinte Vermutung ist, dass es an folgendem Konstrukt hing (aus unerfindlichen Gründen, weil es ja eigentlich sonst auch lief)

Code: Alles auswählen

# sinngemäß und stark gekürzt, alle Namen von der Redaktion geändert
# PS: bitte keine Kommentare zu dem Code (der ist nicht meine Schuld ;-) )
BODY="cat ${FILE} | grep -v unwanted | sort -k 2 -t ."
...
while true
do
  for i in `eval $BODY`; do
    # do something with the $i
   ...
    sleep 60
  done
done
- die Datei $FILE ist statisch
- alles was zwischen for ... done ausgeführt wird hätte (meiner Erfahrung nach) im Fehlerfall irgend eine Ausgabe erzeugt, da waren auch einige Child-Prozesse darunter
- zwischen for ... done erfolgte keinerlei Ausgabe nach stdout/stderr, deswegen weiß ich auch nicht bei welchem Child es hängt
- while ... done wurde zuvor 4 Wochen am Stück ohne Unterbrechung abgearbeitet, schließt so einen generellen Fehler aus
- das Konstrukt war so seit > 5 Jahren im Einsatz

Das mit gdb war letztlich nur eine Idee und hat am Ende nur mein persönlichem Interesse geweckt. Hatte bisher noch nie ein Shell Skript was sich so "unkooperativ" verhalten hat.

SubOptimal

[1] http://www.gridshore.nl/wp-content/uplo ... rement.jpg

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: mit gdb aktuelle Zeile in hängendem Shell Skript ermitte

Beitrag von Meillo » 21.10.2011 11:42:42

SubOptimal hat geschrieben:
- Haengt ein Programm das vom Script gestartet wird oder haengt die ksh?
Der ksh Prozess steckt laut gdb bei einem waitpid() fest und verbraucht keine CPU Zeit. Zum ksh gibt es wie gesagt keinen Childprozess.
Wenn kein Kind da ist, dann sollte waitpid() sofort zurueck kehren. Da waitpid() bestimmt nicht kaputt ist, muss entweder ein Kind existieren oder der Prozess haengt nicht in waitpid() fest.

In jedem Fall musst du versuchen das Problem reproduzierbar zu machen. Sonst kannst du alle Debuggingbemuehungen vergessen.
Genau das, mit dem reproduzierbar machen, ist das Problem. Deshalb dachte ich evtl. per gdb die Zeile "herauskitzeln" zu können.

Hab mich aber heute mal hingehockt und den Gilb der letzten Jahre (inkl. der sichtbaren Fehler) entfernt. Wenn es nun fehlschlägt, dann sieht man im Log zumindest wo. ;-)
Meinte Vermutung ist, dass es an folgendem Konstrukt hing (aus unerfindlichen Gründen, weil es ja eigentlich sonst auch lief)
Ich sehe an dem Konstrukt nichts was auf Fehler hindeuten wuerde ... und ueberhaupt bin ich der Meinung, dass alle verfuegbaren Information nicht ausreichen um irgendwas konkretes aussagen zu koennen. Hart gesagt: So kann man den Fehler nicht finden, ausser zufaellig.
- das Konstrukt war so seit > 5 Jahren im Einsatz
Manchmal sollte man sich ernsthaft ueberlegen das Zeug komplett neu zu schreiben. (Aber ich weiss natuerlich, dass das in Firmen nicht einfach ist mit solchen Entscheidungen.)


Ich wuensche dir das Beste, aber ich fuerchte wenig Erfolg. :-/

:-D
Use ed once in a while!

rendegast
Beiträge: 15041
Registriert: 27.02.2006 16:50:33
Lizenz eigener Beiträge: MIT Lizenz

Re: mit gdb aktuelle Zeile in hängendem Shell Skript ermitte

Beitrag von rendegast » 21.10.2011 17:15:27

- Korn Shell ist die ksh93, ohne Debuginformationen kompiliert und gestrippt
Alle in debian verwendeten sind ksh 93:
http://packages.debian.org/ksh
Und warum nicht eine davon?

Warum das Skript nicht einfach mit echos anreichern

Code: Alles auswählen

echo "$(date) $? STOP01 VERIAB $VARIAB ..." >> $LOGFILE
In, vor und hinter for-, while-, if- Schleifen usw.
(Nur mit den echos nicht irgendwelche Fehlerbehandlungen unterbrechen)

Code: Alles auswählen

      for i in `eval $BODY`; do
        # do something with the $i
       ...
- zwischen for ... done erfolgte keinerlei Ausgabe nach stdout/stderr, deswegen weiß ich auch nicht bei welchem Child es hängt

Code: Alles auswählen

echo "$(date) $? STOP01 ..." >> $LOGFILE
      for i in `eval $BODY`; do
        # do something with the $i
echo "$(date) $? STOP02 $i ..." >> $LOGFILE
       ...
    sleep 60
  done
echo "$(date) $? STOP03 ..." >> $LOGFILE
done
Die echos und LOGFILE könnten auch so konstruiert werden, daß sie immer gleich sein müßten,
sodaß bei checksumme über eine Sammlung LOGFILE die Ausreißer auffallen.
Die Möglichkeiten sind da vielfältg.
- die Datei $FILE ist statisch
Warum braucht es dann eine Nachbearbeitung mit grep und sort?
Wenn sie jedoch gelegentlich neu erzeugt wird, wäre eine Zeitstempel-Kopie des BODY fürs Studium vielleicht interessant.
(Wenn das zBsp. beim 24/7-Betrieb in die Zeit der Zwangstrennung fiele.)
mfg rendegast
-----------------------
Viel Eifer, viel Irrtum; weniger Eifer, weniger Irrtum; kein Eifer, kein Irrtum.
(Lin Yutang "Moment in Peking")

Antworten