uses Classes, SysUtils, gset, mpaslex, _sysent; type TRawStrCompare=class class function c(var a,b:RawByteString):boolean; static; end; TRawStrSet=specialize TSet; class function TRawStrCompare.c(var a,b:RawByteString):boolean; var count1,count2:SizeInt; begin Count1:=Length(a); Count2:=Length(b); Result:=(Count1nil); end; type TState=(sNone,sNameFunc,sBeforeParam,sParamName,sParamType,sAfterParam,sReturn,sEndFunc,sError); type TFuncDecl=class(TStringList) public funit:RawByteString; fhead:RawByteString; fname:RawByteString; fretv:RawByteString; fprint_interface:Boolean; fprint_implementation:Boolean; end; var sysent_maxlen:Integer=0; sysent_func:array[0..high(sysent_table)] of TFuncDecl; procedure AddSysFunc(f:TFuncDecl); var i:Integer; s:Boolean; begin s:=False; For i:=0 to high(sysent_table) do begin if (lowercase(sysent_table[i].sy_name)=lowercase(f.fname)) then begin if (sysent_func[i]<>nil) then begin Writeln('Collision[',i:3,']:',f.fname,' prev unit:',sysent_func[i].funit,' new unit:',f.funit); end else begin Writeln('Found[',i:3,']:',f.fname:sysent_maxlen,' in unit:',f.funit); sysent_func[i]:=f; s:=True; end; end; end; if not s then begin FreeAndNil(f); end; end; procedure print_decl(FuncDecl:TFuncDecl); var i:Integer; begin Write(FuncDecl.fhead,' ',FuncDecl.fname,'('); if (FuncDecl.Count<>0) then For i:=0 to FuncDecl.Count-1 do begin Write(FuncDecl.Strings[i]); end; Write(')'); if (FuncDecl.fretv<>'') then begin Write(':',FuncDecl.fretv); end; Writeln(';'); end; function Max(a, b: Integer): Integer;inline; begin if a > b then Result := a else Result := b; end; function TrimType(const S: RawByteString): RawByteString; var Ofs, Len: sizeint; begin len := Length(S); while (Len>0) and ((S[Len]<=' ') or (S[Len]=',') or (S[Len]=';')) do dec(Len); Ofs := 1; while (Ofs<=Len) and ((S[Ofs]<=' ') or (S[Ofs]=',') or (S[Ofs]<=';')) do Inc(Ofs); result := Copy(S, Ofs, 1 + Len - Ofs); end; function get_str_no_sys(const S:RawByteString):RawByteString; begin Result:=S; if (lowercase(copy(Result,1,4))='sys_') then begin Delete(Result,1,4); end; case lowercase(Result) of 'accept', 'bind', 'close', 'connect', 'dup2', 'execve', 'exit', 'fcntl', 'fpathconf', 'fstat', 'fstatfs', 'getdirentries', 'getpeername', 'getsockname', 'getsockopt', 'ioctl', 'listen', 'nanosleep', 'open', 'openat', 'read', 'readv', 'recvfrom', 'recvmsg', 'sendmsg', 'sendto', 'setsockopt', 'sigaction', 'sigprocmask', 'sigsuspend', 'wait4', 'write', 'writev':Result:='_'+Result; 'debug_init', 'dl_get_info', 'dl_get_list', 'dl_get_metadata', 'dynlib_get_info2', 'dynlib_get_info_for_libdbg', 'dynlib_get_list2', 'dynlib_get_list_for_libdbg', 'dynlib_load_prx', 'dynlib_unload_prx', 'get_proc_type_info', 'is_development_mode', 'kqueueex', 'namedobj_create', 'namedobj_delete', 'netabort', 'netcontrol', 'netgetiflist', 'netgetsockinfo', 'opmc_disable', 'opmc_enable', 'opmc_get_ctr', 'opmc_get_hw', 'opmc_set_ctl', 'opmc_set_ctr', 'opmc_set_hw', 'osem_close', 'osem_open', 'randomized_path', 'rdup', 'regmgr_call', 'set_uevt', 'socketclose', 'socketex', 'test_debug_rwmem', 'workaround8849':Result:='__sys_'+Result; else; end; end; function get_str_decl(FuncDecl:TFuncDecl;align:Boolean):RawByteString; var i,p:Integer; n,t:RawByteString; begin if align then begin i:=Max(0,Length('procedure ')-Length(FuncDecl.fhead)); end else begin i:=1; end; Result:=FuncDecl.fhead+space(i)+get_str_no_sys(FuncDecl.fname)+'('; if (FuncDecl.Count<>0) then For i:=0 to FuncDecl.Count-1 do begin n:=FuncDecl.Strings[i]; t:=''; p:=Pos(':',n); if (p<>0) then begin t:=copy(n,p+1); t:=TrimType(t); t:=lowercase(t); end; if (Copy(t,1,1)='p') then begin case t of 'pointer':; 'pchar':; 'pdword':; 'pqword':; 'pinteger':; 'pbyte':; 'pint64':; 'ppointer':; 'ppchar':; else Writeln('*',t,'*',' in ',FuncDecl.fname,' (',FuncDecl.funit,')'); end; end; Result:=Result+n; end; Result:=Result+')'; if (FuncDecl.fretv<>'') then begin Result:=Result+':'+FuncDecl.fretv; end; Result:=Result+';'; end; Procedure load_pas(const fname:RawByteString); var F:THandle; size:Int64; buf:PChar; state:TState; token:RawByteString; FuncDecl:TFuncDecl; procedure add_to_param(S:RawByteString); begin S:=Trim(S); if (S='') then S:=' '; token:=Trim(token)+S; end; procedure add_param(S:RawByteString); begin S:=Trim(S); if (S<>'') then FuncDecl.Add(S); end; begin if (fname='') then Exit; F:=FileOpen(fname,fmOpenRead or fmShareDenyNone); if (F=feInvalidHandle) then begin Writeln('Error open file:',fname); Exit; end; size:=FileSeek(F,0,fsFromEnd); FileSeek(F,0,fsFromBeginning); buf:=AllocMem(size+1); FileRead(F,buf^,size); mwPasLex.Origin:=buf; FuncDecl:=nil; state:=sNone; while (mwPasLex.RunPosnil) then begin //print_decl(FuncDecl); AddSysFunc(FuncDecl); FuncDecl:=nil; end; end; else; end; end; FreeMem(buf); FileClose(F); end; procedure LoadRecrusive(const basep,reltv:RawByteString); Var Info:TSearchRec; f:RawByteString; begin f:=IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(basep)+reltv); If FindFirst(f+'*',faDirectory,Info)=0 then begin Repeat Case Info.Name of '.','..':; else if not IsExclude(Info.Name) then begin If ((Info.Attr and faDirectory)<>0) then begin LoadRecrusive(basep,IncludeTrailingPathDelimiter(reltv)+Info.Name); end else if (lowercase(ExtractFileExt(Info.Name))='.pas') then begin FileList.Add(IncludeTrailingPathDelimiter(reltv)+Info.Name); //Writeln(IncludeTrailingPathDelimiter(reltv)+Info.Name); load_pas(basep+IncludeTrailingPathDelimiter(reltv)+Info.Name); end; end; end; Until FindNext(info)<>0; FindClose(Info); end; end; procedure LoadSysent; var i:Integer; begin For i:=0 to high(sysent_table) do begin if (sysent_table[i].sy_call=nil) then begin if Length(sysent_table[i].sy_name)>sysent_maxlen then sysent_maxlen:=Length(sysent_table[i].sy_name); Sysentu.Insert(lowercase(sysent_table[i].sy_name)); end; end; end; procedure LoadStats; var i:Integer; f,n:Integer; begin f:=0; n:=0; For i:=0 to high(sysent_table) do begin if (sysent_table[i].sy_call=nil) then begin if (sysent_func[i]<>nil) then begin if (sysent_table[i].sy_narg<>sysent_func[i].Count) then begin Writeln('Wrong narg[',i:3,']:',sysent_table[i].sy_narg,'<>',sysent_func[i].Count,':'); Write(' '); print_decl(sysent_func[i]); end; Inc(f); end else begin Writeln('Not found[',i:3,']:',sysent_table[i].sy_name:sysent_maxlen); Inc(n); end; end; end; Writeln('syscalls status:',f,'/',f+n,':%',(f/(f+n))*100:0:2); end; procedure Save_sysent(const fname:RawByteString); var F:THandle; S:RawByteString; i:Integer; D:TFuncDecl; FUnits:TRawStrSet; iter:TRawStrSet.TIterator; inext:Boolean; begin if (fname='') then Exit; F:=FileCreate(fname); if (F=feInvalidHandle) then begin Writeln('Error create file:',fname); Exit; end; FUnits:=TRawStrSet.Create; For i:=0 to high(sysent_table) do begin D:=sysent_func[i]; if (D<>nil) then begin FUnits.Insert(D.funit); end; end; S:='{This file is automatically generated by "syscalls_gen"}'#13#10; S:=S+#13#10; S:=S+'unit '+ChangeFileExt(ExtractFileName(fname),'')+';'#13#10; S:=S+#13#10; S:=S+'{$mode objfpc}{$H+}'#13#10; S:=S+'{$CALLING SysV_ABI_CDecl}'#13#10; S:=S+#13#10; S:=S+'interface'#13#10; S:=S+#13#10; S:=S+'uses'#13#10; S:=S+' sysent,'#13#10; FileWrite(F,Pchar(S)^,Length(S)); iter:=FUnits.Min; if (iter<>nil) then begin repeat S:=' '+iter.GetData; inext:=iter.Next; if inext then begin S:=S+','; end else begin S:=S+';'; end; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); until not inext; FreeAndNil(iter); end; S:=#13#10; S:=S+'function nosys:Integer;'#13#10; S:=S+'function nosup:Integer;'#13#10; S:=S+'function nzero:Integer;'#13#10; S:=S+#13#10; S:=S+'var'#13#10; S:=S+' sv_size:Integer='+IntToStr(Length(sysent_table))+'; public;'#13#10; S:=S+#13#10; S:=S+' sv_table:array[0..'+IntToStr(high(sysent_table))+'] of t_sysent=('#13#10; FileWrite(F,Pchar(S)^,Length(S)); For i:=0 to high(sysent_table) do begin S:= ' (//['+IntToStr(i)+']'#13#10; S:=S+' sy_narg:'+IntToStr(sysent_table[i].sy_narg)+';'#13#10; S:=S+' sy_call:'; if (sysent_table[i].sy_call=Pointer(@nosys)) then begin S:=S+'@nosys'; end else if (sysent_table[i].sy_call=Pointer(@nosup)) then begin S:=S+'@nosup'; end else if (sysent_table[i].sy_call=Pointer(@nzero)) then begin S:=S+'@nzero'; end else begin // D:=sysent_func[i]; if (D=nil) then begin S:=S+'nil'; end else begin S:=S+'@'+D.fname; end; end; S:=S+';'#13#10; S:=S+' sy_name:'''+sysent_table[i].sy_name+''''#13#10; S:=S+' )'; if (i<>high(sysent_table)) then begin S:=S+','; end; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); end; S:= ' ); public;'#13#10; S:=S+#13#10; S:=S+'implementation'#13#10; S:=S+#13#10; S:=S+'const'#13#10; S:=S+' ENOSYS =78;'#13#10; S:=S+' ENOTSUP=45;'#13#10; S:=S+#13#10; S:=S+'function nosys:Integer;'#13#10; S:=S+'begin'#13#10; S:=S+' Result:=ENOSYS;'#13#10; S:=S+'end;'#13#10; S:=S+#13#10; S:=S+'function nosup:Integer;'#13#10; S:=S+'begin'#13#10; S:=S+' Result:=ENOTSUP;'#13#10; S:=S+'end;'#13#10; S:=S+#13#10; S:=S+'function nzero:Integer;'#13#10; S:=S+'begin'#13#10; S:=S+' Result:=0;'#13#10; S:=S+'end;'#13#10; S:=S+#13#10; S:=S+'end.'#13#10; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); FileClose(F); FUnits.Free; end; procedure Save_syscalls(const fname:RawByteString); var F:THandle; S:RawByteString; i:Integer; D:TFuncDecl; begin if (fname='') then Exit; F:=FileCreate(fname); if (F=feInvalidHandle) then begin Writeln('Error create file:',fname); Exit; end; S:='{This file is automatically generated by "syscalls_gen"}'#13#10; S:=S+#13#10; S:=S+'unit '+ChangeFileExt(ExtractFileName(fname),'')+';'#13#10; S:=S+#13#10; S:=S+'{$mode objfpc}{$H+}'#13#10; S:=S+'{$CALLING SysV_ABI_CDecl}'#13#10; S:=S+#13#10; S:=S+'interface'#13#10; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); For i:=0 to high(sysent_table) do begin D:=sysent_func[i]; if (D<>nil) then if (not D.fprint_interface) then begin S:=get_str_decl(D,True)+#13#10; FileWrite(F,Pchar(S)^,Length(S)); D.fprint_interface:=True; end; end; S:=#13#10; S:=S+'implementation'#13#10; S:=S+#13#10; S:=S+'uses'#13#10; S:=S+' trap,'#13#10; S:=S+' thr_error;'#13#10; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); For i:=0 to high(sysent_table) do begin D:=sysent_func[i]; if (D<>nil) then if (not D.fprint_implementation) then begin S:=get_str_decl(D,False); S:=S+' assembler; nostackframe;'#13#10; S:=S+'asm'#13#10; S:=S+' movq $'+IntToStr(i)+',%rax'#13#10; S:=S+' call fast_syscall'#13#10; S:=S+' jmp cerror'#13#10; S:=S+'end;'#13#10; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); D.fprint_implementation:=True; end; end; S:=#13#10; S:=S+'end.'#13#10; S:=S+#13#10; FileWrite(F,Pchar(S)^,Length(S)); FileClose(F); end; begin mwPasLex:=TmwPasLex.Create; Exclude:=TRawStrSet.Create; Sysentu:=TRawStrSet.Create; FileList:=TStringList.Create; AddExclude('backup'); LoadSysent; LoadRecrusive('..\..\sys',''); LoadStats; Save_sysent('init_sysent.pas'); Save_syscalls('syscalls.pas'); readln; end.