📄 dis.c
字号:
/* * Author: Christopher G. Phillips * Copyright (C) 1994 All Rights Reserved * * NOTICE * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted * provided that the above copyright notice appear in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * The author makes no representations about the suitability of this * software for any purpose. This software is provided ``as is'' * without express or implied warranty. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "dis.h"#define ISASCII(c) (0x20 <= (c) && (c) <= 0x7e)#ifdef DEBUG#define INITIAL 0x01#define DELETIONS 0x02#define TRY 0x04#define LASTTRY 0x08#define MAKEGOOD 0x10#define OVERLAPS 0x20#define LABELS 0x40int debug = 0;#endiflong curoffset; /* current offset into file */short flags; /* flags for current instruction */m68kaddr required[3]; /* instructions that must be valid for current instruction to also be valid */int pcrelative = 0; /* used to signal that PC-relative addresses referenced by JMP and JSR instructions should be stored in ``required'' */extern char instbuf[]; /* used to store the nibbles of an instruction in hexadecimal */extern size_t leninstbuf; /* current length of string in instbuf */struct inst *insts; /* instruction database */m68kaddr maxoffset; /* last offset that may hold an instruction *//* * These macros are used for convenience. They do the following: * * NREQD(o) returns the number of instructions instruction ``o'' depends on * JUMP(o) returns whether instruction ``o'' changes PC unconditionally * (modulo ``jfile'' instructions) * FETCH(o,s) returns whether instruction ``o'' is valid and has size ``s'' * (for ``s'' positive) * DELETE(o) renders instruction ``o'' invalid * SETLABEL(o) marks instruction ``o'' as requiring a label in the output */#define NREQD(o) (insts[o].flags & 3)#define JUMP(o) (insts[o].flags & (ISBRA | ISRTS | ISJMP | ISJSR))#define FETCH(o,s) (/* (o) >= 0 && */ (o) <= maxoffset && \ ((s) == -1 && insts[o].size \ || insts[o].size == (s)))#define DELETE(o) do { \ free(insts[o].required); \ insts[o].required = NULL; \ insts[o].size = 0; \ insts[o].flags = 0; \ } while (0);#define SETLABEL(o) if ((o) >= initialpc && (o) <= initialpc + maxoffset) \ insts[(o) - initialpc].flags |= ISLABELstatic short longestinstsize; /* max possible instruction length */static long gfsize = 0; /* file size */static m68kaddr *notinsts = NULL; /* array of values in ``nfile'' */static size_t nnotinsts = 0;static m68kaddr *breaks = NULL; /* array of values in ``bfile'' */static size_t nbreaks = 0;#ifndef NOBADstatic m68kaddr *bad; /* addresses that cause instructions to be deleted */static m68kaddr *good; /* addresses that cause instructions to be accepted in the final output */#endif/* * Free dynamically allocated memory * and longjmp back to process the next object file. */static voidjumpfree(void){#ifndef NOBAD m68kaddr offset; for (offset = 0; offset <= maxoffset; offset += (odd ? 1 : WORDSIZE)) { if (dobad && insts[offset].size == 0) fprintf(stderr,"%s: Instruction %lx: deleted because of %lx\n", sfile, (long)(offset + initialpc), (long)bad[offset]); if (insts[offset].flags & ISGOOD && bad[offset]) fprintf(stderr,"%s: Instruction %lx: assumed good because of %lx, deleted because of %lx\n", sfile, (long)(offset + initialpc), (long)good[offset], (long)bad[offset]); } free(bad); bad = NULL; free(good); good = NULL;#endif while (gfsize--) free(insts[gfsize].required); free(insts); insts = NULL; gfsize = 0; longjmp(jmp, 1);}/* * Search ``p'' for a string of at least ``minlen'' consecutive * printable characters. Return the index of the start of the string (or -1). */static intfindstring(size_t stored, const unsigned char *p){ int i; int inarow; for (inarow = i = 0; i < stored; i++, p++) if (use_isprint && isprint(*p) || !use_isprint && ISASCII(*p)) { if (++inarow >= minlen) return i - inarow + 1; } else inarow = 0; return -1;}/* * ``p'' contains the nibbles of a floating-point constant in hexadecimal. * These nibbles are converted into longword values and passed to ``fpoint'' * which formats the floating-point value in ``s'' (in printable form). */static intsfpoint(int type, const unsigned char *p, char *s){ u32bit_t longwords[3]; size_t nlongwords; size_t i, j; switch (type) { case SINGLE: nlongwords = 1; break; case DOUBLE: nlongwords = 2; break; case EXTENDED: case PACKED: nlongwords = 3; break; } /* * Convert string to longs. */ for (i = 0; i < nlongwords; i++) { longwords[i] = 0; for (j = 0; j < 2 * WORDSIZE; j++) longwords[i] += (*p++) << (CHAR_BIT * (2 * WORDSIZE - 1 - j)); } return fpoint(longwords, type, s);}/* * Output constants. Return how many floating-point constants were output. * * todo number of input bytes to output. * p nibbles of the constant(s) in hexadecimal. * floattype floating-point type expected (or 0). * numforce specifies how many floating-point constants should be output * regardless of value if ``floattype'' is nonzero, else specifies * that output must be forced if nonzero. * * Returns the number of bytes output. */static size_tdcflush(size_t todo, const unsigned char *p, int floattype, int numforce){ char format[BUFSIZ]; int i; m68kaddr value; size_t n; size_t j; size_t length; int lflags; int first = 1; int dofp; size_t total = todo; while (todo) { lflags = ops2f(1); if ((length = fsizeof(floattype)) == 0) floattype = 0; /* * Determine if a floating-point constant should be output. * After forced constants are output, we stay with the * same type until we get NaN or Denormalized. */ dofp = 0; if (floattype && length <= todo) { if (sfpoint(floattype, p, format) != -1) dofp = 1; } if (floattype && --numforce >= 0 || dofp) { dofp = 1; lflags |= size2f(floattype); } else if (floattype) return total - todo; /* * For integral constants, we do 2 words at a time. * If the address is odd, we do the first byte by itself. */ if (!dofp) { length = 2 * WORDSIZE; if (todo < length) { if (numforce) length = todo; else return total - todo; } if (first && (ppc & 1) && length != todo) length = 1; if ((length % WORDSIZE) == 0) { lflags |= size2f(WORD); for (n = 0, i = 0; i < length / 2; i++) { for (value = 0, j = 0; j < WORDSIZE; j++) value += p[i * WORDSIZE + j] << (CHAR_BIT * (WORDSIZE - 1 - j)); value = signextend(value, 16); if (i) n += sprintf(format + n, ","); n += sprintf(format + n, "#%d", value); } } else { lflags |= size2f(BYTE); for (n = 0, i = 0; i < length; i++) { if (i) n += sprintf(format + n, ","); n += sprintf(format + n, "#%u", p[i]); } } } leninstbuf = 0; for (i = 0; i < length; i++) leninstbuf += sprintf(instbuf + leninstbuf, "%02x", p[i]); pc += length; instprint(lflags, "DC", format); todo -= length; p += length; first = 0; } return total - todo;}/* * Output a string. * Return number of characters output. */static size_tascflush(size_t stored, const unsigned char *p, int force){ char format[BUFSIZ]; size_t length; size_t i; size_t n; size_t left; size_t nbytes; for (length = 0; length < stored; length++) if (use_isprint && !isprint(p[length]) || !use_isprint && !ISASCII(p[length])) break; if (length == stored && !force) return 0; format[0] = '\''; left = length; while (left) { n = 1; leninstbuf = 0; nbytes = (left > slenprint) ? slenprint : left; for (i = length - left; i < length - left + nbytes; i++) { leninstbuf += sprintf(instbuf + leninstbuf, "%02x", p[i]); n += sprintf(format + n, "%c", p[i]); /* * Double single quotes in strings. */ if (p[i] == '\'') format[n++] = '\''; } format[n++] = '\''; format[n++] = '\0'; pc += nbytes; instprint(ops2f(1) | size2f(BYTE), "DC", format); left -= nbytes; } return length;}/* * Convert a floating-point-label type to a floating-point type. */static intfl2ftype(int lflags){ if (lflags & ISLABEL) { if (lflags & L_ISSINGLE) return SINGLE; if (lflags & L_ISDOUBLE) return DOUBLE; if (lflags & L_ISEXTENDED) return EXTENDED; if (lflags & L_ISPACKED) return PACKED; } return 0;}/* * Output the ``stored'' input bytes contained in ``consts''. * If flags specifies a floating-point type, output floating-point * constants of that type as long as the input looks like them. * Output strings as appropriate. Otherwise, output integral constants. * Return number of input bytes *not* output. */static size_tflush(size_t stored, const unsigned char *consts, int lflags, int force){ size_t length; int spos = -2; int labelfptype = fl2ftype(lflags); int labelfpsize = fsizeof(labelfptype); int first = 1; while (stored) { spos = findstring(stored, consts); if (first && labelfpsize && stored >= labelfpsize) { if (spos == -1) length = stored / labelfpsize * labelfpsize; else if (spos > labelfpsize) length = spos / labelfpsize * labelfpsize; else length = labelfpsize; /* * Force a floating-point constant. */ length = dcflush(length, consts, labelfptype, 1); stored -= length; consts += length; first = 0; continue; } if (spos) { int lforce = 1; /* * Output integral constant(s). */ if (spos < 0) { if (force) length = stored; else { if (stored < minlen) return stored; length = stored - minlen + 1; lforce = 0; } } else length = spos; if (length > 0) { if ((length = dcflush(length, consts, 0, lforce)) == 0) return stored; stored -= length; consts += length; } else return stored; } if (spos >= 0) { /* * Output string. */ if ((length = ascflush(stored, consts, force)) == 0) return stored; stored -= length; consts += length; } first = 0; } return 0;}/* * Read a word (and extension words as necessary) from the input file * and determine if it is a possible instruction. * * ``valid'' is set to signal this. */static intvalidinst(void){ m68kword inst; valid = 0; if (nextword(&inst) == 0) { switch (inst >> 12) { case 0: bit_movep_immediate(inst); break; case 1: movebyte(inst); break; case 2: movelong(inst); break; case 3: moveword(inst); break; case 4: misc(inst); break; case 5: addq_subq_scc_dbcc_trapcc(inst); break; case 6: valid = bcc_bsr(inst); break; case 7: moveq(inst); break; case 8: or_div_sbcd(inst); break; case 9: sub_subx(inst); break; case 10: aline(inst); break; case 11: cmp_eor(inst); break; case 12: and_mul_abcd_exg(inst); break; case 13: add_addx(inst); break; case 14: shift_rotate_bitfield(inst); break; case 15: coprocessor(inst); if (!valid) fline(inst); break; } } return valid;}/* * Now that we know where the constants are, make another pass * to determine which of them are referenced using the PC-relative * addressing mode. */static voiddcpass(void){ m68kaddr offset; pass = DCLABELSPASS; if (fseek(infp, 0, SEEK_SET) == -1) { perror("fseek"); jumpfree(); } for (curoffset = offset = 0; offset <= maxoffset; ) if (insts[offset].size) { if (curoffset != offset && fseek(infp, curoffset = offset, SEEK_SET) == -1) { perror("fseek"); jumpfree(); } flags = 0; pc = ppc = offset + initialpc; leninstbuf = 0; validinst(); offset += insts[offset].size; } else if (odd) offset++; else offset += WORDSIZE;}/* * Make a pass over the input, outputting things as we currently see them. */static voidprintall(void){ m68kaddr offset; unsigned char consts[BUFSIZ]; size_t stored = 0; if (fseek(infp, 0, SEEK_SET) == -1) { perror("fseek"); jumpfree(); } pc = ppc = initialpc; leninstbuf = 0; pass = DEBUGPASS; for (curoffset = offset = 0; offset < gfsize /* = maxoffset */; offset += (odd ? 1 : WORDSIZE)) { /* * Determine if there might be a valid instruction * which has the bytes at ``offset'' as operands. */ if (insts[offset].size == 0) { int i = 0; size_t size; for (size = odd ? 1 : WORDSIZE; size <= longestinstsize && size <= offset; size += (odd ? 1 : WORDSIZE)) if (size < insts[offset - size].size) { i = 1; break; } if (i) continue; } if (curoffset != offset && fseek(infp, curoffset = offset, SEEK_SET) == -1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -