FPPS4/sys/kern/kern_exec.pas

1903 lines
40 KiB
Plaintext

unit kern_exec;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
sysutils,
mqueue,
kern_param,
kern_thr,
vnode,
vuio,
vcapability,
elf64,
kern_rtld,
subr_dynlib;
function exec_alloc_args(args:p_image_args):Integer;
procedure exec_free_args(args:p_image_args);
function exec_copyin_args(args:p_image_args;
fname:pchar;
segflg:uio_seg;
argv:ppchar;
envv:ppchar):Integer;
function kern_execve(td:p_kthread;args:p_image_args):Integer;
function main_execve(fname:pchar;argv,envv:ppchar):Integer;
procedure main_switch_context;
function sys_execve(fname:pchar;argv,envv:ppchar):Integer;
implementation
uses
systm,
md_systm,
errno,
kern_proc,
kern_mtx,
vm,
vmparam,
vm_map,
vm_mmap,
sys_vm_object,
vm_pager,
vnamei,
vfs_lookup,
vmount,
vfile,
vstat,
vfcntl,
vfs_vnops,
vfs_subr,
kern_thread,
kern_budget,
kern_descrip,
kern_exit,
vfs_cache,
vnode_if,
sys_resource,
kern_resource,
sys_event,
machdep,
kern_dlsym,
kern_authinfo,
vfs_syscalls,
signal,
trap,
md_context,
subr_backtrace;
function exec_alloc_args(args:p_image_args):Integer;
begin
args^.buf:=AllocMem(PATH_MAX + ARG_MAX);
if (args^.buf=nil) then Exit(ENOMEM);
Result:=0;
end;
procedure exec_free_args(args:p_image_args);
begin
if (args^.buf<>nil) then
begin
FreeMem(args^.buf);
args^.buf:=nil;
end;
if (args^.fname_buf<>nil) then
begin
FreeMem(args^.fname_buf);
args^.fname_buf:=nil;
end;
end;
{
* Copy out argument and environment strings from the old process address
* space into the temporary string buffer.
}
function exec_copyin_args(args :p_image_args;
fname :pchar;
segflg:uio_seg;
argv :ppchar;
envv :ppchar):Integer;
label
err_exit;
var
argp,envp:pchar;
error:Integer;
length:int64;
function f_fuword_argv:Boolean; inline;
begin
if (segflg=UIO_SYSSPACE) then
begin
argp:=md_fuword(argv^);
end else
begin
argp:=fuword(argv^);
end;
Inc(argv);
Result:=(argp<>nil);
end;
function f_fuword_envv:Boolean; inline;
begin
if (segflg=UIO_SYSSPACE) then
begin
envp:=md_fuword(envv^);
end else
begin
envp:=fuword(envv^);
end;
Inc(envv);
Result:=(envp<>nil);
end;
begin
args^:=Default(t_image_args);
if (argv=nil) then
begin
Exit(EFAULT);
end;
{
* Allocate demand-paged memory for the file name, argument, and
* environment strings.
}
error:=exec_alloc_args(args);
if (error<>0) then
begin
Exit(error);
end;
{
* Copy the file name.
}
if (fname<>nil) then
begin
args^.fname:=args^.buf;
if (segflg=UIO_SYSSPACE) then
begin
error:=copystr (fname, args^.fname, PATH_MAX, @length);
end else
begin
error:=copyinstr(fname, args^.fname, PATH_MAX, @length);
end;
if (error<>0) then goto err_exit;
end else
begin
length:=0;
end;
args^.begin_argv:=args^.buf + length;
args^.endp:=args^.begin_argv;
args^.stringspace:=ARG_MAX;
{
* extract arguments first
}
while (f_fuword_argv) do
begin
if (argp=Pointer(-1)) then
begin
error:=EFAULT;
goto err_exit;
end;
if (segflg=UIO_SYSSPACE) then
begin
error:=copystr (argp, args^.endp, args^.stringspace, @length);
end else
begin
error:=copyinstr(argp, args^.endp, args^.stringspace, @length);
end;
if (error<>0) then
begin
if (error=ENAMETOOLONG) then
begin
error:=E2BIG;
end;
goto err_exit;
end;
Dec(args^.stringspace,length);
Inc(args^.endp ,length);
Inc(args^.argc);
end;
args^.begin_envv:=args^.endp;
{
* extract environment strings
}
if (envv<>nil) then
begin
while (f_fuword_envv) do
begin
if (envp=Pointer(-1)) then
begin
error:=EFAULT;
goto err_exit;
end;
if (segflg=UIO_SYSSPACE) then
begin
error:=copystr (envp, args^.endp, args^.stringspace, @length);
end else
begin
error:=copyinstr(envp, args^.endp, args^.stringspace, @length);
end;
if (error<>0) then
begin
if (error=ENAMETOOLONG) then
begin
error:=E2BIG;
end;
goto err_exit;
end;
Dec(args^.stringspace,length);
Inc(args^.endp ,length);
Inc(args^.envc);
end;
end;
Exit(0);
err_exit:
exec_free_args(args);
Exit(error);
end;
{
* Destroy old address space, and allocate a new stack
* The new stack is only SGROWSIZ large because it is grown
* automatically in trap.c.
}
function exec_new_vmspace(imgp:p_image_params):Integer;
var
error:Integer;
vmspace:p_vmspace;
map:vm_map_t;
//obj:vm_object_t;
shared_page_base:Pointer;
shared_page_len :QWORD;
sv_minuser:QWORD;
sv_maxuser:QWORD;
stack_addr:QWORD;
ssiz:QWORD;
limit:QWORD;
is_diag:Boolean;
begin
vmspace:=p_proc.p_vmspace;
{ May be called with Giant held }
//EVENTHANDLER_INVOKE(process_exec, p, imgp);
{
* Blow away entire process VM, if address space not shared,
* otherwise, create a new VM space so that other threads are
* not disrupted
}
map:=@vmspace^.vm_map;
sv_minuser:=VM_MINUSER_ADDRESS;
sv_maxuser:=VM_MAXUSER_ADDRESS;
if (vm_map_min(map)=sv_minuser) and
(vm_map_max(map)=sv_maxuser) then
begin
//shmexit(vmspace);
//pmap_remove_pages(vmspace_pmap(vmspace));
vm_map_remove(map, vm_map_min(map), vm_map_max(map));
end else
begin
error:=vmspace_exec(sv_minuser, sv_maxuser);
if (error<>0) then Exit(error);
end;
if (DWORD(p_proc.p_budget_ptype) < 2) then
begin
//(vmspace->vm_map).needs_wakeup:=1;
//dmem_start_app_process(proc);
end else
begin
//cred = __crget();
//copy authinfo
g_authinfo:=imgp^.authinfo;
is_diag:=sceSblACMgrIsDiagProcess(@g_authinfo);
//crfree(cred);
//(vmspace->vm_map).needs_wakeup:=is_diag<>0;
if (is_diag) then
begin
//dmem_start_app_process(proc);
end;
end;
//budget
ssiz:=MAXSSIZ;
if (g_self_loading<>0) and
(p_proc.p_budget_ptype=PTYPE_BIG_APP) and
((g_appinfo.mmap_flags and 1)<>0) then
begin
limit:=game_fmem_size + ssiz;
if (bigapp_max_fmem_size < limit) then
begin
limit:=bigapp_max_fmem_size;
end;
set_bigapp_limits(limit,0);
end;
//
//calc shared page addres
vmspace^.sv_usrstack:=Pointer(USRSTACK {- (aslr_offset and $ffc000)});
{ Map a shared page }
shared_page_base:=vmspace^.sv_usrstack;
shared_page_len :=p_proc.p_sysent^.sv_shared_page_len;
//mapping shared page (sv_usrstack_len=0x4000)
error:=vm_map_fixed(map,nil,0,
QWORD(shared_page_base), shared_page_len,
VM_PROT_RW,
VM_PROT_RW or VM_PROT_EXECUTE,
MAP_INHERIT_SHARE or
MAP_ACC_NO_CHARGE,
MAP_COW_NO_BUDGET,
nil);
if (error<>0) then
begin
Exit(error);
end;
//copy sigcode
with p_proc.p_sysent^ do
if (sv_sigcode<>nil) and
(sv_szsigcode<>nil) then
begin
copyout(sv_sigcode,shared_page_base,sv_szsigcode^);
end;
//set prot
vm_map_protect(map,
QWORD(shared_page_base),
QWORD(shared_page_base)+shared_page_len,
VM_PROT_READ or VM_PROT_EXECUTE,
False);
{
obj:=sv^.sv_shared_page_obj;
if (obj<>nil) then
begin
vm_object_reference(obj);
error:=vm_map_fixed(map, obj, 0,
sv^.sv_shared_page_base, sv^.sv_shared_page_len,
VM_PROT_READ or VM_PROT_EXECUTE,
VM_PROT_READ or VM_PROT_EXECUTE,
MAP_INHERIT_SHARE or MAP_ACC_NO_CHARGE);
if (error<>0) then
begin
vm_object_deallocate(obj);
Exit(error);
end;
end;
}
ssiz:=MAXSSIZ;
stack_addr:=QWORD(vmspace^.sv_usrstack) - ssiz;
Writeln('vm_map_stack:0x',HexStr(stack_addr,11),'..0x',HexStr(stack_addr+ssiz,11));
error:=vm_map_stack(map,
stack_addr,ssiz,
VM_PROT_RW,VM_PROT_ALL,
MAP_STACK_GROWS_DOWN,
nil);
if (error<>0) then
begin
Exit(error);
end;
if (p_proc.p_vm_container=1) then
begin
error:=vm_map_wire(map,stack_addr,QWORD(vmspace^.sv_usrstack),VM_MAP_WIRE_USER or 8);
if (error<>0) then Exit;
end;
vm_map_set_name(map,stack_addr,QWORD(vmspace^.sv_usrstack),'main stack');
{ vm_ssize and vm_maxsaddr are somewhat antiquated concepts in the
* VM_STACK case, but they are still used to monitor the size of the
* process stack so we can check the stack rlimit.
}
vmspace^.vm_ssize :=sgrowsiz shr PAGE_SHIFT;
vmspace^.vm_maxsaddr:=vmspace^.sv_usrstack - ssiz;
Exit(0);
end;
function exec_copyout_strings(imgp:p_image_params):PQWORD;
var
vms:p_vmspace;
argc,envc:Integer;
vectp:ppchar;
stringp:pchar;
destp:Pointer;
arginfo:p_ps_strings;
stack_base:PQWORD;
execpath_len:QWORD;
canary:array[0..7] of QWORD;
begin
{
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
}
if (imgp^.execpath<>nil) and (imgp^.auxargs<>nil) then
execpath_len:=strlen(imgp^.execpath) + 1
else
execpath_len:=0;
vms:=p_proc.p_vmspace;
vms^.ps_strings:=(vms^.sv_usrstack-SizeOf(t_ps_strings));
arginfo:=vms^.ps_strings;
destp:=Pointer(arginfo);
{
* Copy the image path for the rtld.
}
if (execpath_len<>0) then
begin
Dec(destp,execpath_len);
imgp^.execpathp:=destp;
copyout(imgp^.execpath,destp,execpath_len);
end;
{
* Prepare the canary for SSP.
}
//arc4rand(canary, sizeof(canary), 0);
canary[0]:=QWORD($FEEDBABEFEEDBABE);
canary[1]:=QWORD($FEEDBABEFEEDBABE);
canary[2]:=QWORD($FEEDBABEFEEDBABE);
canary[3]:=QWORD($FEEDBABEFEEDBABE);
canary[4]:=QWORD($FEEDBABEFEEDBABE);
canary[5]:=QWORD($FEEDBABEFEEDBABE);
canary[6]:=QWORD($FEEDBABEFEEDBABE);
canary[7]:=QWORD($FEEDBABEFEEDBABE);
Dec(destp,sizeof(canary));
imgp^.canary:=destp;
copyout(@canary, destp, sizeof(canary));
imgp^.canarylen:=sizeof(canary);
{
* Prepare the pagesizes array.
}
Dec(destp,sizeof(pagesizes));
destp:=AlignUp(destp,8);
imgp^.pagesizes:=destp;
copyout(@pagesizes, destp, sizeof(pagesizes));
imgp^.pagesizeslen:=Length(pagesizes);
Dec(destp,ARG_MAX-imgp^.args^.stringspace);
destp:=AlignUp(destp,8);
{
* If we have a valid auxargs ptr, prepare some room
* on the stack.
}
if (imgp^.auxargs<>nil) then
begin
{
* 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
* lower compatibility.
}
if (imgp^.auxarg_size<>0) then
begin
imgp^.auxarg_size:=imgp^.auxarg_size;
end else
begin
imgp^.auxarg_size:=(AT_COUNT * 2);
end;
{
* The '+ 2' is for the nil pointers at the end of each of
* the arg and env vector sets,and imgp^.auxarg_size is room
* for argument of Runtime loader.
}
vectp:=(destp - (imgp^.args^.argc + imgp^.args^.envc + 2 + imgp^.auxarg_size) * sizeof(Pointer));
end else
begin
{
* The '+ 2' is for the nil pointers at the end of each of
* the arg and env vector sets
}
vectp:=(destp - (imgp^.args^.argc + imgp^.args^.envc + 2) * sizeof(Pointer));
end;
{
* vectp also becomes our initial stack base
}
stack_base:=Pointer(vectp);
stringp:=imgp^.args^.begin_argv;
argc:=imgp^.args^.argc;
envc:=imgp^.args^.envc;
{
* Copy out strings - arguments and environment.
}
copyout(stringp, destp, ARG_MAX - imgp^.args^.stringspace);
{
* Fill in "ps_strings" struct for ps, w, etc.
}
suword(arginfo^.ps_argvstr, vectp);
suword32(PDWORD(@arginfo^.ps_nargvstr)^, argc);
{
* Fill in argument portion of vector table.
}
while (argc>0) do
begin
suword(vectp^, destp);
Inc(vectp);
while (stringp^<>#0) do
begin
Inc(stringp);
Inc(destp);
end;
Inc(stringp);
Inc(destp);
Dec(argc);
end;
{ a nil vector table pointer separates the argp's from the envp's }
suword(vectp^, nil);
Inc(vectp);
suword(arginfo^.ps_envstr, vectp);
suword32(PDWORD(@arginfo^.ps_nenvstr)^, envc);
{
* Fill in environment portion of vector table.
}
while (envc>0) do
begin
suword(vectp^, destp);
Inc(vectp);
while (stringp^<>#0) do
begin
Inc(stringp);
Inc(destp);
end;
Inc(stringp);
Inc(destp);
Dec(envc);
end;
{ end of vector table is a nil pointer }
suword(vectp^, nil);
Exit(stack_base);
end;
{
* Check permissions of file to execute.
* Called with imgp^.vp locked.
* Return 0 for success or error code on failure.
}
function exec_check_permissions(imgp:p_image_params):Integer;
var
vp:p_vnode;
attr:p_vattr;
error:Integer;
begin
vp:=imgp^.vp;
attr:=imgp^.attr;
{ Get file attributes }
error:=VOP_GETATTR(vp, attr);
if (error<>0) then Exit(error);
{
* 1) Check if file execution is disabled for the filesystem that
* this file resides on.
* 2) Ensure that at least one execute bit is on. Otherwise, a
* privileged user will always succeed, and we don't want this
* to happen unless the file really is executable.
* 3) Ensure that the file is a regular file.
}
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_NOEXEC)<>0) or
((attr^.va_mode and (S_IXUSR or S_IXGRP or S_IXOTH))=0) or
(attr^.va_type<>VREG) then
begin
Exit(EACCES);
end;
{
* Zero length files can't be exec'd
}
if (attr^.va_size=0) then Exit(ENOEXEC);
{
* Check for execute permission to file based on current credentials.
}
error:=VOP_ACCESS(vp, VEXEC);
if (error<>0) then Exit(error);
{
* Check number of open-for-writes on the file and deny execution
* if there are any.
}
if (vp^.v_writecount<>0) then Exit(ETXTBSY);
{
* Call filesystem specific open routine (which does nothing in the
* general case).
}
error:=VOP_OPEN(vp, FREAD, nil);
if (error=0) then imgp^.opened:=1;
Exit(error);
end;
function scan_load_sections(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer;
var
i:Integer;
hdr:p_elf64_hdr;
total_size:QWORD;
text_addr :QWORD;
text_size :QWORD;
data_addr :QWORD;
data_size :QWORD;
relro_addr:QWORD;
relro_size:QWORD;
max_size1 :QWORD;
max_size2 :QWORD;
p_memsz :QWORD;
p_vaddr :QWORD;
p_filesz :QWORD;
p_offset :QWORD;
addr:QWORD;
size:QWORD;
used :QWORD;
limit:QWORD;
p_type :Elf64_Word;
p_flags :Byte;
wire :Byte;
_2mb_mode:Boolean;
used_mode_2m:Boolean;
auxargs:p_elf64_auxargs;
vms:p_vmspace;
cache:Pointer;
begin
Result:=0;
total_size:=0;
text_addr :=0;
text_size :=0;
data_addr :=0;
data_size :=0;
relro_addr:=0;
relro_size:=0;
hdr:=imgp^.image_header;
if (p_proc.p_budget_ptype=PTYPE_BIG_APP) then
begin
_2mb_mode:=((g_mode_2mb or 1)=3) or //M2MB_READONLY,M2MB_ENABLE
((g_self_loading<>0) and (g_mode_2mb=M2MB_DEFAULT));
end else
begin
_2mb_mode:=False;
end;
cache:=nil;
if (count<>0) then
begin
max_size1:=0;
max_size2:=0;
scan_max_size(imgp,phdr,count,max_size1,max_size2);
if ((g_appinfo.mmap_flags and 1)<>0) and
(g_self_loading<>0) then
begin
size:=g_mode_2mb_size;
if (max_size2 < g_mode_2mb_size) then
begin
size:=max_size2;
end;
p_offset:=0;
if ((g_mode_2mb or 1)=3) then //M2MB_READONLY,M2MB_ENABLE
begin
p_offset:=size;
end;
p_memsz:=game_fmem_size + max_size1;
if (bigapp_max_fmem_size < (p_memsz - p_offset)) then
begin
Writeln(stderr,'vm_budget ENOMEM');
Exit(ENOMEM);
end;
if ((DWORD(g_mode_2mb) - 2) < 2) then
begin
p_memsz:=p_memsz - size;
size:=0;
end else
begin
if (g_mode_2mb=M2MB_DISABLE) then
begin
size:=0;
end else
begin
size:=max_size2;
if (g_mode_2mb<>M2MB_DEFAULT) then
begin
Writeln(stderr,'unknown 2mb mode');
Assert(false,'unknown 2mb mode');
end;
end;
end;
if (bigapp_max_fmem_size < p_memsz) then
begin
p_memsz:=bigapp_max_fmem_size;
end;
set_bigapp_limits(p_memsz,size);
end;
if ((g_mode_2mb and $fffffffe)=2) then //M2MB_READONLY,M2MB_ENABLE
begin
size:=g_mode_2mb_rsrv;
if (size<=max_size2) then
begin
max_size2:=g_mode_2mb_rsrv;
end;
used :=vm_budget_used (PTYPE_BIG_APP,field_mlock);
limit:=vm_budget_limit(PTYPE_BIG_APP,field_mlock);
if (limit < (used + (max_size1 - max_size2))) then
begin
Writeln(stderr,'vm_budget ENOMEM');
Exit(ENOMEM);
end;
end;
wire:=ord(p_proc.p_budget_ptype=PTYPE_BIG_APP);
For i:=0 to count-1 do
begin
p_type :=phdr^.p_type;
p_memsz:=phdr^.p_memsz;
if ((p_type=PT_SCE_RELRO) or (p_type=PT_LOAD)) and (p_memsz<>0) then
begin
p_flags:=VM_PROT_READ or VM_PROT_WRITE;
if (p_type<>PT_SCE_RELRO) then
begin
p_flags:=convert_prot(phdr^.p_flags);
end;
p_vaddr:=phdr^.p_vaddr;
if (hdr^.e_type=ET_SCE_DYNEXEC) then
begin
p_vaddr:=p_vaddr + QWORD(imgp^.reloc_base);
end;
p_filesz:=phdr^.p_filesz;
p_offset:=phdr^.p_offset;
if (p_type=PT_SCE_RELRO) and (p_proc.p_budget_ptype=PTYPE_BIG_APP) then
begin
if (_2mb_mode=false) then
begin
used_mode_2m:=false;
end else
begin
used_mode_2m:=is_used_mode_2mb(phdr,0,0);
end;
Result:=self_load_section(imgp,
i,
p_vaddr,
p_offset,
p_memsz,
p_filesz,
p_flags,
wire,
used_mode_2m,
'executable',
cache);
end else
begin
if (_2mb_mode=false) then
begin
used_mode_2m:=false;
end else
begin
used_mode_2m:=is_used_mode_2mb(phdr,0,p_proc.p_budget_ptype);
end;
Result:=self_load_section(imgp,
i,
p_vaddr,
p_offset,
p_memsz,
p_filesz,
p_flags,
wire,
used_mode_2m,
'executable',
cache);
end;
if (Result<>0) then
begin
FreeMem(cache);
Exit;
end;
addr:=(p_vaddr and QWORD(not PAGE_MASK));
size:=((p_vaddr and PAGE_MASK) + PAGE_MASK + p_memsz) and QWORD(not PAGE_MASK);
if (p_type=PT_SCE_RELRO) then
begin
relro_addr:=addr;
relro_size:=size;
end else
if ((phdr^.p_flags and PF_X)<>0) and (text_size < size) then
begin
text_size:=size;
text_addr:=addr;
end else
begin
data_size:=size;
data_addr:=addr;
end;
total_size:=total_size+size;
end;
Inc(phdr);
end;
end;
FreeMem(cache);
if (data_addr=0) and (data_size=0) then
begin
data_addr:=text_addr;
data_size:=text_size;
end;
if (data_size > lim_cur(RLIMIT_DATA)) or
(text_size > maxtsiz) or
(total_size > lim_cur(RLIMIT_VMEM)) then
begin
Exit(ENOMEM);
end;
Writeln(' text addr=0x',HexStr(text_addr ,16),'..',HexStr(text_addr +text_size ,16));
Writeln(' data addr=0x',HexStr(data_addr ,16),'..',HexStr(data_addr +data_size ,16));
Writeln(' relro addr=0x',HexStr(relro_addr,16),'..',HexStr(relro_addr+relro_size,16));
vms:=p_proc.p_vmspace;
vms^.vm_tsize:=text_size shr PAGE_SHIFT;
vms^.vm_taddr:=Pointer(text_addr);
vms^.vm_dsize:=data_size shr PAGE_SHIFT;
vms^.vm_daddr:=Pointer(data_addr);
imgp^.relro_addr:=Pointer(relro_addr);
imgp^.relro_size:=relro_size;
addr:=0;
if (imgp^.hdr_e_type<>hdr^.e_type) then
begin
//ET_SCE_EXEC hack
addr:=QWORD(imgp^.reloc_base);
end else
if (hdr^.e_type=ET_SCE_DYNEXEC) then
begin
addr:=text_addr;
end;
imgp^.entry_addr:=Pointer(addr + hdr^.e_entry);
Writeln(' entry_addr=0x',HexStr(imgp^.entry_addr));
//Do not update if the ET_SCE_EXEC hack is used
if (imgp^.hdr_e_type=hdr^.e_type) then
begin
imgp^.reloc_base:=Pointer(addr);
end;
auxargs:=AllocMem(SizeOf(t_elf64_auxargs));
auxargs^.execfd:=-1;
auxargs^.phdr :=0;
auxargs^.phent :=hdr^.e_phentsize;
auxargs^.phnum :=hdr^.e_phnum;
auxargs^.pagesz:=PAGE_SIZE;
auxargs^.base :=(QWORD(vms^.vm_daddr) + PAGE_MASK + lim_max(RLIMIT_DATA)) and QWORD(not PAGE_MASK);
auxargs^.flags :=0;
auxargs^.entry :=QWORD(imgp^.entry_addr);
p_proc.p_osrel:=$dbbcc;
imgp^.auxargs:=auxargs;
MoveChar0(imgp^.execpath^,p_proc.p_prog_name,1024);
if (relro_addr<>0) and (relro_size<>0) then
begin
Result:=vm_map_protect(@vms^.vm_map,relro_addr,relro_addr+relro_size,VM_PROT_READ,False);
Result:=vm_mmap_to_errno(Result);
end;
end;
function dynlib_proc_initialize_step1(imgp:p_image_params):Integer;
var
vms:p_vmspace;
obj:p_lib_info;
text_addr:Pointer;
eh_frame_addr:Pointer;
eh_frame_size:QWORD;
begin
Result:=0;
TAILQ_INIT(@dynlibs_info.list_global);
TAILQ_INIT(@dynlibs_info.list_main);
TAILQ_INIT(@dynlibs_info.init_list);
TAILQ_INIT(@dynlibs_info.fini_list);
TAILQ_INIT(@dynlibs_info.obj_list);
dynlibs_info.obj_count :=0;
dynlibs_info.tls_last_offset :=0;
dynlibs_info.tls_last_size :=0;
dynlibs_info.tls_static_space:=0;
dynlibs_info.tls_count :=1;
dynlibs_info.tls_max :=1;
obj:=obj_new();
obj^.relocbase:=imgp^.reloc_base;
vms:=p_proc.p_vmspace;
text_addr:=vms^.vm_taddr;
obj^.map_base:=text_addr;
obj^.text_size:=vms^.vm_tsize * PAGE_SIZE;
obj^.data_addr:=vms^.vm_daddr;
obj^.data_size:=vms^.vm_dsize * PAGE_SIZE;
obj^.map_size :=((QWORD(obj^.data_addr) + obj^.data_size + PAGE_MASK) and QWORD(not PAGE_MASK)) - QWORD(text_addr);
obj^.relro_addr:=imgp^.relro_addr;
obj^.relro_size:=imgp^.relro_size;
obj^.tls_index :=1;
obj^.tls_size :=imgp^.tls_size;
obj^.tls_align :=imgp^.tls_align;
obj^.tls_init_size:=imgp^.tls_init_size;
obj^.tls_init_addr:=imgp^.tls_init_addr;
eh_frame_addr:=nil;
eh_frame_size:=0;
if (elf64_get_eh_frame_info(imgp^.eh_frame_hdr_addr,
imgp^.eh_frame_hdr_size,
0,
obj^.text_size + QWORD(text_addr),
@eh_frame_addr,
@eh_frame_size)<>0) then
begin
eh_frame_addr:=nil;
eh_frame_size:=0;
end;
obj^.eh_frame_hdr_addr:=imgp^.eh_frame_hdr_addr;
obj^.eh_frame_hdr_size:=imgp^.eh_frame_hdr_size;
obj^.eh_frame_addr :=eh_frame_addr;
obj^.eh_frame_size :=eh_frame_size;
obj^.entry_addr :=imgp^.entry_addr;
obj_set_lib_path(obj,imgp^.execpath);
obj^.rtld_flags.mainprog:=1;
obj^.loaded:=4;
dynlibs_info.libprogram:=obj;
if (imgp^.dyn_exist=0) then
begin
dynlibs_info.dyn_non_exist:=1;
obj^.rel_data:=nil;
//
end else
begin
dynlibs_info.dyn_non_exist:=0;
Result:=acquire_per_file_info_obj(imgp,obj);
if (Result<>0) then
begin
obj_free(dynlibs_info.libprogram);
dynlibs_info.libprogram:=nil;
end;
end;
end;
function dynlib_proc_initialize_step2(imgp:p_image_params):Integer;
var
obj,tail:p_lib_info;
init_proc_addr:Pointer;
fini_proc_addr:Pointer;
begin
Result:=0;
dynlibs_info.proc_param_addr:=imgp^.proc_param_addr;
dynlibs_info.proc_param_size:=imgp^.proc_param_size;
obj:=dynlibs_info.libprogram;
if (imgp^.dyn_exist=0) then
begin
dynlibs_add_obj(obj);
Exit;
end;
Result:=digest_dynamic(obj);
if (Result<>0) then
begin
Writeln(StdErr,'dynlib_proc_initialize_step2:','digest_dynamic()=',Result);
Exit;
end;
init_relo_bits(obj);
dynlibs_add_obj(obj);
dynlibs_info.sym_zero.st_info :=(STB_GLOBAL shl 4) or STT_NOTYPE;
dynlibs_info.sym_zero.st_shndx:=SHN_UNDEF;
dynlibs_info.sym_zero.st_value:=-Int64(obj^.relocbase);
init_proc_addr:=obj^.fini_proc_addr;
fini_proc_addr:=obj^.init_proc_addr;
obj^.fini_proc_addr:=nil;
obj^.init_proc_addr:=nil;
tail:=TAILQ_LAST(@dynlibs_info.obj_list);
if (tail=nil) then
begin
tail:=dynlibs_info.obj_list.tqh_first;
end;
initlist_add_objects(dynlibs_info.fini_proc_list,
dynlibs_info.obj_list.tqh_first,
tail,
dynlibs_info.init_proc_list);
obj^.init_proc_addr:=init_proc_addr;
obj^.fini_proc_addr:=fini_proc_addr;
///
end;
function dynlib_copy_executable_sdk_version():Integer;
var
proc_param:pSceProcParam;
begin
proc_param:=dynlibs_info.proc_param_addr;
//
if (proc_param=nil) then
begin
p_proc.p_sdk_version:=0;
Result:=0;
end else
begin
Result:=copyin(@proc_param^.SDK_version,@p_proc.p_sdk_version,SizeOf(Integer));
end;
end;
procedure dynlib_proc_initialize_step3(imgp:p_image_params);
label
_dyn_not_exist;
var
obj:p_lib_info;
str:RawByteString;
err:Integer;
flags:DWORD;
begin
err:=0;
obj:=nil;
//if (td_proc->sdk_version < 0x5000000) {
// *(byte *)&dynlibs_info->bits = *(byte *)&dynlibs_info->bits | 0x20; (find_symdef mode)
//}
if (imgp^.dyn_exist=0) then goto _dyn_not_exist;
flags:=$40; //priv libs?
if (p_proc.p_budget_ptype=PTYPE_BIG_APP) then flags:=flags or $20; //vm_map_wire
pick_obj(dynlibs_info.libprogram);
str:='/libkernel.sprx';
obj:=preload_prx_modules(pchar(str),flags,err);
dynlibs_info.libkernel:=obj;
if (obj=nil) then
begin
Writeln(StdErr,'preload_prx_modules:',str,' not loaded');
end;
str:='/libSceLibcInternal.sprx';
obj:=preload_prx_modules(pchar(str),flags,err);
if (obj=nil) then
begin
Writeln(StdErr,'preload_prx_modules:',str,' not loaded');
end;
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
begin
objlist_push_tail(dynlibs_info.list_main,obj);
Inc(obj^.ref_count);
objlist_push_tail(obj^.dagmembers,obj);
objlist_push_tail(obj^.dldags ,obj);
//
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
dynlibs_info.rep_unpf:=do_dlsym(dynlibs_info.libkernel,'sceKernelReportUnpatchedFunctionCall',nil,0);
dynlibs_info.__freeze:=do_dlsym(dynlibs_info.libkernel,'__freeze','libkernel_sysc_se', 0);
dynlibs_info.sysc_s00:=do_dlsym(dynlibs_info.libkernel,'sysc_s00','libkernel_sysc_se', 0);
dynlibs_info.sysc_e00:=do_dlsym(dynlibs_info.libkernel,'sysc_e00','libkernel_sysc_se', 0);
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
begin
dynlib_initialize_pltgot_each(obj);
//
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
if (dynlibs_info.libkernel=nil) then
begin
//error
Exit;
end;
imgp^.entry_addr:=dynlibs_info.libkernel^.entry_addr;
p_proc.p_libkernel_start_addr:=dynlibs_info.libkernel^.map_base;
p_proc.p_libkernel___end_addr:=dynlibs_info.libkernel^.map_base + dynlibs_info.libkernel^.text_size;
_dyn_not_exist:
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
begin
if not alloc_obj_id(obj) then
begin
Assert(False,'ID for PRX cannot be assigned.');
end;
//
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
end;
function exec_self_imgact(imgp:p_image_params):Integer;
var
hdr :p_elf64_hdr;
phdr:p_elf64_phdr;
reloc_base:Pointer;
begin
Result:=0;
if (imgp=nil) then Exit(EINVAL);
hdr:=imgp^.image_header;
if (hdr=nil) then Exit(EINVAL);
Case hdr^.e_type of
ET_SCE_EXEC ,
ET_SCE_REPLAY_EXEC,
ET_SCE_DYNEXEC :
else
begin
Writeln(StdErr,'exec_self_imgact:',imgp^.execpath,' unspported e_type:0x',HexStr(hdr^.e_type,4));
Exit(ENOEXEC);
end;
end;
if (hdr^.e_machine<>EM_X86_64) then
begin
Writeln(StdErr,'exec_self_imgact:',imgp^.execpath,' unspported e_machine:',hdr^.e_machine);
Exit(ENOEXEC);
end;
imgp^.hdr_e_type:=hdr^.e_type;
phdr:=get_elf_phdr(hdr);
Result:=scan_phdr(imgp,phdr,hdr^.e_phnum);
if (Result<>0) then
begin
Writeln(StdErr,'exec_self_imgact:','found illegal segment header in ',imgp^.execpath);
Exit;
end;
if (imgp^.dyn_exist=0) and (hdr^.e_type=ET_SCE_DYNEXEC) then
begin
Writeln(StdErr,'exec_self_imgact:','illegal ELF file image',imgp^.execpath);
Exit(ENOEXEC);
end;
rtld_load_auth(imgp);
case hdr^.e_type of
ET_EXEC:
begin
Exit(ENOEXEC);
end;
ET_SCE_REPLAY_EXEC:
begin
g_appinfo.mmap_flags:=g_appinfo.mmap_flags or 2; //is_system ???
end;
ET_SCE_DYNEXEC:
begin
reloc_base:=Pointer(PROC_IMAGE_AREA_START);
//
imgp^.reloc_base :=reloc_base;
imgp^.dyn_vaddr :=reloc_base+QWORD(imgp^.dyn_vaddr );
imgp^.tls_init_addr :=reloc_base+QWORD(imgp^.tls_init_addr );
imgp^.eh_frame_hdr_addr:=reloc_base+QWORD(imgp^.eh_frame_hdr_addr);
imgp^.proc_param_addr :=reloc_base+QWORD(imgp^.proc_param_addr );
end;
ET_SCE_EXEC:
if (PROC_IMAGE_AREA_START=_PROC_AREA_START_1) then
begin
//hack
hdr^.e_type:=ET_SCE_DYNEXEC;
//
reloc_base:=Pointer(_PROC_AREA_START_1);
//
imgp^.reloc_base :=reloc_base;
imgp^.dyn_vaddr :=reloc_base+QWORD(imgp^.dyn_vaddr );
imgp^.tls_init_addr :=reloc_base+QWORD(imgp^.tls_init_addr );
imgp^.eh_frame_hdr_addr:=reloc_base+QWORD(imgp^.eh_frame_hdr_addr);
imgp^.proc_param_addr :=reloc_base+QWORD(imgp^.proc_param_addr );
end;
else;
end;
if (imgp^.dyn_exist=0) then
begin
//
end else
begin
Result:=scan_dyn_offset(imgp,phdr,hdr^.e_phnum);
if (Result<>0) then Exit;
end;
VOP_UNLOCK(imgp^.vp, 0);
Result:=exec_new_vmspace(imgp);
vn_lock(imgp^.vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
if (Result<>0) then Exit;
imgp^.obj:=vm_pager_allocate(OBJT_SELF,
imgp^.vp,
imgp^.max_addr-imgp^.min_addr,
1,
0);
vm_object_set_budget(imgp^.obj,p_proc.p_budget_ptype);
Result:=scan_load_sections(imgp,phdr,hdr^.e_phnum);
if (Result<>0) then
begin
Exit;
end;
Result:=dynlib_proc_initialize_step1(imgp);
if (Result<>0) then
begin
Writeln(StdErr,'exec_self_imgact:',imgp^.execpath,' dynlib_proc_initialize_step1:',Result);
Exit;
end;
Result:=dynlib_proc_initialize_step2(imgp);
if (Result<>0) then
begin
Writeln(StdErr,'exec_self_imgact:',imgp^.execpath,' dynlib_proc_initialize_step1:',Result);
Exit;
end;
Result:=dynlib_copy_executable_sdk_version();
if (Result<>0) then
begin
Writeln(StdErr,'exec_self_imgact:','sdk version is not found in ',imgp^.execpath);
Exit;
end;
if (p_proc.p_vm_container=1) then
begin
vm_map_lock (p_proc.p_vmspace);
vm_map_modflags(p_proc.p_vmspace,MAP_WIREFUTURE or 4,0);
vm_map_unlock (p_proc.p_vmspace);
end;
end;
procedure AUXARGS_ENTRY(var pos:PPointer;id,val:QWORD); inline;
begin
suword(pos^, Pointer(id )); Inc(pos);
suword(pos^, Pointer(val)); Inc(pos);
end;
procedure AUXARGS_ENTRY(var pos:PPointer;id:QWORD;val:Pointer); inline;
begin
suword(pos^, Pointer(id )); Inc(pos);
suword(pos^, Pointer(val)); Inc(pos);
end;
function self_orbis_fixup(stack_base:PPointer;imgp:p_image_params):Integer;
const
osreldate=$000DBBA0;
mp_ncpus=8;
var
args:p_elf64_auxargs;
base:PPointer;
pos :PPointer;
begin
args:=imgp^.auxargs;
base:=stack_base^;
pos:=base + (imgp^.args^.argc + imgp^.args^.envc + 2);
if (args^.execfd<>-1) then
begin
AUXARGS_ENTRY(pos, AT_EXECFD, args^.execfd);
end;
AUXARGS_ENTRY(pos, AT_PHDR , args^.phdr );
AUXARGS_ENTRY(pos, AT_PHENT , args^.phent );
AUXARGS_ENTRY(pos, AT_PHNUM , args^.phnum );
AUXARGS_ENTRY(pos, AT_PAGESZ, args^.pagesz);
AUXARGS_ENTRY(pos, AT_FLAGS , args^.flags );
AUXARGS_ENTRY(pos, AT_ENTRY , args^.entry );
AUXARGS_ENTRY(pos, AT_BASE , args^.base );
if (imgp^.execpathp<>nil) then
begin
AUXARGS_ENTRY(pos, AT_EXECPATH, imgp^.execpathp);
end;
AUXARGS_ENTRY(pos, AT_OSRELDATE, osreldate);
if (imgp^.canary<>nil) then
begin
AUXARGS_ENTRY(pos, AT_CANARY , imgp^.canary );
AUXARGS_ENTRY(pos, AT_CANARYLEN, imgp^.canarylen);
end;
AUXARGS_ENTRY(pos, AT_NCPUS, mp_ncpus);
if (imgp^.pagesizes<>nil) then
begin
AUXARGS_ENTRY(pos, AT_PAGESIZES , imgp^.pagesizes );
AUXARGS_ENTRY(pos, AT_PAGESIZESLEN, imgp^.pagesizeslen);
end;
AUXARGS_ENTRY(pos, AT_STACKPROT, VM_PROT_RW);
AUXARGS_ENTRY(pos, AT_NULL, 0);
FreeMem(imgp^.auxargs);
imgp^.auxargs:=nil;
Dec(base);
suword(base^, Pointer(QWORD(imgp^.args^.argc)));
stack_base^:=base;
Exit(0);
end;
procedure init_tty; //TODO before execve
begin
kern_openat(STDIN_FILENO ,'/dev/deci_stdin' ,UIO_SYSSPACE,O_RDWR,0);
kern_openat(STDOUT_FILENO,'/dev/deci_stdout',UIO_SYSSPACE,O_RDWR,0);
kern_openat(STDERR_FILENO,'/dev/deci_stderr',UIO_SYSSPACE,O_RDWR,0);
kern_openat(3 ,'/dev/null' ,UIO_SYSSPACE,O_RDWR,0); //sys_rdup(pid,fd)
end;
const
fexecv_proc_title='(fexecv)';
function do_execve(td:p_kthread;args:p_image_args):Integer;
label
_fullpath,
exec_fail,
exec_fail_dealloc,
done2;
var
nd:t_nameidata;
stack_base:Pointer;
i,error:Integer;
image_params:t_image_params;
imgp:p_image_params;
attr:t_vattr;
textvp,binvp:p_vnode;
vfslocked:Integer;
tvfslocked:Integer;
newargs,oldargs:p_pargs;
vms:p_vmspace;
begin
textvp:=nil;
binvp :=nil;
vfslocked:=0;
imgp:=@image_params;
image_params:=Default(t_image_params);
if (p_proc.p_budget_ptype=PTYPE_BIG_APP) then
if ((g_appinfo.mmap_flags and 1)<>0) then
begin
if (g_self_loading<>0) then
begin
init_bigapp_limits;
end;
end;
p_proc.p_flag:=p_proc.p_flag or P_INEXEC;
{
* Initialize part of the common data
}
attr:=Default(t_vattr);
imgp^.attr:=@attr;
imgp^.args:=args;
{
* Translate the file name. namei() returns a vnode pointer
* in ni_vp amoung other things.
*
* XXXAUDIT: It would be desirable to also audit the name of the
* interpreter if this is an interpreted binary.
}
if (args^.fname<>nil) then
begin
NDINIT(@nd, LOOKUP, ISOPEN or LOCKLEAF or FOLLOW or SAVENAME or MPSAFE or AUDITVNODE1, UIO_SYSSPACE, args^.fname, td);
end;
if (args^.fname<>nil) then
begin
error:=nd_namei(@nd);
if (error<>0) then goto exec_fail;
vfslocked:=NDHASGIANT(@nd);
binvp:=nd.ni_vp;
imgp^.vp:=binvp;
end else
begin
{
* Some might argue that CAP_READ and/or CAP_MMAP should also
* be required here; such arguments will be entertained.
*
* Descriptors opened only with O_EXEC or O_RDONLY are allowed.
}
error:=fgetvp_exec(args^.fd, CAP_FEXECVE, @binvp);
if (error<>0) then goto exec_fail;
vfslocked:=VFS_LOCK_GIANT(binvp^.v_mount);
vn_lock(binvp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
imgp^.vp:=binvp;
end;
{
* Check file permissions (also 'opens' file)
}
error:=exec_check_permissions(imgp);
if (error<>0) then goto exec_fail_dealloc;
//imgp^.obj:=imgp^.vp^.v_object;
//if (imgp^.obj<>nil) then
//begin
// vm_object_reference(imgp^.obj);
//end;
error:=rtld_load_self(imgp);
if (error<>0) then goto exec_fail_dealloc;
p_proc.p_osrel:=0;
if (args^.fname=nil) then
begin
_fullpath:
VOP_UNLOCK(imgp^.vp, 0);
i:=vn_fullpath(imgp^.vp,@imgp^.execpath,@imgp^.freepath);
if (i<>0) then
begin
imgp^.execpath:=args^.fname;
end;
vn_lock(imgp^.vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
end else
if (args^.fname^<>'/') then
begin
goto _fullpath;
end else
begin
imgp^.execpath:=args^.fname;
end;
error:=exec_self_imgact(imgp);
if (error<>0) then goto exec_fail_dealloc;
{
* NB: We unlock the vnode here because it is believed that none
* of the sv_copyout_strings/sv_fixup operations require the vnode.
}
VOP_UNLOCK(imgp^.vp, 0);
{
* Do the best to calculate the full path to the image file.
}
if (imgp^.auxargs<>nil) and
(
((args^.fname<>nil) and (args^.fname[0]='/')) or
(vn_fullpath(imgp^.vp, @imgp^.execpath, @imgp^.freepath)<>0)
) then
begin
imgp^.execpath:=args^.fname;
end;
{
* Copy out strings (args and env) and initialize stack base
}
stack_base:=exec_copyout_strings(imgp);
{
* If custom stack fixup routine present for this process
* let it do the stack setup.
* Else stuff argument count as first item on stack
}
self_orbis_fixup(@stack_base,imgp);
{
* Malloc things before we need locks.
}
i:=imgp^.args^.begin_envv - imgp^.args^.begin_argv;
{ Cache arguments if they fit inside our allowance }
if (ps_arg_cache_limit >= (i + sizeof(t_pargs))) then
begin
newargs:=pargs_alloc(i);
Move(imgp^.args^.begin_argv^,newargs^.ar_args,i);
end;
{ close files on exec }
fdcloseexec();
vn_lock(imgp^.vp, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
{ Get a reference to the vnode prior to locking the proc }
VREF(binvp);
{
* For security and other reasons, signal handlers cannot
* be shared after an exec. The new process gets a copy of the old
* handlers. In execsigs(), the new process will have its signals
* reset.
}
PROC_LOCK();
if (args^.fname<>nil) then
begin
Move(nd.ni_cnd.cn_nameptr^, p_proc.p_comm, maxInt64(nd.ni_cnd.cn_namelen, MAXCOMLEN));
end else
begin
Move(fexecv_proc_title, p_proc.p_comm, sizeof(fexecv_proc_title));
end;
Move(p_proc.p_comm, td^.td_name, sizeof(td^.td_name));
KernSetThreadDebugName(td,'ps4:');
PROC_UNLOCK();
{
* Free any previous argument cache and replace it with
* the new argument cache, if any.
}
oldargs:=p_proc.p_args;
p_proc.p_args:=newargs;
newargs:=nil;
dynlib_proc_initialize_step3(imgp);
if (dynlibs_info.libkernel=nil) then
begin
error:=ENOENT;
goto exec_fail_dealloc;
end;
PROC_LOCK();
{
* mark as execed, wakeup the process that vforked (if any) and tell
* it that it now has its own resources back
}
p_proc.p_flag:=p_proc.p_flag or P_EXEC;
{
* Notify others that we exec'd, and clear the P_INEXEC flag
* as we're now a bona fide freshly-execed process.
}
KNOTE_LOCKED(@p_proc.p_klist, NOTE_EXEC);
p_proc.p_flag:=p_proc.p_flag and (not P_INEXEC);
{ clear 'fork but no exec' flag, as we _are_ execing }
//p^.p_acflag:= and ~AFORK;
PROC_UNLOCK();
vms:=p_proc.p_vmspace;
{ Set values passed into the program in registers. }
exec_setregs(td, QWORD(imgp^.entry_addr), QWORD(stack_base), QWORD(vms^.sv_usrstack));
vfs_mark_atime(imgp^.vp);
//copy authinfo
g_authinfo:=imgp^.authinfo;
//copy appinfo (TODO before execve)
g_appinfo.AppId:=$60000100;
g_appinfo.mmap_flags:=g_appinfo.mmap_flags or 1; //is_big_app ???
if (p_proc.p_budget_ptype=PTYPE_BIG_APP) then
if ((g_appinfo.mmap_flags and 1)<>0) then
begin
set_bigapp_cred_limits;
end;
//init std tty (TODO before execve)
init_tty;
{
* Free any resources malloc'd earlier that we didn't use.
}
VOP_UNLOCK(imgp^.vp, 0);
{
* Handle deferred decrement of ref counts.
}
if (textvp<>nil) then
begin
tvfslocked:=VFS_LOCK_GIANT(textvp^.v_mount);
vrele(textvp);
VFS_UNLOCK_GIANT(tvfslocked);
end;
if (binvp<>nil) and (error<>0) then
begin
vrele(binvp);
end;
vn_lock(imgp^.vp, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
pargs_drop(oldargs);
pargs_drop(newargs);
exec_fail_dealloc:
{
* free various allocated resources
}
rtld_free_self(imgp);
if (imgp^.vp<>nil) then
begin
if (args^.fname<>nil) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
end;
if (imgp^.opened<>0) then
begin
VOP_CLOSE(imgp^.vp, FREAD);
end;
vput(imgp^.vp);
end;
vm_object_deallocate(imgp^.obj);
FreeMem(imgp^.freepath);
if (error=0) then
begin
//PROC_LOCK();
//td^.td_dbgflags:= or TDB_EXEC;
//PROC_UNLOCK();
{
* Stop the process here if its stop event mask has
* the S_EXEC bit set.
}
//STOPEVENT(p, S_EXEC, 0);
goto done2;
end;
exec_fail:
{ we're done here, clear P_INEXEC }
PROC_LOCK();
p_proc.p_flag:=p_proc.p_flag and (not P_INEXEC);
PROC_UNLOCK();
done2:
VFS_UNLOCK_GIANT(vfslocked);
if (error<>0) then
begin
print_error_td('error execve "'+args^.fname+'" code='+IntToStr(error));
exec_free_args(args);
// sorry, no more process anymore. exit gracefully
exit1(W_EXITCODE(0, SIGABRT));
// NOT REACHED
end;
exec_free_args(args);
Exit(error);
end;
function kern_execve(td:p_kthread;args:p_image_args):Integer;
var
error:Integer;
begin
if (td=nil) then Exit(-1);
Assert((td^.td_pflags and TDP_EXECVMSPC)=0,'nested execve');
error:=do_execve(td, args);
if ((td^.td_pflags and TDP_EXECVMSPC)<>0) then
begin
td^.td_pflags:=td^.td_pflags and (not TDP_EXECVMSPC);
end;
Exit(error);
end;
function main_execve(fname:pchar;argv,envv:ppchar):Integer;
var
error:Integer;
args:t_image_args;
td:p_kthread;
begin
error:=exec_copyin_args(@args, fname, UIO_SYSSPACE, argv, envv);
if (error=0) then
begin
error:=kern_execve(curkthread, @args);
end;
Result:=(error);
if (Result=0) then
begin
//unset sys mark
td:=curkthread;
td^.td_pflags:=td^.td_pflags and (not TDP_KTHREAD);
//unset sys mark
//force JIT mode
set_pcb_flags(curkthread,PCB_IS_JIT);
//force JIT mode
//---> main_switch_context;
end;
end;
procedure main_switch_context;
begin
ipi_sigreturn;
Writeln(stderr,'I''m a teapot!');
end;
function sys_execve(fname:pchar;argv,envv:ppchar):Integer;
var
error:Integer;
args:t_image_args;
begin
error:=exec_copyin_args(@args, fname, UIO_USERSPACE, argv, envv);
if (error=0) then
begin
error:=kern_execve(curkthread, @args);
end;
Result:=(error);
end;
end.