AcessNative - Cleaned up ld-acess syscall debug
[tpg/acess2.git] / AcessNative / ld-acess_src / syscalls.c
1 /*
2  */
3 #define DONT_INCLUDE_SYSCALL_NAMES 1
4 #include "common.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <stddef.h>
11 #include <unistd.h>
12 #ifndef __WIN32__
13 # include <spawn.h>     // posix_spawn
14 #endif
15 #include "request.h"
16
17 #define assert(cnd) do{ \
18         if( !(cnd) ) { \
19                 fprintf(stderr, "%s:%i - assert failed - " #cnd"\n", __FILE__, __LINE__);\
20                 exit(-1); \
21         } \
22 }while(0)
23
24 #define MAX_FPS 16
25
26 // === Types ===
27
28 // === IMPORTS ===
29
30 // === GLOBALS ===
31 FILE    *gaSyscall_LocalFPs[MAX_FPS];
32
33 // === CODE ===
34 const char *ReadEntry(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list *Args)
35 {
36         uint64_t        val64;
37         uint32_t        val32;
38          int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
39         char    *str;
40          int    len;
41
42         // Eat whitespace
43         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
44         if( *ArgTypes == '\0' ) return ArgTypes;
45         
46 //      DEBUG("ArgTypes = '%s'", ArgTypes);
47         
48         // Get direction
49         switch(*ArgTypes)
50         {
51         default:        // Defaults to output
52         case '>':       direction = 1;  break;
53         case '<':       direction = 2;  break;
54         case '?':       direction = 3;  break;
55         }
56         ArgTypes ++;
57         
58         // Eat whitespace
59         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
60         if( *ArgTypes == '\0' ) return ArgTypes;
61         
62         // Get type
63         switch(*ArgTypes)
64         {
65         // 32-bit integer
66         case 'i':
67                 
68                 if( direction != 1 ) {
69                         Warning("ReadEntry: Recieving an integer is not defined");
70                         return NULL;
71                 }
72                 
73                 val32 = va_arg(*Args, uint32_t);
74                 
75                 Dest->Type = ARG_TYPE_INT32;
76                 Dest->Length = sizeof(uint32_t);
77                 Dest->Flags = 0;
78                 
79                 if( DataDest )
80                         *(uint32_t*)DataDest = val32;
81                 break;
82         // 64-bit integer
83         case 'I':
84                 
85                 if( direction != 1 ) {
86                         fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
87                         return NULL;
88                 }
89                 
90                 val64 = va_arg(*Args, uint64_t);
91                 
92                 Dest->Type = ARG_TYPE_INT64;
93                 Dest->Length = sizeof(uint64_t);
94                 Dest->Flags = 0;
95                 if( DataDest )
96                         *(uint64_t*)DataDest = val64;
97                 break;
98         // String
99         case 's':
100                 // Input string makes no sense!
101                 if( direction != 1 ) {
102                         fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
103                         return NULL;
104                 }
105                 
106                 str = va_arg(*Args, char*);
107                 
108                 Dest->Type = ARG_TYPE_STRING;
109                 Dest->Length = strlen(str) + 1;
110                 Dest->Flags = 0;
111                 
112                 if( DataDest )
113                 {
114                         memcpy(DataDest, str, Dest->Length);
115                 }
116                 break;
117         // Data (special handling)
118         case 'd':
119                 len = va_arg(*Args, size_t);
120                 str = va_arg(*Args, char*);
121                 
122                 // Save the pointer for later
123                 if( PtrDest )   *PtrDest = str;
124                 
125                 // Create parameter block
126                 Dest->Type = ARG_TYPE_DATA;
127                 Dest->Length = str ? len : 0;
128                 Dest->Flags = 0;
129                 if( direction & 2 )
130                         Dest->Flags |= ARG_FLAG_RETURN;
131                 
132                 // Has data?
133                 if( direction & 1 )
134                 {
135                         if( DataDest && str )
136                                 memcpy(DataDest, str, len);
137                 }
138                 else
139                         Dest->Flags |= ARG_FLAG_ZEROED;
140                 break;
141         
142         default:
143                 return NULL;
144         }
145         ArgTypes ++;
146         
147         return ArgTypes;
148 }
149
150 /**
151  * \param ArgTypes
152  *
153  * Whitespace is ignored
154  * >i:  Input Integer (32-bits)
155  * >I:  Input Long Integer (64-bits)
156  * >s:  Input String
157  * >d:  Input Buffer (Preceded by valid size)
158  * <I:  Output long integer
159  * <d:  Output Buffer (Preceded by valid size)
160  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
161  *      are returned
162  */
163 uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
164 {
165         va_list args;
166          int    paramCount, dataLength;
167          int    retCount = 2, retLength = sizeof(uint64_t) + sizeof(uint32_t);
168         void    **retPtrs;      // Pointers to return buffers
169         const char      *str;
170         tRequestHeader  *req;
171         void    *dataPtr;
172         uint64_t        retValue;
173          int    i;
174         
175         // DEBUG!
176 //      printf("&tRequestHeader->Params = %i\n", offsetof(tRequestHeader, Params));
177 //      printf("&tRequestValue->Flags = %i\n", offsetof(tRequestValue, Flags));
178 //      printf("&tRequestValue->Length = %i\n", offsetof(tRequestValue, Length));
179         
180         // Get data size
181         va_start(args, ArgTypes);
182         str = ArgTypes;
183         paramCount = 0;
184         dataLength = 0;
185         while(*str)
186         {
187                 tRequestValue   tmpVal;
188                 
189                 str = ReadEntry(&tmpVal, NULL, NULL, str, &args);
190                 if( !str ) {
191                         fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
192                         exit(127);
193                 }
194                 paramCount ++;
195                 if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
196                         dataLength += tmpVal.Length;
197                 
198                 if( tmpVal.Flags & ARG_FLAG_RETURN ) {
199                         retLength += tmpVal.Length;
200                         retCount ++;
201                 }
202         }
203         va_end(args);
204         
205         dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
206         retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
207         
208         // Allocate buffers
209         retPtrs = malloc( sizeof(void*) * (retCount+1) );
210         if( dataLength > retLength)
211                 req = malloc( dataLength );
212         else
213                 req = malloc( retLength );
214         req->ClientID = 0;      //< Filled later
215         req->CallID = SyscallID;
216         req->NParams = paramCount;
217         req->MessageLength = dataLength;
218         dataPtr = &req->Params[paramCount];
219         
220         // Fill `output` and `input`
221         va_start(args, ArgTypes);
222         str = ArgTypes;
223         // - re-zero so they can be used as indicies
224         paramCount = 0;
225         retCount = 0;
226         while(*str)
227         {               
228                 str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, &args);
229                 if( !str )      break;
230                 
231                 if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
232                         dataPtr += req->Params[paramCount].Length;
233                 if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
234                         retCount ++;
235                 
236                 paramCount ++;
237         }
238         va_end(args);
239         
240         // --- Send syscall request
241         if( SendRequest(req, dataLength, retLength) < 0 ) {
242                 fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
243                 exit(127);
244         }
245         
246         dataPtr = (void*)&req->Params[req->NParams];
247         assert(req->NParams >= 2);
248         // return
249         assert(req->Params[0].Type == ARG_TYPE_INT64);
250         assert(req->Params[0].Length == sizeof(uint64_t));
251         retValue = *(uint64_t*)dataPtr;
252         dataPtr += sizeof(uint64_t);
253         // errno
254         assert(req->Params[1].Type == ARG_TYPE_INT32);
255         assert(req->Params[1].Length == sizeof(uint32_t));
256         acess__errno = *(uint32_t*)dataPtr;
257         dataPtr += sizeof(uint32_t);
258         
259         // Write changes to buffers
260         if( req->NParams - 2 != retCount ) {
261                 fprintf(stderr, "syscalls.c: Return count inbalance (%i - 1 != exp %i) [Call %i]\n",
262                         req->NParams, retCount, SyscallID);
263                 exit(127);
264         }
265         retCount = 0;
266         for( i = 2; i < req->NParams; i ++ )
267         {
268                 #if 0
269                  int     j;
270                 printf("Return Data %i: (%i)", i, req->Params[i].Length);
271                 for( j = 0; j < req->Params[i].Length; j ++ )
272                         printf(" %02x", ((uint8_t*)dataPtr)[j]);
273                 printf("\n");
274                 #endif
275                 assert( req->Params[i].Type == ARG_TYPE_DATA );
276                 memcpy( retPtrs[retCount++], dataPtr, req->Params[i].Length );
277                 dataPtr += req->Params[i].Length;
278         }
279         
280         free( req );
281         free( retPtrs );
282         
283         SYSTRACE(": %i 0x%llx", SyscallID, retValue);
284         
285         return retValue;
286 }
287
288
289 int native_open(const char *Path, int Flags)
290 {
291         int     ret;
292        for(ret = 0; ret < MAX_FPS && gaSyscall_LocalFPs[ret]; ret ++ )  ;
293        if(ret == MAX_FPS)       return -1;
294        // TODO: Handle directories
295        gaSyscall_LocalFPs[ret] = fopen(&Path[4], "r+");
296        if(!gaSyscall_LocalFPs[ret])     return -1;
297        return ret;
298 }
299
300 void native_close(int FD)
301 {
302         fclose( gaSyscall_LocalFPs[FD] );
303         gaSyscall_LocalFPs[FD] = NULL;
304 }
305
306 size_t native_read(int FD, void *Dest, size_t Bytes)
307 {
308         return fread( Dest, Bytes, 1, gaSyscall_LocalFPs[FD] );
309 }
310
311 size_t native_write(int FD, const void *Src, size_t Bytes)
312 {
313         return fwrite( Src, Bytes, 1, gaSyscall_LocalFPs[FD] );
314 }
315
316 int native_seek(int FD, int64_t Ofs, int Dir)
317 {
318         if(Dir == 0)
319                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_CUR );
320         else if(Dir > 0)
321                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_SET );
322         else
323                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_END );
324 }
325
326 uint64_t native_tell(int FD)
327 {
328         return ftell( gaSyscall_LocalFPs[FD] );
329 }
330
331 int native_execve(const char *filename, const char *const argv[], const char *const envp[])
332 {
333         int ret;
334         ret = execve(filename, (void*)argv, (void*)envp);
335         perror("native_execve");
336         return ret;
337 }
338
339 int native_spawn(const char *filename, const char *const argv[], const char *const envp[])
340 {
341         int rv;
342         
343         #if __WIN32__
344         rv = _spawnve(_P_NOWAIT, filename, argv, envp);
345         #else
346         rv = posix_spawn(NULL, filename, NULL, NULL, (void*)argv, (void*)envp);
347         #endif
348         
349         return rv;
350 }

UCC git Repository :: git.ucc.asn.au