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