mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-15 11:49:55 +02:00
* Initial release
git-svn-id: trunk@9133 -
This commit is contained in:
parent
e6b1bcdea6
commit
b0be3088b7
10
.gitattributes
vendored
10
.gitattributes
vendored
@ -565,6 +565,16 @@ debugger/watchesdlg.pp svneol=native#text/pascal
|
||||
debugger/watchpropertydlg.lfm svneol=native#text/plain
|
||||
debugger/watchpropertydlg.lrs svneol=native#text/pascal
|
||||
debugger/watchpropertydlg.pp svneol=native#text/pascal
|
||||
debugger/windebug/fpwd/README svneol=native#text/plain
|
||||
debugger/windebug/fpwd/fpwd.lpi svneol=native#text/plain
|
||||
debugger/windebug/fpwd/fpwd.lpr svneol=native#text/pascal
|
||||
debugger/windebug/fpwd/fpwdcommand.pas svneol=native#text/pascal
|
||||
debugger/windebug/fpwd/fpwdglobal.pas svneol=native#text/pascal
|
||||
debugger/windebug/fpwd/fpwdloop.pas svneol=native#text/pascal
|
||||
debugger/windebug/fpwd/fpwdpeimage.pas svneol=native#text/pascal
|
||||
debugger/windebug/fpwd/fpwdtype.pas svneol=native#text/pascal
|
||||
debugger/windebug/windebugger.pp svneol=native#text/pascal
|
||||
debugger/windebug/windextra.pp svneol=native#text/pascal
|
||||
designer/abstractcompiler.pp svneol=native#text/pascal
|
||||
designer/abstracteditor.pp svneol=native#text/pascal
|
||||
designer/abstractfilesystem.pp svneol=native#text/pascal
|
||||
|
10
debugger/windebug/fpwd/README
Normal file
10
debugger/windebug/fpwd/README
Normal file
@ -0,0 +1,10 @@
|
||||
---------------------------------------------------------------------------
|
||||
fpwd - FP standalone windows debugger
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
fpwd is a concept Free Pascal Windows Debugger. It is mainly used to thest
|
||||
the windebugger classes, but it may grow someday to a fully functional
|
||||
debugger written in pascal. I hope you enjoy it.
|
||||
|
||||
Marc Weustink
|
||||
|
389
debugger/windebug/fpwd/fpwd.lpi
Normal file
389
debugger/windebug/fpwd/fpwd.lpi
Normal file
@ -0,0 +1,389 @@
|
||||
<?xml version="1.0"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<PathDelim Value="\"/>
|
||||
<Version Value="5"/>
|
||||
<General>
|
||||
<MainUnit Value="0"/>
|
||||
<IconPath Value="./"/>
|
||||
<TargetFileExt Value=".exe"/>
|
||||
<ActiveEditorIndexAtStart Value="3"/>
|
||||
</General>
|
||||
<LazDoc Paths=""/>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<IgnoreBinaries Value="False"/>
|
||||
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<local>
|
||||
<FormatVersion Value="1"/>
|
||||
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
|
||||
</local>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="1">
|
||||
<Item1>
|
||||
<PackageName Value="LCL"/>
|
||||
</Item1>
|
||||
</RequiredPackages>
|
||||
<Units Count="18">
|
||||
<Unit0>
|
||||
<Filename Value="fpwd.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="fpwd"/>
|
||||
<CursorPos X="3" Y="47"/>
|
||||
<TopLine Value="25"/>
|
||||
<EditorIndex Value="3"/>
|
||||
<UsageCount Value="25"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="fpwdcommand.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="FPWDCommand"/>
|
||||
<CursorPos X="1" Y="7"/>
|
||||
<TopLine Value="1"/>
|
||||
<EditorIndex Value="7"/>
|
||||
<UsageCount Value="25"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit1>
|
||||
<Unit2>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="WinDebugger"/>
|
||||
<CursorPos X="1" Y="34"/>
|
||||
<TopLine Value="34"/>
|
||||
<EditorIndex Value="0"/>
|
||||
<UsageCount Value="24"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit2>
|
||||
<Unit3>
|
||||
<Filename Value="fpwdtype.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="FPWDType"/>
|
||||
<CursorPos X="2" Y="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<EditorIndex Value="4"/>
|
||||
<UsageCount Value="25"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit3>
|
||||
<Unit4>
|
||||
<Filename Value="fpwdutil.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="FPWDUtil"/>
|
||||
<CursorPos X="26" Y="4"/>
|
||||
<TopLine Value="1"/>
|
||||
<UsageCount Value="25"/>
|
||||
</Unit4>
|
||||
<Unit5>
|
||||
<Filename Value="fpwdglobal.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="FPWDGlobal"/>
|
||||
<CursorPos X="1" Y="34"/>
|
||||
<TopLine Value="14"/>
|
||||
<EditorIndex Value="2"/>
|
||||
<UsageCount Value="25"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit5>
|
||||
<Unit6>
|
||||
<Filename Value="..\..\..\..\fpc\fpc.2.0.2\rtl\win32\classes.pp"/>
|
||||
<UnitName Value="Classes"/>
|
||||
<CursorPos X="1" Y="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<UsageCount Value="11"/>
|
||||
</Unit6>
|
||||
<Unit7>
|
||||
<Filename Value="..\..\..\..\fpc\fpc.2.0.2\rtl\win32\windows.pp"/>
|
||||
<UnitName Value="windows"/>
|
||||
<CursorPos X="47" Y="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<UsageCount Value="11"/>
|
||||
</Unit7>
|
||||
<Unit8>
|
||||
<Filename Value="..\..\..\lcl\maps.pp"/>
|
||||
<UnitName Value="maps"/>
|
||||
<CursorPos X="57" Y="36"/>
|
||||
<TopLine Value="25"/>
|
||||
<UsageCount Value="11"/>
|
||||
</Unit8>
|
||||
<Unit9>
|
||||
<Filename Value="..\windextra.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="WindExtra"/>
|
||||
<CursorPos X="25" Y="19"/>
|
||||
<TopLine Value="31"/>
|
||||
<EditorIndex Value="1"/>
|
||||
<UsageCount Value="24"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit9>
|
||||
<Unit10>
|
||||
<Filename Value="fpwdbreak.pas"/>
|
||||
<UnitName Value="FPWDBreak"/>
|
||||
<CursorPos X="1" Y="2"/>
|
||||
<TopLine Value="1"/>
|
||||
<EditorIndex Value="8"/>
|
||||
<UsageCount Value="11"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit10>
|
||||
<Unit11>
|
||||
<Filename Value="..\..\..\..\fpc\fpc.2.0.2\rtl\objpas\types.pp"/>
|
||||
<UnitName Value="types"/>
|
||||
<CursorPos X="1" Y="130"/>
|
||||
<TopLine Value="108"/>
|
||||
<UsageCount Value="10"/>
|
||||
</Unit11>
|
||||
<Unit12>
|
||||
<Filename Value="..\..\..\..\fpc\fpc.2.0.2\rtl\win32\wininc\base.inc"/>
|
||||
<CursorPos X="33" Y="80"/>
|
||||
<TopLine Value="62"/>
|
||||
<UsageCount Value="10"/>
|
||||
</Unit12>
|
||||
<Unit13>
|
||||
<Filename Value="..\..\..\..\fpc\fpc.2.0.2\rtl\win32\wininc\struct.inc"/>
|
||||
<CursorPos X="1" Y="1629"/>
|
||||
<TopLine Value="1619"/>
|
||||
<UsageCount Value="10"/>
|
||||
</Unit13>
|
||||
<Unit14>
|
||||
<Filename Value="..\..\..\..\fpc\fpc.2.0.2\rtl\inc\objpash.inc"/>
|
||||
<CursorPos X="23" Y="118"/>
|
||||
<TopLine Value="107"/>
|
||||
<UsageCount Value="10"/>
|
||||
</Unit14>
|
||||
<Unit15>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<UnitName Value="FPWDLoop"/>
|
||||
<CursorPos X="1" Y="9"/>
|
||||
<TopLine Value="1"/>
|
||||
<EditorIndex Value="5"/>
|
||||
<UsageCount Value="11"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit15>
|
||||
<Unit16>
|
||||
<Filename Value="fpwdpeimage.pas"/>
|
||||
<UnitName Value="FPWDPEImage"/>
|
||||
<CursorPos X="1" Y="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<UsageCount Value="11"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit16>
|
||||
<Unit17>
|
||||
<Filename Value="..\..\..\lcl\lclproc.pas"/>
|
||||
<UnitName Value="LCLProc"/>
|
||||
<CursorPos X="57" Y="32"/>
|
||||
<TopLine Value="14"/>
|
||||
<EditorIndex Value="9"/>
|
||||
<UsageCount Value="11"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit17>
|
||||
</Units>
|
||||
<JumpHistory Count="30" HistoryIndex="29">
|
||||
<Position1>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<Caret Line="6" Column="32" TopLine="3"/>
|
||||
</Position1>
|
||||
<Position2>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<Caret Line="33" Column="1" TopLine="22"/>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<Caret Line="21" Column="1" TopLine="11"/>
|
||||
</Position3>
|
||||
<Position4>
|
||||
<Filename Value="..\windextra.pp"/>
|
||||
<Caret Line="25" Column="1" TopLine="12"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
<Filename Value="..\windextra.pp"/>
|
||||
<Caret Line="34" Column="1" TopLine="12"/>
|
||||
</Position5>
|
||||
<Position6>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<Caret Line="34" Column="1" TopLine="15"/>
|
||||
</Position6>
|
||||
<Position7>
|
||||
<Filename Value="fpwdglobal.pas"/>
|
||||
<Caret Line="34" Column="1" TopLine="12"/>
|
||||
</Position7>
|
||||
<Position8>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<Caret Line="4" Column="1" TopLine="1"/>
|
||||
</Position8>
|
||||
<Position9>
|
||||
<Filename Value="..\windebugger.pp"/>
|
||||
<Caret Line="162" Column="1" TopLine="144"/>
|
||||
</Position9>
|
||||
<Position10>
|
||||
<Filename Value="fpwd.lpr"/>
|
||||
<Caret Line="10" Column="1" TopLine="1"/>
|
||||
</Position10>
|
||||
<Position11>
|
||||
<Filename Value="fpwdcommand.pas"/>
|
||||
<Caret Line="560" Column="49" TopLine="549"/>
|
||||
</Position11>
|
||||
<Position12>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="14" Column="15" TopLine="1"/>
|
||||
</Position12>
|
||||
<Position13>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="4" Column="1" TopLine="1"/>
|
||||
</Position13>
|
||||
<Position14>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="28" Column="28" TopLine="17"/>
|
||||
</Position14>
|
||||
<Position15>
|
||||
<Filename Value="fpwdcommand.pas"/>
|
||||
<Caret Line="13" Column="46" TopLine="1"/>
|
||||
</Position15>
|
||||
<Position16>
|
||||
<Filename Value="fpwdcommand.pas"/>
|
||||
<Caret Line="273" Column="43" TopLine="262"/>
|
||||
</Position16>
|
||||
<Position17>
|
||||
<Filename Value="fpwdglobal.pas"/>
|
||||
<Caret Line="34" Column="1" TopLine="24"/>
|
||||
</Position17>
|
||||
<Position18>
|
||||
<Filename Value="fpwd.lpr"/>
|
||||
<Caret Line="21" Column="1" TopLine="1"/>
|
||||
</Position18>
|
||||
<Position19>
|
||||
<Filename Value="fpwd.lpr"/>
|
||||
<Caret Line="34" Column="1" TopLine="12"/>
|
||||
</Position19>
|
||||
<Position20>
|
||||
<Filename Value="fpwdtype.pas"/>
|
||||
<Caret Line="79" Column="1" TopLine="64"/>
|
||||
</Position20>
|
||||
<Position21>
|
||||
<Filename Value="fpwdtype.pas"/>
|
||||
<Caret Line="34" Column="1" TopLine="12"/>
|
||||
</Position21>
|
||||
<Position22>
|
||||
<Filename Value="fpwdtype.pas"/>
|
||||
<Caret Line="62" Column="1" TopLine="56"/>
|
||||
</Position22>
|
||||
<Position23>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="6" Column="1" TopLine="1"/>
|
||||
</Position23>
|
||||
<Position24>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="32" Column="1" TopLine="12"/>
|
||||
</Position24>
|
||||
<Position25>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="194" Column="1" TopLine="188"/>
|
||||
</Position25>
|
||||
<Position26>
|
||||
<Filename Value="fpwdloop.pas"/>
|
||||
<Caret Line="385" Column="5" TopLine="363"/>
|
||||
</Position26>
|
||||
<Position27>
|
||||
<Filename Value="fpwdpeimage.pas"/>
|
||||
<Caret Line="10" Column="1" TopLine="1"/>
|
||||
</Position27>
|
||||
<Position28>
|
||||
<Filename Value="fpwdpeimage.pas"/>
|
||||
<Caret Line="34" Column="1" TopLine="12"/>
|
||||
</Position28>
|
||||
<Position29>
|
||||
<Filename Value="fpwdcommand.pas"/>
|
||||
<Caret Line="6" Column="1" TopLine="1"/>
|
||||
</Position29>
|
||||
<Position30>
|
||||
<Filename Value="fpwdbreak.pas"/>
|
||||
<Caret Line="2" Column="10" TopLine="1"/>
|
||||
</Position30>
|
||||
</JumpHistory>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="5"/>
|
||||
<PathDelim Value="\"/>
|
||||
<SearchPaths>
|
||||
<OtherUnitFiles Value="..\;$(LazarusDir)\lcl\units\$(TargetCPU)-$(TargetOS)\;c:\fpc\rtl\units\$(TargetCPU)-$(TargetOS)\"/>
|
||||
<SrcPath Value="$(LazarusDir)\lcl\"/>
|
||||
</SearchPaths>
|
||||
<CodeGeneration>
|
||||
<Generate Value="Faster"/>
|
||||
</CodeGeneration>
|
||||
<Other>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<BreakPoints Count="11">
|
||||
<Item1>
|
||||
<Source Value="..\..\..\lcl\interfaces\gtk\gtklistsl.inc"/>
|
||||
<InitialEnabled Value="False"/>
|
||||
<Line Value="358"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Source Value="..\..\..\lcl\interfaces\gtk\gtklistsl.inc"/>
|
||||
<InitialEnabled Value="False"/>
|
||||
<Line Value="324"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Source Value="..\..\gdbmidebugger.pp"/>
|
||||
<Line Value="2039"/>
|
||||
</Item3>
|
||||
<Item4>
|
||||
<Source Value="..\..\..\ideintf\objectinspector.pp"/>
|
||||
<InitialEnabled Value="False"/>
|
||||
<Line Value="1908"/>
|
||||
</Item4>
|
||||
<Item5>
|
||||
<Source Value="..\..\..\ide\msgview.pp"/>
|
||||
<InitialEnabled Value="False"/>
|
||||
<Line Value="506"/>
|
||||
</Item5>
|
||||
<Item6>
|
||||
<Source Value="..\..\..\ide\msgview.pp"/>
|
||||
<InitialEnabled Value="False"/>
|
||||
<Line Value="457"/>
|
||||
</Item6>
|
||||
<Item7>
|
||||
<Source Value="..\..\gdbmidebugger.pp"/>
|
||||
<InitialEnabled Value="False"/>
|
||||
<Line Value="803"/>
|
||||
</Item7>
|
||||
<Item8>
|
||||
<Source Value="..\..\..\lcl\include\customcombobox.inc"/>
|
||||
<Line Value="796"/>
|
||||
</Item8>
|
||||
<Item9>
|
||||
<Source Value="..\..\..\lcl\interfaces\gtk\gtkobject.inc"/>
|
||||
<Line Value="4763"/>
|
||||
</Item9>
|
||||
<Item10>
|
||||
<Source Value="..\..\..\lcl\interfaces\gtk\gtkobject.inc"/>
|
||||
<Line Value="4142"/>
|
||||
</Item10>
|
||||
<Item11>
|
||||
<Source Value="..\..\..\test\maptest.lpr"/>
|
||||
<Line Value="41"/>
|
||||
</Item11>
|
||||
</BreakPoints>
|
||||
<Watches Count="3">
|
||||
<Item1>
|
||||
<Expression Value="Item^"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Expression Value="c"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Expression Value="FCurrent"/>
|
||||
</Item3>
|
||||
</Watches>
|
||||
<Exceptions Count="1">
|
||||
<Item1>
|
||||
<Name Value="ECodeToolError"/>
|
||||
</Item1>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
85
debugger/windebug/fpwd/fpwd.lpr
Normal file
85
debugger/windebug/fpwd/fpwd.lpr
Normal file
@ -0,0 +1,85 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
fpwd - FP standalone windows debugger
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
fpwd is a concept Free Pascal Windows Debugger. It is mainly used to thest
|
||||
the windebugger classes, but it may grow someday to a fully functional
|
||||
debugger written in pascal.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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. *
|
||||
* *
|
||||
***************************************************************************
|
||||
}
|
||||
program fpwd;
|
||||
{$mode objfpc}{$H+}
|
||||
{$APPTYPE CONSOLE}
|
||||
uses
|
||||
SysUtils,
|
||||
Windows,
|
||||
FPWDCommand,
|
||||
FPWDGlobal,
|
||||
FPWDLoop,
|
||||
FPWDPEImage,
|
||||
FPWDType,
|
||||
WinDebugger, WindExtra;
|
||||
|
||||
function CtrlCHandler(CtrlType: Cardinal): BOOL; stdcall;
|
||||
begin
|
||||
Result := False;
|
||||
case CtrlType of
|
||||
CTRL_C_EVENT,
|
||||
CTRL_BREAK_EVENT: begin
|
||||
if GState <> dsRun then Exit;
|
||||
if GMainProcess = nil then Exit;
|
||||
GMainProcess.Interrupt;
|
||||
|
||||
Result := True;
|
||||
end;
|
||||
CTRL_CLOSE_EVENT: begin
|
||||
if (GState in [dsRun, dsPause]) and (GMainProcess <> nil)
|
||||
then TerminateProcess(GMainProcess.Handle, 0);
|
||||
// GState := dsQuit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
S, Last: String;
|
||||
begin
|
||||
WriteLN('MWDebugger starting...');
|
||||
|
||||
SetConsoleCtrlHandler(@CtrlCHandler, True);
|
||||
repeat
|
||||
Write('MWD>');
|
||||
ReadLn(S);
|
||||
if S <> ''
|
||||
then Last := S;
|
||||
if Last = '' then Continue;
|
||||
HandleCommand(Last);
|
||||
until GState = dsQuit;
|
||||
SetConsoleCtrlHandler(@CtrlCHandler, False);
|
||||
end.
|
||||
|
609
debugger/windebug/fpwd/fpwdcommand.pas
Normal file
609
debugger/windebug/fpwd/fpwdcommand.pas
Normal file
@ -0,0 +1,609 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
fpwdcommand.pas - FP standalone windows debugger - Command interpreter
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
This unit contains handles all debugger commands
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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 FPWDCommand;
|
||||
{$mode objfpc}{$H+}
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes, Windows, WinDebugger, WinDExtra, LCLProc;
|
||||
|
||||
procedure HandleCommand(ACommand: String);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
FPWDGlobal, FPWDLoop, FPWDPEImage, FPWDType;
|
||||
|
||||
type
|
||||
TMWDCommandHandler = procedure(AParams: String);
|
||||
|
||||
TMWDCommand = class
|
||||
private
|
||||
FCommand: String;
|
||||
FHandler: TMWDCommandHandler;
|
||||
FHelp: String;
|
||||
public
|
||||
constructor Create(const AHandler: TMWDCommandHandler; const ACommand, AHelp: String);
|
||||
property Command: String read FCommand;
|
||||
property Handler: TMWDCommandHandler read FHandler;
|
||||
property Help: String read FHelp;
|
||||
end;
|
||||
|
||||
TMWDCommandList = class
|
||||
private
|
||||
FCommands: TStringList;
|
||||
function GetItem(const AIndex: Integer): TMWDCommand;
|
||||
public
|
||||
procedure AddCommand(const ACommands: array of String; const AHandler: TMWDCommandHandler; const AHelp: String);
|
||||
function Count: Integer;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function FindCommand(const ACommand: String): TMWDCommand;
|
||||
procedure HandleCommand(ACommand: String);
|
||||
property Items[const AIndex: Integer]: TMWDCommand read GetItem; default;
|
||||
end;
|
||||
|
||||
|
||||
var
|
||||
MCommands: TMWDCommandList;
|
||||
MShowCommands: TMWDCommandList;
|
||||
MSetCommands: TMWDCommandList;
|
||||
|
||||
procedure HandleCommand(ACommand: String);
|
||||
begin
|
||||
MCommands.HandleCommand(ACommand);
|
||||
end;
|
||||
|
||||
|
||||
procedure HandleHelp(AParams: String);
|
||||
var
|
||||
n: Integer;
|
||||
cmd: TMWDCommand;
|
||||
begin
|
||||
if AParams = ''
|
||||
then begin
|
||||
WriteLN('Available commands:');
|
||||
for n := 0 to MCommands.Count - 1 do
|
||||
WriteLN(' ', MCommands[n].Command);
|
||||
end
|
||||
else begin
|
||||
cmd := MCommands.FindCommand(AParams);
|
||||
if cmd = nil
|
||||
then WriteLN('Unknown command: "', AParams, '"')
|
||||
else WriteLN(cmd.Help);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure HandleFile(AParams: String);
|
||||
begin
|
||||
if AParams <> ''
|
||||
then GFileName := AParams;
|
||||
|
||||
// TODO separate exec from args
|
||||
end;
|
||||
|
||||
procedure HandleShow(AParams: String);
|
||||
var
|
||||
cmd: TMWDCommand;
|
||||
S: String;
|
||||
begin
|
||||
S := GetPart([], [' ', #9], AParams);
|
||||
if S = '' then S := 'help';
|
||||
cmd := MShowCommands.FindCommand(S);
|
||||
if cmd = nil
|
||||
then WriteLN('Unknown item: "', S, '"')
|
||||
else cmd.Handler(Trim(AParams));
|
||||
end;
|
||||
|
||||
procedure HandleSet(AParams: String);
|
||||
var
|
||||
cmd: TMWDCommand;
|
||||
S: String;
|
||||
begin
|
||||
S := GetPart([], [' ', #9], AParams);
|
||||
if S = '' then S := 'help';
|
||||
cmd := MSetCommands.FindCommand(S);
|
||||
if cmd = nil
|
||||
then WriteLN('Unknown param: "', S, '"')
|
||||
else cmd.Handler(Trim(AParams));
|
||||
end;
|
||||
|
||||
|
||||
procedure HandleRun(AParams: String);
|
||||
var
|
||||
StartupInfo: TStartupInfo;
|
||||
ProcessInformation: TProcessInformation;
|
||||
ThreadAttributes: TSecurityAttributes;
|
||||
begin
|
||||
if GState <> dsStop
|
||||
then begin
|
||||
WriteLN('The debuggee is already running');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if GFileName = ''
|
||||
then begin
|
||||
WriteLN('No filename set');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
ZeroMemory(@StartUpInfo, SizeOf(StartupInfo));
|
||||
StartUpInfo.cb := SizeOf(StartupInfo);
|
||||
StartUpInfo.dwFlags := {STARTF_USESTDHANDLES or} STARTF_USESHOWWINDOW;
|
||||
StartUpInfo.wShowWindow := SW_SHOWNORMAL or SW_SHOW;
|
||||
|
||||
// ZeroMemory(@ThreadAttributes, SizeOf(ThreadAttributes));
|
||||
// ThreadAttributes.nLength := SizeOf(ThreadAttributes);
|
||||
// ThreadAttributes.lpSecurityDescriptor
|
||||
|
||||
ZeroMemory(@ProcessInformation, SizeOf(ProcessInformation));
|
||||
if not CreateProcess(nil, PChar(GFileName), nil, nil, True, DETACHED_PROCESS or DEBUG_PROCESS or CREATE_NEW_PROCESS_GROUP, nil, nil, StartUpInfo, ProcessInformation)
|
||||
then begin
|
||||
WriteLN('Create process failed');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
WriteLN('Got PID:', ProcessInformation.dwProcessId, ', TID: ',ProcessInformation.dwThreadId);
|
||||
|
||||
GState := dsRun;
|
||||
DebugLoop;
|
||||
end;
|
||||
|
||||
procedure HandleBreak(AParams: String);
|
||||
begin
|
||||
WriteLN('not implemented: break');
|
||||
end;
|
||||
|
||||
procedure HandleContinue(AParams: String);
|
||||
begin
|
||||
if GState <> dsPause
|
||||
then begin
|
||||
WriteLN('The process is not paused');
|
||||
Exit;
|
||||
end;
|
||||
DebugLoop;
|
||||
end;
|
||||
|
||||
procedure HandleKill(AParams: String);
|
||||
begin
|
||||
if not (GState in [dsRun, dsPause]) or (GMainProcess = nil)
|
||||
then begin
|
||||
WriteLN('No process');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
WriteLN('Terminating...');
|
||||
TerminateProcess(GMainProcess.Handle, 0);
|
||||
if GState = dsPause
|
||||
then DebugLoop; // continue runnig so we can terminate
|
||||
end;
|
||||
|
||||
procedure HandleNext(AParams: String);
|
||||
begin
|
||||
if GState <> dsPause
|
||||
then begin
|
||||
WriteLN('The process is not paused');
|
||||
Exit;
|
||||
end;
|
||||
if GCurrentThread = nil
|
||||
then begin
|
||||
WriteLN('No current thread');
|
||||
Exit;
|
||||
end;
|
||||
GCurrentThread.SingleStep;
|
||||
DebugLoop;
|
||||
end;
|
||||
|
||||
procedure HandleList(AParams: String);
|
||||
begin
|
||||
WriteLN('not implemented: list');
|
||||
end;
|
||||
|
||||
procedure HandleMemory(AParams: String);
|
||||
// memory [-<size>] [<adress> <count>|<location> <count>]
|
||||
var
|
||||
P: array[1..3] of String;
|
||||
Size, Count: Integer;
|
||||
Adress: QWord;
|
||||
e, idx: Integer;
|
||||
buf: array[0..256*16 - 1] of Byte;
|
||||
BytesRead: Cardinal;
|
||||
begin
|
||||
if GMainProcess = nil
|
||||
then begin
|
||||
WriteLN('No process');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
P[1] := GetPart([], [' ', #9], AParams);
|
||||
P[2] := GetPart([' ', #9], [' ', #9], AParams);
|
||||
P[3] := GetPart([' ', #9], [' ', #9], AParams);
|
||||
|
||||
idx := 1;
|
||||
Count := 1;
|
||||
Size := 4;
|
||||
case GMode of
|
||||
dm32: Adress := GCurrentContext.Eip;
|
||||
dm64: Adress := GCurrentContext64.Rip;
|
||||
end;
|
||||
|
||||
if P[idx] <> ''
|
||||
then begin
|
||||
if P[idx][1] = '-'
|
||||
then begin
|
||||
Size := -StrToIntDef(P[idx], -Size);
|
||||
if not (Size in [1,2,4,8,16])
|
||||
then begin
|
||||
WriteLN('Illegal size: "', P[idx], '"');
|
||||
Exit;
|
||||
end;
|
||||
Inc(idx);
|
||||
end;
|
||||
if P[idx] <> ''
|
||||
then begin
|
||||
if P[idx][1] = '%'
|
||||
then begin
|
||||
|
||||
end
|
||||
else begin
|
||||
Val(P[idx], Adress, e);
|
||||
if e <> 0
|
||||
then begin
|
||||
WriteLN('Location "',P[idx],'": Symbol resolving not implemented');
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Inc(idx);
|
||||
end;
|
||||
|
||||
if P[idx] <> ''
|
||||
then begin
|
||||
Count := StrToIntDef(P[idx], Count);
|
||||
if Count > 256
|
||||
then begin
|
||||
WriteLN('Limiting count to 256');
|
||||
Count := 256;
|
||||
end;
|
||||
Inc(idx);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
BytesRead := Count * Size;
|
||||
if not GMainProcess.ReadData(Adress, BytesRead, buf)
|
||||
then begin
|
||||
WriteLN('Could not read memory at: ', FormatAdress(Adress));
|
||||
Exit;
|
||||
end;
|
||||
|
||||
e := 0;
|
||||
while BytesRead >= size do
|
||||
begin
|
||||
if e and ((32 div Size) - 1) = 0
|
||||
then Write('[', FormatAdress(Adress), '] ');
|
||||
|
||||
for idx := Size - 1 downto 0 do Write(IntToHex(buf[e * size + idx], 2));
|
||||
|
||||
Inc(e);
|
||||
if e = 32 div Size
|
||||
then WriteLn
|
||||
else Write(' ');
|
||||
Dec(BytesRead, Size);
|
||||
Inc(Adress, Size);
|
||||
end;
|
||||
if e <> 32 div Size
|
||||
then WriteLn;
|
||||
end;
|
||||
|
||||
procedure HandleDisas(AParams: String);
|
||||
begin
|
||||
WriteLN('not implemented: disassemble');
|
||||
end;
|
||||
|
||||
procedure HandleEval(AParams: String);
|
||||
begin
|
||||
WriteLN('not implemented: evaluate');
|
||||
end;
|
||||
|
||||
procedure HandleQuit(AParams: String);
|
||||
begin
|
||||
WriteLN('Quitting...');
|
||||
GState := dsQuit;
|
||||
end;
|
||||
|
||||
//=================
|
||||
// S H O W
|
||||
//=================
|
||||
|
||||
procedure HandleShowHelp(AParams: String);
|
||||
var
|
||||
n: Integer;
|
||||
cmd: TMWDCommand;
|
||||
begin
|
||||
if AParams = ''
|
||||
then begin
|
||||
WriteLN('Available items:');
|
||||
for n := 0 to MShowCommands.Count - 1 do
|
||||
WriteLN(' ', MShowCommands[n].Command);
|
||||
end
|
||||
else begin
|
||||
cmd := MShowCommands.FindCommand(AParams);
|
||||
if cmd = nil
|
||||
then WriteLN('Unknown item: "', AParams, '"')
|
||||
else WriteLN(cmd.Help);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure HandleShowFile(AParams: String);
|
||||
var
|
||||
hFile, hMap: THandle;
|
||||
FilePtr: Pointer;
|
||||
begin
|
||||
if GFileName = ''
|
||||
then begin
|
||||
WriteLN('No filename set');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
hFile := CreateFile(PChar(GFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
|
||||
if hFile = INVALID_HANDLE_VALUE
|
||||
then begin
|
||||
WriteLN('File "', GFileName, '" does not exist');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
hMap := 0;
|
||||
FilePtr := nil;
|
||||
try
|
||||
hMap := CreateFileMapping(hFile, nil, PAGE_READONLY{ or SEC_IMAGE}, 0, 0, nil);
|
||||
if hMap = 0
|
||||
then begin
|
||||
WriteLN('Map error');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
FilePtr := MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
||||
DumpPEImage(GetCurrentProcess, TDbgPtr(FilePtr));
|
||||
finally
|
||||
UnmapViewOfFile(FilePtr);
|
||||
CloseHandle(hMap);
|
||||
CloseHandle(hFile);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure HandleShowCallStack(AParams: String);
|
||||
var
|
||||
Adress, Frame, LastFrame: QWord;
|
||||
Size, Count: integer;
|
||||
begin
|
||||
if (GMainProcess = nil) or (GCurrentProcess = nil)
|
||||
then begin
|
||||
WriteLN('No process');
|
||||
Exit;
|
||||
end;
|
||||
if GState <> dsPause
|
||||
then begin
|
||||
WriteLN('Process not paused');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
case GMode of
|
||||
dm32: begin
|
||||
Adress := GCurrentContext.Eip;
|
||||
Frame := GCurrentContext.Ebp;
|
||||
Size := 4;
|
||||
end;
|
||||
dm64: begin
|
||||
Adress := GCurrentContext64.Rip;
|
||||
Frame := GCurrentContext64.Rdi;
|
||||
Size := 8;
|
||||
end;
|
||||
end;
|
||||
|
||||
WriteLN('Callstack:');
|
||||
WriteLn(' ', FormatAdress(Adress));
|
||||
LastFrame := 0;
|
||||
Count := 25;
|
||||
while (Frame <> 0) and (Frame > LastFrame) do
|
||||
begin
|
||||
if not GCurrentProcess.ReadData(Frame + Size, Size, Adress) or (Adress = 0) then Break;
|
||||
WriteLn(' ', FormatAdress(Adress));
|
||||
Dec(count);
|
||||
if Count <= 0 then Exit;
|
||||
if not GCurrentProcess.ReadData(Frame, Size, Frame) then Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
//=================
|
||||
// S E T
|
||||
//=================
|
||||
|
||||
procedure HandleSetHelp(AParams: String);
|
||||
var
|
||||
n: Integer;
|
||||
cmd: TMWDCommand;
|
||||
begin
|
||||
if AParams = ''
|
||||
then begin
|
||||
WriteLN('Usage: set param [<value>] When no value is given, the current value is shown.');
|
||||
WriteLN('Available params:');
|
||||
for n := 0 to MSetCommands.Count - 1 do
|
||||
WriteLN(' ', MSetCommands[n].Command);
|
||||
end
|
||||
else begin
|
||||
cmd := MSetCommands.FindCommand(AParams);
|
||||
if cmd = nil
|
||||
then WriteLN('Unknown param: "', AParams, '"')
|
||||
else WriteLN(cmd.Help);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure HandleSetMode(AParams: String);
|
||||
const
|
||||
MODE: array[TMWDMode] of String = ('32', '64');
|
||||
begin
|
||||
if AParams = ''
|
||||
then WriteLN(' Mode: ', MODE[GMode])
|
||||
else if AParams = '32'
|
||||
then GMode := dm32
|
||||
else if AParams = '64'
|
||||
then GMode := dm64
|
||||
else WriteLN('Unknown mode: "', AParams, '"')
|
||||
end;
|
||||
|
||||
|
||||
//=================
|
||||
//=================
|
||||
//=================
|
||||
|
||||
{ TMWDCommand }
|
||||
|
||||
constructor TMWDCommand.Create(const AHandler: TMWDCommandHandler; const ACommand, AHelp: String);
|
||||
begin
|
||||
inherited Create;
|
||||
FCommand := ACommand;
|
||||
FHandler := AHandler;
|
||||
FHelp := AHelp;
|
||||
end;
|
||||
|
||||
{ TMWDCommandList }
|
||||
|
||||
procedure TMWDCommandList.AddCommand(const ACommands: array of String; const AHandler: TMWDCommandHandler; const AHelp: String);
|
||||
var
|
||||
n: Integer;
|
||||
begin
|
||||
for n := Low(ACommands) to High(ACommands) do
|
||||
FCommands.AddObject(ACommands[n], TMWDCommand.Create(AHandler, ACommands[n], AHelp));
|
||||
end;
|
||||
|
||||
function TMWDCommandList.Count: Integer;
|
||||
begin
|
||||
Result := FCommands.Count;
|
||||
end;
|
||||
|
||||
constructor TMWDCommandList.Create;
|
||||
begin
|
||||
inherited;
|
||||
FCommands := TStringList.Create;
|
||||
FCommands.Duplicates := dupError;
|
||||
FCommands.Sorted := True;
|
||||
end;
|
||||
|
||||
destructor TMWDCommandList.Destroy;
|
||||
var
|
||||
n: integer;
|
||||
begin
|
||||
for n := 0 to FCommands.Count - 1 do
|
||||
FCommands.Objects[n].Free;
|
||||
FreeAndNil(FCommands);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TMWDCommandList.FindCommand(const ACommand: String): TMWDCommand;
|
||||
var
|
||||
idx: Integer;
|
||||
begin
|
||||
idx := FCommands.IndexOf(ACommand);
|
||||
if idx = -1
|
||||
then Result := nil
|
||||
else Result := TMWDCommand(FCommands.Objects[idx]);
|
||||
end;
|
||||
|
||||
function TMWDCommandList.GetItem(const AIndex: Integer): TMWDCommand;
|
||||
begin
|
||||
Result := TMWDCommand(FCommands.Objects[AIndex]);
|
||||
end;
|
||||
|
||||
procedure TMWDCommandList.HandleCommand(ACommand: String);
|
||||
var
|
||||
cmd: TMWDCommand;
|
||||
S: String;
|
||||
begin
|
||||
S := GetPart([], [' ', #9], ACommand);
|
||||
cmd := FindCommand(S);
|
||||
if cmd = nil
|
||||
then WriteLN('Unknown command: "', S, '"')
|
||||
else cmd.Handler(Trim(ACommand));
|
||||
end;
|
||||
|
||||
//=================
|
||||
//=================
|
||||
//=================
|
||||
|
||||
procedure Initialize;
|
||||
begin
|
||||
MCommands := TMWDCommandList.Create;
|
||||
|
||||
MCommands.AddCommand(['help', 'h', '?'], @HandleHelp, 'help [<command>]: Shows help on a command, or this help if no command given');
|
||||
MCommands.AddCommand(['quit', 'q'], @HandleQuit, 'quit: Quits the debugger');
|
||||
MCommands.AddCommand(['file', 'f'], @HandleFile, 'file <filename>: Loads the debuggee <filename>');
|
||||
MCommands.AddCommand(['show', 's'], @HandleShow, 'show <info>: Enter show help for more info');
|
||||
MCommands.AddCommand(['set'], @HandleSet, 'set param: Enter set help for more info');
|
||||
MCommands.AddCommand(['run', 'r'], @HandleRun, 'run: Starts the loaded debuggee');
|
||||
MCommands.AddCommand(['break', 'b'], @HandleBreak, 'break [-d] <adress>: Set a breakpoint at <adress>. -d removes');
|
||||
MCommands.AddCommand(['continue', 'cont', 'c'], @HandleContinue, 'continue: Continues execution');
|
||||
MCommands.AddCommand(['kill', 'k'], @HandleKill, 'kill: Stops execution of the debuggee');
|
||||
MCommands.AddCommand(['next', 'n'], @HandleNext, 'next: Steps one instruction');
|
||||
MCommands.AddCommand(['list', 'l'], @HandleList, 'list [<adress>|<location>]: Lists the source for <adress> or <location>');
|
||||
MCommands.AddCommand(['memory', 'mem', 'm'], @HandleMemory, 'memory [-<size>] [<adress> <count>|<location> <count>]: Dump <count> (default: 1) from memory <adress> or <location> (default: current) of <size> (default: 4) bytes, where size is 1,2,4,8 or 16.');
|
||||
MCommands.AddCommand(['disassemble', 'dis', 'd'], @HandleDisas, 'disassemble [<adress>|<location>] [<count>]: Disassemble <count> instructions from <adress> or <location> or current IP if none given');
|
||||
MCommands.AddCommand(['evaluate', 'eval', 'e'], @HandleEval, 'evaluate <symbol>: Evaluate <symbol>');
|
||||
|
||||
|
||||
MShowCommands := TMWDCommandList.Create;
|
||||
|
||||
MShowCommands.AddCommand(['help', 'h', '?'], @HandleShowHelp, 'show help [<info>]: Shows help for info or this help if none given');
|
||||
MShowCommands.AddCommand(['file', 'f'], @HandleShowFile, 'show file: Shows the info for the current file');
|
||||
MShowCommands.AddCommand(['callstack', 'c'], @HandleShowCallStack, 'show callstack: Shows the callstack');
|
||||
|
||||
MSetCommands := TMWDCommandList.Create;
|
||||
|
||||
MSetCommands.AddCommand(['help', 'h', '?'], @HandleSetHelp, 'set help [<param>]: Shows help for param or this help if none given');
|
||||
MSetCommands.AddCommand(['mode', 'm'], @HandleSetMode, 'set mode 32|64: Set the mode for retrieving process info');
|
||||
end;
|
||||
|
||||
procedure Finalize;
|
||||
begin
|
||||
FreeAndNil(MCommands);
|
||||
FreeAndNil(MSetCommands);
|
||||
FreeAndNil(MShowCommands);
|
||||
end;
|
||||
|
||||
initialization
|
||||
Initialize;
|
||||
|
||||
finalization
|
||||
Finalize;
|
||||
|
||||
end.
|
77
debugger/windebug/fpwd/fpwdglobal.pas
Normal file
77
debugger/windebug/fpwd/fpwdglobal.pas
Normal file
@ -0,0 +1,77 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
fpwdglobal.pas - FP standalone windows debugger - Globals
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
This unit contains global types / vars
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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 FPWDGlobal;
|
||||
{$mode objfpc}{$H+}
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Windows, FPWDType, Maps, WinDebugger;
|
||||
|
||||
type
|
||||
TMWDState = (dsStop, dsRun, dsPause, dsQuit, dsEvent);
|
||||
TMWDMode = (dm32, dm64);
|
||||
|
||||
var
|
||||
GState: TMWDState;
|
||||
GFileName: String;
|
||||
GMode: TMWDMode = dm32;
|
||||
GCurrentContext64: TContextAMD64;
|
||||
GCurrentContext: TContext absolute GCurrentContext64;
|
||||
|
||||
GMainProcess: TDbgProcess = nil;
|
||||
GCurrentProcess: TDbgProcess = nil;
|
||||
GCurrentThread: TDbgThread = nil;
|
||||
GProcessMap: TMap;
|
||||
|
||||
function GetProcess(const AID: Integer; var AProcess: TDbgProcess): Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
function GetProcess(const AID: Integer; var AProcess: TDbgProcess): Boolean;
|
||||
begin
|
||||
Result := GProcessMap.GetData(AID, AProcess) and (AProcess <> nil);
|
||||
// if not Result
|
||||
// then Log('Unknown Process ID %u', [AID]);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
initialization
|
||||
GState := dsStop;
|
||||
GProcessMap := TMap.Create(itu4, SizeOf(TDbgProcess));;
|
||||
|
||||
finalization
|
||||
FreeAndNil(GProcessMap)
|
||||
|
||||
end.
|
419
debugger/windebug/fpwd/fpwdloop.pas
Normal file
419
debugger/windebug/fpwd/fpwdloop.pas
Normal file
@ -0,0 +1,419 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
fpwdloop.pas - FP standalone windows 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 FPWDLoop;
|
||||
{$mode objfpc}{$H+}
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows, SysUtils, WinDebugger, WinDExtra;
|
||||
|
||||
procedure DebugLoop;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
FPWDGlobal, FPWDPEImage, FPWDType;
|
||||
|
||||
var
|
||||
MDebugEvent: TDebugEvent64;
|
||||
MDebugEvent32: TDebugEvent absolute MDebugEvent;
|
||||
|
||||
procedure HandleCreateProcess(const AEvent: TDebugEvent64);
|
||||
var
|
||||
Proc: TDbgProcess;
|
||||
S: String;
|
||||
begin
|
||||
WriteLN(Format('hFile: 0x%x', [AEvent.CreateProcessInfo.hFile]));
|
||||
WriteLN(Format('hProcess: 0x%x', [AEvent.CreateProcessInfo.hProcess]));
|
||||
WriteLN(Format('hThread: 0x%x', [AEvent.CreateProcessInfo.hThread]));
|
||||
WriteLN('Base adress: ', FormatAdress(AEvent.CreateProcessInfo.lpBaseOfImage));
|
||||
WriteLN('Base adress64: $', IntToHex(PInt64(@AEvent.CreateProcessInfo.lpBaseOfImage)^, 16));
|
||||
WriteLN(Format('Debugsize: %d', [AEvent.CreateProcessInfo.nDebugInfoSize]));
|
||||
WriteLN(Format('Debugoffset: %d', [AEvent.CreateProcessInfo.dwDebugInfoFileOffset]));
|
||||
|
||||
|
||||
if AEvent.CreateProcessInfo.lpBaseOfImage <> nil
|
||||
then DumpPEImage(AEvent.CreateProcessInfo.hProcess, TDbgPtr(AEvent.CreateProcessInfo.lpBaseOfImage));
|
||||
|
||||
if GMainProcess = nil
|
||||
then S := GFileName;
|
||||
Proc := TDbgProcess.Create(S, AEvent.dwProcessId, AEvent.dwThreadId, AEvent.CreateProcessInfo);
|
||||
if GMainProcess = nil
|
||||
then GMainProcess := Proc;
|
||||
GProcessMap.Add(AEvent.dwProcessId, Proc);
|
||||
end;
|
||||
|
||||
procedure HandleCreateThread(const AEvent: TDebugEvent64);
|
||||
begin
|
||||
WriteLN(Format('Start adress: 0x%p', [AEvent.CreateThread.lpStartAddress]));
|
||||
end;
|
||||
|
||||
procedure HandleException(const AEvent: TDebugEvent64);
|
||||
var
|
||||
N: Integer;
|
||||
Info0: QWORD;
|
||||
Info1: QWORD;
|
||||
Info1Str: String;
|
||||
P: PByte;
|
||||
begin
|
||||
if AEvent.Exception.dwFirstChance = 0
|
||||
then Write('Exception: ')
|
||||
else Write('First chance exception: ');
|
||||
|
||||
case AEvent.Exception.ExceptionRecord.ExceptionCode of
|
||||
EXCEPTION_ACCESS_VIOLATION : Write('ACCESS_VIOLATION');
|
||||
EXCEPTION_ARRAY_BOUNDS_EXCEEDED : Write('ARRAY_BOUNDS_EXCEEDED');
|
||||
EXCEPTION_BREAKPOINT : Write('BREAKPOINT');
|
||||
EXCEPTION_DATATYPE_MISALIGNMENT : Write('DATATYPE_MISALIGNMENT');
|
||||
EXCEPTION_FLT_DENORMAL_OPERAND : Write('FLT_DENORMAL_OPERAND');
|
||||
EXCEPTION_FLT_DIVIDE_BY_ZERO : Write('FLT_DIVIDE_BY_ZERO');
|
||||
EXCEPTION_FLT_INEXACT_RESULT : Write('FLT_INEXACT_RESULT');
|
||||
EXCEPTION_FLT_INVALID_OPERATION : Write('FLT_INVALID_OPERATION');
|
||||
EXCEPTION_FLT_OVERFLOW : Write('FLT_OVERFLOW');
|
||||
EXCEPTION_FLT_STACK_CHECK : Write('FLT_STACK_CHECK');
|
||||
EXCEPTION_FLT_UNDERFLOW : Write('FLT_UNDERFLOW');
|
||||
EXCEPTION_ILLEGAL_INSTRUCTION : Write('ILLEGAL_INSTRUCTION');
|
||||
EXCEPTION_IN_PAGE_ERROR : Write('IN_PAGE_ERROR');
|
||||
EXCEPTION_INT_DIVIDE_BY_ZERO : Write('INT_DIVIDE_BY_ZERO');
|
||||
EXCEPTION_INT_OVERFLOW : Write('INT_OVERFLOW');
|
||||
EXCEPTION_INVALID_DISPOSITION : Write('INVALID_DISPOSITION');
|
||||
EXCEPTION_NONCONTINUABLE_EXCEPTION : Write('NONCONTINUABLE_EXCEPTION');
|
||||
EXCEPTION_PRIV_INSTRUCTION : Write('PRIV_INSTRUCTION');
|
||||
EXCEPTION_SINGLE_STEP : Write('SINGLE_STEP');
|
||||
EXCEPTION_STACK_OVERFLOW : Write('STACK_OVERFLOW');
|
||||
else
|
||||
Write(' Unknown code: ', AEvent.Exception.ExceptionRecord.ExceptionCode);
|
||||
end;
|
||||
case GMode of
|
||||
dm64: Info0 := AEvent.Exception64.ExceptionRecord.ExceptionAddress;
|
||||
dm32: Info0 := Cardinal(AEvent.Exception.ExceptionRecord.ExceptionAddress);
|
||||
else
|
||||
Info0 := 0;
|
||||
end;
|
||||
Write(' at: ', FormatAdress(Info0));
|
||||
Write(' Flags:', Format('%x', [AEvent.Exception.ExceptionRecord.ExceptionFlags]), ' [');
|
||||
if AEvent.Exception.ExceptionRecord.ExceptionFlags = 0
|
||||
then Write('Continuable')
|
||||
else Write('Not continuable');
|
||||
Write(']');
|
||||
case GMode of
|
||||
dm64: Write(' ParamCount:', AEvent.Exception64.ExceptionRecord.NumberParameters);
|
||||
dm32: Write(' ParamCount:', AEvent.Exception.ExceptionRecord.NumberParameters);
|
||||
end;
|
||||
|
||||
case AEvent.Exception.ExceptionRecord.ExceptionCode of
|
||||
EXCEPTION_ACCESS_VIOLATION: begin
|
||||
case GMode of
|
||||
dm64: begin
|
||||
Info0 := AEvent.Exception64.ExceptionRecord.ExceptionInformation[0];
|
||||
Info1Str := IntToHex(AEvent.Exception64.ExceptionRecord.ExceptionInformation[1], 16);
|
||||
end;
|
||||
dm32: begin
|
||||
Info0 := AEvent.Exception.ExceptionRecord.ExceptionInformation[0];
|
||||
Info1Str := IntToHex(AEvent.Exception.ExceptionRecord.ExceptionInformation[1], 8);
|
||||
end;
|
||||
end;
|
||||
|
||||
case Info0 of
|
||||
0: begin
|
||||
Write(' Read of address: $', Info1Str);
|
||||
end;
|
||||
1: begin
|
||||
Write(' Write of address: $', Info1Str);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
WriteLN;
|
||||
|
||||
Write(' Info: ');
|
||||
case GMode of
|
||||
dm64: begin
|
||||
with AEvent.Exception64.ExceptionRecord do
|
||||
for n := Low(ExceptionInformation) to high(ExceptionInformation) do
|
||||
begin
|
||||
Write(IntToHex(ExceptionInformation[n], 16), ' ');
|
||||
if n and 3 = 3
|
||||
then begin
|
||||
WriteLN;
|
||||
Write(' ');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
dm32: begin
|
||||
with AEvent.Exception.ExceptionRecord do
|
||||
for n := Low(ExceptionInformation) to high(ExceptionInformation) do
|
||||
begin
|
||||
Write(IntToHex(ExceptionInformation[n], 8), ' ');
|
||||
if n and 7 = 7
|
||||
then begin
|
||||
WriteLN;
|
||||
Write(' ');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
WriteLn;
|
||||
GState := dsPause;
|
||||
end;
|
||||
|
||||
procedure HandleExitProcess(const AEvent: TDebugEvent64);
|
||||
var
|
||||
Proc: TDbgProcess;
|
||||
begin
|
||||
if not GetProcess(AEvent.dwProcessId, Proc) then Exit;
|
||||
|
||||
if Proc = GMainProcess then GMainProcess := nil;
|
||||
GProcessMap.Delete(AEvent.dwProcessId);
|
||||
|
||||
GState := dsStop;
|
||||
WriteLN('Process stopped with exitcode: ', AEvent.ExitProcess.dwExitCode);
|
||||
end;
|
||||
|
||||
procedure HandleExitThread(const AEvent: TDebugEvent64);
|
||||
begin
|
||||
WriteLN('Exitcode: ', AEvent.ExitThread.dwExitCode);
|
||||
end;
|
||||
|
||||
procedure HandleLoadDll(const AEvent: TDebugEvent64);
|
||||
//var
|
||||
// Proc: TDbgProcess;
|
||||
// Lib: TDbgLibrary;
|
||||
begin
|
||||
WriteLN('Base adress: ', FormatAdress(AEvent.LoadDll.lpBaseOfDll));
|
||||
|
||||
|
||||
// if GetProcess(AEvent.dwProcessId, Proc)
|
||||
// then begin
|
||||
// Lib := Proc.AddLib(AEvent.LoadDll);
|
||||
// WriteLN('Name: ', Lib.Name);
|
||||
// DumpPEImage(Proc.Handle, Lib.BaseAddr);
|
||||
// end;
|
||||
end;
|
||||
|
||||
procedure HandleOutputDebug(const AEvent: TDebugEvent64);
|
||||
var
|
||||
Proc: TDbgProcess;
|
||||
S: String;
|
||||
W: WideString;
|
||||
begin
|
||||
if not GetProcess(AEvent.dwProcessId, Proc) then Exit;
|
||||
|
||||
if AEvent.DebugString.fUnicode <> 0
|
||||
then begin
|
||||
if not Proc.ReadWString(TDbgPtr(AEvent.DebugString.lpDebugStringData), AEvent.DebugString.nDebugStringLength, W)
|
||||
then Exit;
|
||||
S := W;
|
||||
end
|
||||
else begin
|
||||
if not Proc.ReadString(TDbgPtr(AEvent.DebugString.lpDebugStringData), AEvent.DebugString.nDebugStringLength, S)
|
||||
then Exit;
|
||||
end;
|
||||
WriteLN('[', AEvent.dwProcessId, ':', AEvent.dwThreadId, '] ', S);
|
||||
end;
|
||||
|
||||
procedure HandleRipEvent(const AEvent: TDebugEvent64);
|
||||
begin
|
||||
WriteLN('Error: ', AEvent.RipInfo.dwError);
|
||||
WriteLN('Type: ', AEvent.RipInfo.dwType);
|
||||
end;
|
||||
|
||||
procedure HandleUnloadDll(const AEvent: TDebugEvent64);
|
||||
begin
|
||||
WriteLN('Base adress: ', FormatAdress(AEvent.UnloadDll.lpBaseOfDll));
|
||||
end;
|
||||
|
||||
procedure DebugLoop;
|
||||
procedure DumpEvent(const AEvent: String);
|
||||
var
|
||||
f: Cardinal;
|
||||
n: integer;
|
||||
begin
|
||||
WriteLN('===');
|
||||
WriteLN(AEvent);
|
||||
WriteLN('---');
|
||||
WriteLN('Process ID: ', MDebugEvent.dwProcessId);
|
||||
WriteLN('Thread ID: ', MDebugEvent.dwThreadId);
|
||||
|
||||
if GCurrentThread = nil then Exit;
|
||||
|
||||
case GMode of
|
||||
dm64: begin
|
||||
with GCurrentContext64 do WriteLN(Format('SegDS: 0x%4.4x, SegES: 0x%4.4x, SegFS: 0x%4.4x, SegGS: 0x%4.4x', [SegDs, SegEs, SegFs, SegGs]));
|
||||
with GCurrentContext64 do WriteLN(Format('RAX: 0x%16.16x, RBX: 0x%16.16x, RCX: 0x%16.16x, RDX: 0x%16.16x, RDI: 0x%16.16x, RSI: 0x%16.16x, R9: 0x%16.16x, R10: 0x%16.16x, R11: 0x%16.16x, R12: 0x%16.16x, R13: 0x%16.16x, R14: 0x%16.16x, R15: 0x%16.16x', [Rax, Rbx, Rcx, Rdx, Rdi, Rsi, R9, R10, R11, R12, R13, R14, R15]));
|
||||
with GCurrentContext64 do WriteLN(Format('SegCS: 0x%4.4x, SegSS: 0x%4.4x, RBP: 0x%16.16x, RIP: 0x%16.16x, RSP: 0x%16.16x, EFlags: 0x%8.8x', [SegCs, SegSs, Rbp, Rip, Rsp, EFlags]));
|
||||
end;
|
||||
dm32: begin
|
||||
with GCurrentContext do WriteLN(Format('DS: 0x%x, ES: 0x%x, FS: 0x%x, GS: 0x%x', [SegDs, SegEs, SegFs, SegGs]));
|
||||
with GCurrentContext do WriteLN(Format('EAX: 0x%x, EBX: 0x%x, ECX: 0x%x, EDX: 0x%x, EDI: 0x%x, ESI: 0x%x', [Eax, Ebx, Ecx, Edx, Edi, Esi]));
|
||||
with GCurrentContext do WriteLN(Format('CS: 0x%x, SS: 0x%x, EBP: 0x%x, EIP: 0x%x, ESP: 0x%x, EFlags: 0x%x', [SegCs, SegSs, Ebp, Eip, Esp, EFlags]));
|
||||
with GCurrentContext do begin
|
||||
Write(Format('DR0: 0x%x, DR1: 0x%x, DR2: 0x%x, DR3: 0x%x', [Dr0, Dr1, Dr2, Dr3]));
|
||||
Write(' DR6: 0x', IntToHex(Dr6, 8), ' [');
|
||||
if Dr6 and $0001 <> 0 then Write('B0 ');
|
||||
if Dr6 and $0002 <> 0 then Write('B1 ');
|
||||
if Dr6 and $0004 <> 0 then Write('B2 ');
|
||||
if Dr6 and $0008 <> 0 then Write('B3 ');
|
||||
if Dr6 and $2000 <> 0 then Write('BD ');
|
||||
if Dr6 and $4000 <> 0 then Write('BS ');
|
||||
if Dr6 and $8000 <> 0 then Write('BT ');
|
||||
Write('] DR7: 0x', IntToHex(Dr7, 8), ' [');
|
||||
if Dr7 and $01 <> 0 then Write('L0 ');
|
||||
if Dr7 and $02 <> 0 then Write('G0 ');
|
||||
if Dr7 and $04 <> 0 then Write('L1 ');
|
||||
if Dr7 and $08 <> 0 then Write('G1 ');
|
||||
if Dr7 and $10 <> 0 then Write('L2 ');
|
||||
if Dr7 and $20 <> 0 then Write('G2 ');
|
||||
if Dr7 and $40 <> 0 then Write('L3 ');
|
||||
if Dr7 and $80 <> 0 then Write('G3 ');
|
||||
if Dr7 and $100 <> 0 then Write('LE ');
|
||||
if Dr7 and $200 <> 0 then Write('GE ');
|
||||
if Dr7 and $2000 <> 0 then Write('GD ');
|
||||
f := Dr7 shr 16;
|
||||
for n := 0 to 3 do
|
||||
begin
|
||||
Write('R/W', n,':');
|
||||
case f and 3 of
|
||||
0: Write('ex');
|
||||
1: Write('wo');
|
||||
2: Write('IO');
|
||||
3: Write('rw');
|
||||
end;
|
||||
f := f shr 2;
|
||||
Write(' LEN', n,':', f and 3 + 1, ' ');
|
||||
f := f shr 2;
|
||||
end;
|
||||
WriteLN(']');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
WriteLN('---');
|
||||
end;
|
||||
|
||||
begin
|
||||
repeat
|
||||
if (GCurrentProcess <> nil) and (GState = dsPause)
|
||||
then begin
|
||||
GCurrentProcess.ContinueDebugEvent(GCurrentThread, MDebugEvent32);
|
||||
end;
|
||||
|
||||
if GState in [dsStop, dsPause, dsEvent]
|
||||
then begin
|
||||
case MDebugEvent.Exception.ExceptionRecord.ExceptionCode of
|
||||
EXCEPTION_BREAKPOINT,
|
||||
EXCEPTION_SINGLE_STEP: ContinueDebugEvent(MDebugEvent.dwProcessId, MDebugEvent.dwThreadId, DBG_CONTINUE);
|
||||
else
|
||||
ContinueDebugEvent(MDebugEvent.dwProcessId, MDebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
|
||||
end;
|
||||
GState := dsRun;
|
||||
end;
|
||||
|
||||
if not WaitForDebugEvent(MDebugEvent32, 10) then Continue;
|
||||
|
||||
GCurrentProcess := nil;
|
||||
GCurrentThread := nil;
|
||||
if not GetProcess(MDebugEvent.dwProcessId, GCurrentPRocess) and (GMainProcess <> nil) then Continue;
|
||||
|
||||
GState := dsEvent;
|
||||
if GCurrentProcess <> nil
|
||||
then begin
|
||||
if GCurrentProcess.HandleDebugEvent(MDebugEvent32) then Continue;
|
||||
if not GCurrentProcess.GetThread(MDebugEvent.dwTHreadID, GCurrentThread)
|
||||
then WriteLN('LOOP: Unable to retrieve current thread')
|
||||
else WriteLN('LOOP: ID:', MDebugEvent.dwTHreadID, ' -> H:', GCurrentThread.Handle);
|
||||
end;
|
||||
|
||||
FillChar(GCurrentContext64, SizeOf(GCurrentContext64), $EE);
|
||||
|
||||
if GCurrentThread <> nil
|
||||
then begin
|
||||
// TODO: move to TDbgThread
|
||||
case GMode of
|
||||
dm64: GCurrentContext64.ContextFlags := CONTEXT_SEGMENTS_AMD64 or CONTEXT_INTEGER_AMD64 or CONTEXT_CONTROL_AMD64;
|
||||
dm32: GCurrentContext.ContextFlags := CONTEXT_SEGMENTS or CONTEXT_INTEGER or CONTEXT_CONTROL {or CONTEXT_DEBUG_REGISTERS};
|
||||
else
|
||||
WriteLN('LOOP: Unknown mode');
|
||||
end;
|
||||
SetLastError(0);
|
||||
// SuspendTHread(GCurrentThread.Handle);
|
||||
if not GetThreadContext(GCurrentThread.Handle, GCurrentContext)
|
||||
then WriteLN('LOOP: Unable to retrieve thread context')
|
||||
else WriteLN('LOOP context: ', IntToHex(GCurrentContext.ContextFlags, 8), ' error: ', GetLastErrorText);
|
||||
// ResumeThread(GCurrentThread.Handle);
|
||||
end;
|
||||
|
||||
case MDebugEvent.dwDebugEventCode of
|
||||
EXCEPTION_DEBUG_EVENT: begin
|
||||
DumpEvent('EXCEPTION_DEBUG_EVENT');
|
||||
HandleException(MDebugEvent);
|
||||
end;
|
||||
CREATE_THREAD_DEBUG_EVENT: begin
|
||||
DumpEvent('CREATE_THREAD_DEBUG_EVENT');
|
||||
HandleCreateThread(MDebugEvent);
|
||||
end;
|
||||
CREATE_PROCESS_DEBUG_EVENT: begin
|
||||
DumpEvent('CREATE_PROCESS_DEBUG_EVENT');
|
||||
HandleCreateProcess(MDebugEvent);
|
||||
end;
|
||||
EXIT_THREAD_DEBUG_EVENT: begin
|
||||
DumpEvent('EXIT_THREAD_DEBUG_EVENT');
|
||||
HandleExitThread(MDebugEvent);
|
||||
end;
|
||||
EXIT_PROCESS_DEBUG_EVENT: begin
|
||||
DumpEvent('EXIT_PROCESS_DEBUG_EVENT');
|
||||
HandleExitProcess(MDebugEvent);
|
||||
end;
|
||||
LOAD_DLL_DEBUG_EVENT: begin
|
||||
DumpEvent('LOAD_DLL_DEBUG_EVENT');
|
||||
HandleLoadDll(MDebugEvent);
|
||||
end;
|
||||
UNLOAD_DLL_DEBUG_EVENT: begin
|
||||
DumpEvent('UNLOAD_DLL_DEBUG_EVENT');
|
||||
HandleUnloadDll(MDebugEvent);
|
||||
end;
|
||||
OUTPUT_DEBUG_STRING_EVENT: begin
|
||||
DumpEvent('OUTPUT_DEBUG_STRING_EVENT');
|
||||
HandleOutputDebug(MDebugEvent);
|
||||
end;
|
||||
RIP_EVENT: begin
|
||||
DumpEvent('RIP_EVENT');
|
||||
HandleRipEvent(MDebugEvent);
|
||||
end;
|
||||
end;
|
||||
until (GState in [dsStop, dsPause, dsQuit]);
|
||||
end;
|
||||
|
||||
end.
|
461
debugger/windebug/fpwd/fpwdpeimage.pas
Normal file
461
debugger/windebug/fpwd/fpwdpeimage.pas
Normal file
@ -0,0 +1,461 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
fpwdpeimage.pas - FP standalone windows debugger - PE Image
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
This unit contains routines to access or dump the PE header of a executable
|
||||
loaded in memory.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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 FPWDPEImage;
|
||||
{$mode objfpc}{$H+}
|
||||
interface
|
||||
|
||||
{$IF DECLARED(TImageNtHeaders)}
|
||||
{$DEFINE _headers_translated_in_rtl_}
|
||||
{$ENDIF}
|
||||
|
||||
uses
|
||||
Windows, SysUtils, FPWDGLobal, WinDebugger;
|
||||
|
||||
const
|
||||
IMAGE_FILE_MACHINE_IA64 = $0200; { Intel IPF }
|
||||
IMAGE_FILE_MACHINE_AMD64 = $8664; { x64 }
|
||||
|
||||
IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; { The application can handle addresses larger than 2 GB. }
|
||||
|
||||
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; { Delay import table }
|
||||
IMAGE_DIRECTORY_ENTRY_COM_DECRIPTOR = 14; { COM descriptor table }
|
||||
|
||||
IMAGE_NT_OPTIONAL_HDR32_MAGIC = $010B;
|
||||
IMAGE_NT_OPTIONAL_HDR64_MAGIC = $020B;
|
||||
|
||||
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 8; { Windows CE system }
|
||||
IMAGE_SUBSYSTEM_XBOX = 9; { Xbox system }
|
||||
|
||||
|
||||
IMAGE_LIBRARY_PROCESS_INIT = $0001; // Reserved.
|
||||
IMAGE_LIBRARY_PROCESS_TERM = $0002; // Reserved.
|
||||
IMAGE_LIBRARY_THREAD_INIT = $0004; // Reserved.
|
||||
IMAGE_LIBRARY_THREAD_TERM = $0008; // Reserved.
|
||||
IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = $0200; { Image understands isolation and doesn't want it }
|
||||
IMAGE_DLLCHARACTERISTICS_NO_SEH = $0400; { Image does not use SEH. No SE handler may reside in this image }
|
||||
IMAGE_DLLCHARACTERISTICS_NO_BIND = $0800; { do not bind this image }
|
||||
// $1000; { Reserved. }
|
||||
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = $2000; { dll is a WDM driver }
|
||||
// $4000; { Reserved. }
|
||||
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = $8000;
|
||||
|
||||
|
||||
// Reserved section characteristics
|
||||
IMAGE_SCN_TYPE_REG = $00000000; // Reserved.
|
||||
IMAGE_SCN_TYPE_DSECT = $00000001; // Reserved.
|
||||
IMAGE_SCN_TYPE_NOLOAD = $00000002; // Reserved.
|
||||
IMAGE_SCN_TYPE_GROUP = $00000004; // Reserved.
|
||||
IMAGE_SCN_TYPE_COPY = $00000010; // Reserved.
|
||||
IMAGE_SCN_TYPE_OVER = $00000400; // Reserved.
|
||||
IMAGE_SCN_MEM_PROTECTED = $00004000; // Obsolete
|
||||
IMAGE_SCN_MEM_SYSHEAP = $00010000; // Obsolete
|
||||
|
||||
{$IFDEF _headers_translated_in_rtl_}
|
||||
|
||||
type
|
||||
(*
|
||||
typedef struct _IMAGE_OPTIONAL_HEADER64 {
|
||||
WORD Magic;
|
||||
BYTE MajorLinkerVersion;
|
||||
BYTE MinorLinkerVersion;
|
||||
DWORD SizeOfCode;
|
||||
DWORD SizeOfInitializedData;
|
||||
DWORD SizeOfUninitializedData;
|
||||
DWORD AddressOfEntryPoint;
|
||||
DWORD BaseOfCode;
|
||||
ULONGLONG ImageBase;
|
||||
DWORD SectionAlignment;
|
||||
DWORD FileAlignment;
|
||||
WORD MajorOperatingSystemVersion;
|
||||
WORD MinorOperatingSystemVersion;
|
||||
WORD MajorImageVersion;
|
||||
WORD MinorImageVersion;
|
||||
WORD MajorSubsystemVersion;
|
||||
WORD MinorSubsystemVersion;
|
||||
DWORD Win32VersionValue;
|
||||
DWORD SizeOfImage;
|
||||
DWORD SizeOfHeaders;
|
||||
DWORD CheckSum;
|
||||
WORD Subsystem;
|
||||
WORD DllCharacteristics;
|
||||
ULONGLONG SizeOfStackReserve;
|
||||
ULONGLONG SizeOfStackCommit;
|
||||
ULONGLONG SizeOfHeapReserve;
|
||||
ULONGLONG SizeOfHeapCommit;
|
||||
DWORD LoaderFlags;
|
||||
DWORD NumberOfRvaAndSizes;
|
||||
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
||||
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
|
||||
*)
|
||||
PImageOptionalHeader64 = ^TImageOptionalHeader64;
|
||||
_IMAGE_OPTIONAL_HEADER64 = packed record
|
||||
Magic: Word;
|
||||
MajorLinkerVersion: Byte;
|
||||
MinorLinkerVersion: Byte;
|
||||
SizeOfCode: DWORD;
|
||||
SizeOfInitializedData: DWORD;
|
||||
SizeOfUninitializedData: DWORD;
|
||||
AddressOfEntryPoint: DWORD;
|
||||
BaseOfCode: DWORD;
|
||||
// BaseOfData: DWORD;
|
||||
ImageBase: Int64;
|
||||
SectionAlignment: DWORD;
|
||||
FileAlignment: DWORD;
|
||||
MajorOperatingSystemVersion: Word;
|
||||
MinorOperatingSystemVersion: Word;
|
||||
MajorImageVersion: Word;
|
||||
MinorImageVersion: Word;
|
||||
MajorSubsystemVersion: Word;
|
||||
MinorSubsystemVersion: Word;
|
||||
Win32VersionValue: DWORD;
|
||||
SizeOfImage: DWORD;
|
||||
SizeOfHeaders: DWORD;
|
||||
CheckSum: DWORD;
|
||||
Subsystem: Word;
|
||||
DllCharacteristics: Word;
|
||||
SizeOfStackReserve: Int64;
|
||||
SizeOfStackCommit: Int64;
|
||||
SizeOfHeapReserve: Int64;
|
||||
SizeOfHeapCommit: Int64;
|
||||
LoaderFlags: DWORD;
|
||||
NumberOfRvaAndSizes: DWORD;
|
||||
DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
|
||||
end;
|
||||
TImageOptionalHeader64 = _IMAGE_OPTIONAL_HEADER64;
|
||||
IMAGE_OPTIONAL_HEADER64 = _IMAGE_OPTIONAL_HEADER64;
|
||||
|
||||
|
||||
|
||||
(*
|
||||
typedef struct _IMAGE_NT_HEADERS64 {
|
||||
DWORD Signature;
|
||||
IMAGE_FILE_HEADER FileHeader;
|
||||
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
||||
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
|
||||
|
||||
*)
|
||||
|
||||
PImageNtHeaders64 = ^TImageNtHeaders64;
|
||||
_IMAGE_NT_HEADERS64 = packed record
|
||||
Signature: DWORD;
|
||||
FileHeader: TImageFileHeader;
|
||||
OptionalHeader: TImageOptionalHeader64;
|
||||
end;
|
||||
TImageNtHeaders64 = _IMAGE_NT_HEADERS64;
|
||||
IMAGE_NT_HEADERS64 = _IMAGE_NT_HEADERS64;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
procedure DumpPEImage(const AProcessHandle: THandle; const AAdress: TDbgPtr);
|
||||
|
||||
implementation
|
||||
|
||||
{$IFDEF _headers_translated_in_rtl_}
|
||||
const
|
||||
DIR_NAMES: array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of string = (
|
||||
'EXPORT',
|
||||
'IMPORT',
|
||||
'RESOURCE',
|
||||
'EXCEPTION',
|
||||
'SECURITY',
|
||||
'BASERELOC',
|
||||
'DEBUG',
|
||||
'COPYRIGHT',
|
||||
'GLOBALPTR',
|
||||
'TLS',
|
||||
'LOAD_CONFIG',
|
||||
'BOUND_IMPORT',
|
||||
'IAT',
|
||||
'DELAY_IMPORT',
|
||||
'COM_DECRIPTOR',
|
||||
'Unknown(15)'
|
||||
);
|
||||
|
||||
|
||||
procedure DumpPEImage(const AProcessHandle: THandle; const AAdress: TDbgPtr);
|
||||
var
|
||||
DosHeader: TImageDosHeader;
|
||||
NtHeaders: TImageNtHeaders64; // read it as 64 bit, so there is enough room. The fields will be decoded manually
|
||||
SectionHeader: TImageSectionHeader;
|
||||
OH: PImageOptionalHeader64;
|
||||
BytesRead: Cardinal;
|
||||
R: Boolean;
|
||||
n: Integer;
|
||||
Is64: Boolean;
|
||||
SectionName: array[0..IMAGE_SIZEOF_SHORT_NAME] of Char;
|
||||
begin
|
||||
if not ReadProcessMemory(AProcessHandle, Pointer(AAdress), @DosHeader, SizeOf(DosHeader), BytesRead)
|
||||
then begin
|
||||
WriteLN('Unable to retrieve DOS header');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if (DosHeader.e_magic <> IMAGE_DOS_SIGNATURE)
|
||||
or (DosHeader._lfanew = 0)
|
||||
then begin
|
||||
WriteLN('Invalid DOS header');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if not ReadProcessMemory(AProcessHandle, Pointer(PChar(AAdress) + DosHeader._lfanew), @NTHeaders, SizeOf(NTHeaders), BytesRead)
|
||||
then begin
|
||||
WriteLN('Unable to retrieve NT headers');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if NTHeaders.Signature <> IMAGE_NT_SIGNATURE
|
||||
then begin
|
||||
WriteLN('Invalid NT header: ', IntToHex(NTHeaders.Signature, 8));
|
||||
Exit;
|
||||
end;
|
||||
|
||||
WriteLN('FileHeader: ');
|
||||
|
||||
with NTHeaders.FileHeader do
|
||||
begin
|
||||
Write(' Machine: ', IntToHex(Machine, 4));
|
||||
case Machine of
|
||||
IMAGE_FILE_MACHINE_I386: WriteLN(' (Intel 386)');
|
||||
IMAGE_FILE_MACHINE_R3000: WriteLN(' (MIPS little-endian, 0x160 big-endian)');
|
||||
IMAGE_FILE_MACHINE_R4000: WriteLN(' (MIPS little-endian)');
|
||||
IMAGE_FILE_MACHINE_R10000: WriteLN(' (MIPS little-endian)');
|
||||
IMAGE_FILE_MACHINE_ALPHA: WriteLN(' (Alpha_AXP)');
|
||||
IMAGE_FILE_MACHINE_POWERPC: WriteLN(' (IBM PowerPC Little-Endian)');
|
||||
IMAGE_FILE_MACHINE_IA64: WriteLN(' (Intel IPF)');
|
||||
IMAGE_FILE_MACHINE_AMD64: WriteLN(' (x64)');
|
||||
else
|
||||
WriteLN;
|
||||
end;
|
||||
WriteLN(' NumberOfSections: ', NumberOfSections);
|
||||
WriteLN(' TimeDateStamp: ', TimeDateStamp);
|
||||
WriteLN(' PointerToSymbolTable: ', PointerToSymbolTable);
|
||||
WriteLN(' NumberOfSymbols: ', NumberOfSymbols);
|
||||
WriteLN(' SizeOfOptionalHeader: ', SizeOfOptionalHeader);
|
||||
Write(' Characteristics: ', IntToHex(Characteristics, 4), ' [');
|
||||
|
||||
if Characteristics and IMAGE_FILE_RELOCS_STRIPPED <> 0 then Write('RELOCS_STRIPPED ');
|
||||
if Characteristics and IMAGE_FILE_EXECUTABLE_IMAGE <> 0 then Write('EXECUTABLE_IMAGE ');
|
||||
if Characteristics and IMAGE_FILE_LINE_NUMS_STRIPPED <> 0 then Write('LINE_NUMS_STRIPPED ');
|
||||
if Characteristics and IMAGE_FILE_LOCAL_SYMS_STRIPPED <> 0 then Write('LOCAL_SYMS_STRIPPED ');
|
||||
if Characteristics and IMAGE_FILE_AGGRESIVE_WS_TRIM <> 0 then Write('AGGRESIVE_WS_TRIM ');
|
||||
if Characteristics and IMAGE_FILE_LARGE_ADDRESS_AWARE <> 0 then Write('LARGE_ADDRESS_AWARE ');
|
||||
if Characteristics and IMAGE_FILE_BYTES_REVERSED_LO <> 0 then Write('BYTES_REVERSED_LO ');
|
||||
if Characteristics and IMAGE_FILE_32BIT_MACHINE <> 0 then Write('32BIT_MACHINE ');
|
||||
if Characteristics and IMAGE_FILE_DEBUG_STRIPPED <> 0 then Write('DEBUG_STRIPPED ');
|
||||
if Characteristics and IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP <> 0 then Write('REMOVABLE_RUN_FROM_SWAP ');
|
||||
if Characteristics and IMAGE_FILE_NET_RUN_FROM_SWAP <> 0 then Write('NET_RUN_FROM_SWAP ');
|
||||
if Characteristics and IMAGE_FILE_SYSTEM <> 0 then Write('SYSTEM ');
|
||||
if Characteristics and IMAGE_FILE_DLL <> 0 then Write('DLL ');
|
||||
if Characteristics and IMAGE_FILE_UP_SYSTEM_ONLY <> 0 then Write('UP_SYSTEM_ONLY ');
|
||||
if Characteristics and IMAGE_FILE_BYTES_REVERSED_HI <> 0 then Write('BYTES_REVERSED_HI ');
|
||||
WriteLN(']');
|
||||
end;
|
||||
|
||||
WriteLN('OptionalHeader: ');
|
||||
OH := @NTHeaders.OptionalHeader;
|
||||
Is64 := OH^.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
|
||||
Write(' Magic: ', IntToHex(OH^.Magic, 4));
|
||||
case OH^.Magic of
|
||||
IMAGE_NT_OPTIONAL_HDR32_MAGIC : WriteLN(' (HDR32)');
|
||||
IMAGE_NT_OPTIONAL_HDR64_MAGIC : WriteLN(' (HDR64)');
|
||||
IMAGE_ROM_OPTIONAL_HDR_MAGIC : WriteLN(' (ROM)');
|
||||
else
|
||||
WriteLN;
|
||||
end;
|
||||
WriteLN(' MajorLinkerVersion: ', OH^.MajorLinkerVersion);
|
||||
WriteLN(' MinorLinkerVersion: ', OH^.MinorLinkerVersion);
|
||||
WriteLN(' SizeOfCode: ', OH^.SizeOfCode);
|
||||
WriteLN(' SizeOfInitializedData: ', OH^.SizeOfInitializedData);
|
||||
WriteLN(' SizeOfUninitializedData: ', OH^.SizeOfUninitializedData);
|
||||
WriteLN(' AddressOfEntryPoint: ', FormatAdress(OH^.AddressOfEntryPoint));
|
||||
WriteLN(' BaseOfCode: ', FormatAdress(OH^.BaseOfCode));
|
||||
if Is64
|
||||
then begin
|
||||
WriteLN(' ImageBase: $', IntToHex(OH^.ImageBase, 16));
|
||||
end
|
||||
else begin
|
||||
WriteLN(' BaseOfData: $', IntToHex(Integer(OH^.ImageBase), 8));
|
||||
WriteLN(' ImageBase: $', IntToHex(Integer(OH^.ImageBase shr 32), 8));
|
||||
end;
|
||||
WriteLN(' SectionAlignment: ', OH^.SectionAlignment);
|
||||
WriteLN(' FileAlignment: ', OH^.FileAlignment);
|
||||
WriteLN(' MajorOperatingSystemVersion: ', OH^.MajorOperatingSystemVersion);
|
||||
WriteLN(' MinorOperatingSystemVersion: ', OH^.MinorOperatingSystemVersion);
|
||||
WriteLN(' MajorImageVersion: ', OH^.MajorImageVersion);
|
||||
WriteLN(' MinorImageVersion: ', OH^.MinorImageVersion);
|
||||
WriteLN(' MajorSubsystemVersion: ', OH^.MajorSubsystemVersion);
|
||||
WriteLN(' MinorSubsystemVersion: ', OH^.MinorSubsystemVersion);
|
||||
WriteLN(' Win32VersionValue: ', OH^.Win32VersionValue);
|
||||
WriteLN(' SizeOfImage: ', OH^.SizeOfImage);
|
||||
WriteLN(' SizeOfHeaders: ', OH^.SizeOfHeaders);
|
||||
WriteLN(' CheckSum: ', OH^.CheckSum);
|
||||
Write(' Subsystem: ', OH^.Subsystem);
|
||||
case OH^.Subsystem of
|
||||
IMAGE_SUBSYSTEM_UNKNOWN: WriteLN(' (Unknown)');
|
||||
IMAGE_SUBSYSTEM_NATIVE: WriteLN(' (Native)');
|
||||
IMAGE_SUBSYSTEM_WINDOWS_CUI: WriteLN(' (Windows CUI)');
|
||||
IMAGE_SUBSYSTEM_WINDOWS_GUI: WriteLN(' (Windows GUI)');
|
||||
IMAGE_SUBSYSTEM_OS2_CUI: WriteLN(' (OS2_CUI)');
|
||||
IMAGE_SUBSYSTEM_POSIX_CUI: WriteLN(' (POSIX CUI)');
|
||||
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: WriteLN(' (Windows CE GUI)');
|
||||
IMAGE_SUBSYSTEM_XBOX: WriteLN(' (XBOX)');
|
||||
else
|
||||
WriteLN;
|
||||
end;
|
||||
Write(' DllCharacteristics: ', IntToHex(OH^.DllCharacteristics, 4), ' [');
|
||||
if OH^.DllCharacteristics and IMAGE_LIBRARY_PROCESS_INIT <> 0 then Write('PROCESS_INIT (reserved) ');
|
||||
if OH^.DllCharacteristics and IMAGE_LIBRARY_PROCESS_TERM <> 0 then Write('PROCESS_TERM (reserved) ');
|
||||
if OH^.DllCharacteristics and IMAGE_LIBRARY_THREAD_INIT <> 0 then Write('THREAD_INIT (reserved) ');
|
||||
if OH^.DllCharacteristics and IMAGE_LIBRARY_THREAD_TERM <> 0 then Write('THREAD_TERM (reserved) ');
|
||||
if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_NO_ISOLATION <> 0 then Write('NO_ISOLATION ');
|
||||
if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_NO_SEH <> 0 then Write('NO_SEH ');
|
||||
if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_NO_BIND <> 0 then Write('NO_BIND ');
|
||||
if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_WDM_DRIVER <> 0 then Write('WDM_DRIVER ');
|
||||
if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE <> 0 then Write('TERMINAL_SERVER_AWARE ');
|
||||
WriteLN(']');
|
||||
|
||||
Write(' SizeOfStackReserve: $');
|
||||
if Is64
|
||||
then begin
|
||||
WriteLN(IntToHex(OH^.SizeOfStackReserve, 16));
|
||||
end
|
||||
else begin
|
||||
WriteLN(IntToHex(Integer(OH^.SizeOfStackReserve), 8));
|
||||
Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again
|
||||
end;
|
||||
Write(' SizeOfStackCommit: $');
|
||||
if Is64
|
||||
then begin
|
||||
WriteLN(IntToHex(OH^.SizeOfStackCommit, 16));
|
||||
end
|
||||
else begin
|
||||
WriteLN(IntToHex(Integer(OH^.SizeOfStackCommit), 8));
|
||||
Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again
|
||||
end;
|
||||
Write(' SizeOfHeapReserve: $');
|
||||
if Is64
|
||||
then begin
|
||||
WriteLN(IntToHex(OH^.SizeOfHeapReserve, 16));
|
||||
end
|
||||
else begin
|
||||
WriteLN(IntToHex(Integer(OH^.SizeOfHeapReserve), 8));
|
||||
Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again
|
||||
end;
|
||||
Write(' SizeOfHeapCommit: $');
|
||||
if Is64
|
||||
then begin
|
||||
WriteLN(IntToHex(OH^.SizeOfHeapCommit, 16));
|
||||
end
|
||||
else begin
|
||||
WriteLN(IntToHex(Integer(OH^.SizeOfHeapCommit), 8));
|
||||
Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again
|
||||
end;
|
||||
WriteLN(' LoaderFlags: ', OH^.LoaderFlags);
|
||||
WriteLN(' NumberOfRvaAndSizes: ', OH^.NumberOfRvaAndSizes);
|
||||
WriteLN(' DataDirectory:');
|
||||
for n := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1 do
|
||||
begin
|
||||
WriteLN(' [', DIR_NAMES[n]+']':14, ' Adress: $', IntToHex(OH^.DataDirectory[n].VirtualAddress, 8), ' Size: ', OH^.DataDirectory[n]. Size);
|
||||
end;
|
||||
|
||||
WriteLN('Sections: ');
|
||||
for n := 0 to NtHeaders.FileHeader.NumberOfSections - 1 do
|
||||
begin
|
||||
if not ReadProcessMemory(AProcessHandle, Pointer(Cardinal(AAdress) + DosHeader._lfanew + SizeOF(NTHeaders) - SizeOF(NTHeaders.OptionalHeader) + NTHeaders.FileHeader.SizeOfOptionalHeader + SizeOf(SectionHeader) * n), @SectionHeader, SizeOf(SectionHeader), BytesRead)
|
||||
then begin
|
||||
WriteLN('Unable to retrieve section: ', n);
|
||||
Continue;
|
||||
end;
|
||||
with SectionHeader do
|
||||
begin
|
||||
Move(Name, SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
||||
SectionName[IMAGE_SIZEOF_SHORT_NAME] := #0;
|
||||
WriteLN(' Name: ',SectionName);
|
||||
WriteLN(' Misc.PhysicalAddress: ',FormatAdress(Misc.PhysicalAddress));
|
||||
WriteLN(' Misc.VirtualSize: ',Misc.VirtualSize);
|
||||
WriteLN(' VirtualAddress: ',FormatAdress(VirtualAddress));
|
||||
WriteLN(' SizeOfRawData: ',SizeOfRawData);
|
||||
WriteLN(' PointerToRawData: ',FormatAdress(PointerToRawData));
|
||||
WriteLN(' PointerToRelocations: ',FormatAdress(PointerToRelocations));
|
||||
WriteLN(' PointerToLinenumbers: ',FormatAdress(PointerToLinenumbers));
|
||||
WriteLN(' NumberOfRelocations: ',NumberOfRelocations);
|
||||
WriteLN(' NumberOfLinenumbers: ',NumberOfLinenumbers);
|
||||
Write(' Characteristics: ', IntToHex(Characteristics, 8), ' [');
|
||||
if Characteristics and IMAGE_SCN_TYPE_REG <> 0 then Write('IMAGE_SCN_TYPE_REG(r) ');
|
||||
if Characteristics and IMAGE_SCN_TYPE_DSECT <> 0 then Write('IMAGE_SCN_TYPE_DSECT(r) ');
|
||||
if Characteristics and IMAGE_SCN_TYPE_NOLOAD <> 0 then Write('IMAGE_SCN_TYPE_NOLOAD(r) ');
|
||||
if Characteristics and IMAGE_SCN_TYPE_GROUP <> 0 then Write('IMAGE_SCN_TYPE_GROUP(r) ');
|
||||
if Characteristics and IMAGE_SCN_TYPE_NO_PAD <> 0 then Write('IMAGE_SCN_TYPE_NO_PAD(r) ');
|
||||
if Characteristics and IMAGE_SCN_TYPE_COPY <> 0 then Write('IMAGE_SCN_TYPE_COPY(r) ');
|
||||
if Characteristics and IMAGE_SCN_CNT_CODE <> 0 then Write('IMAGE_SCN_CNT_CODE ');
|
||||
if Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA <> 0 then Write('IMAGE_SCN_CNT_INITIALIZED_DATA ');
|
||||
if Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA <> 0 then Write('IMAGE_SCN_CNT_UNINITIALIZED_DATA ');
|
||||
if Characteristics and IMAGE_SCN_LNK_OTHER <> 0 then Write('IMAGE_SCN_LNK_OTHER(r) ');
|
||||
if Characteristics and IMAGE_SCN_LNK_INFO <> 0 then Write('IMAGE_SCN_LNK_INFO(r) ');
|
||||
if Characteristics and IMAGE_SCN_TYPE_OVER <> 0 then Write('IMAGE_SCN_TYPE_OVER(r) ');
|
||||
if Characteristics and IMAGE_SCN_LNK_COMDAT <> 0 then Write('IMAGE_SCN_LNK_COMDAT ');
|
||||
if Characteristics and IMAGE_SCN_MEM_PROTECTED <> 0 then Write('IMAGE_SCN_MEM_PROTECTED(o) ');
|
||||
if Characteristics and IMAGE_SCN_MEM_FARDATA <> 0 then Write('IMAGE_SCN_MEM_FARDATA(r) ');
|
||||
if Characteristics and IMAGE_SCN_MEM_SYSHEAP <> 0 then Write('IMAGE_SCN_MEM_SYSHEAP(o) ');
|
||||
if Characteristics and IMAGE_SCN_MEM_PURGEABLE <> 0 then Write('IMAGE_SCN_MEM_PURGEABLE(r) ');
|
||||
if Characteristics and IMAGE_SCN_MEM_16BIT <> 0 then Write('IMAGE_SCN_MEM_16BIT(r) ');
|
||||
if Characteristics and IMAGE_SCN_MEM_LOCKED <> 0 then Write('IMAGE_SCN_MEM_LOCKED(r) ');
|
||||
if Characteristics and IMAGE_SCN_MEM_PRELOAD <> 0 then Write('IMAGE_SCN_MEM_PRELOAD(r) ');
|
||||
// Align
|
||||
if Characteristics and $00F00000 <> 0
|
||||
then Write('IMAGE_SCN_ALIGN_', 1 shl (((Characteristics and $00F00000) shr 20) - 1),'BYTES ');
|
||||
if Characteristics and IMAGE_SCN_LNK_NRELOC_OVFL <> 0 then Write('IMAGE_SCN_LNK_NRELOC_OVFL ');
|
||||
if Characteristics and IMAGE_SCN_MEM_DISCARDABLE <> 0 then Write('IMAGE_SCN_MEM_DISCARDABLE ');
|
||||
if Characteristics and IMAGE_SCN_MEM_NOT_CACHED <> 0 then Write('IMAGE_SCN_MEM_NOT_CACHED ');
|
||||
if Characteristics and IMAGE_SCN_MEM_NOT_PAGED <> 0 then Write('IMAGE_SCN_MEM_NOT_PAGED ');
|
||||
if Characteristics and IMAGE_SCN_MEM_SHARED <> 0 then Write('IMAGE_SCN_MEM_SHARED ');
|
||||
if Characteristics and IMAGE_SCN_MEM_EXECUTE <> 0 then Write('IMAGE_SCN_MEM_EXECUTE ');
|
||||
if Characteristics and IMAGE_SCN_MEM_READ <> 0 then Write('IMAGE_SCN_MEM_READ ');
|
||||
if Characteristics and IMAGE_SCN_MEM_WRITE <> 0 then Write('IMAGE_SCN_MEM_WRITE ');
|
||||
WriteLN(']');
|
||||
end;
|
||||
|
||||
end;
|
||||
end;
|
||||
{$ELSE}
|
||||
procedure DumpPEImage(const AProcessHandle: THandle; const AAdress: TDbgPtr);
|
||||
begin
|
||||
{$WARNING PEHeaders not yet translated}
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
end.
|
421
debugger/windebug/fpwd/fpwdtype.pas
Normal file
421
debugger/windebug/fpwd/fpwdtype.pas
Normal file
@ -0,0 +1,421 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
fpwdtype.pas - FP standalone windows debugger - Type definitions
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
This unit contains types/consts not yet part of the RTL.
|
||||
It also contains some experimental types for mixing win32 and win64
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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 FPWDType;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
{$ALIGN ON}
|
||||
|
||||
// Additional 64bit types
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows;
|
||||
|
||||
type
|
||||
DWORD64 = QWORD;
|
||||
ULONGLONG = QWORD;
|
||||
// LONGLONG = int64;
|
||||
//QWORD = type cardinal;
|
||||
|
||||
const
|
||||
THREAD_TERMINATE = $0001;
|
||||
THREAD_SUSPEND_RESUME = $0002;
|
||||
THREAD_GET_CONTEXT = $0008;
|
||||
THREAD_SET_CONTEXT = $0010;
|
||||
THREAD_SET_INFORMATION = $0020;
|
||||
THREAD_QUERY_INFORMATION = $0040;
|
||||
THREAD_SET_THREAD_TOKEN = $0080;
|
||||
THREAD_IMPERSONATE = $0100;
|
||||
THREAD_DIRECT_IMPERSONATION = $0200;
|
||||
|
||||
THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $3FF;
|
||||
|
||||
|
||||
type
|
||||
PExceptionRecord64 = QWORD;
|
||||
// PExceptionRecord64 = ^_EXCEPTION_RECORD64;
|
||||
_EXCEPTION_RECORD64 = record
|
||||
ExceptionCode: DWORD;
|
||||
ExceptionFlags: DWORD;
|
||||
ExceptionRecord: PExceptionRecord64;
|
||||
ExceptionAddress: QWORD;
|
||||
NumberParameters: DWORD;
|
||||
__unusedAlignment: DWORD;
|
||||
ExceptionInformation: array[0..EXCEPTION_MAXIMUM_PARAMETERS - 1] of QWORD;
|
||||
end;
|
||||
TExceptionRecord64 = _EXCEPTION_RECORD64;
|
||||
EXCEPTION_RECORD64 = _EXCEPTION_RECORD64;
|
||||
|
||||
(*
|
||||
PContext64 = QWORD;
|
||||
PExceptionPointers64 = QWORD;
|
||||
_EXCEPTION_POINTERS64 = record
|
||||
ExceptionRecord : PExceptionRecord64;
|
||||
ContextRecord : PContext64;
|
||||
end;
|
||||
TExceptionPointers64 = _EXCEPTION_POINTERS64;
|
||||
EXCEPTION_POINTERS64 = _EXCEPTION_POINTERS64;
|
||||
*)
|
||||
// PExceptionDebugInfo64 = QWORD;
|
||||
PExceptionDebugInfo64 = ^_EXCEPTION_DEBUG_INFO64;
|
||||
_EXCEPTION_DEBUG_INFO64 = record
|
||||
ExceptionRecord: TExceptionRecord64;
|
||||
dwFirstChance: DWORD;
|
||||
end;
|
||||
TExceptionDebugInfo64 = _EXCEPTION_DEBUG_INFO64;
|
||||
EXCEPTION_DEBUG_INFO64 = _EXCEPTION_DEBUG_INFO64;
|
||||
(*
|
||||
PCreateThreadDebugInfo64 = QWORD;
|
||||
_CREATE_THREAD_DEBUG_INFO64 = record
|
||||
hThread: QWORD;
|
||||
lpThreadLocalBase: QWORD;
|
||||
lpStartAddress: QWORD;
|
||||
end;
|
||||
TCreateThreadDebugInfo = _CREATE_THREAD_DEBUG_INFO;
|
||||
CREATE_THREAD_DEBUG_INFO = _CREATE_THREAD_DEBUG_INFO;
|
||||
|
||||
PCreateProcessDebugInfo = QWORD;
|
||||
_CREATE_PROCESS_DEBUG_INFO = record
|
||||
hFile: THandle;
|
||||
hProcess: THandle;
|
||||
hThread: THandle;
|
||||
lpBaseOfImage: Pointer;
|
||||
dwDebugInfoFileOffset: DWORD;
|
||||
nDebugInfoSize: DWORD;
|
||||
lpThreadLocalBase: Pointer;
|
||||
lpStartAddress: TFNThreadStartRoutine;
|
||||
lpImageName: Pointer;
|
||||
fUnicode: Word;
|
||||
end;
|
||||
TCreateProcessDebugInfo = _CREATE_PROCESS_DEBUG_INFO;
|
||||
CREATE_PROCESS_DEBUG_INFO = _CREATE_PROCESS_DEBUG_INFO;
|
||||
|
||||
PExitThreadDebugInfo64 = QWORD;
|
||||
PExitProcessDebugInfo64 = QWORD;
|
||||
|
||||
PLoadDLLDebugInfo64 = QWORD;
|
||||
_LOAD_DLL_DEBUG_INFO64 = record
|
||||
hFile: QWORD;
|
||||
lpBaseOfDll: QWORD;
|
||||
dwDebugInfoFileOffset: DWORD;
|
||||
nDebugInfoSize: DWORD;
|
||||
lpImageName: Pointer;
|
||||
fUnicode: Word;
|
||||
end;
|
||||
{$EXTERNALSYM _LOAD_DLL_DEBUG_INFO}
|
||||
TLoadDLLDebugInfo = _LOAD_DLL_DEBUG_INFO;
|
||||
LOAD_DLL_DEBUG_INFO = _LOAD_DLL_DEBUG_INFO;
|
||||
{$EXTERNALSYM LOAD_DLL_DEBUG_INFO}
|
||||
|
||||
PUnloadDLLDebugInfo = ^TUnloadDLLDebugInfo;
|
||||
_UNLOAD_DLL_DEBUG_INFO = record
|
||||
lpBaseOfDll: Pointer;
|
||||
end;
|
||||
{$EXTERNALSYM _UNLOAD_DLL_DEBUG_INFO}
|
||||
TUnloadDLLDebugInfo = _UNLOAD_DLL_DEBUG_INFO;
|
||||
UNLOAD_DLL_DEBUG_INFO = _UNLOAD_DLL_DEBUG_INFO;
|
||||
{$EXTERNALSYM UNLOAD_DLL_DEBUG_INFO}
|
||||
|
||||
POutputDebugStringInfo = ^TOutputDebugStringInfo;
|
||||
_OUTPUT_DEBUG_STRING_INFO = record
|
||||
lpDebugStringData: LPSTR;
|
||||
fUnicode: Word;
|
||||
nDebugStringLength: Word;
|
||||
end;
|
||||
{$EXTERNALSYM _OUTPUT_DEBUG_STRING_INFO}
|
||||
TOutputDebugStringInfo = _OUTPUT_DEBUG_STRING_INFO;
|
||||
OUTPUT_DEBUG_STRING_INFO = _OUTPUT_DEBUG_STRING_INFO;
|
||||
{$EXTERNALSYM OUTPUT_DEBUG_STRING_INFO}
|
||||
|
||||
PRIPInfo64 = QWORD;
|
||||
*)
|
||||
|
||||
PDebugEvent64 = ^TDebugEvent64;
|
||||
_DEBUG_EVENT64 = record
|
||||
dwDebugEventCode: DWORD;
|
||||
dwProcessId: DWORD;
|
||||
dwThreadId: DWORD;
|
||||
case Integer of
|
||||
0: (Exception: TExceptionDebugInfo);
|
||||
1: (CreateThread: TCreateThreadDebugInfo);
|
||||
2: (CreateProcessInfo: TCreateProcessDebugInfo);
|
||||
3: (ExitThread: TExitThreadDebugInfo);
|
||||
4: (ExitProcess: TExitProcessDebugInfo);
|
||||
5: (LoadDll: TLoadDLLDebugInfo);
|
||||
6: (UnloadDll: TUnloadDLLDebugInfo);
|
||||
7: (DebugString: TOutputDebugStringInfo);
|
||||
8: (RipInfo: TRIPInfo);
|
||||
9: (Exception64: TExceptionDebugInfo64);
|
||||
end;
|
||||
TDebugEvent64 = _DEBUG_EVENT64;
|
||||
DEBUG_EVENT64 = _DEBUG_EVENT64;
|
||||
|
||||
const
|
||||
CONTEXT_AMD64 = $100000;
|
||||
|
||||
// MWE: added _AMD64 postfix to distinguish between i386 and amd64
|
||||
|
||||
CONTEXT_CONTROL_AMD64 = (CONTEXT_AMD64 or $00000001);
|
||||
CONTEXT_INTEGER_AMD64 = (CONTEXT_AMD64 or $00000002);
|
||||
CONTEXT_SEGMENTS_AMD64 = (CONTEXT_AMD64 or $00000004);
|
||||
CONTEXT_FLOATING_POINT_AMD64 = (CONTEXT_AMD64 or $00000008);
|
||||
CONTEXT_DEBUG_REGISTERS_AMD64 = (CONTEXT_AMD64 or $00000010);
|
||||
|
||||
CONTEXT_FULL_AMD64 = (CONTEXT_CONTROL_AMD64 or CONTEXT_INTEGER_AMD64 or CONTEXT_FLOATING_POINT_AMD64);
|
||||
CONTEXT_ALL_AMD64 = (CONTEXT_CONTROL_AMD64 or CONTEXT_INTEGER_AMD64 or CONTEXT_SEGMENTS_AMD64 or CONTEXT_FLOATING_POINT_AMD64 or CONTEXT_DEBUG_REGISTERS_AMD64);
|
||||
|
||||
CONTEXT_EXCEPTION_ACTIVE_AMD64 = $08000000;
|
||||
CONTEXT_SERVICE_ACTIVE_AMD64 = $10000000;
|
||||
CONTEXT_EXCEPTION_REQUEST_AMD64 = $40000000;
|
||||
CONTEXT_EXCEPTION_REPORTING_AMD64 = $80000000;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Define initial MxCsr and FpCsr control.
|
||||
//
|
||||
|
||||
//#define INITIAL_MXCSR 0x1f80 // initial MXCSR value
|
||||
//#define INITIAL_FPCSR 0x027f // initial FPCSR value
|
||||
|
||||
//
|
||||
// Define 128-bit 16-byte aligned xmm register type.
|
||||
//
|
||||
|
||||
//typedef struct DECLSPEC_ALIGN(16) _M128A {
|
||||
type
|
||||
_M128A = record
|
||||
Low: ULONGLONG;
|
||||
High: LONGLONG;
|
||||
end;
|
||||
M128A = _M128A;
|
||||
TM128A = _M128A;
|
||||
PM128A = TM128A;
|
||||
|
||||
//
|
||||
// Format of data for 32-bit fxsave/fxrstor instructions.
|
||||
//
|
||||
|
||||
//typedef struct _XMM_SAVE_AREA32 {
|
||||
type
|
||||
_XMM_SAVE_AREA32 = record
|
||||
ControlWord: WORD;
|
||||
StatusWord: WORD;
|
||||
TagWord: BYTE;
|
||||
Reserved1: BYTE;
|
||||
ErrorOpcode: WORD;
|
||||
ErrorOffset: DWORD;
|
||||
ErrorSelector: WORD;
|
||||
Reserved2: WORD;
|
||||
DataOffset: DWORD;
|
||||
DataSelector: WORD;
|
||||
Reserved3: WORD;
|
||||
MxCsr: DWORD;
|
||||
MxCsr_Mask: DWORD;
|
||||
FloatRegisters: array[0..7] of M128A;
|
||||
XmmRegisters: array[0..16] of M128A;
|
||||
Reserved4: array[0..95] of BYTE;
|
||||
end;
|
||||
XMM_SAVE_AREA32 = _XMM_SAVE_AREA32;
|
||||
TXmmSaveArea = XMM_SAVE_AREA32;
|
||||
PXmmSaveArea = ^TXmmSaveArea;
|
||||
|
||||
const
|
||||
LEGACY_SAVE_AREA_LENGTH = sizeof(XMM_SAVE_AREA32);
|
||||
|
||||
//
|
||||
// Context Frame
|
||||
//
|
||||
// This frame has a several purposes: 1) it is used as an argument to
|
||||
// NtContinue, 2) is is used to constuct a call frame for APC delivery,
|
||||
// and 3) it is used in the user level thread creation routines.
|
||||
//
|
||||
//
|
||||
// The flags field within this record controls the contents of a CONTEXT
|
||||
// record.
|
||||
//
|
||||
// If the context record is used as an input parameter, then for each
|
||||
// portion of the context record controlled by a flag whose value is
|
||||
// set, it is assumed that that portion of the context record contains
|
||||
// valid context. If the context record is being used to modify a threads
|
||||
// context, then only that portion of the threads context is modified.
|
||||
//
|
||||
// If the context record is used as an output parameter to capture the
|
||||
// context of a thread, then only those portions of the thread's context
|
||||
// corresponding to set flags will be returned.
|
||||
//
|
||||
// CONTEXT_CONTROL specifies SegSs, Rsp, SegCs, Rip, and EFlags.
|
||||
//
|
||||
// CONTEXT_INTEGER specifies Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, and R8-R15.
|
||||
//
|
||||
// CONTEXT_SEGMENTS specifies SegDs, SegEs, SegFs, and SegGs.
|
||||
//
|
||||
// CONTEXT_DEBUG_REGISTERS specifies Dr0-Dr3 and Dr6-Dr7.
|
||||
//
|
||||
// CONTEXT_MMX_REGISTERS specifies the floating point and extended registers
|
||||
// Mm0/St0-Mm7/St7 and Xmm0-Xmm15).
|
||||
//
|
||||
|
||||
//typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
|
||||
type
|
||||
_CONTEXTAMD64 = record
|
||||
|
||||
//
|
||||
// Register parameter home addresses.
|
||||
//
|
||||
// N.B. These fields are for convience - they could be used to extend the
|
||||
// context record in the future.
|
||||
//
|
||||
|
||||
P1Home: DWORD64;
|
||||
P2Home: DWORD64;
|
||||
P3Home: DWORD64;
|
||||
P4Home: DWORD64;
|
||||
P5Home: DWORD64;
|
||||
P6Home: DWORD64;
|
||||
|
||||
//
|
||||
// Control flags.
|
||||
//
|
||||
|
||||
ContextFlags: DWORD;
|
||||
MxCsr: DWORD;
|
||||
|
||||
//
|
||||
// Segment Registers and processor flags.
|
||||
//
|
||||
|
||||
SegCs: WORD;
|
||||
SegDs: WORD;
|
||||
SegEs: WORD;
|
||||
SegFs: WORD;
|
||||
SegGs: WORD;
|
||||
SegSs: WORD;
|
||||
EFlags: DWORD;
|
||||
|
||||
//
|
||||
// Debug registers
|
||||
//
|
||||
|
||||
Dr0: DWORD64;
|
||||
Dr1: DWORD64;
|
||||
Dr2: DWORD64;
|
||||
Dr3: DWORD64;
|
||||
Dr6: DWORD64;
|
||||
Dr7: DWORD64;
|
||||
|
||||
//
|
||||
// Integer registers.
|
||||
//
|
||||
|
||||
Rax: DWORD64;
|
||||
Rcx: DWORD64;
|
||||
Rdx: DWORD64;
|
||||
Rbx: DWORD64;
|
||||
Rsp: DWORD64;
|
||||
Rbp: DWORD64;
|
||||
Rsi: DWORD64;
|
||||
Rdi: DWORD64;
|
||||
R8: DWORD64;
|
||||
R9: DWORD64;
|
||||
R10: DWORD64;
|
||||
R11: DWORD64;
|
||||
R12: DWORD64;
|
||||
R13: DWORD64;
|
||||
R14: DWORD64;
|
||||
R15: DWORD64;
|
||||
|
||||
//
|
||||
// Program counter.
|
||||
//
|
||||
|
||||
Rip: DWORD64;
|
||||
|
||||
//
|
||||
// Floating point state.
|
||||
//
|
||||
|
||||
FltSave: XMM_SAVE_AREA32; // MWE: only translated the FltSave part of the union
|
||||
(*
|
||||
union {
|
||||
XMM_SAVE_AREA32 FltSave;
|
||||
struct {
|
||||
M128A Header[2];
|
||||
M128A Legacy[8];
|
||||
M128A Xmm0;
|
||||
M128A Xmm1;
|
||||
M128A Xmm2;
|
||||
M128A Xmm3;
|
||||
M128A Xmm4;
|
||||
M128A Xmm5;
|
||||
M128A Xmm6;
|
||||
M128A Xmm7;
|
||||
M128A Xmm8;
|
||||
M128A Xmm9;
|
||||
M128A Xmm10;
|
||||
M128A Xmm11;
|
||||
M128A Xmm12;
|
||||
M128A Xmm13;
|
||||
M128A Xmm14;
|
||||
M128A Xmm15;
|
||||
};
|
||||
};
|
||||
*)
|
||||
|
||||
//
|
||||
// Vector registers.
|
||||
//
|
||||
|
||||
VectorRegister: array[0..25] of M128A;
|
||||
VectorControl: DWORD64;
|
||||
|
||||
//
|
||||
// Special debug control registers.
|
||||
//
|
||||
|
||||
DebugControl: DWORD64;
|
||||
LastBranchToRip: DWORD64;
|
||||
LastBranchFromRip: DWORD64;
|
||||
LastExceptionToRip: DWORD64;
|
||||
LastExceptionFromRip: DWORD64;
|
||||
end;
|
||||
CONTEXTAMD64 = _CONTEXTAMD64;
|
||||
TContextAMD64 = _CONTEXTAMD64;
|
||||
PContextAMD64 = ^TContextAMD64;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
690
debugger/windebug/windebugger.pp
Normal file
690
debugger/windebug/windebugger.pp
Normal file
@ -0,0 +1,690 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
windebugger.pp - Native windows debugger
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
This unit contains debugger classes for a native windows debugger
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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 WinDebugger;
|
||||
{$mode objfpc}{$H+}
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows, Classes, Maps, WindExtra;
|
||||
|
||||
type
|
||||
TDbgPtr = PtrUInt;
|
||||
TDbgProcess = class;
|
||||
|
||||
TDbgThread = class(TObject)
|
||||
private
|
||||
FProcess: TDbgProcess;
|
||||
FID: Integer;
|
||||
FHandle: THandle;
|
||||
FBaseAddr: Pointer;
|
||||
FStartAddr: Pointer;
|
||||
FSingleStepping: Boolean;
|
||||
protected
|
||||
public
|
||||
constructor Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle; const ABase, AStart: Pointer);
|
||||
destructor Destroy; override;
|
||||
function SingleStep: Boolean;
|
||||
property ID: Integer read FID;
|
||||
property Handle: THandle read FHandle;
|
||||
property SingleStepping: boolean read FSingleStepping;
|
||||
end;
|
||||
|
||||
(*
|
||||
TDbgSymbol = class(TObject)
|
||||
private
|
||||
FName: String;
|
||||
FOffset: Integer;
|
||||
FLength: Integer;
|
||||
function GetAddress: Pointer;
|
||||
protected
|
||||
public
|
||||
constructor Create(const AName: String; const AOffset: Integer);
|
||||
property Address: Pointer read GetAddress;
|
||||
property Length: Integer read FLength;
|
||||
end;
|
||||
*)
|
||||
|
||||
TDbgBreakpoint = class;
|
||||
TDbgBreakpointEvent = procedure(const ASender: TDbgBreakpoint; const AContext: TContext) of object;
|
||||
TDbgBreakpoint = class(TObject)
|
||||
private
|
||||
FProcess: TDbgProcess;
|
||||
FLocation: TDbgPtr;
|
||||
FOrgValue: Byte;
|
||||
procedure SetBreak;
|
||||
procedure ResetBreak;
|
||||
protected
|
||||
public
|
||||
constructor Create(const AProcess: TDbgProcess; const ALocation: TDbgPtr);
|
||||
destructor Destroy; override;
|
||||
function Hit(const AThreadID: Integer): Boolean;
|
||||
end;
|
||||
|
||||
|
||||
TDbgInstance = class(TObject)
|
||||
private
|
||||
FName: String;
|
||||
FProcess: TDbgProcess;
|
||||
FModuleHandle: THandle;
|
||||
FBaseAddr: TDbgPtr;
|
||||
FBreakList: TList;
|
||||
procedure CheckName;
|
||||
procedure SetName(const AValue: String);
|
||||
public
|
||||
constructor Create(const AProcess: TDbgProcess; const ADefaultName: String; const AModuleHandle: THandle; const ABaseAddr, ANameAddr: TDbgPtr; const AUnicode: Boolean);
|
||||
destructor Destroy; override;
|
||||
property Process: TDbgProcess read FProcess;
|
||||
property ModuleHandle: THandle read FModuleHandle;
|
||||
property BaseAddr: TDbgPtr read FBaseAddr;
|
||||
end;
|
||||
|
||||
TDbgLibrary = class(TDbgInstance)
|
||||
private
|
||||
public
|
||||
constructor Create(const AProcess: TDbgProcess; const ADefaultName: String; const AInfo: TLoadDLLDebugInfo);
|
||||
property Name: String read FName;
|
||||
end;
|
||||
|
||||
TDbgProcess = class(TDbgInstance)
|
||||
private
|
||||
FProcessID: Integer;
|
||||
FThreadID: Integer;
|
||||
FInfo: TCreateProcessDebugInfo;
|
||||
|
||||
FThreadMap: TMap; // map ThreadID -> ThreadObject
|
||||
FLibMap: TMap; // map LibAddr -> LibObject
|
||||
FBreakMap: TMap; // map BreakAddr -> BreakObject
|
||||
|
||||
FMainThread: TDbgThread;
|
||||
|
||||
FSingleStepBreak: TDbgBreakpoint; // set if we are executing the code at the break
|
||||
// if the singlestep is done, set the break
|
||||
FSingleStepSet: Boolean; // set if we set the singlestep to correct the BP
|
||||
|
||||
|
||||
procedure SetName(const AValue: String);
|
||||
procedure ThreadDestroyed(const AThread: TDbgThread);
|
||||
protected
|
||||
public
|
||||
constructor Create(const ADefaultName: String; const AProcessID, AThreadID: Integer; const AInfo: TCreateProcessDebugInfo);
|
||||
destructor Destroy; override;
|
||||
function AddBreak(const ALocation: TDbgPtr): TDbgBreakpoint;
|
||||
function AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary;
|
||||
procedure AddThread(const AID: Integer; const AInfo: TCreateThreadDebugInfo);
|
||||
// function GetLib(const AHandle: THandle; var ALib: TDbgLibrary): Boolean;
|
||||
procedure Interrupt;
|
||||
function GetThread(const AID: Integer; var AThread: TDbgThread): Boolean;
|
||||
procedure ContinueDebugEvent(const AThread: TDbgThread; const ADebugEvent: TDebugEvent);
|
||||
function HandleDebugEvent(const ADebugEvent: TDebugEvent): Boolean;
|
||||
function RemoveBreak(const ALocation: TDbgPtr): TDbgBreakpoint;
|
||||
procedure RemoveLib(const AInfo: TUnloadDLLDebugInfo);
|
||||
procedure RemoveThread(const AID: DWord);
|
||||
|
||||
function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean;
|
||||
function ReadOrdinal(const AAdress: TDbgPtr; out AData): Boolean;
|
||||
function ReadString(const AAdress: TDbgPtr; const AMaxSize: Cardinal; out AData: String): Boolean;
|
||||
function ReadWString(const AAdress: TDbgPtr; const AMaxSize: Cardinal; out AData: WideString): Boolean;
|
||||
|
||||
function WriteData(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean;
|
||||
|
||||
property Handle: THandle read FInfo.hProcess;
|
||||
property Name: String read FName write SetName;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
SysUtils;
|
||||
|
||||
|
||||
procedure Log(const AText: String; const AParams: array of const); overload;
|
||||
begin
|
||||
WriteLN(Format(AText, AParams));
|
||||
end;
|
||||
|
||||
procedure Log(const AText: String); overload;
|
||||
begin
|
||||
WriteLN(AText);
|
||||
end;
|
||||
|
||||
procedure LogLastError;
|
||||
begin
|
||||
WriteLN('ERROR: ', GetLastErrorText);
|
||||
end;
|
||||
|
||||
{ TDbgInstance }
|
||||
|
||||
procedure TDbgInstance.CheckName;
|
||||
begin
|
||||
if FName = ''
|
||||
then FName := Format('@%p', [FBaseAddr]);
|
||||
end;
|
||||
|
||||
constructor TDbgInstance.Create(const AProcess: TDbgProcess; const ADefaultName: String; const AModuleHandle: THandle; const ABaseAddr, ANameAddr: TDbgPtr; const AUnicode: Boolean);
|
||||
var
|
||||
NamePtr: TDbgPtr;
|
||||
S: String;
|
||||
W: WideString;
|
||||
len: Integer;
|
||||
begin
|
||||
FBaseAddr := ABaseAddr;
|
||||
FModuleHandle := AModuleHandle;
|
||||
FBreakList := TList.Create;
|
||||
|
||||
inherited Create;
|
||||
|
||||
W := '';
|
||||
if AProcess.ReadOrdinal(ANameAddr, NamePtr)
|
||||
then begin
|
||||
if AUnicode
|
||||
then begin
|
||||
AProcess.ReadWString(NamePtr, MAX_PATH, W);
|
||||
end
|
||||
else begin
|
||||
if AProcess.ReadString(NamePtr, MAX_PATH, S)
|
||||
then W := S;
|
||||
end;
|
||||
end;
|
||||
|
||||
if W = ''
|
||||
then begin
|
||||
SetLength(S, MAX_PATH);
|
||||
len := GetModuleFileName(FModuleHandle, @S[1], MAX_PATH);
|
||||
if len > 0
|
||||
then SetLength(S, len - 1)
|
||||
else begin
|
||||
S := '';
|
||||
LogLastError;
|
||||
end;
|
||||
W := S;
|
||||
end;
|
||||
|
||||
if W = ''
|
||||
then W := ADefaultName;
|
||||
|
||||
SetName(W);
|
||||
end;
|
||||
|
||||
destructor TDbgInstance.Destroy;
|
||||
var
|
||||
n: integer;
|
||||
begin
|
||||
for n := 0 to FBreakList.Count - 1 do
|
||||
begin
|
||||
Process.RemoveBreak(TDbgBreakpoint(FBreakList[n]).FLocation);
|
||||
end;
|
||||
FBreakList.Clear;
|
||||
|
||||
FreeAndNil(FBreakList);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TDbgInstance.SetName(const AValue: String);
|
||||
begin
|
||||
FName := AValue;
|
||||
CheckName;
|
||||
end;
|
||||
|
||||
{ TDbgLibrary }
|
||||
|
||||
constructor TDbgLibrary.Create(const AProcess: TDbgProcess; const ADefaultName: String; const AInfo: TLoadDLLDebugInfo);
|
||||
begin
|
||||
inherited Create(AProcess, ADefaultName, AInfo.hFile, TDbgPtr(AInfo.lpBaseOfDll), TDbgPtr(AInfo.lpImageName), AInfo.fUnicode <> 0);
|
||||
end;
|
||||
|
||||
{ TDbgProcess }
|
||||
|
||||
function TDbgProcess.AddBreak(const ALocation: TDbgPtr): TDbgBreakpoint;
|
||||
begin
|
||||
Result := TDbgBreakpoint.Create(Self, ALocation);
|
||||
FBreakMap.Add(ALocation, Result);
|
||||
end;
|
||||
|
||||
function TDbgProcess.AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary;
|
||||
begin
|
||||
Result := TDbgLibrary.Create(Self, FormatAdress(AInfo.lpBaseOfDll), AInfo);
|
||||
FLibMap.Add(TDbgPtr(AInfo.lpBaseOfDll), Result);
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.AddThread(const AID: Integer; const AInfo: TCreateThreadDebugInfo);
|
||||
var
|
||||
Thread: TDbgThread;
|
||||
begin
|
||||
Thread := TDbgThread.Create(Self, AID, AInfo.hThread, AInfo.lpThreadLocalBase, AInfo.lpStartAddress);
|
||||
FThreadMap.Add(AID, Thread);
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.ContinueDebugEvent(const AThread: TDbgThread; const ADebugEvent: TDebugEvent);
|
||||
begin
|
||||
case ADebugEvent.dwDebugEventCode of
|
||||
EXCEPTION_DEBUG_EVENT: begin
|
||||
case ADebugEvent.Exception.ExceptionRecord.ExceptionCode of
|
||||
EXCEPTION_BREAKPOINT: begin
|
||||
if AThread = nil then Exit;
|
||||
if FSingleStepBreak = nil then Exit;
|
||||
if AThread.SingleStepping then Exit;
|
||||
AThread.SingleStep;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TDbgProcess.Create(const ADefaultName: String; const AProcessID, AThreadID: Integer; const AInfo: TCreateProcessDebugInfo);
|
||||
const
|
||||
{$IFDEF CPU64}
|
||||
MAP_ID_SIZE = itu8;
|
||||
{$ELSE}
|
||||
MAP_ID_SIZE = itu4;
|
||||
{$ENDIF}
|
||||
begin
|
||||
FProcessID := AProcessID;
|
||||
FThreadID := AThreadID;
|
||||
FInfo := AInfo;
|
||||
|
||||
FThreadMap := TMap.Create(itu4, SizeOf(TDbgThread));
|
||||
FLibMap := TMap.Create(MAP_ID_SIZE, SizeOf(TDbgLibrary));
|
||||
FBreakMap := TMap.Create(MAP_ID_SIZE, SizeOf(TDbgBreakpoint));
|
||||
FSingleStepBreak := nil;
|
||||
|
||||
inherited Create(Self, ADefaultName, AInfo.hFile, TDbgPtr(AInfo.lpBaseOfImage), TDbgPtr(AInfo.lpImageName), AInfo.fUnicode <> 0);
|
||||
|
||||
FMainThread := TDbgThread.Create(Self, AThreadID, FInfo.hThread, FInfo.lpThreadLocalBase, FInfo.lpStartAddress);
|
||||
FThreadMap.Add(AThreadID, FMainThread);
|
||||
end;
|
||||
|
||||
destructor TDbgProcess.Destroy;
|
||||
begin
|
||||
// CloseHandle(FInfo.hThread);
|
||||
CloseHandle(FInfo.hProcess);
|
||||
FreeAndNil(FBreakMap);
|
||||
FreeAndNil(FThreadMap);
|
||||
FreeAndNil(FLibMap);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
(*
|
||||
function TDbgProcess.GetLib(const AHandle: THandle; var ALib: TDbgLibrary): Boolean;
|
||||
var
|
||||
n: Integer;
|
||||
Lib: TDbgLibrary;
|
||||
begin
|
||||
for n := 0 to FLibraries.Count - 1 do
|
||||
begin
|
||||
Lib := TDbgLibrary(FLibraries[n]);
|
||||
if Lib.ModuleHandle <> AHandle then Continue;
|
||||
|
||||
Result := True;
|
||||
ALib := Lib;
|
||||
Exit;
|
||||
end;
|
||||
Result := False;
|
||||
end;
|
||||
*)
|
||||
|
||||
function TDbgProcess.GetThread(const AID: Integer; var AThread: TDbgThread): Boolean;
|
||||
var
|
||||
Thread: TDbgThread;
|
||||
begin
|
||||
Result := FThreadMap.GetData(AID, Thread) and (Thread <> nil);
|
||||
if Result
|
||||
then AThread := Thread
|
||||
else Log('Unknown thread ID %u for process %u', [AID, FProcessID]);
|
||||
end;
|
||||
|
||||
function TDbgProcess.HandleDebugEvent(const ADebugEvent: TDebugEvent): Boolean;
|
||||
var
|
||||
Context: TContext;
|
||||
begin
|
||||
Result := False;
|
||||
case ADebugEvent.dwDebugEventCode of
|
||||
EXCEPTION_DEBUG_EVENT: begin
|
||||
case ADebugEvent.Exception.ExceptionRecord.ExceptionCode of
|
||||
EXCEPTION_BREAKPOINT: begin
|
||||
if not FBreakMap.GetData(TDbgPtr(ADebugEvent.Exception.ExceptionRecord.ExceptionAddress), FSingleStepBreak) then Exit;
|
||||
if FSingleStepBreak = nil then Exit;
|
||||
|
||||
Result := True;
|
||||
if not FSingleStepBreak.Hit(ADebugEvent.dwThreadId)
|
||||
then FSingleStepBreak := nil; // no need for a singlestep if we continue
|
||||
end;
|
||||
EXCEPTION_SINGLE_STEP: begin
|
||||
// check if we are interupting
|
||||
Context.ContextFlags := CONTEXT_DEBUG_REGISTERS;
|
||||
if GetThreadContext(FInfo.hThread, Context)
|
||||
then begin
|
||||
if Context.Dr6 and 1 <> 0
|
||||
then begin
|
||||
// interrupt !
|
||||
// disable break.
|
||||
Context.Dr7 := Context.Dr7 and not $1;
|
||||
Context.Dr0 := 0;
|
||||
if not SetThreadContext(FInfo.hThread, Context)
|
||||
then begin
|
||||
// Heeellppp!!
|
||||
Log('Thread %u: Unable to reset BR0', [ADebugEvent.dwThreadId]);
|
||||
end;
|
||||
// check if we are also singlestepping
|
||||
// if not, then exit, else proceed to next check
|
||||
if Context.Dr6 and $40 = 0
|
||||
then Exit;
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
// if we cant get the context, we probable weren't able to set it either
|
||||
Log('Thread %u: Unable to get context', [ADebugEvent.dwThreadId]);
|
||||
end;
|
||||
|
||||
// check if we are single stepping
|
||||
if FSingleStepBreak = nil then Exit;
|
||||
|
||||
FSingleStepBreak.SetBreak;
|
||||
FSingleStepBreak := nil;
|
||||
Result := FSingleStepSet;
|
||||
FSingleStepSet := False;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
CREATE_THREAD_DEBUG_EVENT: begin
|
||||
AddThread(ADebugEvent.dwThreadId, ADebugEvent.CreateThread)
|
||||
end;
|
||||
EXIT_THREAD_DEBUG_EVENT: begin
|
||||
RemoveThread(ADebugEvent.dwThreadId);
|
||||
end;
|
||||
LOAD_DLL_DEBUG_EVENT: begin
|
||||
AddLib(ADebugEvent.LoadDll);
|
||||
end;
|
||||
UNLOAD_DLL_DEBUG_EVENT: begin
|
||||
RemoveLib(ADebugEvent.UnloadDll);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.Interrupt;
|
||||
var
|
||||
Context: TContext;
|
||||
r: DWORD;
|
||||
begin
|
||||
r := SuspendThread(FInfo.hThread);
|
||||
try
|
||||
Context.ContextFlags := CONTEXT_CONTROL or CONTEXT_DEBUG_REGISTERS;
|
||||
if not GetThreadContext(FInfo.hThread, Context)
|
||||
then begin
|
||||
// Log('Thread %u: Unable to get context', [FID]);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
|
||||
Context.ContextFlags := CONTEXT_DEBUG_REGISTERS;
|
||||
Context.Dr0 := Context.Eip;
|
||||
Context.Dr7 := (Context.Dr7 and $FFF0FFFF) or $1;
|
||||
|
||||
// Context.EFlags := Context.EFlags or $100;
|
||||
|
||||
|
||||
|
||||
if not SetThreadContext(FInfo.hThread, Context)
|
||||
then begin
|
||||
// Log('Thread %u: Unable to set context', [FID]);
|
||||
Exit;
|
||||
end;
|
||||
finally
|
||||
r := ResumeTHread(FInfo.hThread);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDbgProcess.ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean;
|
||||
var
|
||||
BytesRead: Cardinal;
|
||||
begin
|
||||
Result := ReadProcessMemory(Handle, Pointer(AAdress), @AData, ASize, BytesRead) and (BytesRead = ASize);
|
||||
|
||||
if not Result then LogLastError;
|
||||
end;
|
||||
|
||||
function TDbgProcess.ReadOrdinal(const AAdress: TDbgPtr; out AData): Boolean;
|
||||
begin
|
||||
Result := ReadData(AAdress, 4, AData);
|
||||
end;
|
||||
|
||||
function TDbgProcess.ReadString(const AAdress: TDbgPtr; const AMaxSize: Cardinal; out AData: String): Boolean;
|
||||
var
|
||||
BytesRead: Cardinal;
|
||||
buf: array of Char;
|
||||
begin
|
||||
SetLength(buf, AMaxSize + 1);
|
||||
Result := ReadProcessMemory(Handle, Pointer(AAdress), @Buf[0], AMaxSize, BytesRead);
|
||||
if not Result then Exit;
|
||||
if BytesRead < AMaxSize
|
||||
then Buf[BytesRead] := #0
|
||||
else Buf[AMaxSize] := #0;
|
||||
AData := PChar(@Buf[0]);
|
||||
end;
|
||||
|
||||
function TDbgProcess.ReadWString(const AAdress: TDbgPtr; const AMaxSize: Cardinal; out AData: WideString): Boolean;
|
||||
var
|
||||
BytesRead: Cardinal;
|
||||
buf: array of WChar;
|
||||
begin
|
||||
SetLength(buf, AMaxSize + 1);
|
||||
Result := ReadProcessMemory(Handle, Pointer(AAdress), @Buf[0], SizeOf(WChar) * AMaxSize, BytesRead);
|
||||
if not Result then Exit;
|
||||
BytesRead := BytesRead div SizeOf(WChar);
|
||||
if BytesRead < AMaxSize
|
||||
then Buf[BytesRead] := #0
|
||||
else Buf[AMaxSize] := #0;
|
||||
AData := PWChar(@Buf[0]);
|
||||
end;
|
||||
|
||||
function TDbgProcess.RemoveBreak(const ALocation: TDbgPtr): TDbgBreakpoint;
|
||||
begin
|
||||
if FBreakMap = nil then Exit;
|
||||
FBreakMap.Delete(ALocation);
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.RemoveLib(const AInfo: TUnloadDLLDebugInfo);
|
||||
begin
|
||||
if FLibMap = nil then Exit;
|
||||
FLibMap.Delete(TDbgPtr(AInfo.lpBaseOfDll));
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.RemoveThread(const AID: DWord);
|
||||
begin
|
||||
if FThreadMap = nil then Exit;
|
||||
FThreadMap.Delete(AID);
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.SetName(const AValue: String);
|
||||
begin
|
||||
FName := AValue;
|
||||
end;
|
||||
|
||||
procedure TDbgProcess.ThreadDestroyed(const AThread: TDbgThread);
|
||||
begin
|
||||
if AThread = FMainThread
|
||||
then FMainThread := nil;
|
||||
end;
|
||||
|
||||
function TDbgProcess.WriteData(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean;
|
||||
var
|
||||
BytesWritten: Cardinal;
|
||||
begin
|
||||
Result := WriteProcessMemory(Handle, Pointer(AAdress), @AData, ASize, BytesWritten) and (BytesWritten = ASize);
|
||||
|
||||
if not Result then LogLastError;
|
||||
end;
|
||||
|
||||
{ TDbgThread }
|
||||
|
||||
constructor TDbgThread.Create(const AProcess: TDbgProcess; const AID: Integer; const AHandle: THandle; const ABase, AStart: Pointer);
|
||||
begin
|
||||
FID := AID;
|
||||
FHandle := AHandle;
|
||||
FBaseAddr := ABase;
|
||||
FStartAddr := AStart;
|
||||
FProcess := AProcess;
|
||||
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
destructor TDbgThread.Destroy;
|
||||
begin
|
||||
FProcess.ThreadDestroyed(Self);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TDbgThread.SingleStep: Boolean;
|
||||
var
|
||||
Context: TContext;
|
||||
begin
|
||||
Context.ContextFlags := CONTEXT_CONTROL;
|
||||
if not GetThreadContext(FHandle, Context)
|
||||
then begin
|
||||
Log('Thread %u: Unable to get context', [FID]);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
Context.ContextFlags := CONTEXT_CONTROL;
|
||||
Context.EFlags := Context.EFlags or $100;
|
||||
|
||||
if not SetThreadContext(FHandle, Context)
|
||||
then begin
|
||||
Log('Thread %u: Unable to set context', [FID]);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
FSingleStepping := True;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
(*
|
||||
{ TDbgSymbol }
|
||||
|
||||
constructor TDbgSymbol.Create(const AName: String; const ASection: TDbgSection; const AOffset: Integer);
|
||||
begin
|
||||
FName := AName;
|
||||
FSection := ASection;
|
||||
FOffset := AOffset;
|
||||
FLength := 0;
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
function TDbgSymbol.GetAddress: Pointer;
|
||||
begin
|
||||
Result := PChar(FSection.StartAddr) + FOffset - FSection.FOffset;
|
||||
end;
|
||||
*)
|
||||
|
||||
{ TDbgBreak }
|
||||
|
||||
constructor TDbgBreakpoint.Create(const AProcess: TDbgProcess; const ALocation: TDbgPtr);
|
||||
begin
|
||||
FProcess := AProcess;
|
||||
FLocation := ALocation;
|
||||
inherited Create;
|
||||
SetBreak;
|
||||
end;
|
||||
|
||||
destructor TDbgBreakpoint.Destroy;
|
||||
begin
|
||||
ResetBreak;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TDbgBreakpoint.Hit(const AThreadID: Integer): Boolean;
|
||||
var
|
||||
Thread: TDbgThread;
|
||||
Context: TContext;
|
||||
begin
|
||||
Result := False;
|
||||
if FOrgValue = $CC then Exit; // breakpoint on a hardcoded breakpoint
|
||||
// no need to jum back and restore instruction
|
||||
ResetBreak;
|
||||
|
||||
if not FProcess.GetThread(AThreadId, Thread) then Exit;
|
||||
|
||||
Context.ContextFlags := CONTEXT_CONTROL;
|
||||
if not GetThreadContext(Thread.Handle, Context)
|
||||
then begin
|
||||
Log('Break $s: Unable to get context', [FormatAdress(FLocation)]);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
Context.ContextFlags := CONTEXT_CONTROL;
|
||||
Dec(Context.Eip);
|
||||
|
||||
if not SetThreadContext(Thread.Handle, Context)
|
||||
then begin
|
||||
Log('Break %s: Unable to set context', [FormatAdress(FLocation)]);
|
||||
Exit;
|
||||
end;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
procedure TDbgBreakpoint.ResetBreak;
|
||||
begin
|
||||
if FOrgValue = $CC then Exit; // breakpoint on a hardcoded breakpoint
|
||||
|
||||
if not FProcess.WriteData(FLocation, 1, FOrgValue)
|
||||
then begin
|
||||
Log('Unable to reset breakpoint at $%p', [FLocation]);
|
||||
Exit;
|
||||
end;
|
||||
FlushInstructionCache(FProcess.FInfo.hProcess, Pointer(FLocation), 1);
|
||||
end;
|
||||
|
||||
procedure TDbgBreakpoint.SetBreak;
|
||||
const
|
||||
Int3: Byte = $CC;
|
||||
begin
|
||||
if not FProcess.ReadData(FLocation, 1, FOrgValue)
|
||||
then begin
|
||||
Log('Unable to read breakpoint at $%p', [FLocation]);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if FOrgValue = $CC then Exit; // breakpoint on a hardcoded breakpoint
|
||||
|
||||
if not FProcess.WriteData(FLocation, 1, Int3)
|
||||
then begin
|
||||
Log('Unable to set breakpoint at $%p', [FLocation]);
|
||||
Exit;
|
||||
end;
|
||||
FlushInstructionCache(FProcess.FInfo.hProcess, Pointer(FLocation), 1);
|
||||
end;
|
||||
|
||||
end.
|
104
debugger/windebug/windextra.pp
Normal file
104
debugger/windebug/windextra.pp
Normal file
@ -0,0 +1,104 @@
|
||||
{ $Id: $ }
|
||||
{
|
||||
---------------------------------------------------------------------------
|
||||
windextra.pp - Native windows debugger - Extra utilities
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
This unit contains utility functions and missing win32/64 API
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
@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 WindExtra;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Windows;
|
||||
|
||||
function FormatAdress(const P): String;
|
||||
function GetLastErrorText(AErrorCode: Cardinal): String; {$IFNDEF FPC} overload; {$ENDIF}
|
||||
function GetLastErrorText: String; {$IFNDEF FPC} overload; {$ENDIF}
|
||||
|
||||
|
||||
//function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall;
|
||||
//function Wow64GetThreadContext(hThread: THandle; var lpContext: TContext): BOOL; stdcall;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
SysUtils, FPWDGLobal;
|
||||
|
||||
//function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall; external 'kernel32';
|
||||
//function Wow64GetThreadContext(hThread: THandle; var lpContext: TContext): BOOL; stdcall; external 'kernel32';
|
||||
|
||||
|
||||
function FormatAdress(const P): String;
|
||||
begin
|
||||
case GMode of
|
||||
dm32: Result := '$' + IntToHex(DWord(p), 8);
|
||||
dm64: Result := '$' + IntToHex(int64(p), 16);
|
||||
else
|
||||
Result := 'Unknown mode';
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
function GetLastErrorText: String;
|
||||
begin
|
||||
Result := GetLastErrorText(GetLastError);
|
||||
end;
|
||||
|
||||
function GetLastErrorText(AErrorCode: Cardinal): String;
|
||||
var
|
||||
R: cardinal;
|
||||
Temp: PChar;
|
||||
begin
|
||||
Temp := nil;
|
||||
R := FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
nil,
|
||||
AErrorCode,
|
||||
LANG_NEUTRAL,
|
||||
@Temp,
|
||||
0,
|
||||
nil);
|
||||
if R = 0
|
||||
then begin
|
||||
Result := '';
|
||||
end
|
||||
else begin
|
||||
Result := Temp;
|
||||
SetLength(Result, Length(Result)-2);
|
||||
end;
|
||||
if Temp <> nil
|
||||
then LocalFree(HLOCAL(Temp));
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user