grendel-1.0.0a7/backup/
grendel-1.0.0a7/bin/
grendel-1.0.0a7/boards/
grendel-1.0.0a7/clans/
grendel-1.0.0a7/documentation/todo/
grendel-1.0.0a7/help/
grendel-1.0.0a7/logs/
grendel-1.0.0a7/players/
grendel-1.0.0a7/progs/
grendel-1.0.0a7/races/
grendel-1.0.0a7/src/contrib/
grendel-1.0.0a7/src/modules/speller/
grendel-1.0.0a7/src/modules/status/
grendel-1.0.0a7/src/tests/
grendel-1.0.0a7/src/tests/dunit/
{
	Summary:
		Internal debug routines
		
	## $Id: debug.pas,v 1.14 2004/04/10 22:24:03 druid Exp $
}

unit debug;

interface


uses
	SysUtils;
	
 
procedure initDebug();
procedure cleanupDebug();

procedure reportException(E : Exception; const sourceFile : string = '');


implementation


uses
{$IFDEF WIN32}
	Windows,
	JclHookExcept,
	JclDebug,
{$ENDIF}
{$IFDEF LINUX}
	Libc,
{$ENDIF}
	Classes,
	console;


{$IFDEF WIN32}
procedure AnyExceptionNotify(ExceptObj: TObject; ExceptAddr: Pointer; OSException: Boolean);
var
	list : TJclExceptFrameList;
begin
	list := JclLastExceptFrameList;
	
	// (definately a) handled exception, quit
	if (list.items[0].FrameKind = efkAnyException) then
		exit;

	if (ExceptObj = nil) then
		reportException(nil, 'debug.pas:AnyExceptionNotify')
	else
		reportException(ExceptObj as Exception, 'debug.pas:AnyExceptionNotify');
end;

function ExceptionFilter(ExceptionInfo: _EXCEPTION_POINTERS): longint; stdcall;
begin
	//MessageBox(0, 'filter', 'filter', 0);
	Result := 1;
end;

procedure reportException(E : Exception; const sourceFile : string = '');
var
	a : integer;
	strings : TStringList;
begin
	if (E = nil) then
		writeConsole('[EX ' + sourceFile + '] EUnknown', 1)
	else
		writeConsole('[EX ' + sourceFile + '] ' + E.ClassName + ': ' + E.Message, 1);
		
	strings := TStringList.Create();

	JclLastExceptStackListToStrings(strings, False, False, False);

	if (strings.count > 0) then
		begin
		writeConsole('Stacktrace follows:', 1);

		for a := 0 to strings.count - 1 do
			writeConsole(strings[a], 1);
		end
	else
		writeConsole('No stacktrace available.', 1);

	strings.Free();
end;

{$ENDIF}

{$IFDEF LINUX}
function backtrace(var __array; __size : integer) : integer; cdecl; external 'libc.so.6' name 'backtrace';

procedure findSymbol(addr : pointer);
var
	info : TDLInfo;
begin
	dladdr(addr, info);
	
	writeConsole('(' + IntToHex(integer(addr), 8) + ') ' + info.dli_sname + ' in ' + info.dli_fname, 1);
end;

procedure listBackTrace();
var
	l, ret : integer;
	x : array[0..15] of pointer;
begin
	ret := backtrace(x, 16);
	
	for l := 0 to ret - 1 do
		findSymbol(x[l]);
end;

procedure reportException(E : Exception; const sourceFile : string = '');
begin
	E := ExceptObject as Exception;

	writeConsole('[EX ' + sourceFile + '] ' + E.ClassName + ': ' + E.Message, 1);
		
	listBackTrace();
end;
{$ENDIF}

var
	oldExceptProc :  pointer;

procedure ExceptHandler(ExceptObject : TObject; ExceptAddr : Pointer);
begin
	ExceptProc := oldExceptProc;
	
	{$IFDEF LINUX}	
	reportException(ExceptObject as Exception, 'debug.pas:ExceptHandler');
	{$ENDIF}
	
	Halt(1);
end;

procedure initDebug();
begin
{$IFDEF WIN32}
	// initialize the debug 'fail-safe device'
	JclStackTrackingOptions := JclStackTrackingOptions + [stRawMode,stStaticModuleList,stExceptFrame];
	SetUnhandledExceptionFilter(@ExceptionFilter);

	JclStartExceptionTracking();
	JclInitializeLibrariesHookExcept();
	JclAddExceptNotifier(AnyExceptionNotify);
{$ENDIF}

	oldExceptProc := exceptProc;
	ExceptProc := @ExceptHandler;
end;

procedure cleanupDebug();
begin
{$IFDEF WIN32}
	JclStopExceptionTracking();
{$ENDIF}
end;
	
end.