unit kern_mdbg; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface function sys_mdbg_service(op:Integer;arg1,arg2:Pointer):Integer; implementation uses sysutils, errno, systm, kern_mtx, kern_condvar, kern_thr, kern_proc, subr_backtrace; type t_SetProcessProperty=packed record //0x48 f_0:QWORD; f_1:QWORD; f_2:QWORD; f_3:QWORD; f_4:QWORD; name:array[0..31] of AnsiChar; end; t_coredump_ret=packed record //0x28 ret :Integer; flags:Integer; data :array[0..3] of QWORD; end; t_pevt_state=(pevt_none,pevt_inited,pevt_wait,pevt_finish); p_mdbg_pevt=^t_mdbg_pevt; t_mdbg_pevt=record cv :t_cv; mtx:mtx; td_tid :Integer; td_cancel :Integer; td_ret :Integer; td_flags :Integer; td_state :t_pevt_state; crash_state:Integer; // Sce:record Flags :QWORD; PSM_AppName :array[0..3] of QWORD; PSM_SdbInfo :array[0..1] of QWORD; PSM_LogArea :array[0..3] of QWORD; Debug_UserObjArray:array[0..1] of QWORD; Debug_Gnm :array[0..1] of QWORD; end; // end; var g_mdbg_pevt:p_mdbg_pevt=nil; function init_mdbg_pevt:p_mdbg_pevt; var props:p_mdbg_pevt; begin mtx_lock(p_proc.p_mtx); props:=g_mdbg_pevt; if (props<>nil) then begin mtx_unlock(p_proc.p_mtx); Exit(props); end; props:=AllocMem(SizeOf(t_mdbg_pevt)); mtx_init(props^.mtx,'mdbg_pevt_MTX'); cv_init (@props^.cv,'mDBG Debug event'); props^.td_state:=pevt_inited; g_mdbg_pevt:=props; mtx_unlock(p_proc.p_mtx); Writeln('init_mdbg_pevt'); Exit(props); end; function SetProcessProperty(arg1:Pointer):Integer; var data :t_SetProcessProperty; props:p_mdbg_pevt; begin Result:=copyin(arg1,@data,SizeOf(t_SetProcessProperty)); if (Result<>0) then Exit; props:=init_mdbg_pevt; Result:=0; mtx_lock(p_proc.p_mtx); case String(data.name) of 'Sce.PSM:AppName': //1 begin props^.Sce.Flags :=props^.Sce.Flags or $02; props^.Sce.PSM_AppName[0]:=data.f_1; props^.Sce.PSM_AppName[1]:=data.f_2; props^.Sce.PSM_AppName[2]:=data.f_3; props^.Sce.PSM_AppName[3]:=data.f_4; end; 'Sce.PSM:SdbInfo': //2 begin props^.Sce.Flags :=props^.Sce.Flags or $04; props^.Sce.PSM_SdbInfo[0]:=data.f_1; props^.Sce.PSM_SdbInfo[1]:=data.f_2; end; 'Sce.PSM:LogArea': //3 begin props^.Sce.Flags :=props^.Sce.Flags or $08; props^.Sce.PSM_LogArea[0]:=data.f_1; props^.Sce.PSM_LogArea[1]:=data.f_2; props^.Sce.PSM_LogArea[2]:=data.f_3; props^.Sce.PSM_LogArea[3]:=data.f_4; end; 'Sce.Debug:UserObjArray': //4 begin props^.Sce.Flags :=props^.Sce.Flags or $10; props^.Sce.Debug_UserObjArray[0]:=data.f_1; props^.Sce.Debug_UserObjArray[1]:=data.f_2; end; 'Sce.Debug:Gnm': //5 begin props^.Sce.Flags :=props^.Sce.Flags or $20; props^.Sce.Debug_Gnm[0]:=data.f_1; props^.Sce.Debug_Gnm[1]:=data.f_2; end; else Result:=EINVAL; end; mtx_unlock(p_proc.p_mtx); if (Result<>0) then Exit; Writeln('SetProcessProperty("',data.name,'",0x', HexStr(data.f_1,16),',0x', HexStr(data.f_2,16),',0x', HexStr(data.f_3,16),',0x', HexStr(data.f_4,16),')'); end; function sys_mdbg_service(op:Integer;arg1,arg2:Pointer):Integer; var props:p_mdbg_pevt; ret,size:Integer; coredump_ret:t_coredump_ret; begin Result:=0; case op of 1: //SetProcessProperty begin Result:=SetProcessProperty(arg1); end; 3: //sceKernelDebugRaiseException begin print_error_td('sceKernelDebugRaiseException:0x'+HexStr(DWORD(arg1),8)); Assert(False); Result:=EINVAL; end; 4: //sceKernelDebugRaiseExceptionOnReleaseMode begin Writeln('sceKernelDebugRaiseExceptionOnReleaseMode:0x',HexStr(DWORD(arg1),8)); print_backtrace_td(stderr); Result:=0; end; 8: begin //signal coredump thread start and wait props:=init_mdbg_pevt; //td->td_dbgflags = td->td_dbgflags | 0x100; mtx_lock(props^.mtx); props^.td_tid:=curkthread^.td_tid; Result:=0; if (props^.td_cancel=0) then begin props^.td_state:=pevt_wait; cv_signal(@props^.cv); ret:=_cv_wait_sig(@props^.cv,@props^.mtx); Result:=0; props^.td_state:=pevt_inited; if (ret<>0) and (props^.td_cancel=0) then begin Result:=EINTR; end; end; props^.td_cancel:=0; if (props^.crash_state=0) then begin // end else begin Result:=EINVAL; end; if (Result=0) then begin coredump_ret:=Default(t_coredump_ret); coredump_ret.ret :=props^.td_ret; coredump_ret.flags:=props^.td_flags; mtx_unlock(props^.mtx); size:=Integer(arg2); if (size < 0) then begin Result:=EFAULT; end else begin if (DWORD(size) < $28) then begin // end else begin size:=$28; end; Result:=copyout(@coredump_ret,arg1,size); if (Result=0) then begin Writeln('mDBG: Debughandler starting(',curkthread^.td_tid,':',curkthread^.td_name,')'); end; end; Exit; end; mtx_unlock(props^.mtx); end; 9: //sceCoredumpUnregisterCoredumpHandler begin //cancel coredump thread and wait exit mtx_lock(p_proc.p_mtx); props:=g_mdbg_pevt; if (props<>nil) then begin mtx_lock(props^.mtx); props^.td_flags :=props^.td_flags or 1; props^.td_ret :=Integer(arg1); props^.td_cancel:=1; if (props^.td_state=pevt_wait) then begin cv_signal(@props^.cv); end; mtx_unlock(props^.mtx); mtx_unlock(p_proc.p_mtx); //TODO: wait thread exit Exit; end else begin Result:=ESRCH; end; mtx_unlock(p_proc.p_mtx); end; 10: //sceCoredumpAttach* begin //only in coredump thread //(td->td_dbgflags | 0x100)=0 && not sceSblACMgrIsSystemUcred Result:=EPERM; end; 11: begin init_mdbg_pevt; Result:=0; end; 12: begin //wait coredump thread start mtx_lock(p_proc.p_mtx); props:=g_mdbg_pevt; mtx_unlock(p_proc.p_mtx); if (props=nil) then begin Exit(EINVAL); end; mtx_lock(props^.mtx); if (props^.td_state=pevt_inited) then begin ret:=_cv_wait_sig(@props^.cv,@props^.mtx); if (ret<>-1) then begin Result:=ret; end else begin Result:=EINTR; end; end else if (props^.td_state<>pevt_wait) then begin if (props^.td_state=pevt_finish) then begin Result:=ESRCH; end else begin Result:=EAGAIN; end; end; mtx_unlock(props^.mtx); end; 13: begin //coredump thread reset mtx_lock(p_proc.p_mtx); //if (((td->td_dbgflags & 0x100) != 0) && (proc->debug_event == 0)) { // td->td_dbgflags = td->td_dbgflags & (~0x100); //} props:=g_mdbg_pevt; if (props<>nil) then begin mtx_lock(props^.mtx); props^.td_flags:=props^.td_flags and (not 1); if (arg1<>nil) then begin props^.td_state:=pevt_finish; end; mtx_unlock(props^.mtx); end; mtx_unlock(p_proc.p_mtx); end; 20: begin //td->td_dbgflags = td->td_dbgflags | 0x800; Result:=0; end; else begin print_error_td('sys_mdbg_service('+IntToStr(op)+')'); Assert(False); Result:=EINVAL; end; end; end; end.