Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/tools/ido5.3_recomp/libc_impl.c
7858 views
1
#define _GNU_SOURCE // for sigset
2
#include <stdbool.h>
3
#include <stdio.h>
4
#include <stdint.h>
5
#include <stdlib.h>
6
#include <string.h>
7
#include <math.h>
8
#include <assert.h>
9
#include <errno.h>
10
#include <time.h>
11
#include <limits.h>
12
#include <ctype.h>
13
#include <locale.h>
14
#include <libgen.h>
15
16
#ifdef __CYGWIN__
17
#include <windows.h>
18
#endif
19
#ifdef __APPLE__
20
#include <mach-o/dyld.h>
21
#endif
22
23
#include <sys/mman.h>
24
#include <sys/types.h>
25
#include <sys/stat.h>
26
#include <sys/times.h>
27
#include <sys/file.h>
28
#include <sys/wait.h>
29
#include <fcntl.h>
30
#include <utime.h>
31
#include <unistd.h>
32
#include <signal.h>
33
34
#include "libc_impl.h"
35
#include "helpers.h"
36
37
#define MIN(a, b) ((a) < (b) ? (a) : (b))
38
#define MAX(a, b) ((a) > (b) ? (a) : (b))
39
40
#define STRING(param) size_t param##_len = wrapper_strlen(mem, param##_addr); \
41
char param[param##_len + 1]; \
42
for (size_t i = 0; i <= param##_len; i++) { \
43
param[i] = MEM_S8(param##_addr + i); \
44
}
45
46
#if !defined(IDO53) && !defined(IDO71)
47
#define IDO71
48
#endif
49
50
#define MEM_REGION_START 0xfb00000
51
#define MEM_REGION_SIZE (512 * 1024 * 1024)
52
53
#ifdef IDO53
54
// IDO 5.3
55
#define IOB_ADDR 0x0fb528e4
56
#define ERRNO_ADDR 0x0fb52720
57
#define CTYPE_ADDR 0x0fb504f0
58
#define LIBC_ADDR 0x0fb50000
59
#define LIBC_SIZE 0x3000
60
#endif
61
62
#ifdef IDO71
63
// IDO 7.1
64
#define IOB_ADDR 0x0fb4ee44
65
#define ERRNO_ADDR 0x0fb4ec80
66
#define CTYPE_ADDR 0x0fb4cba0
67
#define LIBC_ADDR 0x0fb4c000
68
#define LIBC_SIZE 0x3000
69
#endif
70
71
#define STDIN_ADDR IOB_ADDR
72
#define STDOUT_ADDR (IOB_ADDR + 0x10)
73
#define STDERR_ADDR (IOB_ADDR + 0x20)
74
#define STDIN ((struct FILE_irix *)&MEM_U32(STDIN_ADDR))
75
#define STDOUT ((struct FILE_irix *)&MEM_U32(STDOUT_ADDR))
76
#define STDERR ((struct FILE_irix *)&MEM_U32(STDERR_ADDR))
77
78
#define MALLOC_BINS_ADDR custom_libc_data_addr
79
#define STRTOK_DATA_ADDR (MALLOC_BINS_ADDR + (30 - 3) * 4)
80
#define INTBUF_ADDR (STRTOK_DATA_ADDR + 4)
81
82
#define SIGNAL_HANDLER_STACK_START LIBC_ADDR
83
84
#define NFILE 100
85
86
#define IOFBF 0000 /* full buffered */
87
#define IOLBF 0100 /* line buffered */
88
#define IONBF 0004 /* not buffered */
89
#define IOEOF 0020 /* EOF reached on read */
90
#define IOERR 0040 /* I/O error from system */
91
92
#define IOREAD 0001 /* currently reading */
93
#define IOWRT 0002 /* currently writing */
94
#define IORW 0200 /* opened for reading and writing */
95
#define IOMYBUF 0010 /* stdio malloc()'d buffer */
96
97
#define STDIO_BUFSIZE 16384
98
99
struct timespec_t_irix {
100
int tv_sec;
101
int tv_nsec;
102
};
103
104
struct FILE_irix {
105
int _cnt;
106
uint32_t _ptr_addr;
107
uint32_t _base_addr;
108
uint8_t pad[2];
109
uint8_t _file;
110
uint8_t _flag;
111
};
112
113
static struct {
114
struct {
115
uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest);
116
uint8_t *mem;
117
uint32_t fp_dest;
118
} handlers[65];
119
volatile uint32_t recursion_level;
120
} signal_context;
121
122
static uint32_t cur_sbrk;
123
static uint32_t bufendtab[NFILE]; // this version contains the size and not the end ptr
124
static uint32_t custom_libc_data_addr;
125
126
#define _U 01 /* Upper case */
127
#define _L 02 /* Lower case */
128
#define _N 04 /* Numeral (digit) */
129
#define _S 010 /* Spacing character */
130
#define _P 020 /* Punctuation */
131
#define _C 040 /* Control character */
132
#define _B 0100 /* Blank */
133
#define _X 0200 /* heXadecimal digit */
134
135
static char ctype[] = { 0,
136
137
/* 0 1 2 3 4 5 6 7 */
138
139
/* 0*/ _C, _C, _C, _C, _C, _C, _C, _C,
140
/* 10*/ _C, _S|_C, _S|_C, _S|_C, _S|_C, _S|_C, _C, _C,
141
/* 20*/ _C, _C, _C, _C, _C, _C, _C, _C,
142
/* 30*/ _C, _C, _C, _C, _C, _C, _C, _C,
143
/* 40*/ _S|_B, _P, _P, _P, _P, _P, _P, _P,
144
/* 50*/ _P, _P, _P, _P, _P, _P, _P, _P,
145
/* 60*/ _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X,
146
/* 70*/ _N|_X, _N|_X, _P, _P, _P, _P, _P, _P,
147
/*100*/ _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U,
148
/*110*/ _U, _U, _U, _U, _U, _U, _U, _U,
149
/*120*/ _U, _U, _U, _U, _U, _U, _U, _U,
150
/*130*/ _U, _U, _U, _P, _P, _P, _P, _P,
151
/*140*/ _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L,
152
/*150*/ _L, _L, _L, _L, _L, _L, _L, _L,
153
/*160*/ _L, _L, _L, _L, _L, _L, _L, _L,
154
/*170*/ _L, _L, _L, _P, _P, _P, _P, _C,
155
/*200*/ 0, 0, 0, 0, 0, 0, 0, 0,
156
0, 0, 0, 0, 0, 0, 0, 0,
157
0, 0, 0, 0, 0, 0, 0, 0,
158
0, 0, 0, 0, 0, 0, 0, 0,
159
0, 0, 0, 0, 0, 0, 0, 0,
160
0, 0, 0, 0, 0, 0, 0, 0,
161
0, 0, 0, 0, 0, 0, 0, 0,
162
0, 0, 0, 0, 0, 0, 0, 0,
163
0, 0, 0, 0, 0, 0, 0, 0,
164
0, 0, 0, 0, 0, 0, 0, 0,
165
0, 0, 0, 0, 0, 0, 0, 0,
166
0, 0, 0, 0, 0, 0, 0, 0,
167
0, 0, 0, 0, 0, 0, 0, 0,
168
0, 0, 0, 0, 0, 0, 0, 0,
169
0, 0, 0, 0, 0, 0, 0, 0,
170
0, 0, 0, 0, 0, 0, 0, 0
171
};
172
173
#define REDIRECT_USR_LIB
174
175
#ifdef REDIRECT_USR_LIB
176
static char bin_dir[PATH_MAX + 1];
177
#endif
178
static int g_file_max = 3;
179
180
#if defined(__CYGWIN__) || defined(__APPLE__)
181
static size_t g_Pagesize;
182
#endif
183
184
static uint8_t *memory_map(size_t length)
185
{
186
#if defined(__CYGWIN__) || defined(__APPLE__)
187
uint8_t *mem = mmap(0, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
188
g_Pagesize = sysconf(_SC_PAGESIZE);
189
assert(((uintptr_t)mem & (g_Pagesize-1)) == 0);
190
#else
191
uint8_t *mem = mmap(0, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
192
#endif
193
if (mem == MAP_FAILED) {
194
perror("mmap");
195
exit(1);
196
}
197
return mem;
198
}
199
200
static void memory_allocate(uint8_t *mem, uint32_t start, uint32_t end)
201
{
202
assert(start >= MEM_REGION_START);
203
assert(end <= MEM_REGION_START + MEM_REGION_SIZE);
204
#if defined(__CYGWIN__) || defined(__APPLE__)
205
uintptr_t _start = ((uintptr_t)mem + start) & ~(g_Pagesize-1);
206
uintptr_t _end = ((uintptr_t)mem + end + (g_Pagesize-1)) & ~(g_Pagesize-1);
207
208
if(mprotect((void*)_start, _end - _start, PROT_READ | PROT_WRITE) < 0) {
209
perror("mprotect");
210
exit(1);
211
}
212
#else
213
if (mmap(mem + start, end - start, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
214
perror("mmap");
215
exit(1);
216
}
217
#endif
218
}
219
220
static void memory_unmap(uint8_t *mem, size_t length)
221
{
222
if (munmap(mem, length)) {
223
perror("munmap");
224
exit(1);
225
}
226
}
227
228
229
static void free_all_file_bufs(uint8_t *mem) {
230
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(IOB_ADDR);
231
for (int i = 0; i < g_file_max; i++) {
232
if (f[i]._flag & IOMYBUF) {
233
wrapper_free(mem, f[i]._base_addr);
234
}
235
}
236
}
237
238
static void find_bin_dir(void) {
239
#ifdef REDIRECT_USR_LIB
240
// gets the current executable's path
241
char path[PATH_MAX + 1] = {0};
242
#ifdef __CYGWIN__
243
uint32_t size = GetModuleFileName(NULL, path, PATH_MAX);
244
if (size == 0 || size == PATH_MAX) {
245
return;
246
}
247
#elif defined __APPLE__
248
uint32_t size = PATH_MAX;
249
if (_NSGetExecutablePath(path, &size) < 0) {
250
return;
251
}
252
#else
253
ssize_t size = readlink("/proc/self/exe", path, PATH_MAX);
254
if (size < 0 || size == PATH_MAX) {
255
return;
256
}
257
#endif
258
259
strcpy(bin_dir, dirname(path));
260
#endif
261
}
262
263
int main(int argc, char *argv[]) {
264
int ret;
265
266
find_bin_dir();
267
268
uint8_t *mem = memory_map(MEM_REGION_SIZE);
269
mem -= MEM_REGION_START;
270
int run(uint8_t *mem, int argc, char *argv[]);
271
ret = run(mem, argc, argv);
272
wrapper_fflush(mem, 0);
273
free_all_file_bufs(mem);
274
mem += MEM_REGION_START;
275
memory_unmap(mem, MEM_REGION_SIZE);
276
return ret;
277
}
278
279
void mmap_initial_data_range(uint8_t *mem, uint32_t start, uint32_t end) {
280
custom_libc_data_addr = end;
281
end += 4096;
282
memory_allocate(mem, start, end);
283
cur_sbrk = end;
284
}
285
286
void setup_libc_data(uint8_t *mem) {
287
memory_allocate(mem, LIBC_ADDR, (LIBC_ADDR + LIBC_SIZE));
288
for (size_t i = 0; i < sizeof(ctype); i++) {
289
MEM_S8(CTYPE_ADDR + i) = ctype[i];
290
}
291
STDIN->_flag = IOREAD;
292
STDIN->_file = 0;
293
STDOUT->_flag = IOWRT;
294
STDOUT->_file = 1;
295
STDERR->_flag = IOWRT | IONBF;
296
STDERR->_file = 2;
297
}
298
299
static uint32_t strcpy1(uint8_t *mem, uint32_t dest_addr, const char *str) {
300
for (;;) {
301
char c = *str;
302
++str;
303
MEM_S8(dest_addr) = c;
304
++dest_addr;
305
if (c == '\0') {
306
return dest_addr - 1;
307
}
308
}
309
}
310
311
static uint32_t strcpy2(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) {
312
for (;;) {
313
char c = MEM_S8(src_addr);
314
++src_addr;
315
MEM_S8(dest_addr) = c;
316
++dest_addr;
317
if (c == '\0') {
318
return dest_addr - 1;
319
}
320
}
321
}
322
323
uint32_t wrapper_sbrk(uint8_t *mem, int increment) {
324
uint32_t old = cur_sbrk;
325
memory_allocate(mem, old, (old + increment));
326
cur_sbrk += increment;
327
return old;
328
}
329
330
#if 0
331
uint32_t wrapper_malloc(uint8_t *mem, uint32_t size) {
332
uint32_t orig_size = size;
333
size += 8;
334
size = (size + 0xfff) & ~0xfff;
335
uint32_t ret = wrapper_sbrk(mem, size);
336
MEM_U32(ret) = orig_size;
337
return ret + 8;
338
}
339
340
uint32_t wrapper_calloc(uint8_t *mem, uint32_t num, uint32_t size) {
341
uint64_t new_size = (uint64_t)num * size;
342
assert(new_size == (uint32_t)new_size);
343
uint32_t ret = wrapper_malloc(mem, new_size);
344
return wrapper_memset(mem, ret, 0, new_size);
345
}
346
347
uint32_t wrapper_realloc(uint8_t *mem, uint32_t data_addr, uint32_t size) {
348
if (data_addr == 0) {
349
return wrapper_malloc(mem, size);
350
}
351
uint32_t orig_size = MEM_U32(data_addr - 8);
352
if (size < orig_size || orig_size < 4088 && size < 4088) {
353
MEM_U32(data_addr - 8) = size;
354
return data_addr;
355
}
356
uint32_t new_addr = wrapper_malloc(mem, size);
357
return wrapper_memcpy(mem, new_addr, data_addr, MIN(size, orig_size));
358
}
359
360
void wrapper_free(uint8_t *mem, uint32_t data_addr) {
361
// NOP
362
}
363
#else
364
365
/*
366
Simple bin-based malloc algorithm
367
368
The memory is divided into bins of item sizes 8, 16, 32, 64, 128, ..., 2^30.
369
Size requests are divided into these bin sizes and each bin is handled
370
completely separate from other bins.
371
372
For each bin there is a linked list of free'd items.
373
Linked list node:
374
struct FreeListNode {
375
struct Node *next;
376
size_t free_space_after;
377
uint8_t data[bin_item_size];
378
};
379
At most one value of next and space_after is non-zero.
380
If a node exists in the linked list, it is the memory node to return.
381
struct AllocatedNode {
382
int bin;
383
uint32_t current_size;
384
uint8_t data[bin_item_size];
385
};
386
The returned address is the data element.
387
When the last list node is returned, and free_space_after is big enough
388
for a new node, a new node is created having free_space_after set to
389
(free_space_after - (8 + bin_item_size)), and is appended to the list.
390
391
If the list was empty, a new memory chunk is requested from the system
392
of 65536 bytes, or at least (8 + bin_item_size), rounded up to nearest
393
page size boundary. It can also be smaller if it leaves holes bigger than
394
4096 bytes that can never be used. This chunk is then inserted to the list,
395
and the algorithm restarts.
396
397
This algorithm, for each bin, never uses more than twice as much as is
398
maximally in use (plus 65536 bytes).
399
The malloc/free calls run in O(1) and calloc/realloc calls run in O(size).
400
*/
401
402
size_t mem_used;
403
size_t mem_allocated;
404
size_t max_mem_used;
405
size_t num_sbrks;
406
size_t num_allocs;
407
uint32_t wrapper_malloc(uint8_t *mem, uint32_t size) {
408
int bin = -1;
409
for (int i = 3; i < 30; i++) {
410
if (size <= (1 << i)) {
411
bin = i;
412
break;
413
}
414
}
415
if (bin == -1) {
416
return 0;
417
}
418
++num_allocs;
419
mem_used += size;
420
max_mem_used = MAX(mem_used, max_mem_used);
421
uint32_t item_size = 1 << bin;
422
uint32_t list_ptr = MALLOC_BINS_ADDR + (bin - 3) * 4;
423
uint32_t node_ptr = MEM_U32(list_ptr);
424
if (node_ptr == 0) {
425
uint32_t sbrk_request = 0x10000;
426
if (8 + item_size > sbrk_request) {
427
sbrk_request = 8 + item_size;
428
sbrk_request = (sbrk_request + 0xfff) & ~0xfff;
429
}
430
uint32_t left_over = sbrk_request % (8 + item_size);
431
sbrk_request -= left_over & ~0xfff;
432
mem_allocated += sbrk_request;
433
++num_sbrks;
434
node_ptr = wrapper_sbrk(mem, sbrk_request);
435
MEM_U32(node_ptr + 4) = sbrk_request - (8 + item_size);
436
}
437
uint32_t next = MEM_U32(node_ptr);
438
if (next == 0) {
439
uint32_t free_space_after = MEM_U32(node_ptr + 4);
440
if (free_space_after >= 8 + item_size) {
441
next = node_ptr + 8 + item_size;
442
MEM_U32(next + 4) = free_space_after - (8 + item_size);
443
}
444
} else {
445
assert(MEM_U32(node_ptr + 4) == 0);
446
}
447
MEM_U32(list_ptr) = next;
448
MEM_U32(node_ptr) = bin;
449
MEM_U32(node_ptr + 4) = size;
450
return node_ptr + 8;
451
}
452
453
uint32_t wrapper_calloc(uint8_t *mem, uint32_t num, uint32_t size) {
454
uint64_t new_size = (uint64_t)num * size;
455
assert(new_size == (uint32_t)new_size);
456
uint32_t ret = wrapper_malloc(mem, new_size);
457
return wrapper_memset(mem, ret, 0, new_size);
458
}
459
460
uint32_t wrapper_realloc(uint8_t *mem, uint32_t data_addr, uint32_t size) {
461
if (data_addr == 0) {
462
return wrapper_malloc(mem, size);
463
} else {
464
uint32_t node_ptr = data_addr - 8;
465
int bin = MEM_U32(node_ptr);
466
uint32_t old_size = MEM_U32(node_ptr + 4);
467
uint32_t max_size = 1 << bin;
468
assert(bin >= 3 && bin < 30);
469
assert(old_size <= max_size);
470
if (size <= max_size) {
471
mem_used = mem_used - old_size + size;
472
MEM_U32(node_ptr + 4) = size;
473
return data_addr;
474
} else {
475
uint32_t new_addr = wrapper_malloc(mem, size);
476
wrapper_memcpy(mem, new_addr, data_addr, old_size);
477
wrapper_free(mem, data_addr);
478
return new_addr;
479
}
480
}
481
}
482
483
void wrapper_free(uint8_t *mem, uint32_t data_addr) {
484
uint32_t node_ptr = data_addr - 8;
485
int bin = MEM_U32(node_ptr);
486
uint32_t size = MEM_U32(node_ptr + 4);
487
uint32_t list_ptr = MALLOC_BINS_ADDR + (bin - 3) * 4;
488
assert(bin >= 3 && bin < 30);
489
assert(size <= (1 << bin));
490
MEM_U32(node_ptr) = MEM_U32(list_ptr);
491
MEM_U32(node_ptr + 4) = 0;
492
MEM_U32(list_ptr) = node_ptr;
493
mem_used -= size;
494
}
495
#endif
496
497
int wrapper_fscanf(uint8_t *mem, uint32_t fp_addr, uint32_t format_addr, uint32_t sp) {
498
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
499
STRING(format) // for debug
500
501
int ret = 0;
502
char c;
503
int ch;
504
sp += 2 * 4;
505
for (;;) {
506
c = MEM_S8(format_addr);
507
++format_addr;
508
if (c == '%') {
509
c = MEM_S8(format_addr);
510
++format_addr;
511
if (c == '%') {
512
goto percent;
513
}
514
for (;;) {
515
ch = wrapper_fgetc(mem, fp_addr);
516
if (ch == -1) {
517
return ret;
518
}
519
if (!isspace(ch)) {
520
//wrapper_ungetc(mem, ch, fp_addr);
521
break;
522
}
523
}
524
bool l = false;
525
continue_format:
526
switch (c) {
527
case 'l':
528
assert(!l && "ll not implemented in fscanf");
529
l = true;
530
c = MEM_S8(format_addr);
531
++format_addr;
532
goto continue_format;
533
case 'd':
534
{
535
int64_t num = 0;
536
int sign = 1;
537
bool found_first = false;
538
if (ch == '-') {
539
sign = -1;
540
ch = wrapper_fgetc(mem, fp_addr);
541
if (ch == -1) {
542
return ret;
543
}
544
}
545
for (;;) {
546
if (isdigit(ch)) {
547
num *= 10;
548
num += ch - '0';
549
found_first = true;
550
ch = wrapper_fgetc(mem, fp_addr);
551
if (ch == -1) {
552
break;
553
}
554
} else {
555
wrapper_ungetc(mem, ch, fp_addr);
556
break;
557
}
558
}
559
if (found_first) {
560
uint32_t int_addr = MEM_U32(sp);
561
sp += 4;
562
MEM_S32(int_addr) = (int)(num * sign);
563
++ret;
564
} else {
565
return ret;
566
}
567
break;
568
}
569
default:
570
assert(0 && "fscanf format not implemented");
571
}
572
} else if (c == '\0') {
573
break;
574
} else {
575
percent:
576
ch = wrapper_fgetc(mem, fp_addr);
577
if (ch == -1) {
578
break;
579
}
580
if ((char)ch != c) {
581
break;
582
}
583
}
584
}
585
586
return ret;
587
}
588
589
int wrapper_printf(uint8_t *mem, uint32_t format_addr, uint32_t sp) {
590
STRING(format)
591
if (!strcmp(format, " child died due to signal %d.\n")) {
592
printf(format, MEM_U32(sp + 4));
593
return 1;
594
}
595
assert(0 && "printf not implemented");
596
return 0;
597
}
598
599
int wrapper_sprintf(uint8_t *mem, uint32_t str_addr, uint32_t format_addr, uint32_t sp) {
600
STRING(format) // for debug
601
char temp[32];
602
603
if (!strcmp(format, "%.16e")) {
604
union {
605
uint32_t w[2];
606
double d;
607
} d;
608
d.w[1] = MEM_U32(sp + 2 * 4);
609
d.w[0] = MEM_U32(sp + 3 * 4);
610
sprintf(temp, "%.16e", d.d);
611
strcpy1(mem, str_addr, temp);
612
return 1;
613
}
614
if (!strcmp(format, "\\%03o")) {
615
sprintf(temp, "\\%03o", MEM_U32(sp + 2 * 4));
616
strcpy1(mem, str_addr, temp);
617
return 1;
618
}
619
if (!strcmp(format, "%*ld=")) {
620
sprintf(temp, "%*d=", MEM_U32(sp + 2 * 4), MEM_U32(sp + 3 * 4));
621
strcpy1(mem, str_addr, temp);
622
return 1;
623
}
624
625
uint32_t orig_str_addr = str_addr;
626
uint32_t pos = 0;
627
int ret = 0;
628
char c;
629
sp += 2 * 4;
630
for (;;) {
631
c = MEM_S8(format_addr + pos);
632
++pos;
633
if (c == '%') {
634
bool l = false;
635
c = MEM_S8(format_addr + pos);
636
++pos;
637
uint32_t zeros = 0;
638
bool zero_prefix = false;
639
continue_format:
640
switch (c) {
641
case '0':
642
do {
643
c = MEM_S8(format_addr + pos);
644
++pos;
645
if (c >= '0' && c <= '9') {
646
zeros *= 10;
647
zeros += c - '0';
648
}
649
} while (c >= '0' && c <= '9');
650
goto continue_format;
651
case '#':
652
c = MEM_S8(format_addr + pos);
653
++pos;
654
zero_prefix = true;
655
goto continue_format;
656
break;
657
case 'l':
658
assert(!l && "ll not implemented in fscanf");
659
c = MEM_S8(format_addr + pos);
660
++pos;
661
l = true;
662
goto continue_format;
663
break;
664
case 'd':
665
if (zeros != 0) {
666
char temp1[32];
667
sprintf(temp1, "%%0%dd", zeros);
668
sprintf(temp, temp1, MEM_S32(sp));
669
} else {
670
sprintf(temp, "%d", MEM_S32(sp));
671
}
672
sp += 4;
673
str_addr = strcpy1(mem, str_addr, temp);
674
++ret;
675
break;
676
case 'o':
677
if (zero_prefix) {
678
sprintf(temp, "%#o", MEM_S32(sp));
679
} else {
680
sprintf(temp, "%o", MEM_S32(sp));
681
}
682
sp += 4;
683
str_addr = strcpy1(mem, str_addr, temp);
684
++ret;
685
break;
686
case 'x':
687
if (zero_prefix) {
688
sprintf(temp, "%#x", MEM_S32(sp));
689
} else {
690
sprintf(temp, "%x", MEM_S32(sp));
691
}
692
sp += 4;
693
str_addr = strcpy1(mem, str_addr, temp);
694
++ret;
695
break;
696
case 'u':
697
sprintf(temp, "%u", MEM_S32(sp));
698
sp += 4;
699
str_addr = strcpy1(mem, str_addr, temp);
700
++ret;
701
break;
702
case 's':
703
str_addr = strcpy2(mem, str_addr, MEM_U32(sp));
704
sp += 4;
705
++ret;
706
break;
707
case 'c':
708
MEM_S8(str_addr) = (char)MEM_U32(sp);
709
++str_addr;
710
sp += 4;
711
++ret;
712
break;
713
case '%':
714
MEM_S8(str_addr) = '%';
715
++str_addr;
716
break;
717
default:
718
fprintf(stderr, "%s\n", format);
719
assert(0 && "non-implemented sprintf format");
720
}
721
} else if (c == '\0') {
722
break;
723
} else {
724
MEM_S8(str_addr) = c;
725
++str_addr;
726
}
727
}
728
729
MEM_S8(str_addr) = '\0';
730
STRING(orig_str) // for debug
731
//printf("result: '%s' '%s'\n", format, orig_str);
732
return ret;
733
}
734
735
int wrapper_fprintf(uint8_t *mem, uint32_t fp_addr, uint32_t format_addr, uint32_t sp) {
736
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
737
STRING(format)
738
sp += 8;
739
/*if (!strcmp(format, "%s")) {
740
uint32_t s_addr = MEM_U32(sp);
741
STRING(s)
742
if (fp_addr == STDERR_ADDR) {
743
fprintf(stderr, "%s", s);
744
fflush(stderr);
745
return 1;
746
}
747
}
748
if (!strcmp(format, "%s: %s: ")) {
749
uint32_t s1_addr = MEM_U32(sp), s2_addr = MEM_U32(sp + 4);
750
STRING(s1)
751
STRING(s2)
752
if (fp_addr == STDERR_ADDR) {
753
fprintf(stderr, "%s: %s: ", s1, s2);
754
fflush(stderr);
755
return 1;
756
}
757
}*/
758
int ret = 0;
759
for (;;) {
760
uint32_t pos = format_addr;
761
char ch = MEM_S8(pos);
762
while (ch != '%' && ch != '\0') {
763
++pos;
764
ch = MEM_S8(pos);
765
}
766
if (format_addr != pos) {
767
if (wrapper_fwrite(mem, format_addr, 1, pos - format_addr, fp_addr) != pos - format_addr) {
768
break;
769
}
770
}
771
if (ch == '\0') {
772
break;
773
}
774
++pos;
775
ch = MEM_S8(pos);
776
switch (ch) {
777
case 'd':
778
{
779
char buf[32];
780
sprintf(buf, "%d", MEM_U32(sp));
781
strcpy1(mem, INTBUF_ADDR, buf);
782
if (wrapper_fputs(mem, INTBUF_ADDR, fp_addr) == -1) {
783
return ret;
784
}
785
sp += 4;
786
++ret;
787
break;
788
}
789
case 's':
790
{
791
if (wrapper_fputs(mem, MEM_U32(sp), fp_addr) == -1) {
792
return ret;
793
}
794
sp += 4;
795
++ret;
796
break;
797
}
798
case 'c':
799
{
800
char buf[32];
801
sprintf(buf, "%c", MEM_U32(sp));
802
strcpy1(mem, INTBUF_ADDR, buf);
803
if (wrapper_fputs(mem, INTBUF_ADDR, fp_addr) == -1) {
804
return ret;
805
}
806
sp += 4;
807
++ret;
808
break;
809
}
810
default:
811
fprintf(stderr, "missing format: '%s'\n", format);
812
assert(0 && "non-implemented fprintf format");
813
}
814
format_addr = ++pos;
815
}
816
return ret;
817
}
818
819
int wrapper__doprnt(uint8_t *mem, uint32_t format_addr, uint32_t params_addr, uint32_t fp_addr) {
820
assert(0 && "_doprnt not implemented");
821
return 0;
822
}
823
824
uint32_t wrapper_strlen(uint8_t *mem, uint32_t str_addr) {
825
uint32_t len = 0;
826
while (MEM_S8(str_addr) != '\0') {
827
++str_addr;
828
++len;
829
}
830
return len;
831
}
832
833
int wrapper_open(uint8_t *mem, uint32_t pathname_addr, int flags, int mode) {
834
STRING(pathname)
835
int f = flags & O_ACCMODE;
836
if (flags & 0x100) {
837
f |= O_CREAT;
838
}
839
if (flags & 0x200) {
840
f |= O_TRUNC;
841
}
842
if (flags & 0x400) {
843
f |= O_EXCL;
844
}
845
if (flags & 0x800) {
846
f |= O_NOCTTY;
847
}
848
if (flags & 0x08) {
849
f |= O_APPEND;
850
}
851
int fd = open(pathname, f, mode);
852
MEM_U32(ERRNO_ADDR) = errno;
853
return fd;
854
}
855
856
int wrapper_creat(uint8_t *mem, uint32_t pathname_addr, int mode) {
857
STRING(pathname)
858
int ret = creat(pathname, mode);
859
if (ret < 0) {
860
MEM_U32(ERRNO_ADDR) = errno;
861
}
862
return ret;
863
}
864
865
int wrapper_access(uint8_t *mem, uint32_t pathname_addr, int mode) {
866
STRING(pathname)
867
int ret = access(pathname, mode);
868
if (ret != 0) {
869
MEM_U32(ERRNO_ADDR) = errno;
870
}
871
return ret;
872
}
873
874
int wrapper_rename(uint8_t *mem, uint32_t oldpath_addr, uint32_t newpath_addr) {
875
STRING(oldpath)
876
STRING(newpath)
877
int ret = rename(oldpath, newpath);
878
if (ret != 0) {
879
MEM_U32(ERRNO_ADDR) = errno;
880
}
881
return ret;
882
}
883
884
int wrapper_utime(uint8_t *mem, uint32_t filename_addr, uint32_t times_addr) {
885
STRING(filename)
886
struct utimbuf buf = {0, 0};
887
int ret = utime(filename, times_addr == 0 ? NULL : &buf);
888
if (ret == 0) {
889
if (times_addr != 0) {
890
MEM_U32(times_addr + 0) = buf.actime;
891
MEM_U32(times_addr + 4) = buf.modtime;
892
}
893
} else {
894
MEM_U32(ERRNO_ADDR) = errno;
895
}
896
return ret;
897
}
898
899
int wrapper_flock(uint8_t *mem, int fd, int operation) {
900
int ret = flock(fd, operation);
901
if (ret != 0) {
902
MEM_U32(ERRNO_ADDR) = errno;
903
}
904
return ret;
905
}
906
907
int wrapper_chmod(uint8_t *mem, uint32_t path_addr, uint32_t mode) {
908
STRING(path)
909
int ret = chmod(path, mode);
910
if (ret < 0) {
911
MEM_U32(ERRNO_ADDR) = errno;
912
}
913
return ret;
914
}
915
916
int wrapper_umask(int mode) {
917
return umask(mode);
918
}
919
920
uint32_t wrapper_ecvt(uint8_t *mem, double number, int ndigits, uint32_t decpt_addr, uint32_t sign_addr) {
921
assert(0);
922
}
923
924
uint32_t wrapper_fcvt(uint8_t *mem, double number, int ndigits, uint32_t decpt_addr, uint32_t sign_addr) {
925
assert(0);
926
}
927
928
double wrapper_sqrt(double v) {
929
return sqrt(v);
930
}
931
932
float wrapper_sqrtf(float v) {
933
return sqrtf(v);
934
}
935
936
int wrapper_atoi(uint8_t *mem, uint32_t nptr_addr) {
937
STRING(nptr)
938
return atoi(nptr);
939
}
940
941
int wrapper_atol(uint8_t *mem, uint32_t nptr_addr) {
942
return wrapper_atoi(mem, nptr_addr);
943
}
944
945
double wrapper_atof(uint8_t *mem, uint32_t nptr_addr) {
946
STRING(nptr);
947
return atof(nptr);
948
}
949
950
int wrapper_strtol(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base) {
951
STRING(nptr)
952
char *endptr = NULL;
953
int64_t res = strtoll(nptr, endptr_addr != 0 ? &endptr : NULL, base);
954
if (res > INT_MAX) {
955
MEM_U32(ERRNO_ADDR) = ERANGE;
956
res = INT_MAX;
957
}
958
if (res < INT_MIN) {
959
MEM_U32(ERRNO_ADDR) = ERANGE;
960
res = INT_MIN;
961
}
962
if (endptr != NULL) {
963
MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr);
964
}
965
return res;
966
}
967
968
uint32_t wrapper_strtoul(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr, int base) {
969
STRING(nptr)
970
char *endptr = NULL;
971
uint64_t res = strtoull(nptr, endptr_addr != 0 ? &endptr : NULL, base);
972
if (res > INT_MAX) {
973
MEM_U32(ERRNO_ADDR) = ERANGE;
974
res = INT_MAX;
975
}
976
if (endptr != NULL) {
977
MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr);
978
}
979
return res;
980
}
981
982
double wrapper_strtod(uint8_t *mem, uint32_t nptr_addr, uint32_t endptr_addr) {
983
STRING(nptr)
984
char *endptr = NULL;
985
errno = 0;
986
double res = strtod(nptr, endptr_addr != 0 ? &endptr : NULL);
987
if (errno != 0) {
988
MEM_U32(ERRNO_ADDR) = errno;
989
}
990
if (endptr != NULL) {
991
MEM_U32(endptr_addr) = nptr_addr + (uint32_t)(endptr - nptr);
992
}
993
return res;
994
}
995
996
uint32_t wrapper_strchr(uint8_t *mem, uint32_t str_addr, int c) {
997
c = c & 0xff;
998
for (;;) {
999
unsigned char ch = MEM_U8(str_addr);
1000
if (ch == c) {
1001
return str_addr;
1002
}
1003
if (ch == '\0') {
1004
return 0;
1005
}
1006
++str_addr;
1007
}
1008
}
1009
1010
uint32_t wrapper_strrchr(uint8_t *mem, uint32_t str_addr, int c) {
1011
c = c & 0xff;
1012
uint32_t ret = 0;
1013
for (;;) {
1014
unsigned char ch = MEM_U8(str_addr);
1015
if (ch == c) {
1016
ret = str_addr;
1017
}
1018
if (ch == '\0') {
1019
return ret;
1020
}
1021
++str_addr;
1022
}
1023
}
1024
1025
uint32_t wrapper_strcspn(uint8_t *mem, uint32_t str_addr, uint32_t invalid_addr) {
1026
STRING(invalid)
1027
uint32_t n = strlen(invalid);
1028
uint32_t pos = 0;
1029
char c;
1030
while ((c = MEM_S8(str_addr)) != 0) {
1031
for (int i = 0; i < n; i++) {
1032
if (c == invalid[i]) {
1033
return pos;
1034
}
1035
}
1036
++pos;
1037
++str_addr;
1038
}
1039
return pos;
1040
}
1041
1042
uint32_t wrapper_strpbrk(uint8_t *mem, uint32_t str_addr, uint32_t accept_addr) {
1043
STRING(accept)
1044
uint32_t n = strlen(accept);
1045
char c;
1046
while ((c = MEM_S8(str_addr)) != 0) {
1047
for (int i = 0; i < n; i++) {
1048
if (c == accept[i]) {
1049
return str_addr;
1050
}
1051
}
1052
++str_addr;
1053
}
1054
return 0;
1055
}
1056
1057
static void stat_common(uint8_t *mem, uint32_t buf_addr, struct stat *statbuf) {
1058
struct irix_stat {
1059
int st_dev;
1060
int pad1[3];
1061
int st_ino;
1062
int st_mode;
1063
int st_nlink;
1064
int st_uid;
1065
int st_gid;
1066
int st_rdev;
1067
int pad2[2];
1068
int st_size;
1069
int pad3;
1070
struct timespec_t_irix st_atim;
1071
struct timespec_t_irix st_mtim;
1072
struct timespec_t_irix st_ctim;
1073
int st_blksize;
1074
int st_blocks;
1075
} s;
1076
s.st_dev = statbuf->st_dev;
1077
s.st_ino = statbuf->st_ino;
1078
s.st_mode = statbuf->st_mode;
1079
s.st_nlink = statbuf->st_nlink;
1080
s.st_uid = statbuf->st_uid;
1081
s.st_gid = statbuf->st_gid;
1082
s.st_rdev = statbuf->st_rdev;
1083
s.st_size = statbuf->st_size;
1084
#ifdef __APPLE__
1085
s.st_atim.tv_sec = statbuf->st_atimespec.tv_sec;
1086
s.st_atim.tv_nsec = statbuf->st_atimespec.tv_nsec;
1087
s.st_mtim.tv_sec = statbuf->st_mtimespec.tv_sec;
1088
s.st_mtim.tv_nsec = statbuf->st_mtimespec.tv_nsec;
1089
s.st_ctim.tv_sec = statbuf->st_ctimespec.tv_sec;
1090
s.st_ctim.tv_nsec = statbuf->st_ctimespec.tv_nsec;
1091
#else
1092
s.st_atim.tv_sec = statbuf->st_atim.tv_sec;
1093
s.st_atim.tv_nsec = statbuf->st_atim.tv_nsec;
1094
s.st_mtim.tv_sec = statbuf->st_mtim.tv_sec;
1095
s.st_mtim.tv_nsec = statbuf->st_mtim.tv_nsec;
1096
s.st_ctim.tv_sec = statbuf->st_ctim.tv_sec;
1097
s.st_ctim.tv_nsec = statbuf->st_ctim.tv_nsec;
1098
#endif
1099
memcpy(&MEM_U32(buf_addr), &s, sizeof(s));
1100
}
1101
1102
int wrapper_fstat(uint8_t *mem, int fildes, uint32_t buf_addr) {
1103
struct stat statbuf;
1104
if (fstat(fildes, &statbuf) < 0) {
1105
MEM_U32(ERRNO_ADDR) = errno;
1106
return -1;
1107
} else {
1108
stat_common(mem, buf_addr, &statbuf);
1109
return 0;
1110
}
1111
}
1112
1113
int wrapper_stat(uint8_t *mem, uint32_t pathname_addr, uint32_t buf_addr) {
1114
STRING(pathname)
1115
struct stat statbuf;
1116
if (stat(pathname, &statbuf) < 0) {
1117
MEM_U32(ERRNO_ADDR) = errno;
1118
return -1;
1119
} else {
1120
stat_common(mem, buf_addr, &statbuf);
1121
return 0;
1122
}
1123
}
1124
1125
int wrapper_ftruncate(uint8_t *mem, int fd, int length) {
1126
int ret = ftruncate(fd, length);
1127
if (ret != 0) {
1128
MEM_U32(ERRNO_ADDR) = errno;
1129
}
1130
return ret;
1131
}
1132
1133
void wrapper_bcopy(uint8_t *mem, uint32_t src_addr, uint32_t dst_addr, uint32_t len) {
1134
wrapper_memcpy(mem, dst_addr, src_addr, len);
1135
}
1136
1137
uint32_t wrapper_memcpy(uint8_t *mem, uint32_t dst_addr, uint32_t src_addr, uint32_t len) {
1138
uint32_t saved = dst_addr;
1139
if (dst_addr % 4 == 0 && src_addr % 4 == 0 && len % 4 == 0) {
1140
memcpy(&MEM_U32(dst_addr), &MEM_U32(src_addr), len);
1141
} else {
1142
while (len--) {
1143
MEM_U8(dst_addr) = MEM_U8(src_addr);
1144
++dst_addr;
1145
++src_addr;
1146
}
1147
}
1148
return saved;
1149
}
1150
1151
uint32_t wrapper_memccpy(uint8_t *mem, uint32_t dst_addr, uint32_t src_addr, int c, uint32_t len) {
1152
while (len--) {
1153
uint8_t ch = MEM_U8(src_addr);
1154
MEM_U8(dst_addr) = ch;
1155
++dst_addr;
1156
++src_addr;
1157
if (ch == c) {
1158
return dst_addr;
1159
}
1160
}
1161
return 0;
1162
}
1163
1164
int wrapper_read(uint8_t *mem, int fd, uint32_t buf_addr, uint32_t nbytes) {
1165
uint8_t *buf = (uint8_t *)malloc(nbytes);
1166
ssize_t ret = read(fd, buf, nbytes);
1167
if (ret < 0) {
1168
MEM_U32(ERRNO_ADDR) = errno;
1169
} else {
1170
for (ssize_t i = 0; i < ret; i++) {
1171
MEM_U8(buf_addr + i) = buf[i];
1172
}
1173
}
1174
free(buf);
1175
return (int)ret;
1176
}
1177
1178
int wrapper_write(uint8_t *mem, int fd, uint32_t buf_addr, uint32_t nbytes) {
1179
uint8_t *buf = (uint8_t *)malloc(nbytes);
1180
for (size_t i = 0; i < nbytes; i++) {
1181
buf[i] = MEM_U8(buf_addr + i);
1182
}
1183
ssize_t ret = write(fd, buf, nbytes);
1184
if (ret < 0) {
1185
MEM_U32(ERRNO_ADDR) = errno;
1186
}
1187
free(buf);
1188
return (int)ret;
1189
}
1190
1191
static uint32_t init_file(uint8_t *mem, int fd, int i, const char *path, const char *mode) {
1192
int flags = O_RDONLY;
1193
if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) {
1194
flags = O_RDONLY;
1195
} else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0) {
1196
flags = O_WRONLY | O_CREAT | O_TRUNC;
1197
} else if (strcmp(mode, "a") == 0 || strcmp(mode, "ab") == 0) {
1198
flags = O_WRONLY | O_CREAT | O_APPEND;
1199
} else if (strcmp(mode, "r+") == 0 || strcmp(mode, "r+b") == 0) {
1200
flags = O_RDWR;
1201
} else if (strcmp(mode, "w+") == 0 || strcmp(mode, "w+b") == 0) {
1202
flags = O_RDWR | O_CREAT | O_TRUNC;
1203
} else if (strcmp(mode, "a+") == 0 || strcmp(mode, "a+b") == 0) {
1204
flags = O_RDWR | O_CREAT | O_APPEND;
1205
}
1206
if (fd == -1) {
1207
1208
#ifdef REDIRECT_USR_LIB
1209
char fixed_path[PATH_MAX + 1];
1210
if (!strcmp(path, "/usr/lib/err.english.cc") && bin_dir[0] != '\0') {
1211
int n = snprintf(fixed_path, sizeof(fixed_path), "%s/err.english.cc", bin_dir);
1212
if (n >= 0 && n < sizeof(fixed_path)) {
1213
path = fixed_path;
1214
}
1215
}
1216
#endif
1217
fd = open(path, flags, 0666);
1218
if (fd < 0) {
1219
MEM_U32(ERRNO_ADDR) = errno;
1220
return 0;
1221
}
1222
}
1223
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(IOB_ADDR);
1224
uint32_t ret = 0;
1225
if (i == -1) {
1226
for (i = 3; i < NFILE; i++) {
1227
if (f[i]._flag == 0) {
1228
break;
1229
}
1230
}
1231
}
1232
assert(i < NFILE);
1233
g_file_max = i + 1;
1234
ret = IOB_ADDR + i * sizeof(struct FILE_irix);
1235
f[i]._cnt = 0;
1236
f[i]._ptr_addr = 0;
1237
f[i]._base_addr = 0;
1238
f[i]._file = fd;
1239
f[i]._flag = (flags & O_ACCMODE) == O_RDONLY ? IOREAD : 0;
1240
f[i]._flag |= (flags & O_ACCMODE) == O_WRONLY ? IOWRT : 0;
1241
f[i]._flag |= (flags & O_ACCMODE) == O_RDWR ? IORW : 0;
1242
bufendtab[i] = 0;
1243
return ret;
1244
}
1245
1246
uint32_t wrapper_fopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr) {
1247
STRING(path)
1248
STRING(mode)
1249
return init_file(mem, -1, -1, path, mode);
1250
}
1251
1252
uint32_t wrapper_freopen(uint8_t *mem, uint32_t path_addr, uint32_t mode_addr, uint32_t fp_addr) {
1253
STRING(path)
1254
STRING(mode)
1255
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1256
wrapper_fclose(mem, fp_addr);
1257
return init_file(mem, -1, f - (struct FILE_irix *)&MEM_U32(IOB_ADDR), path, mode);
1258
}
1259
1260
int wrapper_fclose(uint8_t *mem, uint32_t fp_addr) {
1261
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1262
wrapper_fflush(mem, fp_addr);
1263
if (f->_flag & IOMYBUF) {
1264
wrapper_free(mem, f->_base_addr);
1265
}
1266
f->_flag = 0;
1267
close(f->_file);
1268
return 0;
1269
}
1270
1271
static int flush_all(uint8_t *mem) {
1272
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(IOB_ADDR);
1273
int ret = 0;
1274
for (int i = 0; i < g_file_max; i++) {
1275
if (f[i]._flag & IOWRT) {
1276
ret |= wrapper_fflush(mem, IOB_ADDR + i * sizeof(struct FILE_irix));
1277
}
1278
}
1279
return ret;
1280
}
1281
1282
int wrapper_fflush(uint8_t *mem, uint32_t fp_addr) {
1283
if (fp_addr == 0) {
1284
// Flush all
1285
return flush_all(mem);
1286
}
1287
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1288
if (f->_flag & IOWRT) {
1289
int p = 0;
1290
int to_flush = f->_ptr_addr - f->_base_addr;
1291
int c = to_flush;
1292
while (c > 0) {
1293
int r = wrapper_write(mem, f->_file, f->_base_addr + p, c);
1294
if (r < 0) {
1295
f->_file |= IOERR;
1296
return -1;
1297
}
1298
p += r;
1299
c -= r;
1300
}
1301
f->_ptr_addr = f->_base_addr;
1302
f->_cnt += to_flush;
1303
}
1304
return 0;
1305
}
1306
1307
int wrapper_ftell(uint8_t *mem, uint32_t fp_addr) {
1308
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1309
int adjust;
1310
if (f->_cnt < 0) {
1311
f->_cnt = 0;
1312
}
1313
if (f->_flag & IOREAD) {
1314
adjust = -f->_cnt;
1315
} else if (f->_flag & (IOWRT | IORW)) {
1316
adjust = 0;
1317
if ((f->_flag & IOWRT) && f->_base_addr != 0 && (f->_flag & IONBF) == 0) {
1318
adjust = f->_ptr_addr - f->_base_addr;
1319
}
1320
} else {
1321
return -1;
1322
}
1323
int res = wrapper_lseek(mem, f->_file, 0, 1);
1324
if (res >= 0) {
1325
res += adjust;
1326
}
1327
return res;
1328
}
1329
1330
void wrapper_rewind(uint8_t *mem, uint32_t fp_addr) {
1331
(void)wrapper_fseek(mem, fp_addr, 0, SEEK_SET);
1332
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1333
f->_flag &= ~IOERR;
1334
}
1335
1336
int wrapper_fseek(uint8_t *mem, uint32_t fp_addr, int offset, int origin) {
1337
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1338
int c, p;
1339
f->_flag &= ~IOEOF;
1340
if (f->_flag & IOREAD) {
1341
if (origin < SEEK_END && f->_base_addr && !(f->_flag & IONBF)) {
1342
c = f->_cnt;
1343
p = offset;
1344
if (origin == SEEK_SET) {
1345
p += c - lseek(f->_file, 0L, SEEK_CUR);
1346
} else {
1347
offset -= c;
1348
}
1349
if (!(f->_flag & IORW) && c > 0 && p <= c && p >= f->_base_addr - f->_ptr_addr) {
1350
f->_ptr_addr += p;
1351
f->_cnt -= p;
1352
return 0;
1353
}
1354
}
1355
if (f->_flag & IORW) {
1356
f->_ptr_addr = f->_base_addr;
1357
f->_flag &= ~IOREAD;
1358
}
1359
p = lseek(f->_file, offset, origin);
1360
f->_cnt = 0;
1361
} else if (f->_flag & (IOWRT | IORW)) {
1362
wrapper_fflush(mem, fp_addr);
1363
if (f->_flag & IORW) {
1364
f->_cnt = 0;
1365
f->_flag &= ~IOWRT;
1366
f->_ptr_addr = f->_base_addr;
1367
}
1368
p = lseek(f->_file, offset, origin);
1369
}
1370
if (p < 0) {
1371
MEM_U32(ERRNO_ADDR) = errno;
1372
return p;
1373
}
1374
return 0;
1375
}
1376
1377
int wrapper_lseek(uint8_t *mem, int fd, int offset, int whence) {
1378
int ret = (int)lseek(fd, offset, whence);
1379
if (ret == -1) {
1380
MEM_U32(ERRNO_ADDR) = errno;
1381
}
1382
return ret;
1383
}
1384
1385
int wrapper_dup(uint8_t *mem, int fd) {
1386
fd = dup(fd);
1387
if (fd < 0) {
1388
MEM_U32(ERRNO_ADDR) = errno;
1389
}
1390
return fd;
1391
}
1392
1393
int wrapper_dup2(uint8_t *mem, int oldfd, int newfd) {
1394
int fd = dup2(oldfd, newfd);
1395
if (fd < 0) {
1396
MEM_U32(ERRNO_ADDR) = errno;
1397
}
1398
return fd;
1399
}
1400
1401
int wrapper_pipe(uint8_t *mem, uint32_t pipefd_addr) {
1402
int pipefd[2];
1403
int ret = pipe(pipefd);
1404
if (ret == 0) {
1405
MEM_U32(pipefd_addr + 0) = pipefd[0];
1406
MEM_U32(pipefd_addr + 4) = pipefd[1];
1407
} else {
1408
MEM_U32(ERRNO_ADDR) = errno;
1409
}
1410
return ret;
1411
}
1412
1413
void wrapper_perror(uint8_t *mem, uint32_t str_addr) {
1414
STRING(str)
1415
perror(str);
1416
}
1417
1418
int wrapper_fdopen(uint8_t *mem, int fd, uint32_t mode_addr) {
1419
STRING(mode)
1420
return init_file(mem, fd, -1, NULL, mode);
1421
}
1422
1423
uint32_t wrapper_memset(uint8_t *mem, uint32_t dest_addr, int byte, uint32_t n) {
1424
uint32_t saved = dest_addr;
1425
if (dest_addr % 4 == 0 && n % 4 == 0) {
1426
memset(&MEM_U32(dest_addr), byte, n);
1427
} else {
1428
while (n--) {
1429
MEM_U8(dest_addr) = (uint8_t)byte;
1430
++dest_addr;
1431
}
1432
}
1433
return saved;
1434
}
1435
1436
int wrapper_bcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n) {
1437
while (n--) {
1438
if (MEM_U8(s1_addr) != MEM_U8(s2_addr)) {
1439
return 1;
1440
}
1441
++s1_addr;
1442
++s2_addr;
1443
}
1444
return 0;
1445
}
1446
1447
int wrapper_memcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n) {
1448
while (n--) {
1449
unsigned char c1 = MEM_U8(s1_addr);
1450
unsigned char c2 = MEM_U8(s2_addr);
1451
if (c1 < c2) {
1452
return -1;
1453
}
1454
if (c1 > c2) {
1455
return 1;
1456
}
1457
++s1_addr;
1458
++s2_addr;
1459
}
1460
return 0;
1461
}
1462
1463
int wrapper_getpid(void) {
1464
return getpid();
1465
}
1466
1467
int wrapper_getpgrp(uint8_t *mem) {
1468
int ret = getpgrp();
1469
if (ret == -1) {
1470
MEM_U32(ERRNO_ADDR) = errno;
1471
}
1472
return ret;
1473
}
1474
1475
int wrapper_remove(uint8_t *mem, uint32_t path_addr) {
1476
STRING(path)
1477
int ret = remove(path);
1478
if (ret < 0) {
1479
MEM_U32(ERRNO_ADDR) = errno;
1480
}
1481
return ret;
1482
}
1483
1484
int wrapper_unlink(uint8_t *mem, uint32_t path_addr) {
1485
if (path_addr == 0) {
1486
fprintf(stderr, "Warning: unlink with NULL as arguement\n");
1487
MEM_U32(ERRNO_ADDR) = EFAULT;
1488
return -1;
1489
}
1490
STRING(path)
1491
int ret = unlink(path);
1492
if (ret < 0) {
1493
MEM_U32(ERRNO_ADDR) = errno;
1494
}
1495
return ret;
1496
}
1497
1498
int wrapper_close(uint8_t *mem, int fd) {
1499
int ret = close(fd);
1500
if (ret < 0) {
1501
MEM_U32(ERRNO_ADDR) = errno;
1502
}
1503
return ret;
1504
}
1505
1506
int wrapper_strcmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr) {
1507
for (;;) {
1508
char c1 = MEM_S8(s1_addr);
1509
char c2 = MEM_S8(s2_addr);
1510
if (c1 != c2) {
1511
return c1 < c2 ? -1 : 1;
1512
}
1513
if (c1 == '\0') {
1514
return 0;
1515
}
1516
++s1_addr;
1517
++s2_addr;
1518
}
1519
}
1520
1521
int wrapper_strncmp(uint8_t *mem, uint32_t s1_addr, uint32_t s2_addr, uint32_t n) {
1522
if (n == 0) {
1523
return 0;
1524
}
1525
for (;;) {
1526
char c1 = MEM_S8(s1_addr);
1527
char c2 = MEM_S8(s2_addr);
1528
if (c1 != c2) {
1529
return c1 < c2 ? -1 : 1;
1530
}
1531
if (--n == 0 || c1 == '\0') {
1532
return 0;
1533
}
1534
++s1_addr;
1535
++s2_addr;
1536
}
1537
}
1538
1539
uint32_t wrapper_strcpy(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) {
1540
uint32_t saved = dest_addr;
1541
for (;;) {
1542
char c = MEM_S8(src_addr);
1543
++src_addr;
1544
MEM_S8(dest_addr) = c;
1545
++dest_addr;
1546
if (c == '\0') {
1547
return saved;
1548
}
1549
}
1550
}
1551
1552
uint32_t wrapper_strncpy(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr, uint32_t n) {
1553
uint32_t i;
1554
for (i = 0; i < n && MEM_S8(src_addr) != '\0'; i++) {
1555
MEM_S8(dest_addr + i) = MEM_S8(src_addr + i);
1556
}
1557
for (; i < n; i++) {
1558
MEM_S8(dest_addr + i) = '\0';
1559
}
1560
return dest_addr;
1561
}
1562
1563
uint32_t wrapper_strcat(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr) {
1564
uint32_t saved = dest_addr;
1565
while (MEM_S8(dest_addr) != '\0') {
1566
++dest_addr;
1567
}
1568
while (MEM_S8(src_addr) != '\0') {
1569
MEM_S8(dest_addr) = MEM_S8(src_addr);
1570
++src_addr;
1571
++dest_addr;
1572
}
1573
MEM_S8(dest_addr) = '\0';
1574
return saved;
1575
}
1576
1577
uint32_t wrapper_strncat(uint8_t *mem, uint32_t dest_addr, uint32_t src_addr, uint32_t n) {
1578
uint32_t saved = dest_addr;
1579
while (MEM_S8(dest_addr) != '\0') {
1580
++dest_addr;
1581
}
1582
while (n-- && MEM_S8(src_addr) != '\0') {
1583
MEM_S8(dest_addr) = MEM_S8(src_addr);
1584
++src_addr;
1585
++dest_addr;
1586
}
1587
MEM_S8(dest_addr) = '\0';
1588
return saved;
1589
}
1590
1591
uint32_t wrapper_strtok(uint8_t *mem, uint32_t str_addr, uint32_t delimiters_addr) {
1592
if (str_addr == 0) {
1593
str_addr = MEM_U32(STRTOK_DATA_ADDR);
1594
}
1595
if (str_addr == 0) {
1596
// nothing remaining
1597
return 0;
1598
}
1599
uint32_t p;
1600
for (p = str_addr; MEM_S8(p) != '\0'; p++) {
1601
uint32_t q;
1602
for (q = delimiters_addr; MEM_S8(q) != '\0' && MEM_S8(q) != MEM_S8(p); q++) {
1603
}
1604
if (MEM_S8(q) == '\0') {
1605
break;
1606
}
1607
}
1608
if (MEM_S8(p) == '\0') {
1609
return 0;
1610
}
1611
uint32_t ret = p;
1612
for (;;) {
1613
uint32_t q;
1614
for (q = delimiters_addr; MEM_S8(q) != '\0' && MEM_S8(q) != MEM_S8(p); q++) {
1615
}
1616
if (MEM_S8(q) != '\0') {
1617
MEM_S8(p) = '\0';
1618
MEM_U32(STRTOK_DATA_ADDR) = ++p;
1619
return ret;
1620
}
1621
char next = MEM_S8(p);
1622
++p;
1623
if (next == '\0') {
1624
MEM_U32(STRTOK_DATA_ADDR) = 0;
1625
return ret;
1626
}
1627
}
1628
}
1629
1630
uint32_t wrapper_strstr(uint8_t *mem, uint32_t str1_addr, uint32_t str2_addr) {
1631
for (;;) {
1632
if (MEM_S8(str1_addr) == '\0') {
1633
return 0;
1634
}
1635
uint32_t s1 = str1_addr;
1636
uint32_t s2 = str2_addr;
1637
for (;;) {
1638
char c2 = MEM_S8(s2);
1639
if (c2 == '\0') {
1640
return str1_addr;
1641
}
1642
if (MEM_S8(s1) == c2) {
1643
++s1;
1644
++s2;
1645
} else {
1646
break;
1647
}
1648
}
1649
++str1_addr;
1650
}
1651
}
1652
1653
uint32_t wrapper_strdup(uint8_t *mem, uint32_t str_addr) {
1654
uint32_t len = wrapper_strlen(mem, str_addr) + 1;
1655
uint32_t ret = wrapper_malloc(mem, len);
1656
if (ret == 0) {
1657
MEM_U32(ERRNO_ADDR) = ENOMEM;
1658
return 0;
1659
}
1660
return wrapper_memcpy(mem, ret, str_addr, len);
1661
}
1662
1663
int wrapper_toupper(int c) {
1664
return toupper(c);
1665
}
1666
1667
int wrapper_tolower(int c) {
1668
return tolower(c);
1669
}
1670
1671
int wrapper_gethostname(uint8_t *mem, uint32_t name_addr, uint32_t len) {
1672
char buf[256] = {0};
1673
if (len > 256) {
1674
len = 256;
1675
}
1676
int ret = gethostname(buf, len);
1677
if (ret < 0) {
1678
MEM_U32(ERRNO_ADDR) = errno;
1679
} else {
1680
for (uint32_t i = 0; i < len; i++) {
1681
MEM_S8(name_addr + i) = buf[i];
1682
}
1683
}
1684
return ret;
1685
}
1686
1687
int wrapper_isatty(uint8_t *mem, int fd) {
1688
int ret = isatty(fd);
1689
if (ret == 0) {
1690
MEM_U32(ERRNO_ADDR) = errno;
1691
}
1692
return ret;
1693
}
1694
1695
uint32_t wrapper_strftime(uint8_t *mem, uint32_t ptr_addr, uint32_t maxsize, uint32_t format_addr, uint32_t timeptr_addr) {
1696
//assert(0 && "strftime not implemented");
1697
MEM_S8(ptr_addr) = 0;
1698
return 0;
1699
}
1700
1701
int wrapper_times(uint8_t *mem, uint32_t buffer_addr) {
1702
struct tms_irix {
1703
int tms_utime;
1704
int tms_stime;
1705
int tms_cutime;
1706
int tms_cstime;
1707
} r;
1708
struct tms t;
1709
clock_t ret = times(&t);
1710
if (ret == (clock_t)-1) {
1711
MEM_U32(ERRNO_ADDR) = errno;
1712
} else {
1713
r.tms_utime = t.tms_utime;
1714
r.tms_stime = t.tms_stime;
1715
r.tms_cutime = t.tms_cutime;
1716
r.tms_cstime = t.tms_cstime;
1717
}
1718
return (int)ret;
1719
}
1720
1721
int wrapper_clock(void) {
1722
return (int)clock();
1723
}
1724
1725
uint32_t wrapper_ctime(uint8_t *mem, uint32_t timep_addr) {
1726
time_t t = MEM_S32(timep_addr);
1727
char *res = ctime(&t);
1728
size_t len = strlen(res) + 1;
1729
uint32_t ret_addr = wrapper_malloc(mem, len);
1730
uint32_t pos = ret_addr;
1731
while (len--) {
1732
MEM_S8(pos) = *res;
1733
++pos;
1734
++res;
1735
}
1736
return ret_addr;
1737
//assert(0 && "ctime not implemented");
1738
//return 0;
1739
}
1740
1741
uint32_t wrapper_localtime(uint8_t *mem, uint32_t timep_addr) {
1742
time_t t = MEM_S32(timep_addr);
1743
struct irix_tm {
1744
int tm_sec;
1745
int tm_min;
1746
int tm_hour;
1747
int tm_mday;
1748
int tm_mon;
1749
int tm_year;
1750
int tm_wday;
1751
int tm_yday;
1752
int tm_isdst;
1753
};
1754
uint32_t ret = wrapper_malloc(mem, sizeof(struct irix_tm));
1755
struct irix_tm *r = (struct irix_tm *)&MEM_U32(ret);
1756
struct tm *l = localtime(&t);
1757
r->tm_sec = l->tm_sec;
1758
r->tm_min = l->tm_min;
1759
r->tm_hour = l->tm_hour;
1760
r->tm_mday = l->tm_mday;
1761
r->tm_mon = l->tm_mon;
1762
r->tm_year = l->tm_year;
1763
r->tm_wday = l->tm_wday;
1764
r->tm_yday = l->tm_yday;
1765
r->tm_isdst = l->tm_isdst;
1766
return ret;
1767
}
1768
1769
int wrapper_setvbuf(uint8_t *mem, uint32_t fp_addr, uint32_t buf_addr, int mode, uint32_t size) {
1770
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1771
wrapper_fflush(mem, fp_addr);
1772
if ((f->_flag & IOMYBUF) && f->_base_addr != 0) {
1773
wrapper_free(mem, f->_base_addr);
1774
}
1775
size &= ~0xf;
1776
f->_flag &= ~IOMYBUF;
1777
f->_base_addr = buf_addr;
1778
f->_ptr_addr = buf_addr;
1779
f->_cnt = 0;
1780
bufendtab[(fp_addr - IOB_ADDR) / sizeof(struct FILE_irix)] = size;
1781
return 0;
1782
}
1783
1784
int wrapper___semgetc(uint8_t *mem, uint32_t fp_addr) {
1785
assert(0);
1786
}
1787
1788
int wrapper___semputc(uint8_t *mem, int c, uint32_t fp_addr) {
1789
assert(0);
1790
}
1791
1792
int wrapper_fgetc(uint8_t *mem, uint32_t fp_addr) {
1793
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1794
if (--f->_cnt < 0) {
1795
return wrapper___filbuf(mem, fp_addr);
1796
} else {
1797
int ret = MEM_U8(f->_ptr_addr);
1798
++f->_ptr_addr;
1799
return ret;
1800
}
1801
}
1802
1803
int wrapper_fgets(uint8_t *mem, uint32_t str_addr, int count, uint32_t fp_addr) {
1804
bool modified = false;
1805
uint32_t saved = str_addr;
1806
for (count--; count > 0; count--) {
1807
int ch = wrapper_fgetc(mem, fp_addr);
1808
if (ch == -1) {
1809
MEM_S8(str_addr) = '\0';
1810
return modified ? saved : 0;
1811
}
1812
modified = true;
1813
MEM_S8(str_addr) = (char)ch;
1814
++str_addr;
1815
if (ch == '\n') {
1816
break;
1817
}
1818
}
1819
MEM_S8(str_addr) = '\0';
1820
return saved;
1821
}
1822
1823
static void file_assign_buffer(uint8_t *mem, struct FILE_irix *f) {
1824
f->_base_addr = wrapper_malloc(mem, STDIO_BUFSIZE);
1825
f->_ptr_addr = f->_base_addr;
1826
f->_flag |= IOMYBUF;
1827
f->_cnt = 0;
1828
bufendtab[f - (struct FILE_irix *)&MEM_U32(IOB_ADDR)] = STDIO_BUFSIZE;
1829
}
1830
1831
int wrapper___filbuf(uint8_t *mem, uint32_t fp_addr) {
1832
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1833
if (!(f->_flag & IOREAD)) {
1834
if (f->_flag & IORW) {
1835
f->_flag |= IOREAD;
1836
} else {
1837
MEM_U32(ERRNO_ADDR) = 9; // EBADF
1838
return -1;
1839
}
1840
}
1841
if (f->_base_addr == 0) {
1842
file_assign_buffer(mem, f);
1843
}
1844
uint32_t size = bufendtab[(fp_addr - IOB_ADDR) / sizeof(struct FILE_irix)];
1845
int nread = wrapper_read(mem, f->_file, f->_base_addr, size);
1846
int ret = -1;
1847
if (nread > 0) {
1848
f->_ptr_addr = f->_base_addr;
1849
f->_cnt = nread;
1850
ret = MEM_U8(f->_ptr_addr);
1851
++f->_ptr_addr;
1852
--f->_cnt;
1853
} else if (nread == 0) {
1854
f->_flag |= IOEOF;
1855
} else {
1856
f->_flag |= IOERR;
1857
}
1858
return ret;
1859
}
1860
1861
int wrapper___flsbuf(uint8_t *mem, int ch, uint32_t fp_addr) {
1862
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1863
if (wrapper_fflush(mem, fp_addr) != 0) {
1864
return -1;
1865
}
1866
if (f->_base_addr == 0) {
1867
file_assign_buffer(mem, f);
1868
f->_cnt = bufendtab[f - (struct FILE_irix *)&MEM_U32(IOB_ADDR)];
1869
}
1870
MEM_U8(f->_ptr_addr) = ch;
1871
++f->_ptr_addr;
1872
--f->_cnt;
1873
if (f->_flag & IONBF) {
1874
if (wrapper_fflush(mem, fp_addr) != 0) {
1875
return -1;
1876
}
1877
f->_cnt = 0;
1878
}
1879
return ch;
1880
}
1881
1882
int wrapper_ungetc(uint8_t *mem, int ch, uint32_t fp_addr) {
1883
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1884
if (ch == -1 || f->_ptr_addr == f->_base_addr) {
1885
return -1;
1886
}
1887
--f->_ptr_addr;
1888
MEM_U8(f->_ptr_addr) = (uint8_t)ch;
1889
++f->_cnt;
1890
f->_flag &= ~IOEOF;
1891
return ch;
1892
}
1893
1894
uint32_t wrapper_gets(uint8_t *mem, uint32_t str_addr) {
1895
uint32_t p, str0 = str_addr;
1896
int n;
1897
1898
for (;;) {
1899
if (STDIN->_cnt <= 0) {
1900
if (wrapper___filbuf(mem, STDIN_ADDR) == -1) {
1901
if (str0 == str_addr) {
1902
return 0;
1903
}
1904
break;
1905
}
1906
--STDIN->_ptr_addr;
1907
++STDIN->_cnt;
1908
}
1909
n = STDIN->_cnt;
1910
if ((p = wrapper_memccpy(mem, str_addr, STDIN->_ptr_addr, '\n', n)) != 0) {
1911
n = p - str_addr;
1912
}
1913
str_addr += n;
1914
STDIN->_cnt -= n;
1915
STDIN->_ptr_addr += n;
1916
// bufsync
1917
if (p != 0) {
1918
// found '\n' in buffer
1919
--str_addr;
1920
break;
1921
}
1922
}
1923
MEM_S8(str_addr) = '\0';
1924
return str0;
1925
}
1926
1927
uint32_t wrapper_fread(uint8_t *mem, uint32_t data_addr, uint32_t size, uint32_t count, uint32_t fp_addr) {
1928
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1929
int nleft = count * size;
1930
int n;
1931
for (;;) {
1932
if (f->_cnt <= 0) {
1933
if (wrapper___filbuf(mem, fp_addr) == -1) {
1934
return count - (nleft + size - 1) / size;
1935
}
1936
--f->_ptr_addr;
1937
++f->_cnt;
1938
}
1939
n = MIN(nleft, f->_cnt);
1940
data_addr = wrapper_memcpy(mem, data_addr, f->_ptr_addr, n) + n;
1941
f->_cnt -= n;
1942
f->_ptr_addr += n;
1943
if ((nleft -= n) <= 0) {
1944
return count;
1945
}
1946
}
1947
}
1948
1949
uint32_t wrapper_fwrite(uint8_t *mem, uint32_t data_addr, uint32_t size, uint32_t count, uint32_t fp_addr) {
1950
struct FILE_irix *f = (struct FILE_irix *)&MEM_U32(fp_addr);
1951
if (size > 0 && count > 0 && f->_base_addr == 0) {
1952
file_assign_buffer(mem, f);
1953
f->_cnt = bufendtab[f - (struct FILE_irix *)&MEM_U32(IOB_ADDR)];
1954
f->_flag |= IOWRT;
1955
}
1956
uint32_t num_written = 0;
1957
while (count--) {
1958
uint32_t s = size;
1959
while (s > 0) {
1960
uint32_t to_write = f->_cnt;
1961
if (s < to_write) {
1962
to_write = s;
1963
}
1964
if (f->_cnt == 0) {
1965
if (wrapper_fflush(mem, fp_addr) != 0) {
1966
return num_written;
1967
}
1968
}
1969
wrapper_memcpy(mem, f->_ptr_addr, data_addr, to_write);
1970
data_addr += to_write;
1971
f->_ptr_addr += to_write;
1972
f->_cnt -= to_write;
1973
s -= to_write;
1974
}
1975
num_written++;
1976
}
1977
if (f->_flag & IONBF) {
1978
wrapper_fflush(mem, fp_addr); // TODO check error return value
1979
}
1980
return num_written;
1981
}
1982
1983
int wrapper_fputs(uint8_t *mem, uint32_t str_addr, uint32_t fp_addr) {
1984
uint32_t len = wrapper_strlen(mem, str_addr);
1985
uint32_t ret = wrapper_fwrite(mem, str_addr, 1, len, fp_addr);
1986
return ret == 0 && len != 0 ? -1 : 0;
1987
}
1988
1989
int wrapper_puts(uint8_t *mem, uint32_t str_addr) {
1990
int ret = wrapper_fputs(mem, str_addr, STDOUT_ADDR);
1991
if (ret != 0) {
1992
return ret;
1993
}
1994
struct FILE_irix *f = STDOUT;
1995
if (--f->_cnt < 0) {
1996
if (wrapper___flsbuf(mem, '\n', STDOUT_ADDR) != '\n') {
1997
return -1;
1998
}
1999
} else {
2000
MEM_S8(f->_ptr_addr) = '\n';
2001
++f->_ptr_addr;
2002
}
2003
return 0;
2004
}
2005
2006
uint32_t wrapper_getcwd(uint8_t *mem, uint32_t buf_addr, uint32_t size) {
2007
char buf[size];
2008
if (getcwd(buf, size) == NULL) {
2009
MEM_U32(ERRNO_ADDR) = errno;
2010
return 0;
2011
} else {
2012
if (buf_addr == 0) {
2013
buf_addr = wrapper_malloc(mem, size);
2014
}
2015
strcpy1(mem, buf_addr, buf);
2016
return buf_addr;
2017
}
2018
}
2019
2020
int wrapper_time(uint8_t *mem, uint32_t tloc_addr) {
2021
time_t ret = time(NULL);
2022
if (ret == (time_t)-1) {
2023
MEM_U32(ERRNO_ADDR) = errno;
2024
} else if (tloc_addr != 0) {
2025
MEM_S32(tloc_addr) = ret;
2026
}
2027
return ret;
2028
}
2029
2030
void wrapper_bzero(uint8_t *mem, uint32_t str_addr, uint32_t n) {
2031
while (n--) {
2032
MEM_U8(str_addr) = 0;
2033
++str_addr;
2034
}
2035
}
2036
2037
int wrapper_fp_class_d(double d) {
2038
union {
2039
uint32_t w[2];
2040
double d;
2041
} bits;
2042
bits.d = d;
2043
uint32_t a2 = bits.w[1];
2044
uint32_t a1 = a2 >> 20;
2045
uint32_t a0 = a1;
2046
a2 &= 0xfffff;
2047
uint32_t a3 = bits.w[0];
2048
a1 &= 0x7ff;
2049
a0 &= 0x800;
2050
if (a1 == 0x7ff) {
2051
if (a2 == 0 && a3 == 0) {
2052
return a0 == 0 ? 2 : 3;
2053
}
2054
a0 = a2 & 0x80000;
2055
return a0 == 0 ? 1 : 0;
2056
}
2057
if (a1 == 0) {
2058
if (a2 == 0 && a3 == 0) {
2059
return a0 == 0 ? 8 : 9;
2060
}
2061
return a0 == 0 ? 6 : 7;
2062
}
2063
return a0 == 0 ? 4 : 5;
2064
}
2065
2066
double wrapper_ldexp(double d, int i) {
2067
return ldexp(d, i);
2068
}
2069
2070
int64_t wrapper___ll_mul(int64_t a0, int64_t a1) {
2071
return a0 * a1;
2072
}
2073
2074
int64_t wrapper___ll_div(int64_t a0, int64_t a1) {
2075
return a0 / a1;
2076
}
2077
2078
int64_t wrapper___ll_rem(uint64_t a0, int64_t a1) {
2079
return a0 % a1;
2080
}
2081
2082
int64_t wrapper___ll_lshift(int64_t a0, uint64_t shift) {
2083
return a0 << (shift & 0x3f);
2084
}
2085
2086
int64_t wrapper___ll_rshift(int64_t a0, uint64_t shift) {
2087
return a0 >> (shift & 0x3f);
2088
}
2089
2090
uint64_t wrapper___ull_div(uint64_t a0, uint64_t a1) {
2091
return a0 / a1;
2092
}
2093
2094
uint64_t wrapper___ull_rem(uint64_t a0, uint64_t a1) {
2095
return a0 % a1;
2096
}
2097
2098
uint64_t wrapper___ull_rshift(uint64_t a0, uint64_t shift) {
2099
return a0 >> (shift & 0x3f);
2100
}
2101
2102
uint64_t wrapper___d_to_ull(double d) {
2103
return d;
2104
}
2105
2106
int64_t wrapper___d_to_ll(double d) {
2107
return d;
2108
}
2109
2110
uint64_t wrapper___f_to_ull(float f) {
2111
return f;
2112
}
2113
2114
int64_t wrapper___f_to_ll(float f) {
2115
return f;
2116
}
2117
2118
float wrapper___ull_to_f(uint64_t v) {
2119
return v;
2120
}
2121
2122
float wrapper___ll_to_f(int64_t v) {
2123
return v;
2124
}
2125
2126
double wrapper___ull_to_d(uint64_t v) {
2127
return v;
2128
}
2129
2130
double wrapper___ll_to_d(int64_t v) {
2131
return v;
2132
}
2133
2134
void wrapper_abort(uint8_t *mem) {
2135
abort();
2136
}
2137
2138
void wrapper_exit(uint8_t *mem, int status) {
2139
exit(status);
2140
}
2141
2142
void wrapper__exit(uint8_t *mem, int status) {
2143
assert(0 && "_exit not implemented"); // exit() is already overridden
2144
}
2145
2146
void wrapper__cleanup(uint8_t *mem) {
2147
}
2148
2149
uint32_t wrapper__rld_new_interface(uint8_t *mem, uint32_t operation, uint32_t sp) {
2150
assert(0 && "_rld_new_interface not implemented");
2151
return 0;
2152
}
2153
2154
void wrapper__exithandle(uint8_t *mem) {
2155
assert(0 && "_exithandle not implemented");
2156
}
2157
2158
int wrapper__prctl(uint8_t *mem, int operation, uint32_t sp) {
2159
assert(0 && "_prctl not implemented");
2160
return 0;
2161
}
2162
2163
double wrapper__atod(uint8_t *mem, uint32_t buffer_addr, int ndigits, int dexp) {
2164
// ftp://atoum.hst.nerim.net/irix/src/irix-6.5.5-src/6.5.5/m/irix/lib/libc/src/math/atod.c
2165
assert(0 && "_atod not implemented");
2166
return 0.0;
2167
}
2168
2169
int wrapper_pathconf(uint8_t *mem, uint32_t path_addr, int name) {
2170
STRING(path)
2171
if (name == 5) {
2172
errno = 0;
2173
int ret = pathconf(path, _PC_PATH_MAX);
2174
if (errno != 0) {
2175
MEM_U32(ERRNO_ADDR) = errno;
2176
}
2177
return ret;
2178
}
2179
assert(0 && "pathconf not implemented for the specific 'name'");
2180
return 0;
2181
}
2182
2183
uint32_t wrapper_getenv(uint8_t *mem, uint32_t name_addr) {
2184
// Return null for everything, for now
2185
return 0;
2186
}
2187
2188
uint32_t wrapper_gettxt(uint8_t *mem, uint32_t msgid_addr, uint32_t default_str_addr) {
2189
// Return default for now
2190
return default_str_addr;
2191
}
2192
2193
uint32_t wrapper_setlocale(uint8_t *mem, int category, uint32_t locale_addr) {
2194
assert(locale_addr != 0);
2195
STRING(locale)
2196
assert(category == 6); // LC_ALL
2197
char *ret = setlocale(LC_ALL, locale);
2198
// Let's hope the caller doesn't use the return value
2199
return 0;
2200
}
2201
2202
uint32_t wrapper_mmap(uint8_t *mem, uint32_t addr, uint32_t length, int prot, int flags, int fd, int offset) {
2203
assert(0 && "mmap not implemented");
2204
return 0;
2205
}
2206
2207
int wrapper_munmap(uint8_t *mem, uint32_t addr, uint32_t length) {
2208
assert(0 && "munmap not implemented");
2209
return 0;
2210
}
2211
2212
int wrapper_mprotect(uint8_t *mem, uint32_t addr, uint32_t length, int prot) {
2213
assert(0 && "mprotect not implemented");
2214
return 0;
2215
}
2216
2217
int wrapper_sysconf(uint8_t *mem, int name) {
2218
assert(0 && "sysconf not implemented");
2219
return 0;
2220
}
2221
2222
int wrapper_getpagesize(uint8_t *mem) {
2223
return 4096;
2224
}
2225
2226
int wrapper_strerror(uint8_t *mem, int errnum) {
2227
errno = errnum;
2228
perror("strerror");
2229
assert(0 && "strerror not implemented");
2230
return 0;
2231
}
2232
2233
int wrapper_ioctl(uint8_t *mem, int fd, uint32_t request, uint32_t sp) {
2234
assert(0 && "ioctl not implemented");
2235
return 0;
2236
}
2237
2238
int wrapper_fcntl(uint8_t *mem, int fd, int cmd, uint32_t sp) {
2239
assert(0 && "fcntl not implemented");
2240
return 0;
2241
}
2242
2243
static void signal_handler(int signum) {
2244
uint32_t level = signal_context.recursion_level++;
2245
uint8_t *mem = signal_context.handlers[signum].mem;
2246
uint32_t fp_dest = signal_context.handlers[signum].fp_dest;
2247
uint32_t sp = SIGNAL_HANDLER_STACK_START - 16 - level * 0x1000;
2248
signal_context.handlers[signum].trampoline(mem, sp, signum, 0, 0, 0, fp_dest);
2249
signal_context.recursion_level--;
2250
}
2251
2252
uint32_t wrapper_signal(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t handler_addr, uint32_t sp) {
2253
//assert(0 && "signal not implemented");
2254
return 0;
2255
}
2256
2257
uint32_t wrapper_sigset(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t disp_addr, uint32_t sp) {
2258
void (*handler)(int) = signal_handler;
2259
2260
if ((int)disp_addr >= -1 && (int)disp_addr <= 1) {
2261
// SIG_DFL etc.
2262
handler = (void (*)(int))(intptr_t)(int)disp_addr;
2263
}
2264
2265
switch (signum) {
2266
case 2:
2267
signum = SIGINT;
2268
break;
2269
case 13:
2270
signum = SIGPIPE;
2271
break;
2272
case 15:
2273
signum = SIGTERM;
2274
break;
2275
default:
2276
assert(0 && "sigset with this signum not implemented");
2277
break;
2278
}
2279
2280
signal_context.handlers[signum].trampoline = trampoline;
2281
signal_context.handlers[signum].mem = mem;
2282
signal_context.handlers[signum].fp_dest = disp_addr;
2283
2284
return (uint32_t)(uintptr_t)sigset(signum, handler); // for now only support SIG_DFL etc. as return value
2285
}
2286
2287
int wrapper_get_fpc_csr(uint8_t *mem) {
2288
//assert(0 && "get_fpc_csr not implemented");
2289
return 0;
2290
}
2291
2292
int wrapper_set_fpc_csr(uint8_t *mem, int csr) {
2293
//assert(0 && "set_fpc_csr not implemented");
2294
return 0;
2295
}
2296
2297
int wrapper_setjmp(uint8_t *mem, uint32_t addr) {
2298
return 0;
2299
}
2300
2301
void wrapper_longjmp(uint8_t *mem, uint32_t addr, int status) {
2302
assert(0 && "longjmp not implemented");
2303
}
2304
2305
uint32_t wrapper_tempnam(uint8_t *mem, uint32_t dir_addr, uint32_t pfx_addr) {
2306
STRING(dir)
2307
STRING(pfx)
2308
char *ret = tempnam(dir, pfx);
2309
char *ret_saved = ret;
2310
if (ret == NULL) {
2311
MEM_U32(ERRNO_ADDR) = errno;
2312
return 0;
2313
}
2314
size_t len = strlen(ret) + 1;
2315
uint32_t ret_addr = wrapper_malloc(mem, len);
2316
uint32_t pos = ret_addr;
2317
while (len--) {
2318
MEM_S8(pos) = *ret;
2319
++pos;
2320
++ret;
2321
}
2322
free(ret_saved);
2323
return ret_addr;
2324
}
2325
2326
uint32_t wrapper_tmpnam(uint8_t *mem, uint32_t str_addr) {
2327
char buf[1024];
2328
assert(str_addr != 0 && "s NULL not implemented for tmpnam");
2329
char *ret = tmpnam(buf);
2330
if (ret == NULL) {
2331
return 0;
2332
} else {
2333
strcpy1(mem, str_addr, ret);
2334
return str_addr;
2335
}
2336
}
2337
2338
uint32_t wrapper_mktemp(uint8_t *mem, uint32_t template_addr) {
2339
STRING(template)
2340
mktemp(template);
2341
strcpy1(mem, template_addr, template);
2342
return template_addr;
2343
}
2344
2345
int wrapper_mkstemp(uint8_t *mem, uint32_t name_addr) {
2346
STRING(name)
2347
int fd = mkstemp(name);
2348
if (fd < 0) {
2349
MEM_U32(ERRNO_ADDR) = errno;
2350
} else {
2351
strcpy1(mem, name_addr, name);
2352
}
2353
return fd;
2354
}
2355
2356
uint32_t wrapper_tmpfile(uint8_t *mem) {
2357
// create and fopen a temporary file that is removed when the program exits
2358
char name[] = "/tmp/copt_temp_XXXXXX";
2359
int fd = mkstemp(name);
2360
if (fd < 0) {
2361
MEM_U32(ERRNO_ADDR) = errno;
2362
return 0;
2363
}
2364
2365
// the file will be removed from disk when it's closed later
2366
unlink(name);
2367
2368
// fdopen:
2369
uint32_t ret = init_file(mem, fd, -1, NULL, "w+");
2370
if (ret == 0) {
2371
close(fd);
2372
}
2373
return ret;
2374
}
2375
2376
int wrapper_wait(uint8_t *mem, uint32_t wstatus_addr) {
2377
int wstatus;
2378
pid_t ret = wait(&wstatus);
2379
MEM_S32(wstatus_addr) = wstatus;
2380
return ret;
2381
}
2382
2383
int wrapper_kill(uint8_t *mem, int pid, int sig) {
2384
int ret = kill(pid, sig);
2385
if (ret != 0) {
2386
MEM_U32(ERRNO_ADDR) = errno;
2387
}
2388
return ret;
2389
}
2390
2391
int wrapper_execlp(uint8_t *mem, uint32_t file_addr, uint32_t sp) {
2392
uint32_t argv_addr = sp + 4;
2393
return wrapper_execvp(mem, file_addr, argv_addr);
2394
}
2395
2396
int wrapper_execv(uint8_t *mem, uint32_t pathname_addr, uint32_t argv_addr) {
2397
STRING(pathname)
2398
uint32_t argc = 0;
2399
while (MEM_U32(argv_addr + argc * 4) != 0) {
2400
++argc;
2401
}
2402
char *argv[argc + 1];
2403
for (uint32_t i = 0; i < argc; i++) {
2404
uint32_t str_addr = MEM_U32(argv_addr + i * 4);
2405
uint32_t len = wrapper_strlen(mem, str_addr) + 1;
2406
argv[i] = (char *)malloc(len);
2407
char *pos = argv[i];
2408
while (len--) {
2409
*pos++ = MEM_S8(str_addr);
2410
++str_addr;
2411
}
2412
}
2413
argv[argc] = NULL;
2414
execv(pathname, argv);
2415
MEM_U32(ERRNO_ADDR) = errno;
2416
for (uint32_t i = 0; i < argc; i++) {
2417
free(argv[i]);
2418
}
2419
return -1;
2420
}
2421
2422
int wrapper_execvp(uint8_t *mem, uint32_t file_addr, uint32_t argv_addr) {
2423
STRING(file)
2424
uint32_t argc = 0;
2425
while (MEM_U32(argv_addr + argc * 4) != 0) {
2426
++argc;
2427
}
2428
char *argv[argc + 1];
2429
for (uint32_t i = 0; i < argc; i++) {
2430
uint32_t str_addr = MEM_U32(argv_addr + i * 4);
2431
uint32_t len = wrapper_strlen(mem, str_addr) + 1;
2432
argv[i] = (char *)malloc(len);
2433
char *pos = argv[i];
2434
while (len--) {
2435
*pos++ = MEM_S8(str_addr);
2436
++str_addr;
2437
}
2438
}
2439
argv[argc] = NULL;
2440
2441
#ifdef REDIRECT_USR_LIB
2442
if (!strncmp(file, "/usr/lib/", 9) && bin_dir[0] != '\0') {
2443
char fixed_path[PATH_MAX + 1];
2444
#ifdef __CYGWIN__
2445
int n = snprintf(fixed_path, sizeof(fixed_path), "%s/%s.exe", bin_dir, file + 9);
2446
#else
2447
int n = snprintf(fixed_path, sizeof(fixed_path), "%s/%s", bin_dir, file + 9);
2448
#endif
2449
if (n > 0 && n < sizeof(fixed_path)) {
2450
execvp(fixed_path, argv);
2451
} else {
2452
execvp(file, argv);
2453
}
2454
} else {
2455
execvp(file, argv);
2456
}
2457
#else
2458
execvp(file, argv);
2459
#endif
2460
2461
MEM_U32(ERRNO_ADDR) = errno;
2462
for (uint32_t i = 0; i < argc; i++) {
2463
free(argv[i]);
2464
}
2465
return -1;
2466
}
2467
2468
int wrapper_fork(uint8_t *mem) {
2469
int ret = fork();
2470
if (ret == -1) {
2471
MEM_U32(ERRNO_ADDR) = errno;
2472
}
2473
return ret;
2474
}
2475
2476
int wrapper_system(uint8_t *mem, uint32_t command_addr) {
2477
STRING(command)
2478
return system(command); // no errno
2479
}
2480
2481
static int name_compare(uint8_t *mem, uint32_t a_addr, uint32_t b_addr) {
2482
//printf("pc=0x00438180\n");
2483
return wrapper_strcmp(mem, MEM_U32(a_addr), MEM_U32(b_addr));
2484
}
2485
2486
static uint32_t tsearch_tfind(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr, bool insert) {
2487
//assert(compar_addr == 0x438180); // name_compare in as1
2488
2489
if (rootp_addr == 0) {
2490
return 0;
2491
}
2492
while (MEM_U32(rootp_addr) != 0) {
2493
uint32_t node_addr = MEM_U32(rootp_addr);
2494
int r = name_compare(mem, key_addr, MEM_U32(node_addr));
2495
if (r == 0) {
2496
return node_addr;
2497
}
2498
rootp_addr = r < 0 ? node_addr + 4 : node_addr + 8;
2499
}
2500
if (insert) {
2501
uint32_t node_addr = wrapper_malloc(mem, 12);
2502
if (node_addr != 0) {
2503
MEM_U32(rootp_addr) = node_addr;
2504
MEM_U32(node_addr) = key_addr;
2505
MEM_U32(node_addr + 4) = 0;
2506
MEM_U32(node_addr + 8) = 0;
2507
return node_addr;
2508
}
2509
}
2510
return 0;
2511
}
2512
2513
uint32_t wrapper_tsearch(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr) {
2514
return tsearch_tfind(mem, key_addr, rootp_addr, compar_addr, true);
2515
}
2516
2517
uint32_t wrapper_tfind(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr) {
2518
return tsearch_tfind(mem, key_addr, rootp_addr, compar_addr, false);
2519
}
2520
2521
uint32_t wrapper_qsort(uint8_t *mem, uint32_t base_addr, uint32_t num, uint32_t size, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t compare_addr, uint32_t sp) {
2522
assert(0 && "qsort not implemented");
2523
return 0;
2524
}
2525
2526
uint32_t wrapper_regcmp(uint8_t *mem, uint32_t string1_addr, uint32_t sp) {
2527
STRING(string1);
2528
fprintf(stderr, "regex string: %s\n", string1);
2529
assert(0 && "regcmp not implemented");
2530
return 0;
2531
}
2532
2533
uint32_t wrapper_regex(uint8_t *mem, uint32_t re_addr, uint32_t subject_addr, uint32_t sp) {
2534
STRING(subject);
2535
assert(0 && "regex not implemented");
2536
return 0;
2537
}
2538
2539
void wrapper___assert(uint8_t *mem, uint32_t assertion_addr, uint32_t file_addr, int line) {
2540
STRING(assertion)
2541
STRING(file)
2542
__assert(assertion, file, line);
2543
}
2544
2545