1 unit FpDbgDarwinClasses;
2 
3 {$mode objfpc}{$H+}
4 {$linkframework Security}
5 
6 interface
7 
8 uses
9   Classes,
10   SysUtils,
11   BaseUnix,
12   termio,
13   process,
14   FpDbgClasses,
15   FpDbgLoader, FpDbgDisasX86,
16   DbgIntfBaseTypes, DbgIntfDebuggerBase,
17   FpDbgLinuxExtra,
18   FpDbgDwarfDataClasses,
19   FpImgReaderMacho,
20   FpDbgInfo,
21   MacOSAll,
22   FpDbgUtil,
23   UTF8Process,
24   {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
25   FpDbgCommon, FpdMemoryTools,
26   FpErrorMessages;
27 
28 type
29   x86_thread_state32_t = record
30     __eax: cuint;
31     __ebx: cuint;
32     __ecx: cuint;
33     __edx: cuint;
34     __edi: cuint;
35     __esi: cuint;
36     __ebp: cuint;
37     __esp: cuint;
38     __ss: cuint;
39     __eflags: cuint;
40     __eip: cuint;
41     __cs: cuint;
42     __ds: cuint;
43     __es: cuint;
44     __fs: cuint;
45     __gs: cuint;
46   end;
47 
48   x86_thread_state64_t = record
49     __rax: cuint64;
50     __rbx: cuint64;
51     __rcx: cuint64;
52     __rdx: cuint64;
53     __rdi: cuint64;
54     __rsi: cuint64;
55     __rbp: cuint64;
56     __rsp: cuint64;
57     __r8: cuint64;
58     __r9: cuint64;
59     __r10: cuint64;
60     __r11: cuint64;
61     __r12: cuint64;
62     __r13: cuint64;
63     __r14: cuint64;
64     __r15: cuint64;
65     __rip: cuint64;
66     __rflags: cuint64;
67     __cs: cuint64;
68     __fs: cuint64;
69     __gs: cuint64;
70   end;
71 
72   x86_debug_state32_t = record
73     __dr0: cuint32;
74     __dr1: cuint32;
75     __dr2: cuint32;
76     __dr3: cuint32;
77     __dr4: cuint32;
78     __dr5: cuint32;
79     __dr6: cuint32;
80     __dr7: cuint32;
81   end;
82 
83   x86_debug_state64_t = record
84     __dr0: cuint64;
85     __dr1: cuint64;
86     __dr2: cuint64;
87     __dr3: cuint64;
88     __dr4: cuint64;
89     __dr5: cuint64;
90     __dr6: cuint64;
91     __dr7: cuint64;
92   end;
93 
94   x86_debug_state = record
95     case a: byte of
96       1: (ds32: x86_debug_state32_t);
97       2: (ds64: x86_debug_state64_t);
98   end;
99 
100 type
101 
102   { TDbgDarwinThread }
103 
104   TDbgDarwinThread = class(TDbgThread)
105   private
106     FThreadState32: x86_thread_state32_t;
107     FThreadState64: x86_thread_state64_t;
108     FDebugState32: x86_debug_state32_t;
109     FDebugState64: x86_debug_state64_t;
110     FDebugStateRead: boolean;
111     FDebugStateChanged: boolean;
112     FIsSteppingBreakPoint: boolean;
113   protected
ReadThreadStatenull114     function ReadThreadState: boolean;
ReadDebugStatenull115     function ReadDebugState: boolean;
116   public
ResetInstructionPointerAfterBreakpointnull117     function ResetInstructionPointerAfterBreakpoint: boolean; override;
118     procedure ApplyWatchPoints(AWatchPointData: TFpWatchPointData); override;
DetectHardwareWatchpointnull119     function DetectHardwareWatchpoint: Pointer; override;
120     procedure BeforeContinue; override;
121     procedure LoadRegisterValues; override;
122 
GetInstructionPointerRegisterValuenull123     function GetInstructionPointerRegisterValue: TDbgPtr; override;
GetStackPointerRegisterValuenull124     function GetStackPointerRegisterValue: TDbgPtr; override;
GetStackBasePointerRegisterValuenull125     function GetStackBasePointerRegisterValue: TDbgPtr; override;
126   end;
127 
128   { TDbgDarwinProcess }
129 
130   TDbgDarwinProcess = class(TDbgProcess)
131   private
132     FStatus: cint;
133     FProcessStarted: boolean;
134     FTaskPort: mach_port_name_t;
135     FProcProcess: TProcessUTF8;
136     FIsTerminating: boolean;
137     FExceptionSignal: PtrUInt;
138     FMasterPtyFd: cint;
139     FExecutableFilename: string;
GetDebugAccessRightsnull140     function GetDebugAccessRights: boolean;
141     {$ifndef VER2_6}
142     procedure OnForkEvent(Sender : TObject);
143     {$endif}
144   protected
145     procedure InitializeLoaders; override;
CreateThreadnull146     function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; override;
AnalyseDebugEventnull147     function AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent; override;
CreateWatchPointDatanull148     function CreateWatchPointData: TFpWatchPointData; override;
149   public
StartInstancenull150     class function StartInstance(AFileName: string; AParams, AnEnvironment: TStrings; AWorkingDirectory, AConsoleTty: string; AFlags: TStartInstanceFlags; AnOsClasses: TOSDbgClasses; AMemManager: TFpDbgMemManager; out AnError: TFpError): TDbgProcess; override;
isSupportednull151     class function isSupported(ATargetInfo: TTargetDescriptor): boolean; override;
152     constructor Create(const AName: string; const AProcessID, AThreadID: Integer; AnOsClasses: TOSDbgClasses; AMemManager: TFpDbgMemManager); override;
153     destructor Destroy; override;
154 
ReadDatanull155     function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean; override;
WriteDatanull156     function WriteData(const AAdress: TDbgPtr; const ASize: Cardinal; const AData): Boolean; override;
CallParamDefaultLocationnull157     function CallParamDefaultLocation(AParamIdx: Integer): TFpDbgMemLocation; override;
158 
CheckForConsoleOutputnull159     function CheckForConsoleOutput(ATimeOutMs: integer): integer; override;
GetConsoleOutputnull160     function GetConsoleOutput: string; override;
161     procedure SendConsoleInput(AString: string); override;
162 
163     procedure TerminateProcess; override;
164 
Continuenull165     function Continue(AProcess: TDbgProcess; AThread: TDbgThread; SingleStep: boolean): boolean; override;
WaitForDebugEventnull166     function WaitForDebugEvent(out ProcessIdentifier, ThreadIdentifier: THandle): boolean; override;
Pausenull167     function Pause: boolean; override;
168   end;
169   TDbgDarwinProcessClass = class of TDbgDarwinProcess;
170 
171 implementation
172 
173 var
174   DBG_VERBOSE, DBG_WARNINGS: PLazLoggerLogGroup;
175   GConsoleTty: string;
176 
177 type
178   vm_map_t = mach_port_t;
179   vm_offset_t = UIntPtr;
180   vm_address_t = vm_offset_t;
181   vm_size_t = UIntPtr;
182   vm_prot_t = cint;
183   mach_vm_address_t = uint64;
184   mach_msg_Type_number_t = natural_t;
185   mach_vm_size_t = uint64;
186   task_t = mach_port_t;
187   thread_act_t = mach_port_t;
188   thread_act_array = array[0..255] of thread_act_t;
189   thread_act_array_t = ^thread_act_array;
190   thread_state_flavor_t = cint;
191   thread_state_t = ^natural_t;
192 
193 const
194   x86_THREAD_STATE32    = 1;
195   x86_FLOAT_STATE32     = 2;
196   x86_EXCEPTION_STATE32 = 3;
197   x86_THREAD_STATE64    = 4;
198   x86_FLOAT_STATE64     = 5;
199   x86_EXCEPTION_STATE64 = 6;
200   x86_THREAD_STATE      = 7;
201   x86_FLOAT_STATE       = 8;
202   x86_EXCEPTION_STATE   = 9;
203   x86_DEBUG_STATE32     = 10;
204   x86_DEBUG_STATE64     = 11;
205   //x86_DEBUG_STATE       = 12;
206   THREAD_STATE_NONE     = 13;
207   x86_AVX_STATE32       = 16;
208   x86_AVX_STATE64       = 17;
209   x86_AVX_STATE         = 18;
210 
211   x86_THREAD_STATE32_COUNT: mach_msg_Type_number_t = sizeof(x86_thread_state32_t) div sizeof(cint);
212   x86_THREAD_STATE64_COUNT: mach_msg_Type_number_t = sizeof(x86_thread_state64_t) div sizeof(cint);
213   x86_DEBUG_STATE32_COUNT:  mach_msg_Type_number_t = sizeof(x86_debug_state32_t) div sizeof(cint);
214   x86_DEBUG_STATE64_COUNT:  mach_msg_Type_number_t = sizeof(x86_debug_state64_t) div sizeof(cint);
215 
task_for_pidnull216 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';
mach_task_selfnull217 function mach_task_self: mach_port_name_t; cdecl external name 'mach_task_self';
mach_error_stringnull218 function mach_error_string(error_value: mach_error_t): pchar; cdecl; external name 'mach_error_string';
mach_vm_protectnull219 function mach_vm_protect(target_task: vm_map_t; adress: mach_vm_address_t; size: mach_vm_size_t; set_maximum: boolean_t; new_protection: vm_prot_t): kern_return_t; cdecl external name 'mach_vm_protect';
mach_vm_writenull220 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';
mach_vm_readnull221 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';
222 
task_threadsnull223 function task_threads(target_task: task_t; var act_list: thread_act_array_t; var act_listCnt: mach_msg_type_number_t): kern_return_t; cdecl external name 'task_threads';
thread_get_statenull224 function thread_get_state(target_act: thread_act_t; flavor: thread_state_flavor_t; old_state: thread_state_t; var old_stateCnt: mach_msg_Type_number_t): kern_return_t; cdecl external name 'thread_get_state';
thread_set_statenull225 function thread_set_state(target_act: thread_act_t; flavor: thread_state_flavor_t; new_state: thread_state_t; old_stateCnt: mach_msg_Type_number_t): kern_return_t; cdecl external name 'thread_set_state';
226 
posix_openptnull227 function posix_openpt(oflag: cint): cint;cdecl;external 'c' name 'posix_openpt';
ptsnamenull228 function ptsname(__fd:longint):Pchar;cdecl;external 'c' name 'ptsname';
grantptnull229 function grantpt(__fd:longint):longint;cdecl;external 'c' name 'grantpt';
unlockptnull230 function unlockpt(__fd:longint):longint;cdecl;external 'c' name 'unlockpt';
231 
WIFSTOPPEDnull232 Function WIFSTOPPED(Status: Integer): Boolean;
233 begin
234   WIFSTOPPED:=((Status and $FF)=$7F);
235 end;
236 
237 { TDbgDarwinThread }
238 
safefpdup2null239 Function safefpdup2(fildes, fildes2 : cInt): cInt;
240 begin
241   repeat
242     safefpdup2:=fpdup2(fildes,fildes2);
243   until (safefpdup2<>-1) or (fpgeterrno<>ESysEINTR);
244 end;
245 
246 {$ifndef VER2_6}
247 procedure TDbgDarwinProcess.OnForkEvent(Sender: TObject);
248 {$else}
249 procedure OnForkEvent;
250 {$endif VER2_6}
251 var
252   ConsoleTtyFd: cint;
253 begin
254   if FpSetsid<>0 then
255     begin
256     // For some reason, FpSetsid always fails.
257     // writeln('Failed to set sid. '+inttostr(fpgeterrno));
258     end;
259   if GConsoleTty<>'' then
260   begin
261     ConsoleTtyFd:=FpOpen(GConsoleTty, O_RDWR + O_NOCTTY);
262     if ConsoleTtyFd>-1 then
263       begin
264       if (FpIOCtl(ConsoleTtyFd, TIOCSCTTY, nil) = -1) then
265         begin
266         // This call always fails for some reason. That's also why login_tty can not be used. (login_tty
267         // also calls TIOCSCTTY, but when it fails it aborts) The failure is ignored.
268         // writeln('Failed to set tty '+inttostr(fpgeterrno));
269         end;
270 
271       safefpdup2(ConsoleTtyFd,0);
272       safefpdup2(ConsoleTtyFd,1);
273       safefpdup2(ConsoleTtyFd,2);
274       end
275     else
276       writeln('Failed to open tty '+GConsoleTty+'. Errno: '+inttostr(fpgeterrno));
277   end;
278 
279   fpPTrace(PTRACE_TRACEME, 0, nil, nil);
280 end;
281 
ReadThreadStatenull282 function TDbgDarwinThread.ReadThreadState: boolean;
283 var
284   aKernResult: kern_return_t;
285   old_StateCnt: mach_msg_Type_number_t;
286 begin
287   if ID<0 then
288     begin
289     // The ID is set to -1 when the debugger does not have sufficient rights.
290     // In that case just return zero's, so that the debuggee wil just run without
291     // any problems/exceptions in the debugger.
292     FillByte(FThreadState32, SizeOf(FThreadState32),0);
293     FillByte(FThreadState64, SizeOf(FThreadState64),0);
294     result := true;
295     exit;
296     end;
297   if Process.Mode=dm32 then
298     begin
299     old_StateCnt:=x86_THREAD_STATE32_COUNT;
300     aKernResult:=thread_get_state(Id,x86_THREAD_STATE32, @FThreadState32,old_StateCnt);
301     end
302   else
303     begin
304     old_StateCnt:=x86_THREAD_STATE64_COUNT;
305     aKernResult:=thread_get_state(Id,x86_THREAD_STATE64, @FThreadState64,old_StateCnt);
306     end;
307   result := aKernResult = KERN_SUCCESS;
308   if not result then
309     begin
310     debugln(DBG_WARNINGS, 'Failed to call thread_get_state for thread %d. Mach error: '+mach_error_string(aKernResult),[Id]);
311     end;
312   FRegisterValueListValid:=false;
313   FDebugStateRead:=false;
314 end;
315 
TDbgDarwinThread.ReadDebugStatenull316 function TDbgDarwinThread.ReadDebugState: boolean;
317 var
318   aKernResult: kern_return_t;
319   old_StateCnt: mach_msg_Type_number_t;
320 begin
321   if FDebugStateRead then
322   begin
323     result := true;
324     exit;
325   end;
326 
327   if Process.Mode=dm32 then
328   begin
329     old_StateCnt:=x86_DEBUG_STATE32_COUNT;
330     aKernResult:=thread_get_state(ID, x86_DEBUG_STATE32, @FDebugState32, old_StateCnt);
331   end
332   else
333   begin
334     old_StateCnt:=x86_DEBUG_STATE64_COUNT;
335     aKernResult:=thread_get_state(ID, x86_DEBUG_STATE64, @FDebugState64, old_StateCnt);
336   end;
337   if aKernResult <> KERN_SUCCESS then
338   begin
339     debugln(DBG_WARNINGS, 'Failed to call thread_get_state to ge debug-info for thread %d. Mach error: '+mach_error_string(aKernResult),[Id]);
340     result := false;
341   end
342   else
343   begin
344     result := true;
345     FDebugStateRead:=true;
346   end;
347 end;
348 
TDbgDarwinThread.ResetInstructionPointerAfterBreakpointnull349 function TDbgDarwinThread.ResetInstructionPointerAfterBreakpoint: boolean;
350 var
351   aKernResult: kern_return_t;
352   new_StateCnt: mach_msg_Type_number_t;
353 begin
354   result := true;
355   if ID<0 then
356     Exit;
357 
358   if Process.Mode=dm32 then
359     begin
360     Dec(FThreadState32.__eip);
361     new_StateCnt := x86_THREAD_STATE32_COUNT;
362     aKernResult:=thread_set_state(ID,x86_THREAD_STATE32, @FThreadState32, new_StateCnt);
363     end
364   else
365     begin
366     Dec(FThreadState64.__rip);
367     new_StateCnt := x86_THREAD_STATE64_COUNT;
368     aKernResult:=thread_set_state(ID,x86_THREAD_STATE64, @FThreadState64, new_StateCnt);
369     end;
370 
371   if aKernResult <> KERN_SUCCESS then
372     begin
373     debugln(DBG_WARNINGS, 'Failed to call thread_set_state for thread %d. Mach error: '+mach_error_string(aKernResult),[Id]);
374     result := false;
375     end;
376 end;
377 
378 type
379   TDr32bitArr = array[0..4] of cuint32;
380   TDr64bitArr = array[0..4] of cuint64;
381 
382 procedure TDbgDarwinThread.ApplyWatchPoints(AWatchPointData: TFpWatchPointData);
383   procedure UpdateWatches32;
384   var
385     drArr: ^TDr32bitArr;
386     i: Integer;
387     r: boolean;
388     addr: cuint32;
389   begin
390     drArr := @FDebugState32.__dr0;
391 
392     r := True;
393     for i := 0 to 3 do begin
394       addr := cuint32(TFpIntelWatchPointData(AWatchPointData).Dr03[i]);
395       drArr^[i]:=addr;
396     end;
397     FDebugState32.__dr7 := (FDebugState32.__dr7 and $0000FF00);
398     if r then
399       FDebugState32.__dr7 := FDebugState32.__dr7 or cuint32(TFpIntelWatchPointData(AWatchPointData).Dr7);
400   end;
401 
402   procedure UpdateWatches64;
403   var
404     drArr: ^TDr64bitArr;
405     i: Integer;
406     r: boolean;
407     addr: cuint64;
408   begin
409     drArr := @FDebugState64.__dr0;
410 
411     r := True;
412     for i := 0 to 3 do begin
413       addr := cuint64(TFpIntelWatchPointData(AWatchPointData).Dr03[i]);
414       drArr^[i]:=addr;
415     end;
416     FDebugState32.__dr7 := (FDebugState32.__dr7 and $0000FF00);
417     if r then
418       FDebugState32.__dr7 := FDebugState32.__dr7 or cuint64(TFpIntelWatchPointData(AWatchPointData).Dr7);
419   end;
420 
421 begin
422   if ID<0 then
423     Exit;
424   if not ReadDebugState then
425     exit;
426 
427   if Process.Mode=dm32 then
428     UpdateWatches32
429   else
430     UpdateWatches64;
431   FDebugStateChanged:=true;
432 end;
433 
DetectHardwareWatchpointnull434 function TDbgDarwinThread.DetectHardwareWatchpoint: Pointer;
435 var
436   dr6: DWord;
437   wd: TFpIntelWatchPointData;
438 begin
439   result := nil;
440   if ID<0 then
441     Exit;
442   if ReadDebugState then
443     begin
444     if Process.Mode=dm32 then
445       dr6 := FDebugState32.__dr6
446     else
447       dr6 := lo(FDebugState64.__dr6);
448 
449     wd := TFpIntelWatchPointData(Process.WatchPointData);
450     if dr6 and 1 = 1 then result := wd.Owner[0]
451     else if dr6 and 2 = 2 then result := wd.Owner[1]
452     else if dr6 and 4 = 4 then result := wd.Owner[2]
453     else if dr6 and 8 = 8 then result := wd.Owner[3];
454     if (Result = nil) and ((dr6 and 15) <> 0) then
455       Result := Pointer(-1); // not owned watchpoint
456     end;
457 end;
458 
459 procedure TDbgDarwinThread.BeforeContinue;
460 var
461   aKernResult: kern_return_t;
462   old_StateCnt: mach_msg_Type_number_t;
463 begin
464   inherited;
465   if Process.CurrentWatchpoint <> nil then
466     begin
467     if Process.Mode=dm32 then
468       FDebugState32.__dr6:=0
469     else
470       FDebugState64.__dr6:=0;
471     FDebugStateChanged:=true;
472     end;
473 
474   if FDebugStateRead and FDebugStateChanged then
475   begin
476     if Process.Mode=dm32 then
477       begin
478       old_StateCnt:=x86_DEBUG_STATE32_COUNT;
479       aKernResult:=thread_set_state(Id, x86_DEBUG_STATE32, @FDebugState32, old_StateCnt);
480       end
481     else
482       begin
483       old_StateCnt:=x86_DEBUG_STATE64_COUNT;
484       aKernResult:=thread_set_state(Id, x86_DEBUG_STATE64, @FDebugState64, old_StateCnt);
485       end;
486 
487     if aKernResult <> KERN_SUCCESS then
488       debugln(DBG_WARNINGS, 'Failed to call thread_set_state for thread %d. Mach error: '+mach_error_string(aKernResult),[Id]);
489   end;
490 end;
491 
492 procedure TDbgDarwinThread.LoadRegisterValues;
493 begin
494   if Process.Mode=dm32 then with FThreadState32 do
495   begin
496     FRegisterValueList.DbgRegisterAutoCreate['eax'].SetValue(__eax, IntToStr(__eax),4,0);
497     FRegisterValueList.DbgRegisterAutoCreate['ecx'].SetValue(__ecx, IntToStr(__ecx),4,1);
498     FRegisterValueList.DbgRegisterAutoCreate['edx'].SetValue(__edx, IntToStr(__edx),4,2);
499     FRegisterValueList.DbgRegisterAutoCreate['ebx'].SetValue(__ebx, IntToStr(__ebx),4,3);
500     FRegisterValueList.DbgRegisterAutoCreate['esp'].SetValue(__esp, IntToStr(__esp),4,4);
501     FRegisterValueList.DbgRegisterAutoCreate['ebp'].SetValue(__ebp, IntToStr(__ebp),4,5);
502     FRegisterValueList.DbgRegisterAutoCreate['esi'].SetValue(__esi, IntToStr(__esi),4,6);
503     FRegisterValueList.DbgRegisterAutoCreate['edi'].SetValue(__edi, IntToStr(__edi),4,7);
504     FRegisterValueList.DbgRegisterAutoCreate['eip'].SetValue(__eip, IntToStr(__eip),4,8);
505 
506     FRegisterValueList.DbgRegisterAutoCreate['eflags'].Setx86EFlagsValue(__eflags);
507 
508     FRegisterValueList.DbgRegisterAutoCreate['cs'].SetValue(__cs, IntToStr(__cs),4,0);
509     FRegisterValueList.DbgRegisterAutoCreate['ss'].SetValue(__ss, IntToStr(__ss),4,0);
510     FRegisterValueList.DbgRegisterAutoCreate['ds'].SetValue(__ds, IntToStr(__ds),4,0);
511     FRegisterValueList.DbgRegisterAutoCreate['es'].SetValue(__es, IntToStr(__es),4,0);
512     FRegisterValueList.DbgRegisterAutoCreate['fs'].SetValue(__fs, IntToStr(__fs),4,0);
513     FRegisterValueList.DbgRegisterAutoCreate['gs'].SetValue(__gs, IntToStr(__gs),4,0);
514   end else with FThreadState64 do
515     begin
516     FRegisterValueList.DbgRegisterAutoCreate['rax'].SetValue(__rax, IntToStr(__rax),8,0);
517     FRegisterValueList.DbgRegisterAutoCreate['rbx'].SetValue(__rbx, IntToStr(__rbx),8,3);
518     FRegisterValueList.DbgRegisterAutoCreate['rcx'].SetValue(__rcx, IntToStr(__rcx),8,2);
519     FRegisterValueList.DbgRegisterAutoCreate['rdx'].SetValue(__rdx, IntToStr(__rdx),8,1);
520     FRegisterValueList.DbgRegisterAutoCreate['rsi'].SetValue(__rsi, IntToStr(__rsi),8,4);
521     FRegisterValueList.DbgRegisterAutoCreate['rdi'].SetValue(__rdi, IntToStr(__rdi),8,5);
522     FRegisterValueList.DbgRegisterAutoCreate['rbp'].SetValue(__rbp, IntToStr(__rbp),8,6);
523     FRegisterValueList.DbgRegisterAutoCreate['rsp'].SetValue(__rsp, IntToStr(__rsp),8,7);
524 
525     FRegisterValueList.DbgRegisterAutoCreate['r8'].SetValue(__r8, IntToStr(__r8),8,8);
526     FRegisterValueList.DbgRegisterAutoCreate['r9'].SetValue(__r9, IntToStr(__r9),8,9);
527     FRegisterValueList.DbgRegisterAutoCreate['r10'].SetValue(__r10, IntToStr(__r10),8,10);
528     FRegisterValueList.DbgRegisterAutoCreate['r11'].SetValue(__r11, IntToStr(__r11),8,11);
529     FRegisterValueList.DbgRegisterAutoCreate['r12'].SetValue(__r12, IntToStr(__r12),8,12);
530     FRegisterValueList.DbgRegisterAutoCreate['r13'].SetValue(__r13, IntToStr(__r13),8,13);
531     FRegisterValueList.DbgRegisterAutoCreate['r14'].SetValue(__r14, IntToStr(__r14),8,14);
532     FRegisterValueList.DbgRegisterAutoCreate['r15'].SetValue(__r15, IntToStr(__r15),8,15);
533 
534     FRegisterValueList.DbgRegisterAutoCreate['rip'].SetValue(__rip, IntToStr(__rip),8,16);
535     FRegisterValueList.DbgRegisterAutoCreate['eflags'].Setx86EFlagsValue(__rflags);
536 
537     FRegisterValueList.DbgRegisterAutoCreate['cs'].SetValue(__cs, IntToStr(__cs),8,43);
538     FRegisterValueList.DbgRegisterAutoCreate['fs'].SetValue(__fs, IntToStr(__fs),8,46);
539     FRegisterValueList.DbgRegisterAutoCreate['gs'].SetValue(__gs, IntToStr(__gs),8,47);
540   end;
541   FRegisterValueListValid:=true;
542 end;
543 
TDbgDarwinThread.GetInstructionPointerRegisterValuenull544 function TDbgDarwinThread.GetInstructionPointerRegisterValue: TDbgPtr;
545 begin
546   if Process.Mode=dm32 then
547     result := FThreadState32.__eip
548   else
549     result := FThreadState64.__rip;
550 end;
551 
TDbgDarwinThread.GetStackPointerRegisterValuenull552 function TDbgDarwinThread.GetStackPointerRegisterValue: TDbgPtr;
553 begin
554   if Process.Mode=dm32 then
555     result := FThreadState32.__esp
556   else
557     result := FThreadState64.__rsp;
558 end;
559 
TDbgDarwinThread.GetStackBasePointerRegisterValuenull560 function TDbgDarwinThread.GetStackBasePointerRegisterValue: TDbgPtr;
561 begin
562   if Process.Mode=dm32 then
563     result := FThreadState32.__ebp
564   else
565     result := FThreadState64.__rbp;
566 end;
567 
568 { TDbgDarwinProcess }
569 
TDbgDarwinProcess.GetDebugAccessRightsnull570 function TDbgDarwinProcess.GetDebugAccessRights: boolean;
571 var
572   authFlags: AuthorizationFlags;
573   stat: OSStatus;
574   author: AuthorizationRef;
575   authItem: AuthorizationItem;
576   authRights: AuthorizationRights;
577 begin
578   result := false;
579   authFlags := kAuthorizationFlagExtendRights or kAuthorizationFlagPreAuthorize or kAuthorizationFlagInteractionAllowed or ( 1 << 5);
580 
581   stat := AuthorizationCreate(nil, kAuthorizationEmptyEnvironment, authFlags, author);
582   if stat <> errAuthorizationSuccess then
583     begin
584     debugln(DBG_WARNINGS, 'Failed to create authorization. Authorization error: ' + inttostr(stat));
585     exit;
586     end;
587 
588   authItem.name:='system.privilege.taskport';
589   authItem.flags:=0;
590   authItem.value:=nil;
591   authItem.valueLength:=0;
592 
593   authRights.count:=1;
594   authRights.items:=@authItem;
595 
596   stat := AuthorizationCopyRights(author, authRights, kAuthorizationEmptyEnvironment, authFlags, nil);
597   if stat <> errAuthorizationSuccess then
598     begin
599     debugln(DBG_WARNINGS, 'Failed to get debug-(taskport)-privilege. Authorization error: ' + inttostr(stat));
600     exit;
601     end;
602   result := true;
603 end;
604 
605 procedure TDbgDarwinProcess.InitializeLoaders;
606 var
607   PrimaryLoader: TDbgImageLoader;
608 begin
609   PrimaryLoader := TDbgImageLoader.Create(FExecutableFilename);
610   PrimaryLoader.AddToLoaderList(LoaderList);
611 end;
612 
CreateThreadnull613 function TDbgDarwinProcess.CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread;
614 begin
615   IsMainThread:=true;
616   result := TDbgDarwinThread.Create(Self, AthreadIdentifier, AthreadIdentifier)
617 end;
618 
CreateWatchPointDatanull619 function TDbgDarwinProcess.CreateWatchPointData: TFpWatchPointData;
620 begin
621   Result := TFpIntelWatchPointData.Create;
622 end;
623 
624 constructor TDbgDarwinProcess.Create(const AName: string; const AProcessID,
625   AThreadID: Integer; AnOsClasses: TOSDbgClasses; AMemManager: TFpDbgMemManager);
626 var
627   aKernResult: kern_return_t;
628 begin
629   inherited Create(AName, AProcessID, AThreadID, AnOsClasses, AMemManager);
630 
631   GetDebugAccessRights;
632   aKernResult:=task_for_pid(mach_task_self, AProcessID, FTaskPort);
633   if aKernResult <> KERN_SUCCESS then
634     begin
635     debugln(DBG_WARNINGS, 'Failed to get task for process '+IntToStr(AProcessID)+'. Probably insufficient rights to debug applications. Mach error: '+mach_error_string(aKernResult));
636     end;
637 end;
638 
639 destructor TDbgDarwinProcess.Destroy;
640 begin
641   FProcProcess.Free;
642   inherited Destroy;
643 end;
644 
TDbgDarwinProcess.StartInstancenull645 class function TDbgDarwinProcess.StartInstance(AFileName: string; AParams,
646   AnEnvironment: TStrings; AWorkingDirectory, AConsoleTty: string;
647   AFlags: TStartInstanceFlags; AnOsClasses: TOSDbgClasses; AMemManager: TFpDbgMemManager;
648   out AnError: TFpError): TDbgProcess;
649 var
650   PID: TPid;
651   AProcess: TProcessUTF8;
652   AnExecutabeFilename: string;
653   AMasterPtyFd: cint;
654 begin
655   result := nil;
656 
657   AnExecutabeFilename:=ExcludeTrailingPathDelimiter(AFileName);
658   if DirectoryExists(AnExecutabeFilename) then
659     begin
660     if not (ExtractFileExt(AnExecutabeFilename)='.app') then
661       begin
662       DebugLn(DBG_WARNINGS, format('Can not debug %s, because it''s a directory',[AnExecutabeFilename]));
663       Exit;
664       end;
665 
666     AnExecutabeFilename := AnExecutabeFilename + '/Contents/MacOS/' + ChangeFileExt(ExtractFileName(AnExecutabeFilename),'');
667     if not FileExists(AFileName) then
668       begin
669       DebugLn(DBG_WARNINGS, format('Can not find  %s.',[AnExecutabeFilename]));
670       Exit;
671       end;
672     end;
673 
674   AMasterPtyFd:=-1;
675   if siRediretOutput in AFlags then
676     begin
677     if AConsoleTty<>'' then
678       debugln(DBG_VERBOSE, 'It is of no use to provide a console-tty when the console output is being redirected.');
679     AMasterPtyFd := posix_openpt(O_RDWR + O_NOCTTY);
680     if AMasterPtyFd<0 then
681       DebugLn(DBG_WARNINGS, 'Failed to open pseudo-tty. Errno: ' + IntToStr(fpgeterrno))
682     else
683       begin
684       if grantpt(AMasterPtyFd)<>0 then
685         DebugLn(DBG_WARNINGS, 'Failed to set pseudo-tty slave permissions. Errno: ' + IntToStr(fpgeterrno));
686       if unlockpt(AMasterPtyFd)<>0 then
687         DebugLn(DBG_WARNINGS, 'Failed to unlock pseudo-tty slave. Errno: ' + IntToStr(fpgeterrno));
688       AConsoleTty := strpas(ptsname(AMasterPtyFd));
689       end;
690     end;
691 
692   AProcess := TProcessUTF8.Create(nil);
693   try
694     AProcess.OnForkEvent:=@OnForkEvent;
695     AProcess.Executable:=AnExecutabeFilename;
696     AProcess.Parameters:=AParams;
697     AProcess.Environment:=AnEnvironment;
698     AProcess.CurrentDirectory:=AWorkingDirectory;
699     GConsoleTty := AConsoleTty;
700 
701     AProcess.Execute;
702     PID:=AProcess.ProcessID;
703 
704     sleep(100);
705     result := TDbgDarwinProcess.Create(AFileName, Pid, -1, AnOsClasses, AMemManager);
706     TDbgDarwinProcess(result).FMasterPtyFd := AMasterPtyFd;
707     TDbgDarwinProcess(result).FProcProcess := AProcess;
708     TDbgDarwinProcess(result).FExecutableFilename := AnExecutabeFilename;
709   except
710     on E: Exception do
711     begin
712       DebugLn(DBG_WARNINGS, Format('Failed to start process "%s". Errormessage: "%s".',[AFileName, E.Message]));
713       AProcess.Free;
714 
715       if AMasterPtyFd>-1 then
716         FpClose(AMasterPtyFd);
717     end;
718   end;
719 end;
720 
TDbgDarwinProcess.isSupportednull721 class function TDbgDarwinProcess.isSupported(ATargetInfo: TTargetDescriptor
722   ): boolean;
723 begin
724   result := (ATargetInfo.OS = osDarwin) and
725             (ATargetInfo.machineType = mtX86_64);
726 end;
727 
TDbgDarwinProcess.ReadDatanull728 function TDbgDarwinProcess.ReadData(const AAdress: TDbgPtr;
729   const ASize: Cardinal; out AData): Boolean;
730 var
731   aKernResult: kern_return_t;
732   cnt: mach_msg_Type_number_t;
733   b: pointer;
734 begin
735   result := false;
736 
737   aKernResult := mach_vm_read(FTaskPort, AAdress, ASize, PtrUInt(b), cnt);
738   if aKernResult <> KERN_SUCCESS then
739     begin
740     DebugLn(DBG_WARNINGS, 'Failed to read data at address '+FormatAddress(AAdress)+'. Mach error: '+mach_error_string(aKernResult));
741     Exit;
742     end;
743   System.Move(b^, AData, Cnt);
744   MaskBreakpointsInReadData(AAdress, ASize, AData);
745   result := true;
746 end;
747 
TDbgDarwinProcess.WriteDatanull748 function TDbgDarwinProcess.WriteData(const AAdress: TDbgPtr;
749   const ASize: Cardinal; const AData): Boolean;
750 var
751   aKernResult: kern_return_t;
752 begin
753   result := false;
754   aKernResult:=mach_vm_protect(FTaskPort, AAdress, ASize, boolean_t(false), 7 {VM_PROT_READ + VM_PROT_WRITE + VM_PROT_COPY});
755   if aKernResult <> KERN_SUCCESS then
756     begin
757     DebugLn(DBG_WARNINGS, 'Failed to call vm_protect for address '+FormatAddress(AAdress)+'. Mach error: '+mach_error_string(aKernResult));
758     Exit;
759     end;
760 
761   aKernResult := mach_vm_write(FTaskPort, AAdress, vm_offset_t(@AData), ASize);
762   if aKernResult <> KERN_SUCCESS then
763     begin
764     DebugLn(DBG_WARNINGS, 'Failed to write data at address '+FormatAddress(AAdress)+'. Mach error: '+mach_error_string(aKernResult));
765     Exit;
766     end;
767 
768   result := true;
769 end;
770 
CallParamDefaultLocationnull771 function TDbgDarwinProcess.CallParamDefaultLocation(AParamIdx: Integer
772   ): TFpDbgMemLocation;
773 begin
774   case Mode of
775     dm32: case AParamIdx of
776         0: Result := RegisterLoc(0); // EAX
777         1: Result := RegisterLoc(2); // EDX
778         2: Result := RegisterLoc(1); // ECX
779       end;
780     dm64: case AParamIdx of
781         0: Result := RegisterLoc(5); // RDI
782         1: Result := RegisterLoc(4); // RSI
783         2: Result := RegisterLoc(1); // RDX
784       end;
785   end;
786 end;
787 
CheckForConsoleOutputnull788 function TDbgDarwinProcess.CheckForConsoleOutput(ATimeOutMs: integer): integer;
789 Var
790   f: TfdSet;
791   sleepytime: ttimeval;
792 begin
793   sleepytime.tv_sec := ATimeOutMs div 1000;
794   sleepytime.tv_usec := (ATimeOutMs mod 1000)*1000;
795   FpFD_ZERO(f);
796   fpFD_SET(FMasterPtyFd,f);
797   result := fpselect(FMasterPtyFd+1,@f,nil,nil,@sleepytime);
798 end;
799 
TDbgDarwinProcess.GetConsoleOutputnull800 function TDbgDarwinProcess.GetConsoleOutput: string;
801 var
802   ABytesRead: cint;
803   ABuf: array[0..1023] of char;
804 begin
805   ABytesRead := fpRead(FMasterPtyFd, ABuf[0], SizeOf(ABuf));
806   if ABytesRead>0 then
807     result := Copy(ABuf, 0, ABytesRead)
808   else
809     result := '';
810 end;
811 
812 procedure TDbgDarwinProcess.SendConsoleInput(AString: string);
813 begin
814   if FpWrite(FMasterPtyFd, AString[1], length(AString)) <> Length(AString) then
815     debugln(DBG_WARNINGS, 'Failed to send input to console.');
816 end;
817 
818 procedure TDbgDarwinProcess.TerminateProcess;
819 begin
820   FIsTerminating:=true;
821   if fpkill(ProcessID,SIGKILL)<>0 then
822     begin
823     debugln(DBG_WARNINGS, 'Failed to send SIGKILL to process %d. Errno: %d',[ProcessID, errno]);
824     FIsTerminating:=false;
825     end;
826 end;
827 
Continuenull828 function TDbgDarwinProcess.Continue(AProcess: TDbgProcess; AThread: TDbgThread; SingleStep: boolean): boolean;
829 var
830   e: integer;
831 begin
832   fpseterrno(0);
833 {$ifdef linux}
834   fpPTrace(PTRACE_CONT, ProcessID, nil, nil);
835 {$endif linux}
836 {$ifdef darwin}
837   AThread.NextIsSingleStep:=SingleStep;
838   AThread.BeforeContinue;  // TODO: All threads
839   if HasInsertedBreakInstructionAtLocation(AThread.GetInstructionPointerRegisterValue) then begin
840     TempRemoveBreakInstructionCode(AThread.GetInstructionPointerRegisterValue);
841     fpPTrace(PTRACE_SINGLESTEP, ProcessID, pointer(1), pointer(FExceptionSignal));
842     TDbgDarwinThread(AThread).FIsSteppingBreakPoint := True;
843   end
844   else
845   if SingleStep then begin
846     fpPTrace(PTRACE_SINGLESTEP, ProcessID, pointer(1), pointer(FExceptionSignal));
847     TDbgDarwinThread(AThread).FIsSteppingBreakPoint := True;
848   end
849   else if FIsTerminating then
850     fpPTrace(PTRACE_KILL, ProcessID, pointer(1), nil)
851   else
852     fpPTrace(PTRACE_CONT, ProcessID, pointer(1), pointer(FExceptionSignal));
853 {$endif darwin}
854   e := fpgeterrno;
855   if e <> 0 then
856     begin
857     debugln(DBG_WARNINGS, 'Failed to continue process. Errcode: '+inttostr(e));
858     result := false;
859     end
860   else
861     result := true;
862 end;
863 
TDbgDarwinProcess.WaitForDebugEventnull864 function TDbgDarwinProcess.WaitForDebugEvent(out ProcessIdentifier, ThreadIdentifier: THandle): boolean;
865 var
866   aKernResult: kern_return_t;
867   act_list: thread_act_array_t;
868   act_listCtn: mach_msg_type_number_t;
869 begin
870   ThreadIdentifier:=-1;
871 
872   ProcessIdentifier:=FpWaitPid(-1, FStatus, 0);
873   RestoreTempBreakInstructionCodes;
874 
875   result := ProcessIdentifier<>-1;
876   if not result then
877     debugln(DBG_WARNINGS, 'Failed to wait for debug event. Errcode: %d', [fpgeterrno])
878   else if (WIFSTOPPED(FStatus)) then
879     begin
880     aKernResult := task_threads(FTaskPort, act_list, act_listCtn);
881     if aKernResult <> KERN_SUCCESS then
882       begin
883       debugln(DBG_WARNINGS, 'Failed to call task_threads. Mach error: '+mach_error_string(aKernResult));
884       end
885     else if act_listCtn>0 then
886       ThreadIdentifier := act_list^[0];
887     end
888 end;
889 
Pausenull890 function TDbgDarwinProcess.Pause: boolean;
891 begin
892   result := FpKill(ProcessID, SIGTRAP)=0;
893   PauseRequested:=true;
894 end;
895 
TDbgDarwinProcess.AnalyseDebugEventnull896 function TDbgDarwinProcess.AnalyseDebugEvent(AThread: TDbgThread): TFPDEvent;
897 
898 begin
899   FExceptionSignal:=0;
900   if wifexited(FStatus) or wifsignaled(FStatus) then
901     begin
902     SetExitCode(wexitStatus(FStatus));
903     // Clear all pending signals
904     repeat
905     until FpWaitPid(-1, FStatus, WNOHANG)<1;
906 
907     result := deExitProcess
908     end
909   else if WIFSTOPPED(FStatus) then
910     begin
911     //debugln(DBG_WARNINGS, 'Stopped ',FStatus, ' signal: ',wstopsig(FStatus));
912     TDbgDarwinThread(AThread).ReadThreadState;
913     case wstopsig(FStatus) of
914       SIGTRAP:
915         begin
916         if not FProcessStarted then
917           begin
918           result := deCreateProcess;
919           FProcessStarted:=true;
920           end
921         else
922           begin
923           result := deBreakpoint;
924           if not TDbgDarwinThread(AThread).FIsSteppingBreakPoint then
925             AThread.CheckAndResetInstructionPointerAfterBreakpoint;
926           end
927         end;
928       SIGBUS:
929         begin
930         ExceptionClass:='SIGBUS';
931         FExceptionSignal:=SIGBUS;
932         result := deException;
933         end;
934       SIGINT:
935         begin
936         ExceptionClass:='SIGINT';
937         FExceptionSignal:=SIGINT;
938         result := deException;
939         end;
940       SIGSEGV:
941         begin
942         ExceptionClass:='SIGSEGV';
943         FExceptionSignal:=SIGSEGV;
944         result := deException;
945         end;
946       SIGKILL:
947         begin
948         if FIsTerminating then
949           result := deInternalContinue
950         else
951           begin
952           ExceptionClass:='SIGKILL';
953           FExceptionSignal:=SIGKILL;
954           result := deException;
955           end;
956         end;
957       SIGCHLD:
958         begin
959         FExceptionSignal:=SIGCHLD;
960         result := deInternalContinue;
961         end
962       else
963         begin
964         ExceptionClass:='Unknown exception code '+inttostr(wstopsig(FStatus));
965         FExceptionSignal:=wstopsig(FStatus);
966         result := deException;
967         end;
968     end; {case}
969     if result=deException then
970       ExceptionClass:='External: '+ExceptionClass;
971     end
972   else
973     raise exception.CreateFmt('Received unknown status %d from process with pid=%d',[FStatus, ProcessID]);
974 
975   TDbgDarwinThread(AThread).FIsSteppingBreakPoint := False;
976 end;
977 
978 initialization
979   DBG_VERBOSE := DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' {$IFDEF DBG_VERBOSE} , True {$ENDIF} );
980   DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
981 
982   RegisterDbgOsClasses(TOSDbgClasses.Create(
983     TDbgDarwinProcess,
984     TDbgDarwinThread,
985     TX86AsmDecoder
986   ));
987 
988 end.
989