ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
                      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 !]