Difference between revisions of "Logging exceptions"
(Added different examples for current call stack and exception call stack.) |
|||
Line 57: | Line 57: | ||
− | == | + | ==Dump current call stack== |
− | === | + | <delphi>procedure DumpCallStack; |
+ | var | ||
+ | I: Longint; | ||
+ | prevbp: Pointer; | ||
+ | CallerFrame, | ||
+ | CallerAddress, | ||
+ | bp: Pointer; | ||
+ | Report: string; | ||
+ | const | ||
+ | MaxDepth = 20; | ||
+ | NewLine = #13#10; | ||
+ | begin | ||
+ | Report := ''; | ||
+ | bp := get_frame; | ||
+ | // This trick skip SendCallstack item | ||
+ | // bp:= get_caller_frame(get_frame); | ||
+ | try | ||
+ | prevbp := bp - 1; | ||
+ | I := 0; | ||
+ | while bp > prevbp do begin | ||
+ | CallerAddress := get_caller_addr(bp); | ||
+ | CallerFrame := get_caller_frame(bp); | ||
+ | if (CallerAddress = nil) then | ||
+ | Break; | ||
+ | Report := Report + BackTraceStrFunc(CallerAddress) + NewLine; | ||
+ | Inc(I); | ||
+ | if (I >= MaxDepth) or (CallerFrame = nil) then | ||
+ | Break; | ||
+ | prevbp := bp; | ||
+ | bp := CallerFrame; | ||
+ | end; | ||
+ | except | ||
+ | { prevent endless dump if an exception occured } | ||
+ | end; | ||
+ | ShowMessage(Report); | ||
+ | end;</delphi> | ||
− | + | ==Handling exceptions== | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | ===Dump exception call stack=== | ||
− | + | Call stack of exception can be obtained through SysUtils functions '''ExceptAddr''', '''ExceptFrames''' and '''ExceptFrameCount'''. | |
− | + | <delphi>uses SysUtils; | |
− | + | procedure DumpExceptionCallStack(E: Exception); | |
const | const | ||
NewLine = #13#10; | NewLine = #13#10; | ||
Line 93: | Line 121: | ||
Frames := ExceptFrames; | Frames := ExceptFrames; | ||
for I := 0 to ExceptFrameCount - 1 do | for I := 0 to ExceptFrameCount - 1 do | ||
− | Report := Report + NewLine + BackTraceStrFunc(Frames); | + | Report := Report + NewLine + BackTraceStrFunc(Frames[I]); |
ShowMessage(Report); | ShowMessage(Report); | ||
+ | Halt; // End of program execution | ||
+ | end;</delphi> | ||
+ | |||
+ | |||
+ | ===Manual exception handling=== | ||
+ | |||
+ | Manual executions of exception handler can be inserted to many places in code. | ||
+ | |||
+ | <delphi> | ||
+ | try | ||
+ | // Some operation which raise exception | ||
+ | raise Exception.Create('Test error'); | ||
+ | except | ||
+ | on E: Exception do | ||
+ | DumpExceptionCallStack(E); | ||
+ | end;</delphi> | ||
+ | |||
+ | |||
+ | ===Application.OnException=== | ||
+ | |||
+ | This event can be used to override default application wide exceptions handling. Custom logging mechanism could provide show custom dialog, log to file, console, sending report to mail, logging to HTTP server, e.g. | ||
+ | |||
+ | <delphi>procedure TMainForm.CustomExceptionHandler(Sender: TObject; E: Exception); | ||
+ | begin | ||
+ | DumpExceptionCallStack; | ||
Halt; // End of program execution | Halt; // End of program execution | ||
end; | end; | ||
Line 113: | Line 166: | ||
===Exceptions in DLL=== | ===Exceptions in DLL=== | ||
− | |||
− | |||
− | |||
==See also== | ==See also== |
Revision as of 22:45, 3 September 2010
Introduction
Stacktrace is sometimes called Backtrace or Call stack and have meaning of list of stack frames placed on stack containing return address and local variables. Stacktrace is useful to trace back path of execution of nesting procedures.
Compiler have to be directed to get debug information by switches.
- -g - generate debug informations
- -gl - generate line numbers for debug informations
Unit SysUtils
Contains some routines useful for debugging exceptions.
<delphi>{ Exception handling routines } function ExceptObject: TObject; function ExceptAddr: Pointer; function ExceptFrameCount: Longint; function ExceptFrames: PPointer;</delphi>
Unit System
Contains some stack related routines:
<delphi>function SysBackTraceStr(Addr:Pointer): ShortString; // Default address to string converter assigned to BackTraceStrFunc procedure Dump_Stack(var f : text;bp:pointer); // Dump stack to text file procedure DumpExceptionBackTrace(var f:text); // Dump backtrace to text file</delphi>
Procedural variable BackTraceStrFunc responsible to translate memory address to string debug information. Default behavior is implemented by SysBackTraceStr.
STAB
If STAB debugging information is selected (compiler switch -gl), unit lineinfo is automatically included to program and BackTraceStrFunc function is remapped to StabBackTraceStr.
DWARF
If DWARF debugging information is selected (compiler switch -gw), unit lnfodwrf is automatically included to program and BackTraceStrFunc function is remapped to DwarfBacktraceStr.
Unit LCLProc
<delphi>// Debugging procedure RaiseGDBException(const Msg: string); procedure RaiseAndCatchException; procedure DumpExceptionBackTrace; procedure DumpStack; function GetStackTrace(UseCache: boolean): string; procedure GetStackTracePointers(var AStack: TStackTracePointers); function StackTraceAsString(const AStack: TStackTracePointers;
UseCache: boolean): string;
function GetLineInfo(Addr: Pointer; UseCache: boolean): string;</delphi>
FPC help:
Dump current call stack
<delphi>procedure DumpCallStack; var
I: Longint; prevbp: Pointer; CallerFrame, CallerAddress, bp: Pointer; Report: string;
const
MaxDepth = 20; NewLine = #13#10;
begin
Report := ; bp := get_frame; // This trick skip SendCallstack item // bp:= get_caller_frame(get_frame); try prevbp := bp - 1; I := 0; while bp > prevbp do begin CallerAddress := get_caller_addr(bp); CallerFrame := get_caller_frame(bp); if (CallerAddress = nil) then Break; Report := Report + BackTraceStrFunc(CallerAddress) + NewLine; Inc(I); if (I >= MaxDepth) or (CallerFrame = nil) then Break; prevbp := bp; bp := CallerFrame; end; except { prevent endless dump if an exception occured } end; ShowMessage(Report);
end;</delphi>
Handling exceptions
Dump exception call stack
Call stack of exception can be obtained through SysUtils functions ExceptAddr, ExceptFrames and ExceptFrameCount.
<delphi>uses SysUtils;
procedure DumpExceptionCallStack(E: Exception); const
NewLine = #13#10;
var
I: Integer; Frames: PPointer; Report: string;
begin
Report := 'Program exception! ' + NewLine + 'Stacktrace:' + NewLine + NewLine; if E <> nil then begin Report := Report + 'Exception class: ' + E.ClassName + NewLine + 'Message: ' + E.Message + NewLine; end; Report := Report + BackTraceStrFunc(ExceptAddr); Frames := ExceptFrames; for I := 0 to ExceptFrameCount - 1 do Report := Report + NewLine + BackTraceStrFunc(Frames[I]); ShowMessage(Report); Halt; // End of program execution
end;</delphi>
Manual exception handling
Manual executions of exception handler can be inserted to many places in code.
<delphi> try
// Some operation which raise exception raise Exception.Create('Test error');
except
on E: Exception do DumpExceptionCallStack(E);
end;</delphi>
Application.OnException
This event can be used to override default application wide exceptions handling. Custom logging mechanism could provide show custom dialog, log to file, console, sending report to mail, logging to HTTP server, e.g.
<delphi>procedure TMainForm.CustomExceptionHandler(Sender: TObject; E: Exception); begin
DumpExceptionCallStack; Halt; // End of program execution
end;
procedure TMainForm.FormCreate(Sender: TObject); begin
Application.OnException := @CustomExceptionHandler;
end;
procedure TMainForm.ButtonClick(Sender: TObject); begin
raise Exception.Create('Test');
end;</delphi>
Using map file
Use compiler switch -Xm to generate map file.
Exceptions in DLL
See also
External links
- esprinter - tool to get stacktrace from running FreePascal program specified by process id and thread id (for Win32)