mirror of
https://github.com/ldmud/ldmud
synced 2026-08-12 14:26:05 -04:00
238 lines
11 KiB
Text
238 lines
11 KiB
Text
Wie benutze ich den Debugger ?
|
|
- ein kleiner Leitfaden von Sunblade.
|
|
-----------------------------------------
|
|
LPC-Debugger von Sunblade (sunblade@sd.mud.de:2050)
|
|
(Daniel von Dincklage, vonDincklage@ozet.de)
|
|
(patches for 3.2.1@130-Driver)
|
|
|
|
Schritt 0.
|
|
UMBEDINGT EINE SICHERHEITSKOPIE DES ALTEN DRIVERS
|
|
UND DES UNGEPATCHTEN QUELLCODES ANLEGEN !!!
|
|
|
|
Schritt 1.
|
|
Man kopiere ich die Tar.gz-Datei mit den Patches fuer den Debugger und
|
|
wende diese auf die Quelldateien des Drivers an.
|
|
ACHTUNG !
|
|
Ich habe es nur mit dem 3.2@130-Driver ausprobiert, ich werde das mal
|
|
demnaechst auf andere Versionen ausdehen.
|
|
NOCH EINE ACHTUNG !
|
|
Der Debug-Driver ist *AUSSCHLIESSLICH* fuer Homemuds gedacht !
|
|
Das liegt daran, das *wenn* jemand Debuggt, das das ganze Mud anhaelt,
|
|
was kann man auch anderes von einem Single-Threaded-System erwarten.
|
|
***************************************************************************
|
|
ALSO NICHT UND NIEMALS DIESEN DRIVER IN EINEM OFFNEN MUD VERWENDEN !
|
|
***************************************************************************
|
|
|
|
Schritt 2.
|
|
Man kompiliere den gepatchen Driver und probiere ihn aus.
|
|
In dem neuen Driver sind einige Veraenderungen vorgenommen, so das er
|
|
wohl ein wenig langsamer laeuft und mehr Speicher verbraucht, als der
|
|
Driver ohne die Debugging-Funktionen. Dies liegt v.a. daran, das der
|
|
Debug-Driver die Variablennamen sichern muss, die normalerweise
|
|
"entsorgt" werden koennen.
|
|
|
|
Schritt 3.
|
|
Man kann nun mal den Driver ausprobieren. Dazu nimmt man sich einfach ein
|
|
Objekt seiner Wahl und fuege die Zeile
|
|
debugfile(file_name(this_object())[1..strlen(file_name(this_object()))-1],1);
|
|
ein, und erschaffe das Objekt. Falls der Driver meckert, das die efun
|
|
"debugfile" nicht vorhanden ist, ist wohl was beim Patchen bzw. beim
|
|
Compilieren schiefgelaufen.
|
|
Falls nicht, dann muesste man nun den Schirm des Debuggers sehen, der in
|
|
etwa so aussieht:
|
|
|
|
--< Sunblades LPC-Debugger V0.1b : /w/sunblade/automat >-----------------------
|
|
29: // traceprefix("w/sunblade/automat#");
|
|
30: // trace(1|2|4|8|16|32|64|128);
|
|
31: // trace(16);
|
|
32:
|
|
debugfile(file_name(this_object())[1..strlen(file_name(this_object()))-1],1);
|
|
33: > bock = 9876543;
|
|
34: schlabber = "lwkjrhsldkjhglgeuritz";
|
|
35: blubb = this_player();
|
|
36:B foo = 12349;
|
|
37:
|
|
38: seteuid(getuid(this_object()));
|
|
--</w/sunblade/automat.c:create>-<33/72>--------------------------------------
|
|
|
|
Zunaechst einmal eine kleine Einfuehrung, in das was man da alles sieht :
|
|
In der ersten Zeile wird ausgegeben, welche Version des Debuggers vorliegt,
|
|
und, was wichtig ist, welches *OBJEKT* gedebuggt wird. D.h. also welcher
|
|
Name bei this_object() herauskaeme. In diesem Fall ist es
|
|
"/w/sunblade/automat", d.h. die Masterkopie der Datei "/w/sunblade/automat.c".
|
|
Ebensogut koennte dort "/w/sunblade/automat#8" stehen, wenn das ein nomaler
|
|
Clone der Datei waere. (Kurzerklaerung von Clones/Masterkopien bei (* (1)) )
|
|
Die naechsten Zeilen beginnen alle mit einer Zahl, gefolgt von Programmcode.
|
|
Die Zahlen am Anfang einer Zeile geben an, welcher Zeile im Programmquelltext
|
|
die angezeigte Zeile entspricht, damit man sich besser zurechtfindet.
|
|
Hinter den Zeilen werden noch einige Informationen ausgegeben, bevor der
|
|
Quelltext angezeigt wird. So z.B. hier in der Zeile 33 von
|
|
/w/sunblade/automat.c, die da lautet :
|
|
33: > bock = 9876543;
|
|
Das " >" hinter der 33 bedeutet schlicht und einfach, das die
|
|
Programmausfuehrung unmittelbar *BEVOR* dieser Zeile steht. Wenn man also nun
|
|
"n" drueckt, (n = naechster Befehl, wird gleich erklaert) wuerde diese
|
|
Anweisung ausgefueht, d.h. in die Variablen bock wuerde der entsprechende Wert
|
|
abgelegt.
|
|
Es gibt aber noch andere Zeichen, so z.B. in der Zeile 36:
|
|
36:B foo = 12349;
|
|
Das B direkt hinter der Zeilennummer bedeutet, das in dieser Zeile ein sog.
|
|
Breakpoint gesetzt wurde. (Wird ebenfalls gleich erklaert)
|
|
Ansonsten ist nur noch die letzte Zeile der Anzeige von Interesse :
|
|
--</w/sunblade/automat.c:create>-<33/72>--------------------------------------
|
|
In dieser Zeile wird einiges ausgegeben:
|
|
Zum einen die Quelldatei, in der man sich befindet. In diesem Fall ist es
|
|
/w/sunblade/automat.c. Sie muss aber nicht umbedingt der Quelldatei
|
|
entsprechen, die man bearbeitet. Wuerde man sich z.B. anschaun, was in der
|
|
Funktion "set_name" (bzw. SetProp(P_NAME, ) ) geschiet, dann wuerde man
|
|
anstattdessen dort den Namen der Inheritdatei sehen, in dem diese Funktion
|
|
deklariert ist.
|
|
Hinter dem Doppelpunkt sieht man den Namen der aktuellen Funktion, in diesem
|
|
Fall "create". Ansonsten sieht man noch, in welcher Zeile man sich in der
|
|
aktuellen Datei befindet (33) und wieviele Zeilen die aktuelle Datei
|
|
insgesamt besitzt. (72).
|
|
Doch - Was nun ?
|
|
Zunaechst sollte man erstmal "n" (== naechste Instruktion) (+ENTER) druecken
|
|
und schaun was passiert -
|
|
Das Programm fuehrt die naechste Instruktion aus und springt eine Zeile
|
|
weiter - Der Quellcode rutscht herunter, der Zeilenmarker steht auf der
|
|
neuen Instruktion.
|
|
Dies ist schon eine sehr nuetzliche Sache, denn mit Hilfe dieser Funktion
|
|
kann man seinem Programm praktisch zusehen, was es tut, Man kann so sehr
|
|
schnell herausfinden, an welchen Stellen es die falschen IF-Zweige nimmt
|
|
etc. Die naechste Funktion die interessant sein koennte ist die "t"
|
|
(== trace into) Funktion. Sie funktioniert allerdings nur, wenn man mit dem
|
|
Programmmarker auf einer Funktion steht, wie hier:
|
|
--< Sunblades LPC-Debugger: w/sunblade/automat#8 >---------------------------
|
|
40: // write("foo = "+foo+"\n");
|
|
41:
|
|
42: blabbaer(10);
|
|
43: // write(foo+"\n");
|
|
44: > set_name("getraenkeautomat");
|
|
45: set_gender("maennlich");
|
|
46: set_long("Ein portabler Getraenkeautomat.");
|
|
47: set_id("automat");
|
|
48: }
|
|
49:
|
|
--<w/sunblade/automat.c:create>-<44/72>---------------------------------------
|
|
(Fuer alle die sich mit der Lib hier nicht auskennen, set_name setzt den
|
|
Namen des Objektes und ist in diesem Programm inherited)
|
|
Drueckt man hier nun "t", so zeigt der Debugger an, was "innerhalb" der Funktion
|
|
"set_name" passiert :
|
|
--< Sunblades LPC-Debugger: w/sunblade/automat#8 >---------------------------
|
|
133: VERWEISE: query_name, query_cap_name, set_personal
|
|
134: GRUPPEN: grundlegendes
|
|
135: */
|
|
136: void set_name(string str) {
|
|
137: > if(str && str!="")
|
|
138: str=lower_case(str);
|
|
139: name = str;
|
|
140: }
|
|
141:
|
|
142: /*
|
|
--<i/item/name.c:set_name>-<137/351>------------------------------------------
|
|
Haette man nur "n" gedrueckt, so waere der Debugger direkt in die Zeile 45 von
|
|
dem "automat"-Programm gesprungen.
|
|
Man kann nun z.B. solange "n" druecken, bis das Programm mit der Abarbeitung
|
|
der jetztigen Funktion fertig ist. Danach wird zur nomalen "Tagesordnung" des
|
|
Drivers uebergegangen. Wenn man nun in irgendeiner Weise das gedebuggte Objekt
|
|
anspricht, z.B. ess anschaut, dann springt der Debugger sofort wieder an, und
|
|
befindet sich dann in der entsprechenden Funktion des Objektes.
|
|
|
|
Was kann man noch im Debugger alles schickes Tun ?
|
|
- Variablen anschaun :
|
|
Man kann sich mit "i <variablenname>" den Inhalt einer Variablen anschaun.
|
|
Dies geht immer mit globalen Variablen. Lokale Variablen und Parameter
|
|
stehen natuerlich nur in der Funktion zur Verfuegung, in der sie auch
|
|
Deklariert worden sind.
|
|
ACHTUNG !
|
|
Gibt der Debugger den Wert "0" und als Variablentyp "ZAHL" aus, so kann
|
|
dies zwei Bedeutungen haben:
|
|
- Die Zahl 0, wie man sie kennt und mit der man nichts Dividieren kann.
|
|
- Der Wert "uninitialisiert". Das Bedeutet:
|
|
Is in eine Variable nocht *NICHTS* getan worden. D.h. z.B. man hat eine
|
|
Objektvariable "foo" Deklariert und schaut sie sich an, bevor
|
|
man irgendetwas in diese Variable getan hat, dann erhaelt man AUCH
|
|
den Wert 0, Typ ZAHL. Erst wenn man einen Wert in die Variable tut,
|
|
z.B. foo = this_object(), wird der Typ der Variablen auf Objekt
|
|
geaendert.
|
|
(Wenn gewuenscht, dann ueberleg ich mir dazu noch was)
|
|
- Funktionenliste/Variablenliste.
|
|
Man kann mit "lv" bzw. "lf" sich eine Liste **aller** Variablen (lv)
|
|
bzw. Funktionen (lf) des aktuellen Programmes ausgeben lassen.
|
|
ACHTUNG ! Diese sind natuerlich (besonders bei vielen Inherits) recht lang !
|
|
Bei der Funktionenausgabe wird vorher noch ein Flag-Feld ausgegben, das
|
|
so aussieht: [iSN[P|p]Vvp].
|
|
Die einzelnen Flags bedeuten:
|
|
i -> Die Funktion ist inherited.
|
|
S -> Die Funktion ist als static deklariert.
|
|
N -> Die Funktion ist no-mask.
|
|
[P|p] -> Entweder ein P (Funktion ist private) oder ein p (FUnktion ist
|
|
public) oder nix.
|
|
V -> Die Funktion ist Varargs
|
|
v -> Die Funktion ist virtual
|
|
p -> Die Funktion ist protected.
|
|
- Status:
|
|
Man kann sich mit "s" oder "status" einige Informationen ueber das
|
|
aktuelle Objekt ausgeben lassen. (Hoffentlich selbsterklaerend)
|
|
- Naechste Instruktion:
|
|
Man kann mit "n" oder "next" die aktuelle Funktion abarbeiten.
|
|
- Breakpoint setzen:
|
|
Man kann mit z.B. "b w/sunblade/automat 34" einen Breakpoint setzen.
|
|
Der Debugger haelt dann an, wenn man die Zeile 34 in der angegebenen
|
|
Datei erreicht.
|
|
(anm. Bitte keine Flames wegen dieser Funktion, die wird gerade
|
|
verbessert ;) )
|
|
- Continue:
|
|
Man kann mit "c" das Programm ausfuehren lassen. Der Debugger wird
|
|
erst dann wieder aktiviert, wenn er einen Breakpoint erreicht.
|
|
- Trace into:
|
|
Man kann in eine Funktion reinspringen.
|
|
- Funktionsende :
|
|
Arbeitet die aktuelle Funktion bis zum Ende ab.
|
|
|
|
|
|
|
|
Schritt 4
|
|
Anmerkungen, Anregungen etc....
|
|
Falls irgendjemand eine tolle Idee hat, was der Debugger sonst noch koennen
|
|
soll (und NICHT auf der Liste unten steht), oder der Debugger nicht ganz so reagiert
|
|
wie er soll, kann mir ja ganz spontan eine Mail schreiben, und zwar an:
|
|
vonDincklage@ozet.de (oder DanielvDincklage@usa.net falls ersteres nit geht)
|
|
|
|
Ich freue mich ueberigends auch, falls mir jemand schreibt, das der Driver
|
|
coredumpt. Ich werde mich dann *bestimmt* dransetzen...
|
|
Also: Falls das Ding seinen Core durch die Gegend schmeisst, selbigen
|
|
aufheben, und mir drueber schreiben !
|
|
(Ach ja, bitte *NICHT* sofort den Core mitschicken, erst fragen ;)
|
|
Vielleicht is der Bug ja dann schon laengst behoben !)
|
|
|
|
Woran sitze ich im Moment : (nahe Zukunft)
|
|
- Anzeige von Mappings und Closures
|
|
- Aendern von Variableninhalten
|
|
- Goto (d.h. Einmal-Breakpoint)
|
|
- Verbesserung der Breakpoints
|
|
- "LPC-Coredumps" im normalen Driver bei Run-Time-Errors, die dann zuhause
|
|
gedebuggt werden koennen
|
|
- Verschoenerung des Dumps von Arrays
|
|
|
|
Ist fuer die ferne Zukunft geplant:
|
|
- Die Moeglichkeit LPC-Kommandos auswerten zu lassen.
|
|
|
|
|
|
(* (1)) :
|
|
[Kurzerklaerung: Von jedem Objekt das mehrfach im Mud vorhanden is, wird
|
|
eine Masterkopie angelegt, die vielen Objekte, die die
|
|
Spieler dann mithaben, sind dann die Clones. Es wuerde also *EINMAL*
|
|
"/obj/fackel" exisiteren und mehrfach "/obj/fackel#23128" (bzw. mit einer
|
|
jeweils anderen Zahl hinter dem #). Raeume exisiteren (im Normalfall) nur als
|
|
Masterkope. Warum das komplierte System ? Ganz einfach - In der Masterkopie
|
|
speichert man nur den Programmkode, der ja fuer alle Fackeln gleich ist. Die
|
|
einzelnen Fackeln brauchen dann nur noch die Variablen zu speichern, d.h.
|
|
jede "Clone"-Fackel muss dann nur noch z.B. speichern, wie lange sie selber
|
|
noch brennen soll. Den Programmcode kann sie aus der Masterfackel benutzen
|
|
Weitergehende Infos dazu findet sicher irgendwo in der MudLib-Doku, oder
|
|
jemanden Fragen der sich mit sowas auskennt !]
|
|
|
|
|
|
|