lazarus/components/fpdebug/app/fpd/fpdloop.pas
2014-03-12 21:35:06 +00:00

231 lines
6.6 KiB
ObjectPascal

{ $Id$ }
{
---------------------------------------------------------------------------
fpdloop.pas - FP standalone debugger - Debugger main loop
---------------------------------------------------------------------------
This unit contains the main loop of the debugger. It waits for a debug
event and handles it
---------------------------------------------------------------------------
@created(Mon Apr 10th WET 2006)
@lastmod($Date$)
@author(Marc Weustink <marc@@dommelstein.nl>)
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
***************************************************************************
}
unit FPDLoop;
{$mode objfpc}{$H+}
interface
uses
{$IFDEF WINDOWS}
FpDbgWinExtra,
{$ENDIF}
Classes, SysUtils, FileUtil, FpDbgInfo, FpDbgClasses, FpDbgDisasX86, DbgIntfBaseTypes;
procedure DebugLoop;
implementation
uses
FPDGlobal, FPDType, FpDbgUtil, FpdMemoryTools;
procedure DebugLoop;
procedure ShowDisas;
var
a: TDbgPtr;
Code, CodeBytes: String;
begin
WriteLN('===');
{$ifdef windows}
{$ifdef cpui386}
a := GCurrentContext^.EIP;
Write(' [', FormatAddress(a), ']');
Disassemble(GCurrentProcess.Handle, False, a, CodeBytes, Code);
{$else}
a := GCurrentContext^.RIP;
Write(' [', FormatAddress(a), ']');
Disassemble(GCurrentProcess.Handle, True, a, CodeBytes, Code);
{$endif}
{$else}
a := 0;
{$endif}
WriteLN(' ', CodeBytes, ' ', Code);
end;
procedure ShowCode;
var
a: TDbgPtr;
sym, symproc: TFpDbgSymbol;
S: TStringList;
Name: String;
begin
WriteLN('===');
{$ifdef windows}
{$ifdef cpui386}
a := GCurrentContext^.EIP;
{$else}
a := GCurrentContext^.RIP;
{$endif}
{$else}
a := 0;
{$endif}
sym := GCurrentProcess.FindSymbol(a);
if sym = nil
then begin
WriteLn(' [', FormatAddress(a), '] ???');
Exit;
end;
symproc := sym;
while not (symproc.kind in [skProcedure, skFunction]) do
symproc := symproc.Parent;
if sym <> symproc
then begin
if symproc = nil
then WriteLn('???')
else begin
WriteLn(symproc.FileName, ' ', symproc.Line, ':', symproc.Column, ' ', symproc.Name);
end;
Write(' ');
end;
WriteLn(sym.FileName, ' ', sym.Line, ':', sym.Column, ' ', sym.Name);
Write(' [', FormatAddress(LocToAddrOrNil(sym.Address)), '+', a-LocToAddrOrNil(sym.Address), '] ');
Name := sym.Filename;
if not FileExistsUTF8(Name)
then begin
if ExtractFilePath(Name) = ''
then begin
Name := IncludeTrailingPathDelimiter(ExtractFilePath(GFileName)) + Name;
if not FileExistsUTF8(Name)
then Name := '';
end
else Name := '';
end;
if Name = ''
then begin
WriteLn(' File not found');
Exit;
end;
S := TStringList.Create;
try
S.LoadFromFile(UTF8ToSys(Name));
if S.Count < sym.Line
then WriteLn('Line not found')
else WriteLn(S[sym.Line - 1]);
except
on E: Exception do WriteLn(E.Message);
end;
S.Free;
end;
var
AFirstLoop: boolean;
AProcessIdentifier: THandle;
ALib: TDbgLibrary;
begin
repeat
if (GState in [dsStop, dsPause, dsEvent])
then begin
GCurrentProcess.Continue(GCurrentProcess, GCurrentThread, GState);
GState := dsRun;
end;
if not GCurrentProcess.WaitForDebugEvent(AProcessIdentifier) then Continue;
if assigned(GCurrentProcess) and not assigned(GMainProcess) then
begin
GMainProcess:=GCurrentProcess;
AFirstLoop:=true;
end
else
AFirstLoop:=false;
GCurrentProcess := nil;
GCurrentThread := nil;
if not GetProcess(AProcessIdentifier, GCurrentProcess) and not AFirstLoop then Continue;
if AFirstLoop then
GCurrentProcess := GMainProcess;
//if not GetThread(MDebugEvent.dwTHreadID, GCurrentThread)
//then WriteLN('LOOP: Unable to retrieve current thread');
GState := dsEvent;
begin
case GCurrentProcess.ResolveDebugEvent(GCurrentThread) of
deException : GState := dsPause;
deCreateProcess :
begin
GProcessMap.Add(AProcessIdentifier, GCurrentProcess);
//if AEvent.CreateProcessInfo.lpBaseOfImage <> nil
//then DumpPEImage(AEvent.CreateProcessInfo.hProcess, TDbgPtr(AEvent.CreateProcessInfo.lpBaseOfImage));
if GBreakOnLibraryLoad
then GState := dsPause;
end;
deExitProcess :
begin
if GCurrentProcess = GMainProcess then GMainProcess := nil;
GProcessMap.Delete(AProcessIdentifier);
GState := dsStop;
WriteLN('Process stopped with exitcode: ', GCurrentProcess.ExitCode);
end;
deLoadLibrary :
begin
if GCurrentProcess.GetLib(GCurrentProcess.LastEventProcessIdentifier, ALib)
and (GImageInfo <> iiNone)
then begin
WriteLN('Name: ', ALib.Name);
//if GImageInfo = iiDetail
//then DumpPEImage(Proc.Handle, Lib.BaseAddr);
end;
if GBreakOnLibraryLoad
then GState := dsPause;
end;
deBreakpoint :
begin
GState:=dsPause;
end;
end; {case}
end;
until (GState in [dsStop, dsPause, dsQuit]);
if GState = dsPause
then begin
ShowDisas;
ShowCode;
end;
end;
end.