+ added dwarfloading to windebugger

git-svn-id: trunk@10056 -
This commit is contained in:
marc 2006-10-11 00:13:42 +00:00
parent 53cc3f202c
commit 13f2d243a5
8 changed files with 237 additions and 83 deletions

View File

@ -36,14 +36,14 @@ unit FPWDCommand;
interface
uses
SysUtils, Classes, Windows, WinDebugger, WinDExtra, LCLProc;
SysUtils, Classes, Windows, WinDExtra, LCLProc;
procedure HandleCommand(ACommand: String);
implementation
uses
FPWDGlobal, FPWDLoop, FPWDPEImage, FPWDType;
FPWDGlobal, FPWDLoop, FPWDPEImage;
type
TMWDCommandHandler = procedure(AParams: String);
@ -170,7 +170,7 @@ begin
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');
WriteLN('Create process failed: ', GetLastErrorText);
Exit;
end;

View File

@ -185,7 +185,6 @@ var
begin
WriteLN('Base adress: ', FormatAddress(AEvent.LoadDll.lpBaseOfDll));
if GetProcess(AEvent.dwProcessId, Proc)
and Proc.GetLib(AEvent.LoadDll.hFile, Lib)
then begin
@ -330,6 +329,35 @@ procedure DebugLoop;
{$endif}
WriteLN(' ', CodeBytes, ' ', Code);
end;
procedure ShowCode;
var
a: TDbgPtr;
sym, symproc: TDbgSymbol;
begin
WriteLN('===');
{$ifdef cpui386}
a := GCurrentContext^.EIP;
{$else}
a := GCurrentContext^.RIP;
{$endif}
sym := GCurrentProcess.FindSymbol(a);
if sym = nil
then begin
WriteLn(' [', FormatAddress(a), '] ???');
Exit;
end;
symproc := sym;
while not (symproc.kind in [skProcedure, skFunction]) do
symproc := symproc.Parent;
if symproc = nil
then WriteLn('???')
else WriteLn(symproc.FileName, ':', symproc.Line, ' ', symproc.Name);
WriteLn(' [', FormatAddress(a), '] ', sym.FileName, ':', sym.Line, ' ', sym.Name);
end;
begin
repeat
@ -415,7 +443,10 @@ begin
until (GState in [dsStop, dsPause, dsQuit]);
if GState = dsPause
then ShowDisas
then begin
ShowDisas;
ShowCode;
end;
end;
end.

View File

@ -74,7 +74,7 @@ var
R: Boolean;
n: Integer;
Is64: Boolean;
SectionName: array[0..IMAGE_SIZEOF_SHORT_NAME] of Char;
SectionName: array[0..255] of Char;
begin
if not ReadProcessMemory(AProcessHandle, Pointer(AAdress), @DosHeader, SizeOf(DosHeader), BytesRead)
then begin
@ -260,9 +260,28 @@ begin
end;
with SectionHeader do
begin
Move(Name, SectionName, IMAGE_SIZEOF_SHORT_NAME);
SectionName[IMAGE_SIZEOF_SHORT_NAME] := #0;
WriteLN(' Name: ',SectionName);
Write(' Name: ');
if (Name[0] = Ord('/')) and (Name[1] in [Ord('0')..Ord('9')])
then begin
// long name
if ReadProcessMemory(
AProcessHandle,
Pointer(PtrUInt(AAdress + NTHeaders.FileHeader.PointerToSymbolTable + NTHeaders.FileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL + StrToIntDef(PChar(@Name[1]), 0))),
@SectionName,
SizeOf(SectionName),
BytesRead
)
then WriteLn(SectionName)
else WriteLn('Unable to retrieve sectionname @', PChar(@Name[1]));
end
else begin
// short name
Move(Name, SectionName, IMAGE_SIZEOF_SHORT_NAME);
SectionName[IMAGE_SIZEOF_SHORT_NAME] := #0; // make it #0 terminated
WriteLn(SectionName);
end;
WriteLN(' Misc.PhysicalAddress: ',FormatAddress(Misc.PhysicalAddress));
WriteLN(' Misc.VirtualSize: ',Misc.VirtualSize);
WriteLN(' VirtualAddress: ',FormatAddress(VirtualAddress));

View File

@ -39,7 +39,7 @@ unit WinDDwarf;
interface
uses
Classes, Types, SysUtils, WinDDwarfConst, Maps, Math, WinDLoader;
Classes, Types, SysUtils, WinDebugger, WinDDwarfConst, Maps, Math, WinDLoader;
type
// compilation unit header
@ -136,6 +136,7 @@ type
private
FOwner: TDbgDwarf;
FVerbose: Boolean;
FValid: Boolean; // set if the compilationunit has compile unit tag.
// --- Header ---
FLength: QWord; // length of info
@ -183,6 +184,7 @@ type
destructor Destroy; override;
function GetDefinition(AAbbrev: Cardinal; out ADefinition: TDwarfAbbrev): Boolean;
property FileName: String read FFileName;
property Valid: Boolean read FValid;
end;
{ TDwarfVerboseCompilationUnit }
@ -223,8 +225,15 @@ type
type
TImageSection = (dsAbbrev, dsARanges, dsFrame, dsInfo, dsLine, dsLoc, dsMacinfo, dsPubNames, dsPubTypes, dsRanges, dsStr);
TDwarfSection = dsAbbrev..dsStr;
TDwarfSection = (dsAbbrev, dsARanges, dsFrame, dsInfo, dsLine, dsLoc, dsMacinfo, dsPubNames, dsPubTypes, dsRanges, dsStr);
TDwarfSectionInfo = record
Section: TDwarfSection;
VirtualAdress: QWord;
Size: QWord; // the virtual size
RawData: Pointer;
end;
PDwarfSectionInfo = ^TDwarfSectionInfo;
const
DWARF_SECTION_NAME: array[TDwarfSection] of String = (
@ -233,17 +242,10 @@ const
'.debug_pubtypes', '.debug_ranges', '.debug_str'
);
type
TDwarfSectionInfo = record
Section: TDwarfSection;
VirtualAdress: QWord;
Size: QWord; // the virtual size
RawData: Pointer;
end;
{ TDbgDwarf }
TDbgDwarf = class
type
TDbgDwarf = class(TDbgInfo)
private
FCompilationUnits: TList;
FImageBase: QWord;
@ -252,11 +254,11 @@ type
protected
function GetCompilationUnitClass: TDwarfCompilationUnitClass; virtual;
public
constructor Create(ALoader: TDbgImageLoader);
constructor Create(ALoader: TDbgImageLoader); override;
destructor Destroy; override;
function LoadCompilationUnits: Integer;
function PointerFromRVA(ARVA: QWord): Pointer;
function PointerFromVA(ASection: TImageSection; AVA: QWord): Pointer;
function PointerFromVA(ASection: TDwarfSection; AVA: QWord): Pointer;
property CompilationUnits[AIndex: Integer]: TDwarfCompilationUnit read GetCompilationUnit;
end;
@ -627,7 +629,7 @@ var
Section: TDwarfSection;
p: PDbgImageSection;
begin
inherited Create;
inherited Create(ALoader);
FCompilationUnits := TList.Create;
FImageBase := ALoader.ImageBase;
for Section := Low(Section) to High(Section) do
@ -683,7 +685,7 @@ begin
CU64^.AbbrevOffset,
CU64^.AddressSize,
True);
p := @CU64^.Version + CU64^.Length;
p := Pointer(@CU64^.Version) + CU64^.Length;
end
else begin
if CU32^.Length = 0 then Break;
@ -695,9 +697,10 @@ begin
CU32^.AbbrevOffset,
CU32^.AddressSize,
False);
p := @CU32^.Version + CU32^.Length;
p := Pointer(@CU32^.Version) + CU32^.Length;
end;
FCompilationUnits.Add(CU);
if CU.Valid then SetHasInfo;
end;
Result := FCompilationUnits.Count;
end;
@ -707,7 +710,7 @@ begin
Result := Pointer(PtrUInt(FImageBase + ARVA));
end;
function TDbgDwarf.PointerFromVA(ASection: TImageSection; AVA: QWord): Pointer;
function TDbgDwarf.PointerFromVA(ASection: TDwarfSection; AVA: QWord): Pointer;
begin
Result := FSections[ASection].RawData + AVA - FImageBase - FSections[ASection].VirtualAdress;
end;
@ -731,29 +734,32 @@ var
begin
if AScope = nil then Exit;
if not LocateEntry(DW_TAG_subprogram, AScope, True, Scope, AttribList)
then Exit;
Info.Scope := Scope;
if LocateAttribute(Scope^.Entry, DW_AT_low_pc, AttribList, Attrib, Form)
if LocateEntry(DW_TAG_subprogram, AScope, True, Scope, AttribList)
then begin
ReadValue(Attrib, Form, Info.StartPC);
if LocateAttribute(Scope^.Entry, DW_AT_name, AttribList, Attrib, Form)
then ReadValue(Attrib, Form, Info.Name)
else Info.Name := 'undefined';
if LocateAttribute(Scope^.Entry, DW_AT_high_pc, AttribList, Attrib, Form)
then ReadValue(Attrib, Form, Info.EndPC)
else Info.EndPC := Info.StartPC;
Info.LineInfo := nil; // filled in when the first time needed
if Info.StartPC <> 0
Info.Scope := Scope;
if LocateAttribute(Scope^.Entry, DW_AT_low_pc, AttribList, Attrib, Form)
then begin
if FAddressMap.HasId(Info.StartPC)
then WriteLN('WARNING duplicate start adress: ', IntToHex(Info.StartPC, FAddressSize * 2))
else FAddressMap.Add(Info.StartPC, Info);
ReadValue(Attrib, Form, Info.StartPC);
if LocateAttribute(Scope^.Entry, DW_AT_name, AttribList, Attrib, Form)
then ReadValue(Attrib, Form, Info.Name)
else Info.Name := 'undefined';
if LocateAttribute(Scope^.Entry, DW_AT_high_pc, AttribList, Attrib, Form)
then ReadValue(Attrib, Form, Info.EndPC)
else Info.EndPC := Info.StartPC;
Info.LineInfo := nil; // filled in when the first time needed
if Info.StartPC <> 0
then begin
if FAddressMap.HasId(Info.StartPC)
then WriteLN('WARNING duplicate start adress: ', IntToHex(Info.StartPC, FAddressSize * 2))
else FAddressMap.Add(Info.StartPC, Info);
end;
end;
end
else begin
Scope := AScope;
end;
BuildAddessMap(Scope^.Child);
@ -765,7 +771,7 @@ var
AttribList: TPointerDynArray;
Attrib: Pointer;
Form: Cardinal;
StatementList: QWord;
StatementList, Ofs: QWord;
Scope: PDwarfScopeInfo;
begin
inherited Create;
@ -774,6 +780,17 @@ begin
FLength := ALength;
FVersion := AVersion;
FAbbrevOffset := AAbbrevOffset;
// check for address as offset
if FAbbrevOffset > FOwner.FSections[dsAbbrev].Size
then begin
Ofs := FAbbrevOffset - FOwner.FImageBase - FOwner.FSections[dsAbbrev].VirtualAdress;
if (Ofs >= 0) and (Ofs < FOwner.FSections[dsAbbrev].Size)
then begin
WriteLN('WARNING: Got Abbrev ofset as address, adjusting..');
FAbbrevOffset := Ofs;
end;
end;
FAddressSize := AAddressSize;
FIsDwarf64 := AIsDwarf64;
@ -793,6 +810,7 @@ begin
WriteLN('WARNING compilation unit has no compile_unit tag');
Exit;
end;
FValid := True;
if LocateAttribute(Scope^.Entry, DW_AT_name, AttribList, Attrib, Form)
then ReadValue(Attrib, Form, FFileName);
@ -830,6 +848,7 @@ destructor TDwarfCompilationUnit.Destroy;
if Scope^.Next = nil
then begin
Scope := Scope^.Parent;
if Scope = nil then Break;
Scope^.Child := nil;
end
else Scope := Scope^.Next;
@ -2044,14 +2063,14 @@ begin
if LNP64^.Signature = DWARF_HEADER64_SIGNATURE
then begin
UnitLength := LNP64^.UnitLength;
DataEnd := @LNP64^.Version + UnitLength;
DataEnd := Pointer(@LNP64^.Version) + UnitLength;
Version := LNP64^.Version;
HeaderLength := LNP64^.HeaderLength;
Info := @LNP64^.Info;
end
else begin
UnitLength := LNP32^.UnitLength;
DataEnd := @LNP32^.Version + UnitLength;
DataEnd := Pointer(@LNP32^.Version) + UnitLength;
Version := LNP32^.Version;
HeaderLength := LNP32^.HeaderLength;
Info := @LNP32^.Info;

View File

@ -36,7 +36,7 @@ unit WinDebugger;
interface
uses
Windows, Classes, Maps, WindExtra;
Windows, Classes, Maps, WinDExtra, WinDLoader;
type
TDbgProcess = class;
@ -136,6 +136,20 @@ type
property Children[AIndex: Integer]: TDbgSymbol read GetChild;
end;
TDbgInfo = class(TObject)
private
FHasInfo: Boolean;
protected
procedure SetHasInfo;
public
constructor Create(ALoader: TDbgImageLoader); virtual;
function FindSymbol(const AName: String): TDbgSymbol; virtual;
function FindSymbol(AAdress: TDbgPtr): TDbgSymbol; virtual;
property HasInfo: Boolean read FHasInfo;
end;
TDbgBreakpoint = class;
TDbgBreakpointEvent = procedure(const ASender: TDbgBreakpoint; const AContext: TContext) of object;
TDbgBreakpoint = class(TObject)
@ -162,8 +176,10 @@ type
FModuleHandle: THandle;
FBaseAddr: TDbgPtr;
FBreakList: TList;
FSymbols: TDbgSymbol;
procedure BuildSymbols;
FDbgInfo: TDbgInfo;
FLoader: TDbgImageLoader;
procedure LoadInfo;
procedure CheckName;
procedure SetName(const AValue: String);
public
@ -181,6 +197,8 @@ type
property Name: String read FName;
end;
{ TDbgProcess }
TDbgProcess = class(TDbgInstance)
private
FProcessID: Integer;
@ -190,6 +208,8 @@ type
FThreadMap: TMap; // map ThreadID -> ThreadObject
FLibMap: TMap; // map LibAddr -> LibObject
FBreakMap: TMap; // map BreakAddr -> BreakObject
FSymInstances: TList; // list of dbgInstances with debug info
FMainThread: TDbgThread;
@ -207,6 +227,8 @@ type
function AddBreak(const ALocation: TDbgPtr): TDbgBreakpoint;
function AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary;
procedure AddThread(const AID: Integer; const AInfo: TCreateThreadDebugInfo);
function FindSymbol(const AName: String): TDbgSymbol;
function FindSymbol(AAdress: TDbgPtr): TDbgSymbol;
function GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean;
function GetThread(const AID: Integer; out AThread: TDbgThread): Boolean;
procedure Interrupt;
@ -232,7 +254,7 @@ type
implementation
uses
SysUtils, WinDSymbols;
SysUtils, WinDSymbols, WinDDwarf;
procedure LogLastError;
begin
@ -241,16 +263,10 @@ end;
{ TDbgInstance }
procedure TDbgInstance.BuildSymbols;
begin
FSymbols := TDbgSymbol.Create(FName, skInstance, FBaseAddr);
AddSymbols(FSymbols, FModuleHandle);
end;
procedure TDbgInstance.CheckName;
begin
if FName = ''
then FName := Format('@%p', [FBaseAddr]);
then FName := Format('@%p', [Pointer(PtrUInt(FBaseAddr))]);
end;
constructor TDbgInstance.Create(const AProcess: TDbgProcess; const ADefaultName: String; const AModuleHandle: THandle; const ABaseAddr, ANameAddr: TDbgPtr; const AUnicode: Boolean);
@ -297,7 +313,8 @@ begin
then W := ADefaultName;
SetName(W);
BuildSymbols;
LoadInfo;
end;
destructor TDbgInstance.Destroy;
@ -311,10 +328,18 @@ begin
FBreakList.Clear;
FreeAndNil(FBreakList);
FreeAndNil(FSymbols);
FreeAndNil(FDbgInfo);
FreeAndNil(FLoader);
inherited;
end;
procedure TDbgInstance.LoadInfo;
begin
FLoader := TDbgWinPEImageLoader.Create(FModuleHandle);
FDbgInfo := TDbgDwarf.Create(FLoader);
TDbgDwarf(FDbgInfo).LoadCompilationUnits;
end;
procedure TDbgInstance.SetName(const AValue: String);
begin
FName := AValue;
@ -340,6 +365,8 @@ function TDbgProcess.AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary;
begin
Result := TDbgLibrary.Create(Self, HexValue(AInfo.lpBaseOfDll, SizeOf(Pointer), [hvfIncludeHexchar]), AInfo);
FLibMap.Add(TDbgPtr(AInfo.lpBaseOfDll), Result);
if Result.FDbgInfo.HasInfo
then FSymInstances.Add(Result);
end;
procedure TDbgProcess.AddThread(const AID: Integer; const AInfo: TCreateThreadDebugInfo);
@ -383,10 +410,15 @@ begin
FBreakMap := TMap.Create(MAP_ID_SIZE, SizeOf(TDbgBreakpoint));
FSingleStepBreak := nil;
FSymInstances := TList.Create;
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);
FMainThread := TDbgThread.Create(Self, AThreadID, AInfo.hThread, AInfo.lpThreadLocalBase, AInfo.lpStartAddress);
FThreadMap.Add(AThreadID, FMainThread);
if FDbgInfo.HasInfo
then FSymInstances.Add(Self);
end;
destructor TDbgProcess.Destroy;
@ -396,9 +428,29 @@ begin
FreeAndNil(FBreakMap);
FreeAndNil(FThreadMap);
FreeAndNil(FLibMap);
FreeAndNil(FSymInstances);
inherited;
end;
function TDbgProcess.FindSymbol(const AName: String): TDbgSymbol;
begin
Result := FDbgInfo.FindSymbol(AName);
end;
function TDbgProcess.FindSymbol(AAdress: TDbgPtr): TDbgSymbol;
var
n: Integer;
Inst: TDbgInstance;
begin
for n := 0 to FSymInstances.Count - 1 do
begin
Inst := TDbgInstance(FSymInstances[n]);
Result := Inst.FDbgInfo.FindSymbol(AAdress);
if Result <> nil then Exit;
end;
Result := nil;
end;
function TDbgProcess.GetLib(const AHandle: THandle; out ALib: TDbgLibrary): Boolean;
var
Iterator: TMapIterator;
@ -602,9 +654,15 @@ begin
end;
procedure TDbgProcess.RemoveLib(const AInfo: TUnloadDLLDebugInfo);
var
Lib: TDbgLibrary;
begin
if FLibMap = nil then Exit;
if not FLibMap.GetData(TDbgPtr(AInfo.lpBaseOfDll), Lib) then Exit;
if Lib.FDbgInfo.HasInfo
then FSymInstances.Remove(Lib);
FLibMap.Delete(TDbgPtr(AInfo.lpBaseOfDll));
// TODO: Free lib ???
end;
procedure TDbgProcess.RemoveThread(const AID: DWord);
@ -681,6 +739,29 @@ begin
end;
{ TDbgInfo }
constructor TDbgInfo.Create(ALoader: TDbgImageLoader);
begin
inherited Create;
end;
function TDbgInfo.FindSymbol(const AName: String): TDbgSymbol;
begin
Result := nil;
end;
function TDbgInfo.FindSymbol(AAdress: TDbgPtr): TDbgSymbol;
begin
Result := nil;
end;
procedure TDbgInfo.SetHasInfo;
begin
FHasInfo := True;
end;
{ TDbgSymbol }
function TDbgSymbol.GetChild(AIndex: Integer): TDbgSymbol;

View File

@ -127,7 +127,7 @@ begin
nil,
AErrorCode,
LANG_NEUTRAL,
@Temp,
Pointer(@Temp), // the fuction needs either a PChar or a PPChar, depending on FORMAT_MESSAGE_ALLOCATE_BUFFER
0,
nil);
if R = 0

View File

@ -56,7 +56,6 @@ type
TDbgImageLoader = class(TObject)
private
FFileName: String;
FImage64Bit: Boolean;
FImageBase: QWord;
FSections: TStringList;
@ -68,9 +67,8 @@ type
procedure LoadSections; virtual; abstract;
procedure UnloadSections; virtual; abstract;
public
constructor Create(const AFileName: String); virtual;
constructor Create;
destructor Destroy; override;
property FileName: String read FFileName;
property ImageBase: QWord read FImageBase;
Property Image64Bit: Boolean read FImage64Bit;
property Section[const AName: String]: PDbgImageSection read GetSection;
@ -97,10 +95,11 @@ type
FModulePtr: Pointer;
procedure DoCleanup;
protected
constructor Create(const AFileName: String); override;
function LoadData(out AModuleBase: Pointer; out AHeaders: PImageNtHeaders): Boolean; override;
procedure UnloadData; override;
public
constructor Create(const AFileName: String);
constructor Create(AFileHandle: THandle);
end;
implementation
@ -120,10 +119,9 @@ begin
FSections.Objects[idx] := TObject(p);
end;
constructor TDbgImageLoader.Create(const AFileName: String);
constructor TDbgImageLoader.Create;
begin
inherited Create;
FFileName := AFileName;
FSections := TStringList.Create;
FSections.Sorted := True;
FSections.Duplicates := dupError;
@ -192,7 +190,7 @@ begin
for n := 0 to NtHeaders^.FileHeader.NumberOfSections - 1 do
begin
SectionHeader := @NtHeaders^.OptionalHeader + NtHeaders^.FileHeader.SizeOfOptionalHeader + SizeOf(SectionHeader^) * n;
SectionHeader := Pointer(@NtHeaders^.OptionalHeader) + NtHeaders^.FileHeader.SizeOfOptionalHeader + SizeOf(SectionHeader^) * n;
// make a null terminated name
Move(SectionHeader^.Name, SectionName, IMAGE_SIZEOF_SHORT_NAME);
SectionName[IMAGE_SIZEOF_SHORT_NAME] := #0;
@ -218,10 +216,22 @@ end;
constructor TDbgWinPEImageLoader.Create(const AFileName: String);
begin
FFileHandle := INVALID_HANDLE_VALUE;
FMapHandle := 0;
FModulePtr := nil;
inherited Create(AFileName);
FFileHandle := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if FFileHandle = INVALID_HANDLE_VALUE
then begin
WriteLN('Cannot open file: ', AFileName);
end;
inherited Create;
end;
constructor TDbgWinPEImageLoader.Create(AFileHandle: THandle);
begin
FFileHandle := AFileHandle;
if FFileHandle = INVALID_HANDLE_VALUE
then begin
WriteLN('Invalid file handle');
end;
inherited Create;
end;
procedure TDbgWinPEImageLoader.DoCleanup;
@ -243,12 +253,6 @@ var
DosHeader: PImageDosHeader;
begin
Result := False;
FFileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if FFileHandle = INVALID_HANDLE_VALUE
then begin
WriteLN('Cannot open file: ', FileName);
Exit;
end;
try
FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY{ or SEC_IMAGE}, 0, 0, nil);

View File

@ -198,7 +198,7 @@ begin
Sections.Sorted := True;
for n := 0 to NtHeaders^.FileHeader.NumberOfSections - 1 do
begin
SectionHeader := @NTHeaders^.OptionalHeader + NTHeaders^.FileHeader.SizeOfOptionalHeader + SizeOf(SectionHeader^) * n;
SectionHeader := Pointer(@NTHeaders^.OptionalHeader) + NTHeaders^.FileHeader.SizeOfOptionalHeader + SizeOf(SectionHeader^) * n;
// make a null terminated name
Move(SectionHeader^.Name, SectionName, IMAGE_SIZEOF_SHORT_NAME);
SectionName[IMAGE_SIZEOF_SHORT_NAME] := #0;