3 #include "Script_internal.h"
4 #include "endianness.h"
9 #define COMMENT(F, FMT, ...) fprintf(F, "; " FMT, __VA_ARGS__)
11 static int dump_sections(AF
* a
, FILE *f
, size_t start
, size_t count
) {
14 fprintf(f
, ".sections\n");
17 for(; i
< count
; i
++) {
18 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
19 int off
= AF_read_int(a
);
20 fprintf(f
, "\"%s\" = %d\n", buf
, off
);
27 #include "StringEscape.h"
28 static int dump_strings(AF
* a
, FILE *f
, struct strings
*str
) {
29 if(!str
->count
) return 1;
30 fprintf(f
, ".%s\n", "strings");
31 char *p
, escapebuf
[4096];
33 for (i
=0; i
<str
->count
; ++i
) {
34 escape(str
->strings
[i
], escapebuf
, sizeof(escapebuf
));
35 fprintf(f
, "\"%s\"\n", escapebuf
);
40 static void free_fixup_data(struct fixup_data
*ret
) {
42 for(i
= 0; i
<= FIXUP_MAX
; i
++) {
43 free(ret
->codeindex_per
[i
]);
49 /* fixup_data needs to be zeroed */
50 static int get_fixups(AF
* a
, size_t start
, size_t count
, struct fixup_data
*ret
) {
52 if(!(ret
->types
= malloc(count
))) goto err
;
53 if(!(ret
->codeindex
= malloc(count
* sizeof(unsigned)))) goto err
;
57 if(count
!= (size_t) AF_read(a
, ret
->types
, count
)) goto err
;
58 for(i
= 0; i
< count
; i
++) {
59 assert(ret
->types
[i
]>=0 && ret
->types
[i
]<=FIXUP_MAX
);
60 ret
->count
[ret
->types
[i
]]++;
61 ret
->codeindex
[i
] = AF_read_uint(a
);
63 for(i
= 0; i
<= FIXUP_MAX
; i
++) {
64 ret
->codeindex_per
[i
] = malloc(ret
->count
[i
] * sizeof(unsigned));
65 if(!ret
->codeindex_per
[i
]) goto err
;
66 ret
->count
[i
] = 0; /* reset to 0 to use as index i.t. next loop */
69 for(i
= 0; i
< count
; i
++) {
70 ret
->codeindex_per
[ret
->types
[i
]][ret
->count
[ret
->types
[i
]]++] = ret
->codeindex
[i
];
79 static int dump_fixups(FILE *f
, size_t count
, struct fixup_data
*fxd
) {
80 static const char* typenames
[] = {
81 [FIXUP_GLOBALDATA
] = "FIXUP_GLOBALDATA",
82 [FIXUP_FUNCTION
] = "FIXUP_FUNCTION",
83 [FIXUP_STRING
] = "FIXUP_STRING",
84 [FIXUP_IMPORT
] = "FIXUP_IMPORT",
85 [FIXUP_DATADATA
] = "FIXUP_DATADATA",
86 [FIXUP_STACK
] = "FIXUP_STACK",
89 fprintf(f
, ".%ss\n", "fixup");
91 for(i
= 0; i
< count
; i
++) {
92 fprintf(f
, "%s: %.12u\n", typenames
[(int)fxd
->types
[i
]], fxd
->codeindex
[i
]);
98 static int dump_import_export(AF
* a
, FILE *f
, size_t start
, size_t count
, int import
) {
99 static const char* secnames
[2] = { "export", "import" };
100 const char* secname
= secnames
[import
];
102 char buf
[256]; /* arbitrarily chosen */
104 AF_set_pos(a
, start
);
105 fprintf(f
, ".%ss\n", secname
);
106 for(i
= 0; i
< count
; i
++) {
107 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
108 fprintf(f
, "%.12zu\"%s\"\n", i
, buf
);
110 unsigned int addr
= AF_read_uint(a
);
111 fprintf(f
, "%d:%.12u\n", addr
>> 24, addr
& 0x00FFFFFF);
117 static struct export
* get_exports(AF
* a
, size_t start
, size_t count
) {
119 struct export
* fl
= malloc(count
* sizeof(struct export
));
120 AF_set_pos(a
, start
);
121 char buf
[4096]; size_t i
;
122 for(i
= 0; i
< count
; i
++) {
123 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
124 fl
[i
].fn
= strdup(buf
);
125 unsigned int addr
= AF_read_uint(a
);
126 fl
[i
].type
= addr
>> 24;
127 fl
[i
].instr
= (addr
& 0x00FFFFFF);
132 static struct importlist
get_imports(AF
* a
, size_t start
, size_t count
) {
133 struct importlist ret
= {0};
134 if(!count
) return ret
;
135 ret
.names
= malloc(count
* sizeof(char*));
136 if(!ret
.names
) return ret
;
137 AF_set_pos(a
, start
);
138 char buf
[4096]; size_t i
;
139 for(i
= 0; i
< count
; i
++) {
140 if(!AF_read_string(a
, buf
, sizeof(buf
))) {
142 return (struct importlist
) {0};
144 ret
.names
[i
] = strdup(buf
);
154 static int sort_comp(const void* xp
, const void *yp
) {
155 const unsigned *x
= xp
, *y
= yp
;
156 if(*x
== *y
) return 0;
157 else if(*x
> *y
) return 1;
162 static struct labels
get_labels(unsigned *code
, size_t count
) {
163 struct labels ret
= {0, 0};
164 if(!count
) return ret
;
169 while(insno
< count
) {
170 if(ret
.count
+ 1 > capa
) {
171 capa
= capa
? capa
* 2 : 16;
172 if(!(p
= realloc(ret
.insno
, capa
* sizeof(unsigned*)))) {
173 if(ret
.insno
) free(ret
.insno
);
177 } else ret
.insno
= p
;
179 insn
= code
[insno
] & 0x00ffffff;
182 assert(insn
< SCMD_MAX
);
184 case SCMD_JZ
: case SCMD_JMP
: case SCMD_JNZ
:
190 for(; i
< opcodes
[insn
].argcount
; i
++) {
191 int val
= code
[insno
];
194 if((int) insno
+ val
< 0 || insno
+ val
>= count
|| code
[insno
+ val
] > SCMD_MAX
) {
195 fprintf(stderr
, "error: label referenced from jump at %zu is out of bounds\n"
196 "or points to non-instruction start code.\n", insno
);
199 ret
.insno
[ret
.count
] = insno
+ val
;
204 qsort(ret
.insno
, ret
.count
, sizeof(unsigned), sort_comp
);
208 static struct strings
get_strings(AF
* a
, size_t start
, size_t size
) {
209 struct strings ret
= {0,0,0};
211 if(!size
) return ret
;
212 if(!(ret
.data
= malloc(size
))) return ret
;
213 AF_set_pos(a
, start
);
214 if(size
!= (size_t) AF_read(a
, ret
.data
, size
)) {
220 size_t i
, strcnt
= 0;
221 for(i
= 0; i
< size
; i
++) {
222 if(!ret
.data
[i
]) strcnt
++;
223 else if(ret
.data
[i
] < 9 || (unsigned char) ret
.data
[i
] > 127
224 || (ret
.data
[i
] > 13 && ret
.data
[i
] < 32))
228 fprintf(stderr
, "warning: %d unusual bytes in string data section, file may be corrupted\n", corrupt
);
230 if(ret
.data
[size
-1]) {
231 fprintf(stderr
, "%s", "warning: string data section doesn't end with 0, data probably corrupted\n");
233 ret
.data
[size
-1] = 0;
235 if(!(ret
.strings
= malloc(strcnt
* sizeof(char*)))) goto free1
;
240 for(i
= 0; i
< size
; i
++) {
242 ret
.strings
[strcnt
] = p
;
253 static char* get_varname(struct export
* exp
, size_t expcount
, unsigned globaloffset
) {
255 for(; i
< expcount
; i
++)
256 if(exp
[i
].type
== EXPORT_DATA
&& exp
[i
].instr
== globaloffset
)
261 unsigned *get_code(AF
*a
, size_t start
, size_t count
) {
262 unsigned *ret
= malloc(count
* sizeof(unsigned));
264 AF_set_pos(a
, start
);
266 for(i
=0; i
<count
; i
++)
267 ret
[i
] = AF_read_uint(a
);
271 static unsigned get_varsize_from_instr(unsigned* code
, size_t codecount
, size_t index
) {
272 assert(index
< codecount
);
273 switch(code
[index
]) {
274 case SCMD_MEMREADB
: case SCMD_MEMWRITEB
:
276 case SCMD_MEMREADW
: case SCMD_MEMWRITEW
:
278 case SCMD_MEMWRITEPTR
:
279 case SCMD_MEMREADPTR
:
280 case SCMD_MEMZEROPTR
:
281 case SCMD_MEMINITPTR
:
282 case SCMD_MEMREAD
: case SCMD_MEMWRITE
:
289 struct fixup_resolved
{
294 static int fixup_cmp(const void *a
, const void *b
) {
295 const struct fixup_resolved
*u1
= a
;
296 const struct fixup_resolved
*u2
= b
;
297 return (u1
->code
- u2
->code
);
300 /* assumes list members are sorted. set iter to -1 for first call */
301 int find_next_match(struct fixup_resolved
*list
, size_t nel
, unsigned value
, size_t *iter
) {
302 struct fixup_resolved comparer
= {
305 if(*iter
== (size_t)-1) {
306 struct fixup_resolved
* ret
= bsearch(&comparer
, list
, nel
, sizeof(list
[0]), fixup_cmp
);
309 while(*iter
>=1 && list
[*iter
-1].code
== value
)
314 if(*iter
< nel
&& list
[*iter
].code
== value
)
320 static int has_datadata_fixup(unsigned gdoffset
, struct fixup_data
*fxd
) {
322 for(i
= 0; i
< fxd
->count
[FIXUP_DATADATA
]; i
++)
323 if(fxd
->codeindex_per
[FIXUP_DATADATA
][i
] == gdoffset
)
328 struct varinfo
find_fixup_for_globaldata(FILE *f
, size_t offset
,
329 struct fixup_resolved
*fxlist_resolved
, size_t fxlist_cnt
,
330 unsigned* code
, size_t codecount
)
333 size_t iter
= (size_t)-1, x
;
334 struct varinfo ret
= {0,0};
335 while(find_next_match(fxlist_resolved
, fxlist_cnt
, offset
, &iter
)) {
336 x
= fxlist_resolved
[iter
].offset
;
338 assert(x
+ 1 < codecount
);
341 unsigned oldvarsize
= ret
.varsize
;
342 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+1);
343 if(!ret
.varsize
) switch(code
[x
+1]) {
345 // li mar, @Obj; mr ax, mar; callobj ax
346 if(x
+5 < codecount
&&
347 code
[x
+2] == AR_MAR
&&
348 code
[x
+4] == SCMD_CALLOBJ
&&
349 code
[x
+3] == code
[x
+5]) {
354 // li mar, @var; muli dx, 4; ptrget mar; ptrassert; dynamicbounds dx
355 if(x
+5 < codecount
&&
356 code
[x
+2] != AR_MAR
&&
357 code
[x
+4] == SCMD_MEMREADPTR
&&
360 // muli is used as an array index like:
361 // muli REG, 4; add MAR, REG; PUSH/POP MAR; ...
362 else if(x
+11 < codecount
&&
363 code
[x
+4] == SCMD_ADDREG
&&
364 code
[x
+5] == AR_MAR
&&
365 code
[x
+6] == code
[x
+2] &&
366 code
[x
+7] == SCMD_PUSHREG
&&
367 code
[x
+8] == AR_MAR
&&
368 code
[x
+9] == SCMD_POPREG
&&
369 code
[x
+10] == AR_MAR
) {
370 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+11);
373 code
[x
+11] == SCMD_ADDREG
&&
374 code
[x
+12] == AR_MAR
&&
375 code
[x
+13] != code
[x
+2]
377 /* this variation adds another reg to mar before calling ptrget */
378 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+14);
379 else if(!ret
.varsize
&&
381 code
[x
+11] == SCMD_PUSHREG
&&
383 /* this variation pushes ax on the stack before doing a ptrget ax, which overwrites ax */
384 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+13);
386 /* muli dx, 4; add mar, dx; add mar, cx; ptr... */
387 else if(x
+10 < codecount
&&
388 code
[x
+4] == SCMD_ADDREG
&&
389 code
[x
+5] == AR_MAR
&&
390 (code
[x
+6] == AR_CX
|| code
[x
+6] == AR_DX
) &&
391 code
[x
+7] == SCMD_ADDREG
&&
392 code
[x
+8] == AR_MAR
&&
393 (code
[x
+9] == AR_CX
|| code
[x
+9] == AR_DX
))
394 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+10);
395 else if(x
+7 < codecount
&&
396 code
[x
+4] == SCMD_ADDREG
&&
397 code
[x
+5] == AR_MAR
&&
398 code
[x
+6] == code
[x
+2]) {
399 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+7);
402 code
[x
+7] == SCMD_PUSHREG
&&
404 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+9);
409 // addreg is typically used on an index register into an array
410 // followed by a byteread/store of the desired size
411 // the index register needs to be added to mar reg
412 assert(x
+2 < codecount
&& code
[x
+2] == AR_MAR
);
413 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+4);
414 // a typical method call
415 if(!ret
.varsize
&& x
+8 < codecount
&&
416 code
[x
+4] == SCMD_REGTOREG
&&
417 code
[x
+5] == AR_MAR
&&
418 code
[x
+7] == SCMD_CALLOBJ
&&
419 code
[x
+6] == code
[x
+8])
423 // ptrget and similar ops are typically preceded by push mar, pop mar
424 if(x
+4 < codecount
&&
425 code
[x
+2] == AR_MAR
&&
426 code
[x
+3] == SCMD_POPREG
&&
427 code
[x
+4] == AR_MAR
) {
428 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+5);
429 if(!ret
.varsize
&& x
+7 < codecount
&&
430 code
[x
+5] == SCMD_ADDREG
&&
432 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+8);
433 } else if(x
+2 < codecount
&&
435 /* ptrget is sometimes preceded by push ax */
436 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+3);
441 /* don't bother guessing the varsize if we already determined it */
442 ret
.varsize
= oldvarsize
;
444 fprintf(stderr
, "warning: '%s' globaldata fixup on insno %zu offset %zu\n",
445 opcodes
[code
[x
+1]].mnemonic
, x
+1, offset
);
446 COMMENT(f
, "warning: '%s' globaldata fixup on insno %zu offset %zu\n",
447 opcodes
[code
[x
+1]].mnemonic
, x
+1, offset
);
449 if(oldvarsize
!= 0 && oldvarsize
!= ret
.varsize
)
457 static int is_all_zeroes(const char* buf
, int len
) {
459 if(*buf
!= 0) return 0;
465 static const char* get_varsize_typename(unsigned varsize
) {
466 static const char typenames
[][6] = {[0]="ERR", [1]="char", [2]="short", [4]="int"};
468 case 0: case 1: case 2: case 4:
469 return typenames
[varsize
];
476 static struct varinfo
get_varinfo_from_code(
477 unsigned *code
, size_t codesize
,
479 struct fixup_data
*fxd
,
480 struct fixup_resolved
*gd_fixups_resolved
,
484 if(has_datadata_fixup(offset
, fxd
))
485 vi
= (struct varinfo
){0,4};
487 vi
= find_fixup_for_globaldata(f
, offset
, gd_fixups_resolved
, fxd
->count
[FIXUP_GLOBALDATA
], code
, codesize
);
488 if(vi
.varsize
== 0 && has_datadata_fixup(offset
+200, fxd
))
494 int get_varinfo_from_exports(size_t offs
, struct export
*exp
, size_t expcount
, struct varinfo
*vi
)
496 struct export
*end
= exp
+ expcount
;
497 for(; exp
< end
; ++exp
)
498 if(exp
->instr
== offs
&& exp
->type
== EXPORT_DATA
) {
499 vi
->varsize
= 1; /* unfortunately no size info is available, so we need to default to char for safety */
505 static int dump_globaldata(AF
*a
, FILE *f
, size_t start
, size_t size
,
506 struct export
* exp
, size_t expcount
,
507 struct fixup_data
*fxd
,
508 unsigned *code
, size_t codesize
) {
511 size_t fxcount
= fxd
->count
[FIXUP_GLOBALDATA
];
512 struct fixup_resolved
*gd_fixups_resolved
= malloc(sizeof(struct fixup_resolved
) * fxcount
);
513 if(!gd_fixups_resolved
) return 0;
515 for(i
=0; i
< fxcount
; i
++) {
516 unsigned x
= fxd
->codeindex_per
[FIXUP_GLOBALDATA
][i
];
517 assert(x
< codesize
);
518 gd_fixups_resolved
[i
].code
= code
[x
];
519 gd_fixups_resolved
[i
].offset
= x
;
521 qsort(gd_fixups_resolved
, fxcount
, sizeof(gd_fixups_resolved
[0]), fixup_cmp
);
523 fprintf(f
, ".%s\n", "data");
524 AF_set_pos(a
, start
);
526 for(i
= 0; i
< size
; ) {
528 vi
= get_varinfo_from_code(code
, codesize
, i
, fxd
, gd_fixups_resolved
, f
);
529 if(vi
.varsize
== 0) get_varinfo_from_exports(i
, exp
, expcount
, &vi
);
537 off_t savepos
= AF_get_pos(a
);
538 if(i
+ 204 <= size
) {
540 assert(200 == AF_read(a
, buf
, 200));
541 /* read the datadata fixup content*/
543 if(x
== i
&& is_all_zeroes(buf
, 200)) {
545 AF_set_pos(a
, savepos
+ 200);
550 AF_set_pos(a
, savepos
);
558 x
= AF_read_short(a
);
561 x
= ByteArray_readByte(a
->b
);
565 x
= ByteArray_readByte(a
->b
);
566 if(vi
.numrefs
) comment
= " ; warning: couldn't determine varsize, default to 1";
568 comment
= " ; unreferenced variable, assuming char";
573 vi2
= get_varinfo_from_code(code
, codesize
, j
, fxd
, gd_fixups_resolved
, f
);
574 if(vi2
.varsize
|| vi
.numrefs
|| get_varinfo_from_exports(j
, exp
, expcount
, &vi2
)) break;
575 x
= ByteArray_readByte(a
->b
);
577 ByteArray_set_position_rel(a
->b
, -1);
586 char* vn
= get_varname(exp
, expcount
, i
), buf
[32];
587 const char *tn
= get_varsize_typename(vi
.varsize
);
588 if(!tn
|| (vi
.varsize
== 200 && !is_str
)) {
589 snprintf(buf
, sizeof buf
, "char[%u]", vi
.varsize
);
592 if(has_datadata_fixup(i
, fxd
)) {
593 if(vn
) fprintf(f
, "export %s %s = .data + %d%s\n", tn
, vn
, x
, comment
);
594 else fprintf(f
, "%s var%.6zu = .data + %d%s\n", tn
, i
, x
, comment
);
596 if(vn
) fprintf(f
, "export %s %s = %d%s\n", tn
, vn
, x
, comment
);
597 else fprintf(f
, "%s var%.6zu = %d%s\n", tn
, i
, x
, comment
);
601 free(gd_fixups_resolved
);
605 static int disassemble_code_and_data(AF
* a
, ASI
* s
, FILE *f
, int flags
, struct fixup_data
*fxd
, struct strings
*str
) {
606 int debugmode
= getenv("AGSDEBUG") != 0;
607 size_t start
= s
->codestart
;
608 size_t len
= s
->codesize
* sizeof(unsigned);
610 unsigned *code
= get_code(a
, s
->codestart
, s
->codesize
);
612 struct export
* fl
= get_exports(a
, s
->exportstart
, s
->exportcount
);
614 dump_globaldata(a
, f
, s
->globaldatastart
, s
->globaldatasize
, fl
, s
->exportcount
, fxd
, code
, s
->codesize
);
616 if(!len
) return 1; /* its valid for a scriptfile to have no code at all */
619 struct importlist il
= get_imports(a
, s
->importstart
, s
->importcount
);
621 struct labels lbl
= get_labels(code
, s
->codesize
);
623 AF_set_pos(a
, start
);
624 fprintf(f
, ".%s\n", "text");
626 size_t currInstr
= 0, currExp
= 0, currFixup
= 0, currLbl
= 0;
628 /* the data_data fixups appear to be glued separately onto the fixup logic,
629 * they are the only entries not sorted by instrucion number */
630 while(currFixup
< s
->fixupcount
&& fxd
->types
[currFixup
] == FIXUP_DATADATA
) currFixup
++;
631 while(currInstr
< s
->codesize
) {
632 if(flags
& DISAS_DEBUG_OFFSETS
) COMMENT(f
, "offset: %llu (insno %zu)\n", (long long) AF_get_pos(a
), currInstr
);
633 unsigned regs
, args
, insn
= AF_read_uint(a
), op
= insn
& 0x00ffffff;
634 assert(op
< SCMD_MAX
);
635 while(currExp
< s
->exportcount
&& fl
[currExp
].type
!= EXPORT_FUNCTION
)
637 if(currExp
< s
->exportcount
&& fl
[currExp
].instr
== currInstr
) {
638 /* new function starts here */
639 curr_func
= fl
[currExp
].fn
;
640 char comment
[64], *p
= strrchr(fl
[currExp
].fn
, '$');
644 if((n
= atoi(p
+1)) >= 100)
645 sprintf(comment
, " ; variadic, %d fixed args", n
- 100);
647 sprintf(comment
, " ; %d args", n
);
649 fprintf(f
, "\n%s:%s\n", curr_func
, comment
);
652 if(currLbl
< lbl
.count
) {
653 if(lbl
.insno
[currLbl
] == currInstr
) {
655 while(currLbl
< lbl
.count
&& lbl
.insno
[currLbl
] == currInstr
) {
656 currLbl
++; numrefs
++;
658 fprintf(f
, "label%.12zu: ", currInstr
);
659 COMMENT(f
, "inside %s, ", curr_func
? curr_func
: "???");
660 COMMENT(f
, "referenced by %zu spots\n", numrefs
);
666 regs
= opcodes
[op
].regcount
;
667 args
= opcodes
[op
].argcount
;
669 if(insn
== SCMD_LINENUM
&& (flags
& DISAS_SKIP_LINENO
)) {
670 insn
= AF_read_uint(a
);
671 COMMENT(f
, "line %u\n", insn
);
676 if(flags
& DISAS_DEBUG_BYTECODE
) {
677 unsigned char insbuf
[16];
678 unsigned iblen
= 0, val
;
679 val
= end_htole32(insn
);
680 memcpy(insbuf
+iblen
, &val
, 4); iblen
+= 4;
682 off_t currpos
= AF_get_pos(a
);
685 for(l
= 0; l
< args
; l
++) {
686 assert(iblen
+4 <= sizeof(insbuf
));
687 val
= AF_read_uint(a
);
688 val
= end_htole32(val
);
689 memcpy(insbuf
+iblen
, &val
, 4); iblen
+= 4;
692 char printbuf
[sizeof(insbuf
)*2 + 1], *pb
= printbuf
;
693 for(l
= 0; l
< iblen
; l
++, pb
+=2)
694 sprintf(pb
, "%02x", (int) insbuf
[l
]);
695 COMMENT(f
, "%s\n", printbuf
);
697 AF_set_pos(a
, currpos
);
701 fprintf(f
, "%.12zu""\t%s ", currInstr
- 1, opcodes
[op
].mnemonic
);
703 fprintf(f
, /*"%.12zu"*/"\t%s ", /*currInstr - 1, */opcodes
[op
].mnemonic
);
705 if(insn
== SCMD_REGTOREG
) {
706 /* the "mov" instruction differs from all others in that the source comes first
707 we do not want that. */
709 src
= AF_read_uint(a
);
711 dst
= AF_read_uint(a
);
713 fprintf(f
, "%s, %s\n", regnames
[dst
], regnames
[src
]);
717 for (l
= 0; l
< args
; l
++) {
718 char escapebuf
[4096];
719 if(l
) fprintf(f
, ", ");
720 insn
= AF_read_uint(a
);
722 if((!l
&& regs
) || (l
== 1 && regs
== 2))
723 fprintf(f
, "%s", regnames
[insn
]);
725 while(currFixup
< s
->fixupcount
&& fxd
->types
[currFixup
] == FIXUP_DATADATA
)
726 currFixup
++; /* DATADATA fixups are unrelated to the code */
727 if(currFixup
< s
->fixupcount
&& fxd
->codeindex
[currFixup
] == currInstr
- 1) {
728 switch(fxd
->types
[currFixup
]) {
731 fprintf(f
, "IMP:%s", il
.names
[insn
]);
733 fprintf(f
, "%s", il
.names
[insn
]);
735 case FIXUP_FUNCTION
: {
737 for(; x
< s
->exportcount
; x
++) {
738 if(fl
[x
].type
== EXPORT_FUNCTION
&& fl
[x
].instr
== insn
) {
739 fprintf(f
, "%s", fl
[x
].fn
);
745 case FIXUP_GLOBALDATA
: {
746 char *vn
= get_varname(fl
, s
->exportcount
, insn
);
747 if(vn
) fprintf(f
, "@%s", vn
);
748 else fprintf(f
, "@var%.6u", insn
);
750 case FIXUP_STACK
: /* it is unclear if and where those ever get generated */
751 fprintf(f
, ".stack + %d", insn
);
754 escape(str
->data
+ insn
, escapebuf
, sizeof(escapebuf
));
755 fprintf(f
, "\"%s\"", escapebuf
);
762 case SCMD_JMP
: case SCMD_JZ
: case SCMD_JNZ
:
763 fprintf(f
, "label%.12zu", currInstr
+ (int) insn
);
766 fprintf(f
, "%d", insn
);
777 int ASI_disassemble(AF
* a
, ASI
* s
, char *fn
, int flags
) {
780 if((f
= fopen(fn
, "wb")) == 0)
782 AF_set_pos(a
, s
->start
);
783 struct fixup_data fxd
= {0};
784 if(!get_fixups(a
, s
->fixupstart
, s
->fixupcount
, &fxd
)) return 0;
785 struct strings str
= get_strings(a
, s
->stringsstart
, s
->stringssize
);
787 //if(!dump_globaldata(a, fd, s->globaldatastart, s->globaldatasize)) goto err_close;
788 if(!disassemble_code_and_data(a
, s
, f
, flags
, &fxd
, &str
)) goto err_close
;
789 if(!dump_strings(a
, f
, &str
)) goto err_close
;
790 if((flags
& DISAS_DEBUG_FIXUPS
) && !dump_fixups(f
, s
->fixupcount
, &fxd
)) goto err_close
;
791 if(!dump_import_export(a
, f
, s
->importstart
, s
->importcount
, 1)) goto err_close
;
792 if(!dump_import_export(a
, f
, s
->exportstart
, s
->exportcount
, 0)) goto err_close
;
793 if(!dump_sections(a
, f
, s
->sectionstart
, s
->sectioncount
)) goto err_close
;
795 free_fixup_data(&fxd
);
803 int ASI_read_script(AF
*a
, ASI
* s
) {
804 s
->start
= AF_get_pos(a
);
807 if(l
!= (size_t) AF_read(a
, sig
, l
)) return 0;
808 assert(memcmp("SCOM", sig
, 4) == 0);
809 s
->version
= AF_read_int(a
);
810 s
->globaldatasize
= AF_read_int(a
);
811 s
->codesize
= AF_read_int(a
);
812 s
->stringssize
= AF_read_int(a
);
813 if(s
->globaldatasize
) {
814 s
->globaldatastart
= AF_get_pos(a
);
815 l
= s
->globaldatasize
;
816 if(!AF_read_junk(a
, l
)) return 0;
817 } else s
->globaldatastart
= 0;
819 s
->codestart
= AF_get_pos(a
);
820 l
= s
->codesize
* sizeof(int);
821 if(!AF_read_junk(a
, l
)) return 0;
822 } else s
->codestart
= 0;
824 s
->stringsstart
= AF_get_pos(a
);
826 if(!AF_read_junk(a
, l
)) return 0;
827 } else s
->stringsstart
= 0;
828 s
->fixupcount
= AF_read_int(a
);
830 s
->fixupstart
= AF_get_pos(a
);
832 if(!AF_read_junk(a
, l
)) return 0; /* fixup types */
834 if(!AF_read_junk(a
, l
)) return 0; /* fixups */
835 } else s
->fixupstart
= 0;
836 s
->importcount
= AF_read_int(a
);
838 s
->importstart
= AF_get_pos(a
);
841 for(; i
< s
->importcount
; i
++)
842 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
843 } else s
->importstart
= 0;
844 s
->exportcount
= AF_read_int(a
);
846 s
->exportstart
= AF_get_pos(a
);
849 for(; i
< s
->exportcount
; i
++) {
850 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
851 AF_read_int(a
); /* export_addr */
853 } else s
->exportstart
= 0;
856 if (s
->version
>= 83) {
857 s
->sectioncount
= AF_read_int(a
);
858 if(s
->sectioncount
) {
859 s
->sectionstart
= AF_get_pos(a
);
862 for(; i
< s
->sectioncount
; i
++) {
863 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
864 AF_read_int(a
); /* section offset */
868 if(0xbeefcafe != AF_read_uint(a
)) return 0;
869 s
->len
= AF_get_pos(a
) - s
->start
;