cheat-engine/Cheat Engine/binutils.pas
2019-12-19 17:49:30 +01:00

1087 lines
27 KiB
ObjectPascal
Executable file

unit binutils;
//responsible for launching and retrieving data from the binutil tools
{$mode objfpc}{$H+}
{$warn 2005 off}
interface
uses
{$ifdef darwin}macport,{$endif}
{$ifdef windows}windows, {$endif}
newkernelhandler, forms, Classes, SysUtils, process, LastDisassembleData, strutils, maps;
type
TSection=record
name: string;
size: dword;
end;
TSectionArray=array of TSection;
TImportListEntry=record
name: string;
address: ptruint;
end;
TImportList=array of TImportListEntry;
TBinarySection=record
sectionname: string;
data: array of byte;
end;
TBinarySections=array of TBinarySection;
type
TBinUtils=class
private
disassemblercache: TMap;
fpath: string;
procedure setPath(path: string);
procedure cleanEntry(_entry: Pointer);
public
name: string;
description: string;
prefix: string;
lasterror: string;
arch: string;
OnDisassemble: integer; //lua function reference
ASParam: string;
LDParam: string;
OBJDUMPParam: string;
DisassemblerCommentChar: string;
constructor create;
destructor destroy; override;
procedure clearDisassemblerCache;
procedure clearLongRangeDisassemblerCache(address: ptruint);
function compile(script: tstringlist): boolean;
function compileproject(filelist: tstringlist): boolean;
procedure LinkObjectFiles(objectfiles: tstringlist; const imports: TImportList; targetfilename: string; targetaddress:ptruint=0);
procedure ObjectToBinary(objectfile: string; binfile: string);
procedure stripSection(objectfile: string; section: string);
function assemble(script: tstringlist; extraparams: string; out filename: string): boolean;
procedure nm(filename: string; defined: tstringlist; undefined: tstringlist; registersymbols: boolean=false);
procedure GetSections(filename: string; var sections: TSectionArray);
procedure ldAndExtract(objectfile, linkfilename, extraparams: string; imports: TImportList; var sections: TBinarySections);
procedure ldAndInject(objectfiles: tstringlist);
procedure disassemble(var ldd: TLastDisassembleData); //address and bytes are filled in
published
property path: string read fpath write setPath;
end;
var
binutilslist: TList;
defaultBinutils: TBinUtils; //used by the disassembler and single line assember if set (gui thing)
implementation
uses dialogs, lua, LuaHandler, ProcessHandlerUnit, symbolhandler;
type
TDisassemblerCacheEntry=record
bytes: pbyte;
bytesize: integer;
instruction: pchar;
parameter: pchar;
extra: pchar;
end;
PDisassemblerCacheEntry=^TDisassemblerCacheEntry;
constructor TBinUtils.create;
begin
disassemblercache:=TMap.Create(ituPtrSize,sizeof(TDisassemblerCacheEntry));
end;
destructor TBinUtils.destroy;
begin
clearDisassemblerCache;
disassemblercache.free;
inherited destroy;
end;
procedure TBinUtils.cleanEntry(_entry: pointer);
var entry: PDisassemblerCacheEntry;
begin
if _entry=nil then exit;
entry:=_entry;
if entry^.bytes<>nil then
begin
FreeMemAndNil(entry^.bytes);
end;
if entry^.instruction<>nil then
begin
strdispose(entry^.instruction);
entry^.instruction:=nil;
end;
if entry^.parameter<>nil then
begin
strdispose(entry^.parameter);
entry^.parameter:=nil;
end;
if entry^.extra<>nil then
begin
strdispose(entry^.extra);
entry^.extra:=nil;
end;
end;
procedure TBinUtils.clearLongRangeDisassemblerCache(address: ptruint);
var
it: TMapIterator;
entry: PDisassemblerCacheEntry;
id: ptruint;
mina: ptruint;
maxa: ptruint;
begin
//clear all entries that are 25000 bytes before after address (leaving about 50000 out of 100000 entries)
if address>25000 then
mina:=address-25000;
if mina>address then //overflow
mina:=0;
maxa:=address+25000;
if maxa<address then
maxa:={$ifdef cpu32}qword($ffffffff){$else}qword($ffffffffffffffff){$endif};
it:=TMapIterator.Create(disassemblercache);
try
it.first;
while not it.eom do
begin
entry:=it.DataPtr;
it.GetID(id);
if (id<mina) or (id>maxa) then
begin
cleanentry(entry);
disassemblercache.Delete(id);
end;
it.next;
end;
finally
it.free;
end;
end;
procedure TBinUtils.clearDisassemblerCache; //full clear
var it: TMapIterator;
entry: PDisassemblerCacheEntry;
begin
it:=TMapIterator.Create(disassemblercache);
try
it.First;
while not it.EOM do
begin
entry:=it.DataPtr;
cleanEntry(entry);
it.Next;
end;
finally
it.free;
end;
disassemblercache.Clear;
end;
procedure TBinUtils.setPath(path: string);
begin
fpath:=path;
if length(fpath)>0 then
begin
if fpath[length(fpath)]<>DirectorySeparator then
fpath:=fpath+DirectorySeparator;
end;
end;
procedure TBinUtils.disassemble(var ldd: TLastDisassembleData);
var entry: TDisassemblerCacheEntry;
p: TProcess;
i,j: integer;
output: TStringStream;
r: tstringlist;
t: integer;
s: string;
buffer: pbyte;
br: ptruint;
f: string;
fs: tfilestream;
line1, line2: string;
a1, a2: string;
address1, address2: int64;
instr: string;
param: string;
comment: string;
found: boolean;
luavm: PLua_state;
os: string;
params: array of string;
begin
//check if this address is in the disassembled cache, and if so, add it
luavm:=GetLuaState;
getmem(buffer, 512);
try
FillByte(buffer^, 512,0);
br:=0;
ReadProcessMemory(processhandle, pointer(ldd.address), buffer, 512, br);
if br=0 then
begin
ldd.opcode:='??';
ldd.parameters:='';
setlength(ldd.bytes,0);
exit;
end;
if disassemblercache.GetData(ldd.address, entry) then
begin
//return this data
if (entry.bytesize<512) and CompareMem(buffer, entry.bytes, entry.bytesize) then
begin
//no change in bytes, so accept it
ldd.opcode:=entry.instruction;
setlength(ldd.Bytes, entry.bytesize);
for i:=0 to entry.bytesize-1 do
ldd.bytes[i]:=entry.bytes[i];
ldd.parameters:=entry.parameter;
exit;
end;
end;
if disassemblercache.Count>100000 then
clearLongRangeDisassemblerCache(ldd.address);
//still here, disassemble this address and a couple of instructions after it as well
f:=GetTempFileName;
fs:=tfilestream.Create(f, fmCreate);
fs.WriteBuffer(buffer[0], 512);
fs.Free;
p:=TProcess.Create(Application);
output:=nil;
try
p.CurrentDirectory:=fpath;
p.executable:='"'+fpath+prefix+'objdump'+'"';
p.Options:=[poUsePipes, poNoConsole];
p.parameters.add(OBJDUMPParam);
p.parameters.add('--adjust-vma=0x'+inttohex(ldd.address,8));
p.parameters.Add('--stop-address=0x'+inttohex(ldd.address+512,8));
p.Parameters.add('--prefix-addresses');
p.Parameters.add('-z');
p.Parameters.add('-bbinary');
p.Parameters.add('-D');
p.Parameters.add('-m'+arch);
p.parameters.add('"'+f+'"');
//lua
if OnDisassemble<>0 then
begin
//LuaCS.enter;
t:=lua_gettop(luavm);
try
lua_rawgeti(luavm, LUA_REGISTRYINDEX, OnDisassemble);
lua_pushinteger(Luavm, ldd.address);
if lua_pcall(luavm, 1, 1, 0)=0 then
begin
s:=Lua_ToString(Luavm, -1);
for i:=1 to WordCount(s, [' ']) do
p.parameters.Add(ExtractWord(i,s,[' ']));
end;
finally
lua_settop(luavm, t);
end;
end;
{ try
p.Execute;
except
on e: exception do
begin
OutputDebugString(e.message);
raise;
end;
end; }
setlength(params, p.parameters.Count);
for i:=0 to p.parameters.count-1 do
params[i]:=p.Parameters[i];
if RunCommand(p.Executable, params, os,[poNoConsole]) then
begin
output:=TStringStream.create('');
output.WriteString(os);
end
else
begin
//failure to run
ldd.opcode:='Invalid';
ldd.parameters:='binutils';
setlength(ldd.bytes,0);
exit;
end;
{
output:=TStringStream.create('');
repeat
if p.Output.NumBytesAvailable>0 then
output.CopyFrom(p.Output, p.Output.NumBytesAvailable)
else
sleep(1);
until not p.Running;
p.WaitOnExit; //just to be sure
if p.Output.NumBytesAvailable>0 then
output.CopyFrom(p.Output, p.Output.NumBytesAvailable); }
{if p.ExitCode<>0 then
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;}
//parse the output
r:=tstringlist.create;
try
output.position:=0;
r.loadfromstream(output);
found:=false;
for i:=0 to r.count-2 do
begin
line1:=r[i];
line2:=r[i+1];
if (copy(line1, 1,2)='0x') and (copy(line1, 1,2)='0x') then
begin
a1:=ExtractWord(1, line1, [' ',#8,#9]);
a2:=ExtractWord(1, line2, [' ',#8,#9]);
if TryStrToInt64(a1,address1) and TryStrToInt64(a2,address2) then
begin
instr:=ExtractWord(2, line1, [' ',#8,#9]);
param:='';
comment:='';
j:=WordPosition(3, line1, [' ',#8,#9]);
if j>0 then
param:=copy(line1, j, length(line1));
if DisassemblerCommentChar<>'' then
begin
j:=pos(DisassemblerCommentChar, param);
if j>0 then
begin
comment:=copy(param, j, length(param));
param:=copy(param,1, j-1);
end;
end;
//valid
if disassemblercache.GetData(address1, entry) then
begin
cleanEntry(@entry);
disassemblercache.Delete(address1);
end;
FillByte(entry,sizeof(entry),0);
entry.bytesize:=address2-address1;
if (entry.bytesize>64) or (entry.bytesize<=0) then
break;
getmem(entry.bytes, entry.bytesize);
if entry.bytes=nil then
break;
for j:=0 to entry.bytesize-1 do
entry.bytes[j]:=buffer[address1-ldd.address+j];
entry.instruction:=strnew(pchar(instr));
entry.parameter:=strnew(pchar(param));
entry.extra:=strnew(pchar(comment));
disassemblercache.Add(address1, entry);
if not found then
begin
//fill it in
ldd.opcode:=instr;
setlength(ldd.Bytes, entry.bytesize);
for j:=0 to entry.bytesize-1 do
ldd.bytes[j]:=$90; //entry.bytes[j];
ldd.parameters:=param;
found:=true;
end;
end;
end;
end; //for
if not found then
begin
ldd.opcode:='??';
ldd.parameters:='';
setlength(ldd.bytes,0);
end;
finally
r.free;
end;
finally
deletefile(f);
if output<>nil then
output.free;
p.free;
end;
finally
if buffer<>nil then
FreeMemAndNil(buffer);
end;
end;
procedure TbinUtils.ObjectToBinary(objectfile: string; binfile: string);
var objcopyprocess: tprocess;
begin
objcopyprocess:=TProcess.create(nil);
objcopyprocess.CurrentDirectory:=fpath;
objcopyprocess.executable:='"'+fpath+prefix+'objcopy'+'"';
objcopyprocess.Options:=[poUsePipes, poNoConsole];
objcopyprocess.Parameters.Add('-Obinary');
objcopyprocess.Parameters.Add(objectfile);
objcopyprocess.Parameters.Add(binfile);
objcopyprocess.Execute;
if objcopyprocess.WaitOnExit then
begin
if objcopyprocess.ExitCode<>0 then
begin
setlength(lasterror, objcopyprocess.Stderr.NumBytesAvailable+1);
objcopyprocess.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create('ObjectToBinary: objcopy:'+lasterror);
end;
end
else
raise exception.create('ObjectToBinary: Wait error on objcopy');
end;
procedure TBinUtils.LinkObjectFiles(objectfiles: tstringlist; const imports: TImportList; targetfilename: string; targetaddress:ptruint=0);
var
p: tprocess;
i: integer;
begin
if targetaddress=$00400000 then targetaddress:=$00400010; //does not work with 0x00400000
p:=TProcess.create(nil);
p.CurrentDirectory:=fpath;
p.executable:='"'+fpath+prefix+'ld'+'"';
p.Options:=[poUsePipes, poNoConsole];
p.Parameters.Add('-static');
p.parameters.add(LDParam); //-mi386pe for 32-bit
p.Parameters.Add('-T NUL');
if targetaddress<>0 then
p.parameters.add('-Ttext 0x'+inttohex(targetaddress,1));
for i:=0 to objectfiles.count-1 do
p.Parameters.Add(objectfiles[i]);
for i:=0 to length(imports)-1 do
p.Parameters.Add('--defsym='+imports[i].name+'=0x'+inttohex(imports[i].address,8));
p.Parameters.Add('-o "'+targetfilename+'"');
p.Execute;
if p.WaitOnExit then
begin
if p.ExitCode<>0 then
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;
end;
end;
procedure TBinUtils.ldAndInject(objectfiles: tstringlist);
var
p: tprocess;
m: tmemorystream;
z: tfilestream;
size,size2: integer;
i,j: integer;
tempfile: string='';
imports: TImportList;
defined, undefined: tstringlist;
found: boolean;
mem: pointer=nil;
x: ptruint;
begin
//first get all the imports
defined:=tstringlist.create;
undefined:=tstringlist.create;
try
for i:=0 to objectfiles.count-1 do
nm(objectfiles[i], defined, undefined);
//go through the undefined list and fill them in (where possible)
setlength(imports,0);
for i:=0 to undefined.count-1 do
begin
found:=false;
for j:=0 to length(imports)-1 do
begin
if imports[j].name=undefined[i] then
begin
found:=true;
break;
end;
end;
if not found then
begin
j:=length(imports);
setlength(imports, j+1);
imports[j].name:=undefined[i];
imports[j].address:=symhandler.getAddressFromName(undefined[i]); //error out if not found
end;
end;
finally
defined.free;
undefined.free;
end;
//still here so the undefinedlist has been handled
tempfile:=GetTempFileName;
LinkObjectFiles(objectfiles, imports, tempfile );
ObjectToBinary(tempfile, tempfile+'.bin');
z:=tfilestream.create(tempfile+'.bin', fmOpenRead);
size:=z.Size+4096;
z.free;
if size=0 then raise exception.create('Failure getting filesize');
//still here so linking was succesful
repeat
size2:=size;
if mem<>nil then VirtualFreeEx(processhandle, mem, 0,MEM_RELEASE);
mem:=VirtualAllocEx(processhandle, nil,size,mem_reserve or mem_commit, PAGE_EXECUTE_READWRITE);
if mem=nil then raise exception.create('Failure allocating memory');
LinkObjectFiles(objectfiles, imports, tempfile, ptruint(mem) );
ObjectToBinary(tempfile, tempfile+'.bin');
z:=tfilestream.create(tempfile+'.bin' ,fmOpenRead);
size:=z.Size+4096;
z.free;
until size<=size2; //repeat linking until the proper size is found (at most 2)
m:=tmemorystream.create;
m.loadfromfile(tempfile+'.bin');
WriteProcessMemory(processhandle, mem, m.memory, m.size,x);
m.free;
defined.clear;
undefined.clear;
nm(tempfile, defined, undefined, true);
end;
procedure TBinUtils.ldAndExtract(objectfile, linkfilename, extraparams: string; imports: TImportList; var sections: TBinarySections); //for gnu assembler
var
p: TProcess;
i: integer;
linkedfilename: string;
bindata: TMemoryStream;
begin
p:=TProcess.create(nil);
try
p.CurrentDirectory:=fpath;
p.executable:='"'+fpath+prefix+'ld'+'"';
p.Options:=[poUsePipes, poNoConsole];
p.Parameters.add(extraparams);
p.parameters.add(LDParam);
p.Parameters.Add('-T "'+linkfilename+'"');
p.Parameters.Add('"'+objectfile+'"');
for i:=0 to length(imports)-1 do
p.Parameters.Add('--defsym='+imports[i].name+'=0x'+inttohex(imports[i].address,8));
linkedfilename:=GetTempFileName;
p.parameters.add('-o "'+linkedfilename+'"');
p.Execute;
p.WaitOnExit;
if p.ExitCode<>0 then
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;
finally
p.free;
end;
for i:=0 to length(sections)-1 do
begin
p:=TProcess.Create(nil);
try
p.CurrentDirectory:=fpath;
p.executable:='"'+fpath+prefix+'objcopy'+'"';
p.Options:=[poUsePipes, poNoConsole];
p.Parameters.Add('-Obinary');
p.Parameters.Add('-j'+sections[i].sectionname);
p.Parameters.Add(linkedfilename);
p.Parameters.Add(linkedfilename+'.bin');
// showmessage(p.Parameters.Text);
p.Execute;
p.WaitOnExit;
if p.ExitCode<>0 then
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;
bindata:=TMemoryStream.create;
try
bindata.LoadFromFile(linkedfilename+'.bin');
setlength(sections[i].data, bindata.Size);
bindata.Position:=0;
bindata.ReadBuffer(sections[i].data[0], bindata.Size);
finally
bindata.free;
end;
finally
p.free;
end;
end;
end;
procedure TBinUtils.GetSections(filename: string; var sections: TSectionArray);
var
output: TStringStream;
p: TProcess;
ec: integer;
i,j: integer;
r: TStringList;
idx, _name, size: string;
s: string;
begin
p:=TProcess.Create(nil);
output:=nil;
r:=nil;
try
p.CurrentDirectory:=fpath;
p.Executable:='"'+fpath+prefix+'objdump'+'"';
p.Options:=[poUsePipes, poNoConsole];
p.Parameters.Add('-h');
p.Parameters.Add('"'+filename+'"');
p.Execute;
output:=TStringStream.create('');
repeat
if p.Output.NumBytesAvailable>0 then
output.CopyFrom(p.Output, p.Output.NumBytesAvailable)
else
sleep(1);
until not p.Running;
p.WaitOnExit; //just to be sure
if p.Output.NumBytesAvailable>0 then
output.CopyFrom(p.Output, p.Output.NumBytesAvailable);
if p.ExitCode<>0 then
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;
r:=TStringList.create;
output.position:=0;
r.LoadFromStream(output);
//search for lines with: integer, string, hexvalue
for i:=0 to r.Count-1 do
begin
s:=trim(r[i]);
if WordCount(r[i],[' ',#8])>3 then
begin
idx:=ExtractWord(1, s,[' ',#8]);
if TryStrToInt(idx, j) then
begin
_name:=ExtractWord(2, s,[' ',#8]);
size:=ExtractWord(3, s,[' ',#8]);
if TryStrToInt('0x'+size, j) then
begin
if (j>0) then
begin
setlength(sections, length(sections)+1);
sections[length(sections)-1].name:=_name;
sections[length(sections)-1].size:=j;
end;
end;
end;
end;
end;
finally
if r<>nil then
r.free;
if output<>nil then
output.free;
if p<>nil then
p.free;
end;
end;
procedure TBinUtils.nm(filename: string; defined: tstringlist; undefined: tstringlist; registersymbols: boolean=false);
{
Executes nm and keeps a list of all defined and undefined symbols
The call can be done with a defined and undefined list already filled in. In that case, just update
}
var
p: TProcess;
ec: integer;
output: TStringStream;
s: tstringlist;
i,j: integer;
line: string;
str: string;
a: ptruint;
e: integer;
begin
output:=TStringStream.Create('');
p:=TProcess.Create(nil);
try
p.CurrentDirectory:=fpath;
p.Executable:='"'+fpath+prefix+'nm'+'"';
p.Options:=[poUsePipes, poNoConsole];
p.Parameters.Add('"'+filename+'"');
p.Execute;
repeat
if p.Output.NumBytesAvailable>0 then
output.CopyFrom(p.Output, p.Output.NumBytesAvailable)
else
sleep(1);
until not p.Running;
p.WaitOnExit; //just to be sure
if p.Output.NumBytesAvailable>0 then
output.CopyFrom(p.Output, p.Output.NumBytesAvailable);
ec:=p.ExitCode;
if ec=0 then
begin
s:=tstringlist.create;
output.Position:=0;
s.LoadFromStream(output);
for i:=0 to s.Count-1 do
begin
line:=trim(s[i]);
if (length(line)>2) then
begin
if (line[1]='U') then
begin
str:=copy(line, 3, length(line));
if (defined.IndexOf(str)<>-1) or (undefined.IndexOf(str)<>-1) then continue; //it's already defined somewhere else or already in the undefined list
undefined.add(str); //add it to the undefined list
end
else
begin
str:=copy(line, RPos(' ',line)+1, length(line));
j:=undefined.IndexOf(str); //check if it was undefined previously
if j<>-1 then undefined.Delete(j); //yes, found it
defined.add(str);
{
if registersymbols then
begin
j:=pos(' ',line);
if j>0 then
begin
str:=copy(line,1,j-1);
a:=StrToInt64('$'+str);
end;
end; }
end;
end;
end;
s.free;
end
else
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;
finally
p.free;
output.free;
end;
end;
procedure TBinUtils.stripSection(objectfile: string; section: string);
var
p: TProcess;
begin
p:=tprocess.create(nil);
p.CurrentDirectory:=fpath;
p.Executable:='"'+fpath+prefix+'objcopy'+'"';
p.Options:=[poUsePipes, poWaitOnExit, poNoConsole];
p.parameters.add('--remove-section '+section);
p.Execute;
p.WaitOnExit;
p.free;
end;
function TBinUtils.compile(script: tstringlist): boolean;
//compiles the given C code , allocates memory for it, links it, and then copies it to the allocated code, and registers the symbols
//single scripts only. (no multifile supported. Use compileproject for that)
//On hold. This needs to be rewritten to be dynamic instead of static and then fill in the relocation table and importtable (my ld can't link above 0x100000000)
//fuck it, just compile a dll and then force load the dll by parsing the import table
var
p: TProcess;
inputfile: string='';
outputfile: string='';
i,j: integer;
found: boolean;
outputfilelist: tstringlist;
begin
result:=false;
p:=tprocess.create(nil);
inputfile:=GetTempFileName;
DeleteFile(inputfile+'.c');
DeleteFile(outputfile+'.o');
if renamefile(inputfile,inputfile+'.c') then
begin
outputfile:=inputfile+'.o';
inputfile:=inputfile+'.c';
try
script.SaveToFile(inputfile);
p.CurrentDirectory:=fpath;
p.Executable:='"'+fpath+prefix+'gcc'+'"';
p.Options:=[poUsePipes, poWaitOnExit, poNoConsole];
p.parameters.add('-c "'+inputfile+'"');
p.parameters.add('-o "'+outputfile+'"');
p.parameters.add(outputfile);
p.Execute;
if p.WaitOnExit then
begin
if p.exitcode=0 then //compilation success
begin
stripSection(outputfile,'.pdata'); //the mingw I use adds a .pdata section which does not like 64-bit
outputfilelist:=tstringlist.create;
outputfilelist.add(outputfile);
ldAndInject(outputfilelist);
outputfilelist.free;
end;
end;
finally
if inputfile<>'' then
deletefile(inputfile);
if outputfile<>'' then
deletefile(outputfile);
end;
end;
end;
function TBinUtils.compileproject(filelist: tstringlist): boolean;
begin
result:=false;
end;
function TBinUtils.assemble(script: tstringlist; extraparams: string; out filename: string): boolean;
var
p: TProcess;
origfile: string;
ec: integer;
begin
p:=TProcess.Create(nil);
origfile:=GetTempFileName;
script.SaveToFile(origfile);
filename:=GetTempFileName;
try
p.CurrentDirectory:=fpath;
p.Executable:='"'+fpath+prefix+'as'+'"';
p.Options:=[poUsePipes, poWaitOnExit, poNoConsole];
p.Parameters.add(extraparams);
p.parameters.add(ASParam);
p.Parameters.Add('"'+origfile+'"');
p.Parameters.Add('-o "'+filename+'"');
p.Execute;
p.WaitOnExit;
ec:=p.ExitCode;
result:=ec=0;
if not result then
begin
setlength(lasterror, p.Stderr.NumBytesAvailable+1);
p.Stderr.ReadBuffer(lasterror[1], length(lasterror)-1);
lasterror[length(lasterror)]:=#0;
raise exception.create(lasterror);
end;
finally
p.free;
deletefile(origfile);
end;
end;
initialization
binutilslist:=Tlist.create;
{
--[[
Registers the ARM binutils with CE
--]]
local armconfig={}
armconfig.Name="ARM" --set the name if there are multiple binutils for whatever reason
armconfig.Description="BinUtils for ARM" -- ^
armconfig.Architecture="arm" --used by the objdump -m<architecture>
armconfig.OnDisassemble=function(address)
if (address & 1)==1 then
return "-Mforce-thumb"
end
end
armconfig.Path=getCheatEngineDir()..[[binutils\arm\bin]]
armconfig.Prefix="arm-linux-androideabi-"
registerBinUtil(armconfig)
}
finalization
if binutilslist <> nil then
binutilslist.Free;
end.