Merge pull request #218 from saper/build-fixes
[envytools.git] / envydis / core-dis.c
bloba4a717ce1666de2324188c268abbd4883fb9c12c
1 /*
2 * Copyright (C) 2009-2011 Marcelina Koƛcielnicka <mwk@0x04.net>
3 * All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
25 #include "dis-intern.h"
26 #include "easm.h"
27 #include <stdlib.h>
29 struct disctx {
30 const struct disisa *isa;
31 struct varinfo *varinfo;
32 int oplen;
33 struct litem **atoms;
34 int atomsnum;
35 int atomsmax;
36 int endmark;
39 static inline ull bf_(int s, int l, ull *a, ull *m) {
40 int idx = s / 0x40;
41 int bit = s % 0x40;
42 ull res = 0;
43 ull m0 = (((1ull << l) - 1) << bit);
44 m[idx] |= m0;
45 res |= (a[idx] & m0) >> bit;
46 if (bit + l > 0x40) {
47 ull m1 = (((1ull << l) - 1) >> (0x40 - bit));
48 m[idx+1] |= m1;
49 res |= (a[idx+1] & m1) << (0x40 - bit);
51 return res;
53 #define BF(s, l) bf_(s, l, a, m)
55 ull getbf(const struct bitfield *bf, ull *a, ull *m) {
56 ull res = 0;
57 int pos = bf->shr;
58 int i;
59 for (i = 0; i < sizeof(bf->sbf) / sizeof(bf->sbf[0]); i++) {
60 res |= BF(bf->sbf[i].pos, bf->sbf[i].len) << pos;
61 pos += bf->sbf[i].len;
63 switch (bf->mode) {
64 case BF_UNSIGNED:
65 break;
66 case BF_SIGNED:
67 if (res & 1ull << (pos - 1))
68 res -= 1ull << pos;
69 break;
70 case BF_SLIGHTLY_SIGNED:
71 if (res & 1ull << (pos - 1) && res & 1ull << (pos - 2))
72 res -= 1ull << pos;
73 break;
74 case BF_ULTRASIGNED:
75 res -= 1ull << pos;
76 break;
77 case BF_LUT:
78 res = bf->lut[res];
79 break;
81 res ^= bf->xorend;
82 res += bf->addend;
83 return res;
86 struct easm_expr *getrbf(const struct rbitfield *bf, ull *a, ull *m) {
87 ull res = 0;
88 int pos = bf->shr;
89 int i;
90 for (i = 0; i < sizeof(bf->sbf) / sizeof(bf->sbf[0]); i++) {
91 res |= BF(bf->sbf[i].pos, bf->sbf[i].len) << pos;
92 pos += bf->sbf[i].len;
94 switch (bf->mode) {
95 case RBF_UNSIGNED:
96 break;
97 case RBF_SIGNED:
98 if (res & 1ull << (pos - 1))
99 res -= 1ull << pos;
100 break;
101 case RBF_SLIGHTLY_SIGNED:
102 if (res & 1ull << (pos - 1) && res & 1ull << (pos - 2))
103 res -= 1ull << pos;
104 break;
105 case RBF_ULTRASIGNED:
106 res -= 1ull << pos;
107 break;
109 if (bf->pcrel) {
110 struct easm_expr *expr = easm_expr_simple(EASM_EXPR_POS);
111 if (bf->pospreadd)
112 expr = easm_expr_bin(EASM_EXPR_ADD, expr, easm_expr_num(EASM_EXPR_NUM, bf->pospreadd));
113 if (bf->shr)
114 expr = easm_expr_bin(EASM_EXPR_AND, expr, easm_expr_num(EASM_EXPR_NUM, -(1ull << bf->shr)));
115 expr = easm_expr_bin(EASM_EXPR_ADD, expr, easm_expr_num(EASM_EXPR_NUM, res));
116 if (bf->addend)
117 expr = easm_expr_bin(EASM_EXPR_ADD, expr, easm_expr_num(EASM_EXPR_NUM, bf->addend));
118 return expr;
119 } else {
120 res += bf->addend;
121 return easm_expr_num(EASM_EXPR_NUM, res);
125 #define GETBF(bf) getbf(bf, a, m)
126 #define GETRBF(bf) getrbf(bf, a, m)
128 static inline struct litem *makeli(struct easm_expr *e) {
129 struct litem *li = calloc(sizeof *li, 1);
130 li->type = LITEM_EXPR;
131 li->expr = e;
132 return li;
135 void atomtab_d DPROTO {
136 const struct insn *tab = v;
137 int i;
138 while ((a[0]&tab->mask) != tab->val || !var_ok(tab->fmask, tab->ptype, ctx->varinfo))
139 tab++;
140 m[0] |= tab->mask;
141 for (i = 0; i < ARRAY_SIZE(tab->atoms); i++)
142 if (tab->atoms[i].fun_dis)
143 tab->atoms[i].fun_dis (ctx, a, m, tab->atoms[i].arg);
146 void atomopl_d DPROTO {
147 ctx->oplen = *(int*)v;
150 void atomendmark_d DPROTO {
151 ctx->endmark = 1;
154 void atomsestart_d DPROTO {
155 struct litem *li = calloc(sizeof *li, 1);
156 li->type = LITEM_SESTART;
157 ADDARRAY(ctx->atoms, li);
160 void atomseend_d DPROTO {
161 struct litem *li = calloc(sizeof *li, 1);
162 li->type = LITEM_SEEND;
163 ADDARRAY(ctx->atoms, li);
166 void atomname_d DPROTO {
167 struct litem *li = calloc(sizeof *li, 1);
168 li->type = LITEM_NAME;
169 li->str = strdup(v);
170 ADDARRAY(ctx->atoms, li);
173 void atomcmd_d DPROTO {
174 struct litem *li = makeli(easm_expr_str(EASM_EXPR_LABEL, strdup(v)));
175 ADDARRAY(ctx->atoms, li);
178 void atomunk_d DPROTO {
179 struct litem *li = calloc(sizeof *li, 1);
180 li->type = LITEM_NAME;
181 li->str = strdup(v);
182 li->isunk = 1;
183 ADDARRAY(ctx->atoms, li);
186 void atomimm_d DPROTO {
187 const struct bitfield *bf = v;
188 struct easm_expr *expr = easm_expr_num(EASM_EXPR_NUM, GETBF(bf));
189 ADDARRAY(ctx->atoms, makeli(expr));
192 void atomrimm_d DPROTO {
193 const struct rbitfield *bf = v;
194 struct easm_expr *expr = GETRBF(bf);
195 ADDARRAY(ctx->atoms, makeli(expr));
198 void atomctarg_d DPROTO {
199 const struct rbitfield *bf = v;
200 struct easm_expr *expr = GETRBF(bf);
201 expr->special = EASM_SPEC_CTARG;
202 ADDARRAY(ctx->atoms, makeli(expr));
205 void atombtarg_d DPROTO {
206 const struct rbitfield *bf = v;
207 struct easm_expr *expr = GETRBF(bf);
208 expr->special = EASM_SPEC_BTARG;
209 ADDARRAY(ctx->atoms, makeli(expr));
212 void atomign_d DPROTO {
213 const int *n = v;
214 (void)BF(n[0], n[1]);
217 // print reg if non-0, ignore otherwise. return 1 if printed anything.
218 static struct easm_expr *printreg (struct disctx *ctx, ull *a, ull *m, const struct reg *reg) {
219 struct easm_expr *expr;
220 ull num = 0;
221 if (reg->bf)
222 num = GETBF(reg->bf);
223 if (reg->specials) {
224 int i;
225 for (i = 0; reg->specials[i].num != -1; i++) {
226 if (!var_ok(reg->specials[i].fmask, 0, ctx->varinfo))
227 continue;
228 if (num == reg->specials[i].num) {
229 switch (reg->specials[i].mode) {
230 case SR_NAMED:
231 expr = easm_expr_str(EASM_EXPR_REG, strdup(reg->specials[i].name));
232 expr->special = EASM_SPEC_REGSP;
233 return expr;
234 case SR_ZERO:
235 return 0;
236 case SR_ONE:
237 return easm_expr_num(EASM_EXPR_NUM, 1);
238 case SR_DISCARD:
239 return easm_expr_simple(EASM_EXPR_DISCARD);
244 const char *suf = "";
245 if (reg->suffix)
246 suf = reg->suffix;
247 if (reg->hilo) {
248 if (num & 1)
249 suf = "h";
250 else
251 suf = "l";
252 num >>= 1;
254 char *str;
255 if (reg->bf)
256 str = aprintf("%s%lld%s", reg->name, num, suf);
257 else
258 str = aprintf("%s%s", reg->name, suf);
259 expr = easm_expr_str(EASM_EXPR_REG, str);
260 if (reg->cool)
261 expr->special = EASM_SPEC_REGSP;
262 if (reg->always_special)
263 expr->special = EASM_SPEC_ERR;
264 return expr;
267 void atomreg_d DPROTO {
268 const struct reg *reg = v;
269 struct easm_expr *expr = printreg(ctx, a, m, reg);
270 if (!expr) expr = easm_expr_num(EASM_EXPR_NUM, 0);
271 ADDARRAY(ctx->atoms, makeli(expr));
274 void atomdiscard_d DPROTO {
275 struct easm_expr *expr = easm_expr_simple(EASM_EXPR_DISCARD);
276 ADDARRAY(ctx->atoms, makeli(expr));
279 void atommem_d DPROTO {
280 const struct mem *mem = v;
281 int type = EASM_EXPR_MEM;
282 struct easm_expr *expr = 0;
283 struct easm_expr *pexpr = 0;
284 if (mem->reg)
285 expr = printreg(ctx, a, m, mem->reg);
286 if (mem->imm) {
287 struct easm_expr *imm = GETRBF(mem->imm);
288 if (mem->postincr) {
289 type = EASM_EXPR_MEMPP;
290 pexpr = imm;
291 } else {
292 if (expr) {
293 expr = easm_expr_bin(EASM_EXPR_ADD, expr, imm);
294 } else {
295 expr = imm;
299 if (mem->reg2) {
300 struct easm_expr *sexpr = printreg(ctx, a, m, mem->reg2);
301 if (sexpr) {
302 if (mem->reg2shr) {
303 uint64_t num = 1ull << mem->reg2shr;
304 struct easm_expr *ssexpr = easm_expr_num(EASM_EXPR_NUM, num);
305 sexpr = easm_expr_bin(EASM_EXPR_MUL, sexpr, ssexpr);
307 if (expr)
308 expr = easm_expr_bin(EASM_EXPR_ADD, expr, sexpr);
309 else
310 expr = sexpr;
313 if (!expr) expr = easm_expr_num(EASM_EXPR_NUM, 0);
314 if (mem->name) {
315 struct easm_expr *nex;
316 if (pexpr)
317 nex = easm_expr_bin(type, expr, pexpr);
318 else
319 nex = easm_expr_un(type, expr);
320 if (mem->idx)
321 nex->str = aprintf("%s%lld", mem->name, GETBF(mem->idx));
322 else
323 nex->str = strdup(mem->name);
324 nex->mods = calloc(sizeof *nex->mods, 1);
325 expr = nex;
326 } else if (type != EASM_EXPR_MEM) {
327 abort();
329 if (mem->literal && expr->type == EASM_EXPR_MEM)
330 expr->special = EASM_SPEC_LITERAL;
331 ADDARRAY(ctx->atoms, makeli(expr));
334 void atomvec_d DPROTO {
335 const struct vec *vec = v;
336 struct easm_expr *expr = 0;
337 ull base = GETBF(vec->bf);
338 ull cnt = GETBF(vec->cnt);
339 ull mask = -1ull;
340 if (vec->mask)
341 mask = GETBF(vec->mask);
342 int k = 0, i;
343 for (i = 0; i < cnt; i++) {
344 struct easm_expr *sexpr;
345 if (mask & 1ull<<i) {
346 char *name = aprintf("%s%lld", vec->name, base + k++);
347 sexpr = easm_expr_str(EASM_EXPR_REG, name);
348 if (vec->cool)
349 sexpr->special = EASM_SPEC_REGSP;
350 } else {
351 sexpr = easm_expr_simple(EASM_EXPR_DISCARD);
353 if (expr)
354 expr = easm_expr_bin(EASM_EXPR_VEC, expr, sexpr);
355 else
356 expr = sexpr;
358 if (!expr)
359 expr = easm_expr_simple(EASM_EXPR_ZVEC);
360 ADDARRAY(ctx->atoms, makeli(expr));
363 void atombf_d DPROTO {
364 const struct bitfield *bf = v;
365 uint64_t num1 = GETBF(&bf[0]);
366 uint64_t num2 = num1 + GETBF(&bf[1]);
367 struct easm_expr *expr = easm_expr_bin(EASM_EXPR_VEC,
368 easm_expr_num(EASM_EXPR_NUM, num1),
369 easm_expr_num(EASM_EXPR_NUM, num2));
370 ADDARRAY(ctx->atoms, makeli(expr));
373 struct dis_op_chunk {
374 int len;
375 int isbe;
378 struct dis_res {
379 enum dis_status {
380 DIS_STATUS_OK = 0,
381 DIS_STATUS_EOF = 0x1, /* EOF in the middle of an opcode */
382 DIS_STATUS_UNK_FORM = 0x2, /* failed to determine instruction format - opcode length uncertain */
383 DIS_STATUS_UNK_INSN = 0x4, /* failed to determine instruction name - unknown opcode or due to one of the above errors */
384 DIS_STATUS_UNK_OPERAND = 0x8, /* failed to determine instruction operands */
385 DIS_STATUS_UNUSED_BITS = 0x10, /* instruction decoded, but unused bitfields have non-default values */
386 } status;
387 uint32_t oplen;
388 struct dis_op_chunk *chunks;
389 int chunksnum;
390 int chunksmax;
391 // uint32_t align;
392 // uint32_t askip;
393 ull a[MAXOPLEN], m[MAXOPLEN];
394 struct easm_insn *insn;
395 int endmark;
396 // uint32_t *umask;
399 static void dis_del_res(struct dis_res *dres)
401 easm_del_insn(dres->insn);
403 free(dres);
406 static struct easm_sinsn *dis_parse_sinsn(struct disctx *ctx, enum dis_status *status, int *spos);
408 static struct easm_expr *dis_parse_expr(struct disctx *ctx, enum dis_status *status, int *spos) {
409 if (*spos >= ctx->atomsnum)
410 abort();
411 if (ctx->atoms[*spos]->type == LITEM_EXPR)
412 return ctx->atoms[(*spos)++]->expr;
413 if (ctx->atoms[(*spos)++]->type != LITEM_SESTART)
414 abort();
415 struct easm_expr *res = easm_expr_sinsn(dis_parse_sinsn(ctx, status, spos));
416 if (ctx->atoms[(*spos)++]->type != LITEM_SEEND)
417 abort();
418 return res;
421 static struct easm_sinsn *dis_parse_sinsn(struct disctx *ctx, enum dis_status *status, int *spos) {
422 struct easm_sinsn *res = calloc(sizeof *res, 1);
423 res->str = ctx->atoms[*spos]->str;
424 res->isunk = ctx->atoms[*spos]->isunk;
425 if (res->isunk)
426 *status |= DIS_STATUS_UNK_INSN;
427 if (ctx->atoms[(*spos)++]->type != LITEM_NAME)
428 abort();
429 struct easm_mods *mods = calloc (sizeof *mods, 1);
430 while (*spos < ctx->atomsnum && ctx->atoms[*spos]->type != LITEM_SEEND) {
431 if (ctx->atoms[*spos]->type == LITEM_NAME) {
432 struct easm_mod *mod = calloc(sizeof *mod, 1);
433 mod->str = ctx->atoms[*spos]->str;
434 mod->isunk = ctx->atoms[*spos]->isunk;
435 if (mod->isunk)
436 *status |= DIS_STATUS_UNK_OPERAND;
437 ADDARRAY(mods->mods, mod);
438 (*spos)++;
439 } else {
440 struct easm_operand *op = calloc (sizeof *op, 1);
441 op->mods = mods;
442 mods = calloc (sizeof *mods, 1);
443 ADDARRAY(op->exprs, dis_parse_expr(ctx, status, spos));
444 ADDARRAY(res->operands, op);
447 res->mods = mods;
448 return res;
451 static struct easm_subinsn *dis_parse_subinsn(struct disctx *ctx, enum dis_status *status, int *spos) {
452 struct easm_subinsn *res = calloc(sizeof *res, 1);
453 while (ctx->atoms[*spos]->type != LITEM_NAME)
454 ADDARRAY(res->prefs, dis_parse_expr(ctx, status, spos));
455 res->sinsn = dis_parse_sinsn(ctx, status, spos);
456 return res;
459 static struct easm_insn *dis_parse_insn(struct disctx *ctx, enum dis_status *status) {
460 int spos = 0;
461 struct easm_insn *res = calloc(sizeof *res, 1);
462 ADDARRAY(res->subinsns, dis_parse_subinsn(ctx, status, &spos));
463 if (spos != ctx->atomsnum)
464 abort();
465 return res;
468 struct decoctx {
469 const struct disisa *isa;
470 struct varinfo *varinfo;
471 uint8_t *code;
472 int *marks;
473 const char **names;
474 uint32_t codebase;
475 uint32_t codesz;
476 struct label *labels;
477 int labelsnum;
478 int labelsmax;
481 struct dis_res *do_dis(struct decoctx *deco, uint32_t cur) {
482 struct disctx c = { 0 };
483 struct disctx *ctx = &c;
484 struct dis_res *res = calloc(sizeof *res, 1);
485 int i;
486 int stride = ed_getcstride(deco->isa, deco->varinfo);
487 for (i = 0; i < MAXOPLEN*8 && cur + i/stride < deco->codesz; i++) {
488 res->a[i/8] |= (ull)deco->code[cur*stride + i] << (i&7)*8;
490 ctx->isa = deco->isa;
491 ctx->varinfo = deco->varinfo;
492 if (deco->isa->tsched && (cur % deco->isa->schedpos) == 0)
493 atomtab_d (ctx, res->a, res->m, deco->isa->tsched);
494 else
495 atomtab_d (ctx, res->a, res->m, deco->isa->troot);
496 res->oplen = ctx->oplen;
497 if (res->oplen + cur > deco->codesz)
498 res->status |= DIS_STATUS_EOF;
499 if (res->oplen == 0) {
500 res->status |= DIS_STATUS_UNK_FORM;
501 res->oplen = ctx->isa->opunit;
503 res->endmark = ctx->endmark;
504 /* XXX unused status */
505 res->insn = dis_parse_insn(ctx, &res->status);
507 for (i = 0; i < ctx->atomsnum; ++i)
508 free(ctx->atoms[i]);
509 free(ctx->atoms);
511 return res;
514 static void mark(struct decoctx *ctx, uint32_t ptr, int m) {
515 if (ptr < ctx->codebase || ptr >= ctx->codebase + ctx->codesz)
516 return;
517 ctx->marks[ptr - ctx->codebase] |= m;
520 static int is_nr_mark(struct decoctx *ctx, uint32_t ptr) {
521 if (ptr < ctx->codebase || ptr >= ctx->codebase + ctx->codesz)
522 return 0;
523 return ctx->marks[ptr - ctx->codebase] & 0x40;
526 char *deco_label(struct decoctx *ctx, uint64_t val) {
527 int i;
528 for (i = 0; i < ctx->labelsnum; i++)
529 if (ctx->labels[i].val == val && ctx->labels[i].name)
530 return strdup(ctx->labels[i].name);
531 return 0;
534 static void dis_pp_sinsn(struct decoctx *deco, struct dis_res *dres, struct easm_sinsn *sinsn, uint64_t pos);
536 static void dis_pp_expr(struct decoctx *deco, struct dis_res *dres, struct easm_expr *expr, uint64_t pos) {
537 if (expr->e1)
538 dis_pp_expr(deco, dres, expr->e1, pos);
539 if (expr->e2)
540 dis_pp_expr(deco, dres, expr->e2, pos);
541 if (expr->sinsn)
542 dis_pp_sinsn(deco, dres, expr->sinsn, pos);
543 easm_substpos_expr(expr, pos);
544 if (easm_cfold_expr(expr)) {
545 if (expr->special == EASM_SPEC_CTARG) {
546 mark(deco, expr->num, 2);
547 expr->alabel = deco_label(deco, expr->num);
548 if (is_nr_mark(deco, expr->num))
549 dres->endmark = 1;
550 } else if (expr->special == EASM_SPEC_BTARG) {
551 mark(deco, expr->num, 1);
552 expr->alabel = deco_label(deco, expr->num);
554 if (expr->num & 1ull << 63 && !expr->special) {
555 expr->type = EASM_EXPR_NEG;
556 expr->e1 = easm_expr_num(EASM_EXPR_NUM, -expr->num);
557 expr->num = 0;
560 if (expr->type == EASM_EXPR_ADD && expr->e1->type == EASM_EXPR_NUM && expr->e1->num == 0) {
561 struct easm_expr *oe2 = expr->e2;
562 free(expr->e1);
563 *expr = *oe2;
564 free(oe2);
566 if ((expr->type == EASM_EXPR_ADD || expr->type == EASM_EXPR_SUB) && expr->e2->type == EASM_EXPR_NUM && expr->e2->num == 0) {
567 struct easm_expr *oe1 = expr->e1;
568 free(expr->e2);
569 *expr = *oe1;
570 free(oe1);
572 if (expr->type == EASM_EXPR_ADD && expr->e2->type == EASM_EXPR_NUM && expr->e2->num & 1ull << 63) {
573 expr->e2->num = -expr->e2->num;
574 expr->type = EASM_EXPR_SUB;
576 if (expr->type == EASM_EXPR_MEM && expr->special == EASM_SPEC_LITERAL) {
577 if (expr->e1->type != EASM_EXPR_NUM) {
578 expr->special = EASM_SPEC_NONE;
579 } else {
580 ull ptr = expr->e1->num;
581 mark(deco, ptr, 0x10);
582 if (ptr < deco->codebase || ptr > deco->codebase + deco->codesz) {
583 expr->special = EASM_SPEC_NONE;
584 } else {
585 if (ed_getcbsz(deco->isa, deco->varinfo) != 8)
586 abort();
587 uint32_t num = 0;
588 int j;
589 for (j = 0; j < 4; j++)
590 num |= deco->code[ptr - deco->codebase + j] << j*8;
591 expr->alit = num;
597 static void dis_pp_sinsn(struct decoctx *deco, struct dis_res *dres, struct easm_sinsn *sinsn, uint64_t pos) {
598 int i, j;
599 for (i = 0; i < sinsn->operandsnum; i++)
600 for (j = 0; j < sinsn->operands[i]->exprsnum; j++)
601 dis_pp_expr(deco, dres, sinsn->operands[i]->exprs[j], pos);
604 static void dis_pp_subinsn(struct decoctx *deco, struct dis_res *dres, struct easm_subinsn *subinsn, uint64_t pos) {
605 int i;
606 for (i = 0; i < subinsn->prefsnum; i++)
607 dis_pp_expr(deco, dres, subinsn->prefs[i], pos);
608 dis_pp_sinsn(deco, dres, subinsn->sinsn, pos);
611 static void dis_pp_insn(struct decoctx *deco, struct dis_res *dres, struct easm_insn *insn, uint64_t pos) {
612 int i;
613 for (i = 0; i < insn->subinsnsnum; i++)
614 dis_pp_subinsn(deco, dres, insn->subinsns[i], pos);
617 void dis_dopp(struct decoctx *deco, struct dis_res *dres, uint64_t pos) {
618 dis_pp_insn(deco, dres, dres->insn, pos);
622 * Disassembler driver
624 * You pass a block of memory to this function, disassembly goes out to given
625 * FILE*.
628 void envydis (const struct disisa *isa, FILE *out, uint8_t *code, uint32_t start, int num, struct varinfo *varinfo, int quiet, struct label *labels, int labelsnum, const struct envy_colors *cols)
630 struct decoctx c = { 0 };
631 struct decoctx *ctx = &c;
632 int cur = 0, i, j;
633 ctx->code = code;
634 ctx->codesz = num;
635 ctx->marks = calloc(num, sizeof *ctx->marks);
636 ctx->names = calloc(num, sizeof *ctx->names);
637 ctx->codebase = start;
638 ctx->varinfo = varinfo;
639 ctx->isa = isa;
640 ctx->labels = labels;
641 ctx->labelsnum = labelsnum;
642 int stride = ed_getcstride(ctx->isa, ctx->varinfo);
643 int cbsz = ed_getcbsz(ctx->isa, ctx->varinfo);
644 if (labels) {
645 for (i = 0; i < labelsnum; i++) {
646 mark(ctx, labels[i].val, labels[i].type);
647 if (labels[i].val >= ctx->codebase && labels[i].val < ctx->codebase + ctx->codesz) {
648 if (labels[i].name)
649 ctx->names[labels[i].val - ctx->codebase] = labels[i].name;
651 if (labels[i].size) {
652 for (j = 0; j < labels[i].size; j+=4)
653 mark(ctx, labels[i].val + j, labels[i].type);
656 int done;
657 do {
658 done = 1;
659 cur = 0;
660 int active = 0;
661 while (cur < num) {
662 if (!active && (ctx->marks[cur] & 3) && !(ctx->marks[cur] & 8)) {
663 done = 0;
664 active = 1;
665 ctx->marks[cur] |= 8;
667 if (active) {
668 struct dis_res *dres = do_dis(ctx, cur);
669 dis_dopp(ctx, dres, cur + start);
670 if (dres->oplen && !dres->endmark && !(ctx->marks[cur] & 4))
671 cur += dres->oplen;
672 else
673 active = 0;
674 dis_del_res(dres);
675 } else {
676 cur++;
679 } while (!done);
680 } else {
681 while (cur < num) {
682 struct dis_res *dres = do_dis(ctx, cur);
683 dis_dopp(ctx, dres, cur + start);
684 if (dres->oplen)
685 cur += dres->oplen;
686 else
687 cur++;
688 dis_del_res(dres);
691 cur = 0;
692 int active = 0;
693 int skip = 0, nonzero = 0;
694 while (cur < num) {
695 int mark = ctx->marks[cur];
696 if (ctx->names[cur]) {
697 if (skip) {
698 if (nonzero)
699 fprintf(out, "%s[%x bytes skipped]\n", cols->err, skip);
700 else
701 fprintf(out, "%s[%x zero bytes skipped]\n", cols->reset, skip);
702 skip = 0;
703 nonzero = 0;
705 if (mark & 0x1b0)
706 fprintf (out, "%s%s:\n", cols->reset, ctx->names[cur]);
707 else if (mark & 2)
708 fprintf (out, "\n%s%s:\n", cols->ctarg, ctx->names[cur]);
709 else if (mark & 1)
710 fprintf (out, "%s%s:\n", cols->btarg, ctx->names[cur]);
711 else
712 fprintf (out, "%s%s:\n", cols->reset, ctx->names[cur]);
714 if (mark & 0x1b0 && !active) {
715 if (skip) {
716 if (nonzero)
717 fprintf(out, "%s[%x bytes skipped]\n", cols->err, skip);
718 else
719 fprintf(out, "%s[%x zero bytes skipped]\n", cols->reset, skip);
720 skip = 0;
721 nonzero = 0;
723 if (cbsz != 8)
724 abort();
725 fprintf (out, "%s%08x:%s", cols->mem, cur + start, cols->reset);
726 if (mark & 0x80) {
727 uint8_t val = code[cur];
728 fprintf (out, " %s%02x\n", cols->num, val);
729 cur += 1;
730 } else if (mark & 0x100) {
731 uint16_t val = 0;
732 for (i = 0; i < 2 && cur + i < num; i++) {
733 val |= code[cur + i] << i*8;
735 fprintf (out, " %s%04x\n", cols->num, val);
736 cur += 2;
737 } else if (mark & 0x10) {
738 uint32_t val = 0;
739 for (i = 0; i < 4 && cur + i < num; i++) {
740 val |= code[cur + i] << i*8;
742 fprintf (out, " %s%08x\n", cols->num, val);
743 cur += 4;
744 } else {
745 fprintf (out, " %s\"", cols->num);
746 while (code[cur]) {
747 switch (code[cur]) {
748 case '\n':
749 fprintf (out, "\\n");
750 break;
751 case '\\':
752 fprintf (out, "\\\\");
753 break;
754 case '\"':
755 fprintf (out, "\\\"");
756 break;
757 default:
758 fprintf (out, "%c", code[cur]);
759 break;
761 cur++;
763 cur++;
764 fprintf (out, "\"\n");
766 continue;
768 if (!active && mark & 7)
769 active = 1;
770 if (!active && labels) {
771 for (i = 0; i < stride; i++)
772 if (code[cur*stride+i])
773 nonzero = 1;
774 cur++;
775 skip++;
776 continue;
778 if (skip) {
779 if (nonzero)
780 fprintf(out, "%s[%x bytes skipped]\n", cols->err, skip);
781 else
782 fprintf(out, "%s[%x zero bytes skipped]\n", cols->reset, skip);
783 skip = 0;
784 nonzero = 0;
786 struct dis_res *dres = do_dis(ctx, cur);
787 dis_dopp(ctx, dres, cur + start);
789 if (dres->endmark || mark & 4)
790 active = 0;
792 if (mark & 2 && !ctx->names[cur])
793 fprintf (out, "\n");
794 switch (mark & 3) {
795 case 0:
796 if (!quiet)
797 fprintf (out, "%s%08x:%s", cols->reset, cur + start, cols->reset);
798 break;
799 case 1:
800 fprintf (out, "%s%08x:%s", cols->btarg, cur + start, cols->reset);
801 break;
802 case 2:
803 fprintf (out, "%s%08x:%s", cols->ctarg, cur + start, cols->reset);
804 break;
805 case 3:
806 fprintf (out, "%s%08x:%s", cols->bctarg, cur + start, cols->reset);
807 break;
810 if (!quiet) {
811 for (i = 0; i < isa->maxoplen; i += isa->opunit) {
812 fprintf (out, " ");
813 for (j = isa->opunit*stride - 1; j >= 0; j--)
814 if (i+j/stride && i+j/stride >= dres->oplen) {
815 fprintf (out, " ");
816 } else if (cur+i+j/stride >= num) {
817 fprintf (out, "%s??", cols->err);
818 } else {
819 fprintf (out, "%s%02x", cols->reset, code[(cur + i)*stride + j]);
822 fprintf (out, " ");
824 if (mark & 2)
825 fprintf (out, "%sC", cols->ctarg);
826 else
827 fprintf (out, " ");
828 if (mark & 1)
829 fprintf (out, "%sB", cols->btarg);
830 else
831 fprintf (out, " ");
832 fprintf(out, " ");
833 } else if (quiet == 1) {
834 if (mark)
835 fprintf (out, "\n");
838 easm_print_insn(out, cols, dres->insn);
840 if (dres->status & DIS_STATUS_UNK_FORM) {
841 fprintf (out, " %s[unknown op length]%s", cols->err, cols->reset);
842 } else {
843 int fl = 0;
844 for (i = dres->oplen; i < MAXOPLEN * 8; i++)
845 dres->a[i/8] &= ~(0xffull << (i & 7) * 8);
846 for (i = 0; i < MAXOPLEN; i++) {
847 dres->a[i] &= ~dres->m[i];
848 if (dres->a[i])
849 fl = 1;
851 if (fl) {
852 fprintf (out, " %s[unknown:", cols->err);
853 for (i = 0; i < dres->oplen || i == 0; i += isa->opunit) {
854 fprintf (out, " ");
855 for (j = isa->opunit*stride - 1; j >= 0; j--)
856 if (cur+i+j >= num)
857 fprintf (out, "??");
858 else
859 fprintf (out, "%02llx", (dres->a[(i+j)/8] >> ((i + j)&7) * 8) & 0xff);
861 fprintf (out, "]");
864 if (dres->status & DIS_STATUS_EOF) {
865 fprintf (out, " %s[incomplete]%s", cols->err, cols->reset);
867 if (dres->status & DIS_STATUS_UNK_INSN) {
868 fprintf (out, " %s[unknown instruction]%s", cols->err, cols->reset);
870 if (dres->status & DIS_STATUS_UNK_OPERAND) {
871 fprintf (out, " %s[unknown operand]%s", cols->err, cols->reset);
873 fprintf (out, "%s\n", cols->reset);
874 cur += dres->oplen;
876 dis_del_res(dres);
878 free(ctx->marks);
879 free(ctx->names);