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

279 lines
7.8 KiB
ObjectPascal

unit FpDbgDarwinClasses;
{$mode objfpc}{$H+}
{$linkframework security}
interface
uses
Classes,
SysUtils,
BaseUnix,
FpDbgClasses,
FpDbgLoader,
DbgIntfBaseTypes,
FpDbgLinuxExtra,
FpDbgInfo,
MacOSAll,
FpDbgUtil,
LazLoggerBase;
type
{ TDbgDarwinProcess }
TDbgDarwinProcess = class(TDbgProcess)
private
FStatus: cint;
FProcessStarted: boolean;
FTaskPort: mach_port_name_t;
function GetDebugAccessRights: boolean;
protected
function InitializeLoader: TDbgImageLoader; override;
public
class function StartInstance(AFileName: string; AParams: string): TDbgProcess; override;
constructor Create(const AName: string; const AProcessID, AThreadID: Integer); override;
function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean; override;
function WriteData(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean; override;
function Continue(AProcess: TDbgProcess; AThread: TDbgThread; AState: TFPDState): boolean; override;
function WaitForDebugEvent(out ProcessIdentifier: THandle): boolean; override;
function ResolveDebugEvent(AThread: TDbgThread): TFPDEvent; override;
end;
procedure RegisterDbgClasses;
implementation
type
vm_map_t = mach_port_t;
vm_offset_t = UIntPtr;
vm_address_t = vm_offset_t;
vm_size_t = UIntPtr;
vm_prot_t = cint;
mach_vm_address_t = uint64;
mach_msg_Type_number_t = natural_t;
mach_vm_size_t = uint64;
function task_for_pid(target_tport: mach_port_name_t; pid: integer; var t: mach_port_name_t): kern_return_t; cdecl external name 'task_for_pid';
function mach_task_self: mach_port_name_t; cdecl external name 'mach_task_self';
function mach_error_string(error_value: mach_error_t): pchar; cdecl; external name 'mach_error_string';
function vm_protect(target_task: vm_map_t; adress: vm_address_t; size: vm_size_t; set_maximum: boolean_t; new_protection: vm_prot_t): kern_return_t; cdecl external name 'vm_protect';
function mach_vm_write(target_task: vm_map_t; address: mach_vm_address_t; data: vm_offset_t; dataCnt: mach_msg_Type_number_t): kern_return_t; cdecl external name 'mach_vm_write';
function mach_vm_read(target_task: vm_map_t; address: mach_vm_address_t; size: mach_vm_size_t; var data: vm_offset_t; var dataCnt: mach_msg_Type_number_t): kern_return_t; cdecl external name 'mach_vm_read';
procedure RegisterDbgClasses;
begin
OSDbgClasses.DbgProcessClass:=TDbgDarwinProcess;
end;
{ TDbgDarwinProcess }
function TDbgDarwinProcess.GetDebugAccessRights: boolean;
var
authFlags: AuthorizationFlags;
stat: OSStatus;
author: AuthorizationRef;
authItem: AuthorizationItem;
authRights: AuthorizationRights;
begin
result := false;
authFlags := kAuthorizationFlagExtendRights or kAuthorizationFlagPreAuthorize or kAuthorizationFlagInteractionAllowed or ( 1 << 5);
stat := AuthorizationCreate(nil, kAuthorizationEmptyEnvironment, authFlags, author);
if stat <> errAuthorizationSuccess then
begin
debugln('Failed to create authorization. Authorization error: ' + inttostr(stat));
exit;
end;
authItem.name:='system.privilege.taskport';
authItem.flags:=0;
authItem.value:=nil;
authItem.valueLength:=0;
authRights.count:=1;
authRights.items:=@authItem;
stat := AuthorizationCopyRights(author, authRights, kAuthorizationEmptyEnvironment, authFlags, nil);
if stat <> errAuthorizationSuccess then
begin
debugln('Failed to get debug-(taskport)-privilege. Authorization error: ' + inttostr(stat));
exit;
end;
result := true;
end;
function TDbgDarwinProcess.InitializeLoader: TDbgImageLoader;
begin
result := TDbgImageLoader.Create(Name);
end;
constructor TDbgDarwinProcess.Create(const AName: string; const AProcessID, AThreadID: Integer);
var
aKernResult: kern_return_t;
begin
inherited Create(AName, AProcessID, AThreadID);
LoadInfo;
if DbgInfo.HasInfo
then FSymInstances.Add(Self);
GetDebugAccessRights;
aKernResult:=task_for_pid(mach_task_self, AProcessID, FTaskPort);
if aKernResult <> KERN_SUCCESS then
begin
DebugLn('Failed to get task for process '+IntToStr(AProcessID)+'. Probably insufficient rights to debug applications. Mach error: '+mach_error_string(aKernResult));
end;
end;
class function TDbgDarwinProcess.StartInstance(AFileName: string; AParams: string): TDbgProcess;
var
PID: TPid;
stat: longint;
begin
pid := FpFork;
if PID=0 then
begin
// We are in the child-process
fpPTrace(PTRACE_TRACEME, 0, nil, nil);
FpExecve(AFileName, nil, nil);
end
else if PID<>-1 then
begin
sleep(100);
result := TDbgDarwinProcess.Create(AFileName, Pid,-1);
end;
end;
function TDbgDarwinProcess.ReadData(const AAdress: TDbgPtr;
const ASize: Cardinal; out AData): Boolean;
var
aKernResult: kern_return_t;
cnt: mach_msg_Type_number_t;
b: pointer;
begin
result := false;
aKernResult := mach_vm_read(FTaskPort, AAdress, ASize, PtrUInt(b), cnt);
if aKernResult <> KERN_SUCCESS then
begin
DebugLn('Failed to read data at address '+FormatAddress(ProcessID)+'. Mach error: '+mach_error_string(aKernResult));
Exit;
end;
System.Move(b^, AData, Cnt);
result := true;
end;
function TDbgDarwinProcess.WriteData(const AAdress: TDbgPtr;
const ASize: Cardinal; const AData): Boolean;
var
aKernResult: kern_return_t;
begin
result := false;
aKernResult:=vm_protect(FTaskPort, PtrUInt(AAdress), ASize, boolean_t(false), 7 {VM_PROT_READ + VM_PROT_WRITE + VM_PROT_COPY});
if aKernResult <> KERN_SUCCESS then
begin
DebugLn('Failed to call vm_protect for address '+FormatAddress(AAdress)+'. Mach error: '+mach_error_string(aKernResult));
Exit;
end;
aKernResult := mach_vm_write(FTaskPort, AAdress, vm_offset_t(@AData), ASize);
if aKernResult <> KERN_SUCCESS then
begin
DebugLn('Failed to write data at address '+FormatAddress(AAdress)+'. Mach error: '+mach_error_string(aKernResult));
Exit;
end;
result := true;
end;
function TDbgDarwinProcess.Continue(AProcess: TDbgProcess; AThread: TDbgThread;
AState: TFPDState): boolean;
var
e: integer;
begin
fpseterrno(0);
{$ifdef linux}
fpPTrace(PTRACE_CONT, ProcessID, nil, nil);
{$endif linux}
{$ifdef darwin}
fpPTrace(PTRACE_CONT, ProcessID, pointer(1), nil);
{$endif darwin}
writeln('Cont');
e := fpgeterrno;
if e <> 0 then
begin
writeln('Failed to continue process. Errcode: ',e);
result := false;
end
else
result := true;
end;
function TDbgDarwinProcess.WaitForDebugEvent(out ProcessIdentifier: THandle): boolean;
begin
ProcessIdentifier:=FpWaitPid(-1, FStatus, 0);
writeln('waited');
result := ProcessIdentifier<>-1;
if not result then
writeln('Failed to wait for debug event. Errcode: ', fpgeterrno);
end;
function TDbgDarwinProcess.ResolveDebugEvent(AThread: TDbgThread): TFPDEvent;
Function WIFSTOPPED(Status: Integer): Boolean;
begin
WIFSTOPPED:=((Status and $FF)=$7F);
end;
begin
if wifexited(FStatus) then
begin
SetExitCode(wexitStatus(FStatus));
writeln('Exit');
result := deExitProcess
end
else if WIFSTOPPED(FStatus) then
begin
writeln('Stopped ',FStatus, ' signal: ',wstopsig(FStatus));
case wstopsig(FStatus) of
SIGTRAP:
begin
if not FProcessStarted then
begin
result := deCreateProcess;
FProcessStarted:=true;
end
else
begin
result := deBreakpoint;
writeln('Breakpoint');
end;
end;
SIGBUS:
begin
writeln('Received SIGBUS');
result := deException;
end;
SIGINT:
begin
writeln('Received SIGINT');
result := deException;
end;
SIGSEGV:
begin
writeln('Received SIGSEGV');
result := deException;
end;
end; {case}
end
else if wifsignaled(FStatus) then
writeln('ERROR: ', wtermsig(FStatus));
end;
end.