123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- MODULE Debugging; (** AUTHOR "fof"; PURPOSE "Debugging facilities"; **)
- IMPORT SYSTEM, Streams, KernelLog, Files, StringPool, Modules, Objects, Reflection, Machine, Commands, Locks, Dates, Heaps;
- VAR
- DefaultLog, Log-: Streams.Writer; f: Files.File; lock: Locks.RWLock;
- PROCEDURE Memory*( from, tov: ADDRESS );
- VAR i: ADDRESS; val: SIZE;
- BEGIN
- Log.String( ">>>>>" ); Log.Ln;
- IF from = 0 THEN Log.String( "NIL Region" ); Log.Ln; ELSE
- FOR i := from TO tov BY SIZEOF(ADDRESS) DO
- Log.Address( i ); Log.String( "H (" ); Log.Int( i, 0 );
- Log.String( "," ); Log.Int( i - from, 4 ); Log.String( ") " );
- SYSTEM.GET( i, val ); Log.Address( val ); Log.String( "H = " );
- Log.Int( val, 10 ); Log.Ln;
- END;
- END;
- Log.String( "<<<<<" ); Log.Ln;
- Log.Update;
- END Memory;
- PROCEDURE CallerBP(bp: ADDRESS): ADDRESS;
- VAR n: ADDRESS;
- BEGIN
- IF bp # NIL THEN
- SYSTEM.GET(bp, n);
- IF ODD(n) THEN INC(bp, SIZEOF(ADDRESS)) END;
- SYSTEM.GET(bp, bp);
- END;
- RETURN bp;
- END CallerBP;
- PROCEDURE ViewStack( ebp, esp: ADDRESS; CONST s: ARRAY OF CHAR);
- VAR i: ADDRESS; val: LONGINT; prevBP:ADDRESS;
- CONST adrSize= SIZEOF(ADDRESS);
- BEGIN
- Log.String( ">>>>> " ); Log.String(s); Log.String (" >>>>>> "); Log.Ln;
- prevBP := CallerBP(ebp);
- IF prevBP-ebp > 1024 THEN prevBP := ebp END;
- FOR i := prevBP TO esp BY -adrSize DO
- Log.Address( i ); Log.String( "H (" ); Log.Int( i, 0 ); Log.String( "," );
- Log.Int( i - ebp, 4 ); Log.String( ") " ); SYSTEM.GET( i, val );
- Log.Address( val ); Log.String( "H = " ); Log.Int( val, 10 );
- IF i = prevBP THEN Log.String(" <----- caller EBP"); END;
- IF i = ebp THEN Log.String(" <----- EBP"); END;
- IF i = esp THEN Log.String(" <----- ESP"); END;
- Log.Ln;
- END;
- Log.String( "<<<<<" ); Log.Ln;
- Log.Update;
- END ViewStack;
- PROCEDURE Stack*(CONST s: ARRAY OF CHAR);
- VAR bp,oldbp: ADDRESS;
- BEGIN
- bp := SYSTEM.GetFramePointer();
- oldbp := CallerBP(bp);
- ViewStack(oldbp,bp+4*SIZEOF(ADDRESS),s);
- END Stack;
- PROCEDURE TraceBackThis( eip, ebp: ADDRESS; stacklow, stackhigh:ADDRESS ); (* do a stack trace back w.r.t. given instruction and frame pointers *)
- BEGIN
- Log.Ln; Log.String( "#######################" );
- Log.Ln; Log.String( "# Debugging.TraceBack #" );
- Log.Ln; Log.String( "#######################" );
- Log.Ln; Reflection.StackTraceBack( Log, eip, ebp, stacklow, stackhigh, TRUE , FALSE );
- Log.Update;
- END TraceBackThis;
- PROCEDURE TraceBack*; (* do a stack trace back starting at the calling instruction position *)
- BEGIN
- Enter;
- TraceBackThis( Machine.CurrentPC(), SYSTEM.GetFramePointer(), SYSTEM.GetStackPointer(), Objects.GetStackBottom(Objects.CurrentProcess()) );
- Exit;
- END TraceBack;
- (* TraceBackAll implemented in System.ShowStacks *)
- PROCEDURE FileStart*(context: Commands.Context); (* start writing to a the file Debugging.Text *)
- VAR w: Files.Writer; filename: ARRAY 256 OF CHAR;
- BEGIN
- IF context # NIL THEN
- context.arg.String(filename);
- ELSE
- filename := ""
- END;
- IF (filename = "") THEN filename := "Debugging.Text" END;
- KernelLog.String("filename = "); KernelLog.String(filename); KernelLog.String("<"); KernelLog.Ln;
- f := Files.New( filename );
- Files.OpenWriter( w, f, 0 );
- Log := w
- END FileStart;
- PROCEDURE FileEnd*; (* stop writing to Debugging.Text *)
- BEGIN
- Log.Update; Files.Register( f ); f.Update; f := NIL; Log := DefaultLog;
- END FileEnd;
- (* shortcut for String, usage deprecated *)
- PROCEDURE Str*( CONST name: ARRAY OF CHAR );
- BEGIN
- Log.String( name );
- END Str;
- PROCEDURE String*(CONST name: ARRAY OF CHAR);
- BEGIN
- Log.String(name);
- END String;
- PROCEDURE Address*(i: ADDRESS);
- BEGIN
- Log.Address(i);
- END Address;
- PROCEDURE Int*( i: HUGEINT; j: WORD );
- BEGIN
- Log.Int( i, j );
- END Int;
- PROCEDURE Set*(set: SET);
- VAR i: WORD; first: BOOLEAN;
- BEGIN
- Log.String("{"); first := TRUE;
- FOR i := MIN(SET) TO MAX(SET) DO
- IF i IN set THEN
- IF first THEN first := FALSE ELSE Log.String(",") END;
- Log.Int(i,1)
- END;
- END;
- Log.String("}");
- END Set;
- PROCEDURE Float*( r: LONGREAL; len: WORD );
- BEGIN
- Log.Float( r, len );
- END Float;
- PROCEDURE Hex*( i: HUGEINT; j: WORD );
- BEGIN
- Log.Hex( i, j );
- END Hex;
- PROCEDURE HIntHex*( x: HUGEINT );
- BEGIN
- Hex( SHORT( ASH( x, -32 ) ),1 ); Hex( SHORT( x ),1 )
- END HIntHex;
- PROCEDURE Char*( c: CHAR );
- BEGIN
- Log.Char( c );
- END Char;
- PROCEDURE Update*;
- BEGIN
- Log.Update;
- END Update;
- PROCEDURE Ln*;
- BEGIN
- Log.Ln; Update;
- END Ln;
- PROCEDURE Type*( p: ANY ); (* output the type name of object pointed to by p *)
- VAR t: Modules.TypeDesc;
- BEGIN
- IF p = NIL THEN Str( "NIL (no type)" )
- ELSE
- t := Modules.TypeOf( p );
- IF t = NIL THEN Str( "unknown" ) ELSE Str( t.mod.name ); Str( "." ); Str( t.name ); END;
- END;
- END Type;
- PROCEDURE Str0*( idx: StringPool.Index ); (* output string index as string *)
- VAR name: ARRAY 256 OF CHAR;
- BEGIN
- StringPool.GetString( idx, name ); Log.String( name );
- END Str0;
- PROCEDURE Enter*; (* start exclusive writing *)
- VAR a: ANY; p: Objects.Process; dt: Dates.DateTime;
- BEGIN
- lock.AcquireWrite; Ln;
- Str( "{ [P " ); p := Objects.CurrentProcess(); Int( p.id,1 ); Str( " " ); a := Objects.ActiveObject(); Type( a ); Str( "] " );
- dt := Dates.Now(); Int(dt.hour,0); Char(':'); Int(dt.minute,0); Char(':'); Int(dt.second,0);
- END Enter;
- PROCEDURE Exit*; (* end exclusive writing *)
- BEGIN
- Str( "}" ); Log.Update; lock.ReleaseWrite;
- END Exit;
- PROCEDURE Nothing;
- BEGIN
- END Nothing;
- PROCEDURE Halt*;
- BEGIN HALT (1234);
- END Halt;
- PROCEDURE DisableGC*;
- BEGIN
- Heaps.GC := Nothing;
- TRACE(Heaps.GC, "disabled");
- END DisableGC;
- PROCEDURE EnableGC*;
- BEGIN
- Heaps.GC := Heaps.InvokeGC;
- TRACE(Heaps.GC, "enabled");
- END EnableGC;
- (* useful for debugging the GC / metadata *)
- PROCEDURE ReportProcedureDescriptors*;
- VAR m: Modules.Module; i,j: SIZE;
- BEGIN
- m := Modules.root;
- WHILE (m # NIL) DO
- TRACE(m.name);
- IF m.procTable # NIL THEN
- FOR i := 0 TO LEN(m.procTable)-1 DO
- (*TRACE(m.procTable[i]);*)
- Log.Address(m.procTable[i]);
- Log.String(":");
- Reflection.WriteProc(Log, m.procTable[i].pcFrom);
- Log.String(" ptrs @ ");
- FOR j := 0 TO LEN(m.procTable[i].offsets)-1 DO
- Log.Int(m.procTable[i].offsets[j],1);
- Log.String(" ");
- END;
- Log.Ln;
- END;
- END;
- m := m.next;
- END;
- END ReportProcedureDescriptors;
- PROCEDURE ReportModule* (context: Commands.Context);
- VAR m: Modules.Module; name: Modules.Name;
- BEGIN
- IF ~context.arg.GetString (name) THEN
- context.result := Commands.CommandParseError;
- RETURN;
- END;
- m := Modules.root;
- WHILE (m # NIL) DO
- IF m.name = name THEN
- Reflection.Report (context.out, m.refs, 0);
- context.result := Commands.Ok;
- RETURN;
- END;
- m := m.next;
- END;
- context.result := Commands.CommandError;
- END ReportModule;
- PROCEDURE Test*;
- BEGIN
- Stack("Stack");
- END Test;
- BEGIN
- Streams.OpenWriter( DefaultLog, KernelLog.Send ); Log := DefaultLog; NEW( lock );
- END Debugging.
- System.FreeDownTo Debugging ~
- Debugging.ReportProcedureDescriptors
|