dis.c (6025B) - raw
1 /* Disassembler for the CVM bytecode 2 3 Because of Forth's very dynamic nature, this disassembler can't hope to 4 disassemble a whole memory space. As soon as we hit a cell or a does, we can't 5 continue. However, this can be useful to disassemble small pieces of code such 6 as the ones compiled by the Forth backend of CC. 7 */ 8 #include <stdio.h> 9 10 11 #define ARGNONE 0 12 #define ARGBYTE 1 13 #define ARGINT 2 14 #define ARGFIVE 3 // byte + int 15 #define ARGOP 4 // byte + ?disp 16 #define ARGBINOP 5 // opidx + byte + ?disp 17 #define ARGOPN 6 // op + immediate 18 #define ARGERR 7 // can't continue, arg size unknown 19 #define OPHASDISP 0x08 20 21 #define BINOPCNT 0x10 22 static char* binops[BINOPCNT] = { 23 "+", "-", "*", "/", "%", "<<", ">>", "err", 24 "&", "|", "^", "err", "err", "err", "err", "err" 25 }; 26 27 struct op { 28 char *name; // NULL= no op 29 int arg; 30 }; 31 32 #define OPCNT 0x70 33 static struct op ops[OPCNT] = { 34 {"BR", ARGINT}, 35 {"CALL", ARGINT}, 36 {"RET", ARGNONE}, 37 {"BRWR", ARGNONE}, 38 {"BRA", ARGNONE}, 39 {"BRC", ARGFIVE}, 40 {"BRCDROP", ARGFIVE}, 41 {"YIELD", ARGNONE}, 42 43 {"PSADD", ARGINT}, 44 {"RSADD", ARGINT}, 45 {"WLIT", ARGINT}, 46 {"ALIT", ARGINT}, 47 {"WADDN", ARGINT}, 48 {"AADDN", ARGINT}, 49 {"W2A", ARGNONE}, 50 {"WSWAPA", ARGNONE}, 51 52 {"WFETCH", ARGOP}, 53 {NULL, ARGERR}, 54 {"WSWAP", ARGOP}, 55 {"MADDN", ARGOPN}, 56 {"WCMP", ARGOP}, 57 {"WIFETCH", ARGOP}, 58 {"WISTORE", ARGOP}, 59 {"WLEA", ARGOP}, 60 61 {"WFETCH16", ARGOP}, 62 {NULL, ARGERR}, 63 {"WSWAP16", ARGOP}, 64 {"MADDN16", ARGOPN}, 65 {"WCMP16", ARGOP}, 66 {"WIFETCH16", ARGOP}, 67 {"WISTORE16", ARGOP}, 68 {"WLEA", ARGOP}, 69 70 {"WFETCH8", ARGOP}, 71 {NULL, ARGERR}, 72 {"WSWAP8", ARGOP}, 73 {"MADDN8", ARGOPN}, 74 {"WCMP8", ARGOP}, 75 {"WIFETCH8", ARGOP}, 76 {"WISTORE8", ARGOP}, 77 {"WLEA", ARGOP}, 78 79 {NULL, ARGERR}, 80 {"BOOTRD", ARGNONE}, 81 {"STDOUT", ARGNONE}, 82 {"MAYBEKEY", ARGNONE}, 83 {NULL, ARGERR}, 84 {"MAKEMEM", ARGNONE}, 85 {"ADDDISP", ARGNONE}, 86 {NULL, ARGERR}, 87 88 {"MAYBEWORD", ARGNONE}, 89 {"WORD", ARGNONE}, 90 {"PARSE", ARGNONE}, 91 {"FIND", ARGNONE}, 92 {"WNF", ARGNONE}, 93 {"FINDMOD", ARGNONE}, 94 {NULL, ARGERR}, 95 {NULL, ARGERR}, 96 97 {"STACKCHK", ARGNONE}, 98 {"COMPWORD", ARGNONE}, 99 {"RUNWORD", ARGNONE}, 100 {"COMPILING", ARGNONE}, 101 {"STARTCOMP", ARGNONE}, 102 {"STOPCOMP", ARGNONE}, 103 {"RSADDWR", ARGNONE}, 104 {"COMPOP", ARGNONE}, 105 106 {"ALIGN4", ARGNONE}, 107 {"ENTRY", ARGNONE}, 108 {"CODE", ARGNONE}, 109 {"CODE16", ARGNONE}, 110 {"CODE8", ARGNONE}, 111 {"COMPBINOP", ARGNONE}, 112 {NULL, ARGERR}, 113 {NULL, ARGERR}, 114 115 {"WBINOP", ARGBINOP}, 116 {"WBINOP16", ARGBINOP}, 117 {"WBINOP8", ARGBINOP}, 118 {"DIVMOD", ARGNONE}, 119 {NULL, ARGERR}, 120 {"LT", ARGNONE}, 121 {"NEG", ARGNONE}, 122 {NULL, ARGERR}, 123 124 {"BYE", ARGNONE}, 125 {"BYEFAIL", ARGNONE}, 126 {"QUIT", ARGNONE}, 127 {"ABORT_", ARGNONE}, 128 {"DBG", ARGNONE}, 129 {"USLEEP", ARGNONE}, 130 {NULL, ARGERR}, 131 {NULL, ARGERR}, 132 133 {NULL, ARGERR}, 134 {NULL, ARGERR}, 135 {NULL, ARGERR}, 136 {NULL, ARGERR}, 137 {NULL, ARGERR}, 138 {"WCHECKZ", ARGNONE}, 139 {"STOREC", ARGBYTE}, 140 {"ACHECKZ", ARGNONE}, 141 142 {"FCHILD", ARGNONE}, 143 {"FOPEN", ARGNONE}, 144 {"FREADBUF", ARGNONE}, 145 {"FCLOSE", ARGNONE}, 146 {"FINFO", ARGNONE}, 147 {"FITER", ARGNONE}, 148 {NULL, ARGERR}, 149 {"FSEEK", ARGNONE}, 150 151 {"MOUNTDRV", ARGNONE}, 152 {"UNMOUNTDRV", ARGNONE}, 153 {"DRVRD", ARGNONE}, 154 {"DRVWR", ARGNONE}, 155 {NULL, ARGERR}, 156 {NULL, ARGERR}, 157 {NULL, ARGERR}, 158 {NULL, ARGERR}, 159 }; 160 161 /* Now this systen below is really fragile. Offsets will change often, and those 162 have to be maintained. But oh well... */ 163 struct call { 164 int addr; 165 char *name; 166 }; 167 168 #define CALLCNT 8 169 struct call calls[CALLCNT] = { 170 {0x2e8, "-"}, 171 {0x1760, "dup"}, 172 {0x18a4, "rot"}, 173 {0x18f8, "nip"}, 174 {0x1a94, "!"}, 175 {0x1b18, "@"}, 176 {0x1e54, "execute"}, 177 {0x1e94, "not"}, 178 }; 179 180 static int offset = 0; 181 182 int getint() { 183 int n = 0; 184 for (int i=0; i<4; i++) { 185 n |= getchar() << (i*8); 186 } 187 offset += 4; 188 return n; 189 } 190 191 void printhalop(int n) { 192 printf("\t"); 193 switch (n & 7) { 194 case 0: printf("W"); break; 195 case 1: printf("A"); break; 196 case 2: printf("PSP"); break; 197 case 3: printf("RSP"); break; 198 case 4: printf("m"); break; 199 default: printf("err"); 200 } 201 if (n & 0x10) printf("&"); 202 if (n & 0x20) printf(">A"); 203 if (n & 0x40) printf("<>"); 204 } 205 206 int printarg(int arg) { // returns 1 on success, 0 on error 207 int n; 208 switch (arg) { 209 case ARGNONE: break; 210 case ARGBYTE: 211 n = getchar(); 212 offset++; 213 printf("\t%x", n); 214 break; 215 case ARGINT: 216 n = getint(); 217 printf("\t%x", n); 218 break; 219 case ARGFIVE: 220 printarg(ARGBYTE); 221 printarg(ARGINT); 222 break; 223 case ARGOP: 224 n = getchar(); 225 offset++; 226 printhalop(n); 227 if (n&OPHASDISP) printarg(ARGINT); 228 break; 229 case ARGBINOP: 230 n = getchar(); 231 offset++; 232 printf("\t%s", binops[n]); 233 printarg(ARGOP); 234 break; 235 case ARGOPN: 236 printarg(ARGOP); 237 printarg(ARGINT); 238 break; 239 case ARGERR: 240 fprintf(stderr, "Can't parse this op's arg\n"); 241 return 0; 242 default: 243 fprintf(stderr, "Something's wrong\n"); 244 return 0; 245 } 246 return 1; 247 } 248 249 int printcall() { 250 int addr = getint(); 251 for (int i=0; i<CALLCNT; i++) { 252 if (calls[i].addr == addr) { 253 printf("\t%s", calls[i].name); 254 return 1; 255 } 256 } 257 printf("\t%x", addr); 258 return 1; 259 } 260 261 int main() { 262 int c = getchar(); 263 while (c != EOF) { 264 printf("%08x ", offset++); 265 if ((c >= OPCNT) || (ops[c].name == NULL)) { 266 fprintf(stderr, "Invalid opcode %x\n", c); 267 return 1; 268 } 269 fputs(ops[c].name, stdout); 270 if (c == 1) { // 1 == CALL 271 if (!printcall()) return 1; 272 } else { 273 if (!printarg(ops[c].arg)) return 1; 274 } 275 putchar('\n'); 276 c = getchar(); 277 } 278 }