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
, size_t start
, size_t len
) {
31 fprintf(f
, ".%s\n", "strings");
32 char *buf
= malloc(len
), *p
= buf
, escapebuf
[4096];
33 if(len
!= (size_t) AF_read(a
, buf
, len
)) {
38 escape(p
, escapebuf
, sizeof(escapebuf
));
39 fprintf(f
, "\"%s\"\n", escapebuf
);
43 if(len
== 0 || --len
== 0) break;
49 static void free_fixup_data(struct fixup_data
*ret
) {
51 for(i
= 0; i
<= FIXUP_MAX
; i
++) {
52 free(ret
->codeindex_per
[i
]);
58 /* fixup_data needs to be zeroed */
59 static int get_fixups(AF
* a
, size_t start
, size_t count
, struct fixup_data
*ret
) {
61 if(!(ret
->types
= malloc(count
))) goto err
;
62 if(!(ret
->codeindex
= malloc(count
* sizeof(unsigned)))) goto err
;
66 if(count
!= (size_t) AF_read(a
, ret
->types
, count
)) goto err
;
67 for(i
= 0; i
< count
; i
++) {
68 assert(ret
->types
[i
]>=0 && ret
->types
[i
]<=FIXUP_MAX
);
69 ret
->count
[ret
->types
[i
]]++;
70 ret
->codeindex
[i
] = AF_read_uint(a
);
72 for(i
= 0; i
<= FIXUP_MAX
; i
++) {
73 ret
->codeindex_per
[i
] = malloc(ret
->count
[i
] * sizeof(unsigned));
74 if(!ret
->codeindex_per
[i
]) goto err
;
75 ret
->count
[i
] = 0; /* reset to 0 to use as index i.t. next loop */
78 for(i
= 0; i
< count
; i
++) {
79 ret
->codeindex_per
[ret
->types
[i
]][ret
->count
[ret
->types
[i
]]++] = ret
->codeindex
[i
];
88 static int dump_fixups(FILE *f
, size_t count
, struct fixup_data
*fxd
) {
89 static const char* typenames
[] = {
90 [FIXUP_GLOBALDATA
] = "FIXUP_GLOBALDATA",
91 [FIXUP_FUNCTION
] = "FIXUP_FUNCTION",
92 [FIXUP_STRING
] = "FIXUP_STRING",
93 [FIXUP_IMPORT
] = "FIXUP_IMPORT",
94 [FIXUP_DATADATA
] = "FIXUP_DATADATA",
95 [FIXUP_STACK
] = "FIXUP_STACK",
98 fprintf(f
, ".%ss\n", "fixup");
100 for(i
= 0; i
< count
; i
++) {
101 fprintf(f
, "%s: %.12u\n", typenames
[(int)fxd
->types
[i
]], fxd
->codeindex
[i
]);
107 static int dump_import_export(AF
* a
, FILE *f
, size_t start
, size_t count
, int import
) {
108 static const char* secnames
[2] = { "export", "import" };
109 const char* secname
= secnames
[import
];
111 char buf
[256]; /* arbitrarily chosen */
113 AF_set_pos(a
, start
);
114 fprintf(f
, ".%ss\n", secname
);
115 for(i
= 0; i
< count
; i
++) {
116 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
117 fprintf(f
, "%.12zu\"%s\"\n", i
, buf
);
119 unsigned int addr
= AF_read_uint(a
);
120 fprintf(f
, "%d:%.12u\n", addr
>> 24, addr
& 0x00FFFFFF);
126 static struct export
* get_exports(AF
* a
, size_t start
, size_t count
) {
128 struct export
* fl
= malloc(count
* sizeof(struct export
));
129 AF_set_pos(a
, start
);
130 char buf
[4096]; size_t i
;
131 for(i
= 0; i
< count
; i
++) {
132 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
133 fl
[i
].fn
= strdup(buf
);
134 unsigned int addr
= AF_read_uint(a
);
135 fl
[i
].type
= addr
>> 24;
136 fl
[i
].instr
= (addr
& 0x00FFFFFF);
141 static struct importlist
get_imports(AF
* a
, size_t start
, size_t count
) {
142 struct importlist ret
= {0};
143 if(!count
) return ret
;
144 ret
.names
= malloc(count
* sizeof(char*));
145 if(!ret
.names
) return ret
;
146 AF_set_pos(a
, start
);
147 char buf
[4096]; size_t i
;
148 for(i
= 0; i
< count
; i
++) {
149 if(!AF_read_string(a
, buf
, sizeof(buf
))) {
151 return (struct importlist
) {0};
153 ret
.names
[i
] = strdup(buf
);
163 static int sort_comp(const void* xp
, const void *yp
) {
164 const unsigned *x
= xp
, *y
= yp
;
165 if(*x
== *y
) return 0;
166 else if(*x
> *y
) return 1;
171 static struct labels
get_labels(unsigned *code
, size_t count
) {
172 struct labels ret
= {0, 0};
173 if(!count
) return ret
;
178 while(insno
< count
) {
179 if(ret
.count
+ 1 > capa
) {
180 capa
= capa
? capa
* 2 : 16;
181 if(!(p
= realloc(ret
.insno
, capa
* sizeof(unsigned*)))) {
182 if(ret
.insno
) free(ret
.insno
);
186 } else ret
.insno
= p
;
188 insn
= code
[insno
] & 0x00ffffff;
191 assert(insn
< SCMD_MAX
);
193 case SCMD_JZ
: case SCMD_JMP
: case SCMD_JNZ
:
199 for(; i
< opcodes
[insn
].argcount
; i
++) {
200 int val
= code
[insno
];
203 if((int) insno
+ val
< 0 || insno
+ val
>= count
|| code
[insno
+ val
] > SCMD_MAX
) {
204 dprintf(2, "error: label referenced from jump at %zu is out of bounds\n"
205 "or points to non-instruction start code.\n", insno
);
208 ret
.insno
[ret
.count
] = insno
+ val
;
213 qsort(ret
.insno
, ret
.count
, sizeof(unsigned), sort_comp
);
217 static struct strings
get_strings(AF
* a
, size_t start
, size_t size
) {
218 struct strings ret
= {0,0,0};
219 if(!size
) return ret
;
220 if(!(ret
.data
= malloc(size
))) return ret
;
221 AF_set_pos(a
, start
);
222 if(size
!= (size_t) AF_read(a
, ret
.data
, size
)) {
228 size_t i
, strcnt
= 0;
229 for(i
= 0; i
< size
; i
++) {
230 if(!ret
.data
[i
]) strcnt
++;
232 if(!(ret
.strings
= malloc(strcnt
* sizeof(char*)))) goto free1
;
237 for(i
= 0; i
< size
; i
++) {
239 ret
.strings
[strcnt
] = p
;
250 static char* get_varname(struct export
* exp
, size_t expcount
, unsigned globaloffset
) {
252 for(; i
< expcount
; i
++)
253 if(exp
[i
].type
== EXPORT_DATA
&& exp
[i
].instr
== globaloffset
)
258 unsigned *get_code(AF
*a
, size_t start
, size_t count
) {
259 unsigned *ret
= malloc(count
* sizeof(unsigned));
261 AF_set_pos(a
, start
);
263 for(i
=0; i
<count
; i
++)
264 ret
[i
] = AF_read_uint(a
);
268 static unsigned get_varsize_from_instr(unsigned* code
, size_t codecount
, size_t index
) {
269 assert(index
< codecount
);
270 switch(code
[index
]) {
271 case SCMD_MEMREADB
: case SCMD_MEMWRITEB
:
273 case SCMD_MEMREADW
: case SCMD_MEMWRITEW
:
275 case SCMD_MEMWRITEPTR
:
276 case SCMD_MEMREADPTR
:
277 case SCMD_MEMZEROPTR
:
278 case SCMD_MEMINITPTR
:
279 case SCMD_MEMREAD
: case SCMD_MEMWRITE
:
286 struct fixup_resolved
{
291 static int fixup_cmp(const void *a
, const void *b
) {
292 const struct fixup_resolved
*u1
= a
;
293 const struct fixup_resolved
*u2
= b
;
294 return (u1
->code
- u2
->code
);
297 /* assumes list members are sorted. set iter to -1 for first call */
298 int find_next_match(struct fixup_resolved
*list
, size_t nel
, unsigned value
, size_t *iter
) {
299 struct fixup_resolved comparer
= {
302 if(*iter
== (size_t)-1) {
303 struct fixup_resolved
* ret
= bsearch(&comparer
, list
, nel
, sizeof(list
[0]), fixup_cmp
);
306 while(*iter
>=1 && list
[*iter
-1].code
== value
)
311 if(*iter
< nel
&& list
[*iter
].code
== value
)
317 static int has_datadata_fixup(unsigned gdoffset
, struct fixup_data
*fxd
) {
319 for(i
= 0; i
< fxd
->count
[FIXUP_DATADATA
]; i
++)
320 if(fxd
->codeindex_per
[FIXUP_DATADATA
][i
] == gdoffset
)
325 struct varinfo
find_fixup_for_globaldata(FILE *f
, size_t offset
,
326 struct fixup_resolved
*fxlist_resolved
, size_t fxlist_cnt
,
327 unsigned* code
, size_t codecount
)
330 size_t iter
= (size_t)-1, x
;
331 struct varinfo ret
= {0,0};
332 while(find_next_match(fxlist_resolved
, fxlist_cnt
, offset
, &iter
)) {
333 x
= fxlist_resolved
[iter
].offset
;
335 assert(x
+ 1 < codecount
);
338 unsigned oldvarsize
= ret
.varsize
;
339 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+1);
340 if(!ret
.varsize
) switch(code
[x
+1]) {
342 // li mar, @Obj; mr ax, mar; callobj ax
343 if(x
+5 < codecount
&&
344 code
[x
+2] == AR_MAR
&&
345 code
[x
+4] == SCMD_CALLOBJ
&&
346 code
[x
+3] == code
[x
+5]) {
351 // li mar, @var; muli dx, 4; ptrget mar; ptrassert; dynamicbounds dx
352 if(x
+5 < codecount
&&
353 code
[x
+2] != AR_MAR
&&
354 code
[x
+4] == SCMD_MEMREADPTR
&&
357 // muli is used as an array index like:
358 // muli REG, 4; add MAR, REG; PUSH/POP MAR; ...
359 else if(x
+11 < codecount
&&
360 code
[x
+4] == SCMD_ADDREG
&&
361 code
[x
+5] == AR_MAR
&&
362 code
[x
+6] == code
[x
+2] &&
363 code
[x
+7] == SCMD_PUSHREG
&&
364 code
[x
+8] == AR_MAR
&&
365 code
[x
+9] == SCMD_POPREG
&&
366 code
[x
+10] == AR_MAR
) {
367 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+11);
370 code
[x
+11] == SCMD_ADDREG
&&
371 code
[x
+12] == AR_MAR
&&
372 code
[x
+13] != code
[x
+2]
374 /* this variation adds another reg to mar before calling ptrget */
375 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+14);
376 else if(!ret
.varsize
&&
378 code
[x
+11] == SCMD_PUSHREG
&&
380 /* this variation pushes ax on the stack before doing a ptrget ax, which overwrites ax */
381 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+13);
383 /* muli dx, 4; add mar, dx; add mar, cx; ptr... */
384 else if(x
+10 < codecount
&&
385 code
[x
+4] == SCMD_ADDREG
&&
386 code
[x
+5] == AR_MAR
&&
387 (code
[x
+6] == AR_CX
|| code
[x
+6] == AR_DX
) &&
388 code
[x
+7] == SCMD_ADDREG
&&
389 code
[x
+8] == AR_MAR
&&
390 (code
[x
+9] == AR_CX
|| code
[x
+9] == AR_DX
))
391 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+10);
392 else if(x
+7 < codecount
&&
393 code
[x
+4] == SCMD_ADDREG
&&
394 code
[x
+5] == AR_MAR
&&
395 code
[x
+6] == code
[x
+2]) {
396 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+7);
399 code
[x
+7] == SCMD_PUSHREG
&&
401 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+9);
406 // addreg is typically used on an index register into an array
407 // followed by a byteread/store of the desired size
408 // the index register needs to be added to mar reg
409 assert(x
+2 < codecount
&& code
[x
+2] == AR_MAR
);
410 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+4);
411 // a typical method call
412 if(!ret
.varsize
&& x
+8 < codecount
&&
413 code
[x
+4] == SCMD_REGTOREG
&&
414 code
[x
+5] == AR_MAR
&&
415 code
[x
+7] == SCMD_CALLOBJ
&&
416 code
[x
+6] == code
[x
+8])
420 // ptrget and similar ops are typically preceded by push mar, pop mar
421 if(x
+4 < codecount
&&
422 code
[x
+2] == AR_MAR
&&
423 code
[x
+3] == SCMD_POPREG
&&
424 code
[x
+4] == AR_MAR
) {
425 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+5);
426 if(!ret
.varsize
&& x
+7 < codecount
&&
427 code
[x
+5] == SCMD_ADDREG
&&
429 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+8);
430 } else if(x
+2 < codecount
&&
432 /* ptrget is sometimes preceded by push ax */
433 ret
.varsize
= get_varsize_from_instr(code
, codecount
, x
+3);
438 /* don't bother guessing the varsize if we already determined it */
439 ret
.varsize
= oldvarsize
;
441 dprintf(2, "warning: '%s' globaldata fixup on insno %zu offset %zu\n",
442 opcodes
[code
[x
+1]].mnemonic
, x
+1, offset
);
443 COMMENT(f
, "warning: '%s' globaldata fixup on insno %zu offset %zu\n",
444 opcodes
[code
[x
+1]].mnemonic
, x
+1, offset
);
446 if(oldvarsize
!= 0 && oldvarsize
!= ret
.varsize
)
454 static int is_all_zeroes(const char* buf
, int len
) {
456 if(*buf
!= 0) return 0;
462 static const char* get_varsize_typename(unsigned varsize
) {
463 static const char typenames
[][6] = {[0]="ERR", [1]="char", [2]="short", [4]="int"};
465 case 0: case 1: case 2: case 4:
466 return typenames
[varsize
];
473 static struct varinfo
get_varinfo_from_code(
474 unsigned *code
, size_t codesize
,
476 struct fixup_data
*fxd
,
477 struct fixup_resolved
*gd_fixups_resolved
,
481 if(has_datadata_fixup(offset
, fxd
))
482 vi
= (struct varinfo
){0,4};
484 vi
= find_fixup_for_globaldata(f
, offset
, gd_fixups_resolved
, fxd
->count
[FIXUP_GLOBALDATA
], code
, codesize
);
485 if(vi
.varsize
== 0 && has_datadata_fixup(offset
+200, fxd
))
491 int get_varinfo_from_exports(size_t offs
, struct export
*exp
, size_t expcount
, struct varinfo
*vi
)
493 struct export
*end
= exp
+ expcount
;
494 for(; exp
< end
; ++exp
)
495 if(exp
->instr
== offs
&& exp
->type
== EXPORT_DATA
) {
496 vi
->varsize
= 1; /* unfortunately no size info is available, so we need to default to char for safety */
502 static int dump_globaldata(AF
*a
, FILE *f
, size_t start
, size_t size
,
503 struct export
* exp
, size_t expcount
,
504 struct fixup_data
*fxd
,
505 unsigned *code
, size_t codesize
) {
508 size_t fxcount
= fxd
->count
[FIXUP_GLOBALDATA
];
509 struct fixup_resolved
*gd_fixups_resolved
= malloc(sizeof(struct fixup_resolved
) * fxcount
);
510 if(!gd_fixups_resolved
) return 0;
512 for(i
=0; i
< fxcount
; i
++) {
513 unsigned x
= fxd
->codeindex_per
[FIXUP_GLOBALDATA
][i
];
514 assert(x
< codesize
);
515 gd_fixups_resolved
[i
].code
= code
[x
];
516 gd_fixups_resolved
[i
].offset
= x
;
518 qsort(gd_fixups_resolved
, fxcount
, sizeof(gd_fixups_resolved
[0]), fixup_cmp
);
520 fprintf(f
, ".%s\n", "data");
521 AF_set_pos(a
, start
);
523 for(i
= 0; i
< size
; ) {
525 vi
= get_varinfo_from_code(code
, codesize
, i
, fxd
, gd_fixups_resolved
, f
);
526 if(vi
.varsize
== 0) get_varinfo_from_exports(i
, exp
, expcount
, &vi
);
534 off_t savepos
= AF_get_pos(a
);
535 if(i
+ 204 <= size
) {
537 assert(200 == AF_read(a
, buf
, 200));
538 /* read the datadata fixup content*/
540 if(x
== i
&& is_all_zeroes(buf
, 200)) {
542 AF_set_pos(a
, savepos
+ 200);
547 AF_set_pos(a
, savepos
);
555 x
= AF_read_short(a
);
558 x
= ByteArray_readByte(a
->b
);
562 x
= ByteArray_readByte(a
->b
);
563 if(vi
.numrefs
) comment
= " ; warning: couldn't determine varsize, default to 1";
565 comment
= " ; unreferenced variable, assuming char";
570 vi2
= get_varinfo_from_code(code
, codesize
, j
, fxd
, gd_fixups_resolved
, f
);
571 if(vi2
.varsize
|| vi
.numrefs
|| get_varinfo_from_exports(j
, exp
, expcount
, &vi2
)) break;
572 x
= ByteArray_readByte(a
->b
);
574 ByteArray_set_position_rel(a
->b
, -1);
583 char* vn
= get_varname(exp
, expcount
, i
),
584 *tn
= get_varsize_typename(vi
.varsize
), buf
[32];
585 if(!tn
|| (vi
.varsize
== 200 && !is_str
)) {
586 snprintf(buf
, sizeof buf
, "char[%u]", vi
.varsize
);
589 if(has_datadata_fixup(i
, fxd
)) {
590 if(vn
) fprintf(f
, "export %s %s = .data + %d%s\n", tn
, vn
, x
, comment
);
591 else fprintf(f
, "%s var%.6zu = .data + %d%s\n", tn
, i
, x
, comment
);
593 if(vn
) fprintf(f
, "export %s %s = %d%s\n", tn
, vn
, x
, comment
);
594 else fprintf(f
, "%s var%.6zu = %d%s\n", tn
, i
, x
, comment
);
598 free(gd_fixups_resolved
);
602 static int disassemble_code_and_data(AF
* a
, ASI
* s
, FILE *f
, int flags
, struct fixup_data
*fxd
) {
603 int debugmode
= getenv("AGSDEBUG") != 0;
604 size_t start
= s
->codestart
;
605 size_t len
= s
->codesize
* sizeof(unsigned);
607 unsigned *code
= get_code(a
, s
->codestart
, s
->codesize
);
609 struct export
* fl
= get_exports(a
, s
->exportstart
, s
->exportcount
);
611 dump_globaldata(a
, f
, s
->globaldatastart
, s
->globaldatasize
, fl
, s
->exportcount
, fxd
, code
, s
->codesize
);
613 if(!len
) return 1; /* its valid for a scriptfile to have no code at all */
616 struct importlist il
= get_imports(a
, s
->importstart
, s
->importcount
);
618 struct labels lbl
= get_labels(code
, s
->codesize
);
620 struct strings str
= get_strings(a
, s
->stringsstart
, s
->stringssize
);
622 AF_set_pos(a
, start
);
623 fprintf(f
, ".%s\n", "text");
625 size_t currInstr
= 0, currExp
= 0, currFixup
= 0, currLbl
= 0;
627 /* the data_data fixups appear to be glued separately onto the fixup logic,
628 * they are the only entries not sorted by instrucion number */
629 while(currFixup
< s
->fixupcount
&& fxd
->types
[currFixup
] == FIXUP_DATADATA
) currFixup
++;
630 while(currInstr
< s
->codesize
) {
631 if(flags
& DISAS_DEBUG_OFFSETS
) COMMENT(f
, "offset: %llu (insno %zu)\n", (long long) AF_get_pos(a
), currInstr
);
632 unsigned regs
, args
, insn
= AF_read_uint(a
), op
= insn
& 0x00ffffff;
633 assert(op
< SCMD_MAX
);
634 while(currExp
< s
->exportcount
&& fl
[currExp
].type
!= EXPORT_FUNCTION
)
636 if(currExp
< s
->exportcount
&& fl
[currExp
].instr
== currInstr
) {
637 /* new function starts here */
638 curr_func
= fl
[currExp
].fn
;
639 char comment
[64], *p
= strrchr(fl
[currExp
].fn
, '$');
643 if((n
= atoi(p
+1)) >= 100)
644 sprintf(comment
, " ; variadic, %d fixed args", n
- 100);
646 sprintf(comment
, " ; %d args", n
);
648 fprintf(f
, "\n%s:%s\n", curr_func
, comment
);
651 if(currLbl
< lbl
.count
) {
652 if(lbl
.insno
[currLbl
] == currInstr
) {
654 while(currLbl
< lbl
.count
&& lbl
.insno
[currLbl
] == currInstr
) {
655 currLbl
++; numrefs
++;
657 fprintf(f
, "label%.12zu: ", currInstr
);
658 COMMENT(f
, "inside %s, ", curr_func
? curr_func
: "???");
659 COMMENT(f
, "referenced by %zu spots\n", numrefs
);
665 regs
= opcodes
[op
].regcount
;
666 args
= opcodes
[op
].argcount
;
668 if(insn
== SCMD_LINENUM
&& (flags
& DISAS_SKIP_LINENO
)) {
669 insn
= AF_read_uint(a
);
670 COMMENT(f
, "line %u\n", insn
);
675 if(flags
& DISAS_DEBUG_BYTECODE
) {
676 unsigned char insbuf
[16];
677 unsigned iblen
= 0, val
;
678 val
= end_htole32(insn
);
679 memcpy(insbuf
+iblen
, &val
, 4); iblen
+= 4;
681 off_t currpos
= AF_get_pos(a
);
684 for(l
= 0; l
< args
; l
++) {
685 assert(iblen
+4 <= sizeof(insbuf
));
686 val
= AF_read_uint(a
);
687 val
= end_htole32(val
);
688 memcpy(insbuf
+iblen
, &val
, 4); iblen
+= 4;
691 char printbuf
[sizeof(insbuf
)*2 + 1], *pb
= printbuf
;
692 for(l
= 0; l
< iblen
; l
++, pb
+=2)
693 sprintf(pb
, "%02x", (int) insbuf
[l
]);
694 COMMENT(f
, "%s\n", printbuf
);
696 AF_set_pos(a
, currpos
);
700 fprintf(f
, "%.12zu""\t%s ", currInstr
- 1, opcodes
[op
].mnemonic
);
702 fprintf(f
, /*"%.12zu"*/"\t%s ", /*currInstr - 1, */opcodes
[op
].mnemonic
);
704 if(insn
== SCMD_REGTOREG
) {
705 /* the "mov" instruction differs from all others in that the source comes first
706 we do not want that. */
708 src
= AF_read_uint(a
);
710 dst
= AF_read_uint(a
);
712 fprintf(f
, "%s, %s\n", regnames
[dst
], regnames
[src
]);
716 for (l
= 0; l
< args
; l
++) {
717 char escapebuf
[4096];
718 if(l
) fprintf(f
, ", ");
719 insn
= AF_read_uint(a
);
721 if((!l
&& regs
) || (l
== 1 && regs
== 2))
722 fprintf(f
, "%s", regnames
[insn
]);
724 while(currFixup
< s
->fixupcount
&& fxd
->types
[currFixup
] == FIXUP_DATADATA
)
725 currFixup
++; /* DATADATA fixups are unrelated to the code */
726 if(currFixup
< s
->fixupcount
&& fxd
->codeindex
[currFixup
] == currInstr
- 1) {
727 switch(fxd
->types
[currFixup
]) {
730 fprintf(f
, "IMP:%s", il
.names
[insn
]);
732 fprintf(f
, "%s", il
.names
[insn
]);
734 case FIXUP_FUNCTION
: {
736 for(; x
< s
->exportcount
; x
++) {
737 if(fl
[x
].type
== EXPORT_FUNCTION
&& fl
[x
].instr
== insn
) {
738 fprintf(f
, "%s", fl
[x
].fn
);
744 case FIXUP_GLOBALDATA
: {
745 char *vn
= get_varname(fl
, s
->exportcount
, insn
);
746 if(vn
) fprintf(f
, "@%s", vn
);
747 else fprintf(f
, "@var%.6u", insn
);
749 case FIXUP_STACK
: /* it is unclear if and where those ever get generated */
750 fprintf(f
, ".stack + %d", insn
);
753 escape(str
.data
+ insn
, escapebuf
, sizeof(escapebuf
));
754 fprintf(f
, "\"%s\"", escapebuf
);
761 case SCMD_JMP
: case SCMD_JZ
: case SCMD_JNZ
:
762 fprintf(f
, "label%.12zu", currInstr
+ (int) insn
);
765 fprintf(f
, "%d", insn
);
776 int ASI_disassemble(AF
* a
, ASI
* s
, char *fn
, int flags
) {
779 if((f
= fopen(fn
, "w")) == 0)
781 AF_set_pos(a
, s
->start
);
782 struct fixup_data fxd
= {0};
783 if(!get_fixups(a
, s
->fixupstart
, s
->fixupcount
, &fxd
)) return 0;
785 //if(!dump_globaldata(a, fd, s->globaldatastart, s->globaldatasize)) goto err_close;
786 if(!disassemble_code_and_data(a
, s
, f
, flags
, &fxd
)) goto err_close
;
787 if(!dump_strings(a
, f
, s
->stringsstart
, s
->stringssize
)) goto err_close
;
788 if((flags
& DISAS_DEBUG_FIXUPS
) && !dump_fixups(f
, s
->fixupcount
, &fxd
)) goto err_close
;
789 if(!dump_import_export(a
, f
, s
->importstart
, s
->importcount
, 1)) goto err_close
;
790 if(!dump_import_export(a
, f
, s
->exportstart
, s
->exportcount
, 0)) goto err_close
;
791 if(!dump_sections(a
, f
, s
->sectionstart
, s
->sectioncount
)) goto err_close
;
793 free_fixup_data(&fxd
);
801 int ASI_read_script(AF
*a
, ASI
* s
) {
802 s
->start
= AF_get_pos(a
);
805 if(l
!= (size_t) AF_read(a
, sig
, l
)) return 0;
806 assert(memcmp("SCOM", sig
, 4) == 0);
807 s
->version
= AF_read_int(a
);
808 s
->globaldatasize
= AF_read_int(a
);
809 s
->codesize
= AF_read_int(a
);
810 s
->stringssize
= AF_read_int(a
);
811 if(s
->globaldatasize
) {
812 s
->globaldatastart
= AF_get_pos(a
);
813 l
= s
->globaldatasize
;
814 if(!AF_read_junk(a
, l
)) return 0;
815 } else s
->globaldatastart
= 0;
817 s
->codestart
= AF_get_pos(a
);
818 l
= s
->codesize
* sizeof(int);
819 if(!AF_read_junk(a
, l
)) return 0;
820 } else s
->codestart
= 0;
822 s
->stringsstart
= AF_get_pos(a
);
824 if(!AF_read_junk(a
, l
)) return 0;
825 } else s
->stringsstart
= 0;
826 s
->fixupcount
= AF_read_int(a
);
828 s
->fixupstart
= AF_get_pos(a
);
830 if(!AF_read_junk(a
, l
)) return 0; /* fixup types */
832 if(!AF_read_junk(a
, l
)) return 0; /* fixups */
833 } else s
->fixupstart
= 0;
834 s
->importcount
= AF_read_int(a
);
836 s
->importstart
= AF_get_pos(a
);
839 for(; i
< s
->importcount
; i
++)
840 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
841 } else s
->importstart
= 0;
842 s
->exportcount
= AF_read_int(a
);
844 s
->exportstart
= AF_get_pos(a
);
847 for(; i
< s
->exportcount
; i
++) {
848 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
849 AF_read_int(a
); /* export_addr */
851 } else s
->exportstart
= 0;
854 if (s
->version
>= 83) {
855 s
->sectioncount
= AF_read_int(a
);
856 if(s
->sectioncount
) {
857 s
->sectionstart
= AF_get_pos(a
);
860 for(; i
< s
->sectioncount
; i
++) {
861 if(!AF_read_string(a
, buf
, sizeof(buf
))) return 0;
862 AF_read_int(a
); /* section offset */
866 if(0xbeefcafe != AF_read_uint(a
)) return 0;
867 s
->len
= AF_get_pos(a
) - s
->start
;