1 /* $NetBSD: db_disasm.c,v 1.9 1996/10/13 03:35:38 christos Exp $ */ 2 /* 3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Ludd by 7 * Bertram Barth. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed at Ludd, University of 20 * Lule}, Sweden and its contributors. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/reboot.h> 40 41 #include <machine/db_machdep.h> 42 #include <ddb/db_sym.h> 43 #include <ddb/db_variables.h> 44 45 #include <vax/vax/db_disasm.h> 46 47 #ifdef VMS_MODE 48 #define DEFERRED '@' 49 #define LITERAL '#' 50 #else 51 #define DEFERRED '*' 52 #define LITERAL '$' 53 #endif 54 /* 55 * disassembling vax instructions works as follows: 56 * 57 * 1. get first byte as opcode (check for two-byte opcodes!) 58 * 2. lookup in op-table for mnemonic and operand-list 59 * 2.a store the mnemonic 60 * 3. for each operand in list: get the size/type 61 * 3.a evaluate addressing mode for this operand 62 * 3.b store each operand(s) 63 * 4. db_printf the opcode and the (value of the) operands 64 * 5. return the start of the next instruction 65 * 66 * - if jump/branch calculate (and display) the target-address 67 */ 68 69 /* 70 #define BROKEN_DB_REGS 71 */ 72 #ifdef BROKEN_DB_REGS 73 struct { /* Due to order and contents of db_regs[], we can't */ 74 char *name; /* use this array to extract register-names. */ 75 void *valuep; /* eg. "psl" vs "pc", "pc" vs "sp" */ 76 } my_db_regs[16] = { 77 { "r0", NULL }, 78 { "r1", NULL }, 79 { "r2", NULL }, 80 { "r3", NULL }, 81 { "r4", NULL }, 82 { "r5", NULL }, 83 { "r6", NULL }, 84 { "r7", NULL }, 85 { "r8", NULL }, 86 { "r9", NULL }, 87 { "r10", NULL }, 88 { "r11", NULL }, 89 { "ap", NULL }, /* aka "r12" */ 90 { "fp", NULL }, /* aka "r13" */ 91 { "sp", NULL }, /* aka "r14" */ 92 { "pc", NULL }, /* aka "r15" */ 93 }; 94 #else 95 #define my_db_regs db_regs 96 #endif 97 98 typedef struct { 99 char dasm[256]; /* disassebled instruction as text */ 100 char *curp; /* pointer into result */ 101 char *ppc; /* pseudo PC */ 102 int opc; /* op-code */ 103 char *argp; /* pointer into argument-list */ 104 int itype; /* instruction-type, eg. branch, call, unspec */ 105 int atype; /* argument-type, eg. byte, long, address */ 106 int off; /* offset specified by last argument */ 107 int addr; /* address specified by last argument */ 108 } inst_buffer; 109 110 #define ITYPE_INVALID -1 111 #define ITYPE_UNSPEC 0 112 #define ITYPE_BRANCH 1 113 #define ITYPE_CALL 2 114 115 int get_byte __P((inst_buffer * ib)); 116 int get_word __P((inst_buffer * ib)); 117 int get_long __P((inst_buffer * ib)); 118 119 int get_opcode __P((inst_buffer * ib)); 120 int get_operands __P((inst_buffer * ib)); 121 int get_operand __P((inst_buffer * ib, int size)); 122 123 void add_char __P((inst_buffer * ib, int c)); 124 void add_str __P((inst_buffer * ib, char *s)); 125 void add_int __P((inst_buffer * ib, int i)); 126 void add_xint __P((inst_buffer * ib, int i)); 127 void add_sym __P((inst_buffer * ib, int i)); 128 void add_off __P((inst_buffer * ib, int i)); 129 130 #define err_print printf 131 132 /* 133 * Disassemble instruction at 'loc'. 'altfmt' specifies an 134 * (optional) alternate format (altfmt for vax: don't assume 135 * that each external label is a procedure entry mask). 136 * Return address of start of next instruction. 137 * Since this function is used by 'examine' and by 'step' 138 * "next instruction" does NOT mean the next instruction to 139 * be executed but the 'linear' next instruction. 140 */ 141 db_addr_t 142 db_disasm(loc, altfmt) 143 db_addr_t loc; 144 boolean_t altfmt; 145 { 146 db_expr_t diff; 147 db_sym_t sym; 148 char *symname; 149 150 inst_buffer ib; 151 152 bzero(&ib, sizeof(ib)); 153 ib.ppc = (void *) loc; 154 ib.curp = ib.dasm; 155 156 if (!altfmt) { /* ignore potential entry masks in altfmt */ 157 diff = INT_MAX; 158 symname = NULL; 159 sym = db_search_symbol(loc, DB_STGY_PROC, &diff); 160 db_symbol_values(sym, &symname, 0); 161 162 if (symname && !diff) { /* symbol at loc */ 163 db_printf("function \"%s()\", entry-mask 0x%x\n\t\t", 164 symname, (unsigned short) get_word(&ib)); 165 ib.ppc += 2; 166 } 167 } 168 get_opcode(&ib); 169 get_operands(&ib); 170 db_printf("%s\n", ib.dasm); 171 172 return ((u_int) ib.ppc); 173 } 174 175 int 176 get_opcode(ib) 177 inst_buffer *ib; 178 { 179 ib->opc = get_byte(ib); 180 if (ib->opc >> 2 == 0x3F) { /* two byte op-code */ 181 ib->opc = ib->opc << 8; 182 ib->opc += get_byte(ib); 183 } 184 switch (ib->opc) { 185 case 0xFA: /* CALLG */ 186 case 0xFB: /* CALLS */ 187 case 0xFC: /* XFC */ 188 ib->itype = ITYPE_CALL; 189 break; 190 case 0x16: /* JSB */ 191 case 0x17: /* JMP */ 192 ib->itype = ITYPE_BRANCH; 193 break; 194 default: 195 ib->itype = ITYPE_UNSPEC; 196 } 197 if (ib->opc < 0 || ib->opc > 0xFF) { 198 add_str(ib, "invalid or two-byte opcode "); 199 add_xint(ib, ib->opc); 200 ib->itype = ITYPE_INVALID; 201 } else { 202 add_str(ib, vax_inst[ib->opc].mnemonic); 203 add_char(ib, '\t'); 204 } 205 return (ib->opc); 206 } 207 208 int 209 get_operands(ib) 210 inst_buffer *ib; 211 { 212 int aa = 0; /* absolute address mode ? */ 213 int size; 214 215 if (ib->opc < 0 || ib->opc > 0xFF) { 216 /* invalid or two-byte opcode */ 217 ib->argp = NULL; 218 return (-1); 219 } 220 ib->argp = vax_inst[ib->opc].argdesc; 221 222 while (*ib->argp) { 223 switch (*ib->argp) { 224 225 case 'b': /* branch displacement */ 226 switch (*(++ib->argp)) { 227 case 'b': 228 ib->off = (signed char) get_byte(ib); 229 break; 230 case 'w': 231 ib->off = (short) get_word(ib); 232 break; 233 case 'l': 234 ib->off = get_long(ib); 235 break; 236 default: 237 err_print("XXX eror\n"); 238 } 239 /* add_int(ib, ib->off); */ 240 ib->addr = (u_int) ib->ppc + ib->off; 241 add_off(ib, ib->addr); 242 break; 243 244 case 'a': /* absolute adressing mode */ 245 aa = 1; /* do not break here ! */ 246 247 default: 248 switch (*(++ib->argp)) { 249 case 'b': /* Byte */ 250 size = SIZE_BYTE; 251 break; 252 case 'w': /* Word */ 253 size = SIZE_WORD; 254 break; 255 case 'l': /* Long-Word */ 256 case 'f': /* F_Floating */ 257 size = SIZE_LONG; 258 break; 259 case 'q': /* Quad-Word */ 260 case 'd': /* D_Floating */ 261 case 'g': /* G_Floating */ 262 size = SIZE_QWORD; 263 break; 264 case 'o': /* Octa-Word */ 265 case 'h': /* H_Floating */ 266 size = SIZE_OWORD; 267 break; 268 default: 269 err_print("invalid op-type %X (%c) found.\n", 270 *ib->argp, *ib->argp); 271 size = 0; 272 } 273 if (aa) { 274 /* get the address */ 275 ib->addr = get_operand(ib, size); 276 add_sym(ib, ib->addr); 277 } else { 278 /* get the operand */ 279 ib->addr = get_operand(ib, size); 280 add_off(ib, ib->addr); 281 } 282 } 283 284 if (!*ib->argp || !*++ib->argp) 285 break; 286 if (*ib->argp++ == ',') { 287 add_char(ib, ','); 288 add_char(ib, ' '); 289 } else { 290 err_print("XXX error\n"); 291 add_char(ib, '\0'); 292 return (-1); 293 } 294 } 295 296 add_char(ib, '\0'); 297 return (0); 298 } 299 300 int 301 get_operand(ib, size) 302 inst_buffer *ib; 303 int size; 304 { 305 int c = get_byte(ib); 306 int mode = c >> 4; 307 int reg = c & 0x0F; 308 int lit = c & 0x3F; 309 int tmp = 0; 310 char buf[16]; 311 312 switch (mode) { 313 case 0: /* literal */ 314 case 1: /* literal */ 315 case 2: /* literal */ 316 case 3: /* literal */ 317 add_char(ib, LITERAL); 318 add_int(ib, lit); 319 tmp = lit; 320 break; 321 322 case 4: /* indexed */ 323 sprintf(buf, "[%s]", my_db_regs[reg].name); 324 get_operand(ib, 0); 325 add_str(ib, buf); 326 break; 327 328 case 5: /* register */ 329 add_str(ib, my_db_regs[reg].name); 330 break; 331 332 case 6: /* register deferred */ 333 add_char(ib, '('); 334 add_str(ib, my_db_regs[reg].name); 335 add_char(ib, ')'); 336 break; 337 338 case 7: /* autodecrement */ 339 add_char(ib, '-'); 340 add_char(ib, '('); 341 add_str(ib, my_db_regs[reg].name); 342 add_char(ib, ')'); 343 if (reg == 0x0F) { /* pc is not allowed in this mode */ 344 err_print("autodecrement not allowd for PC.\n"); 345 } 346 break; 347 348 case 9: /* autoincrement deferred */ 349 add_char(ib, DEFERRED); 350 if (reg == 0x0F) { /* pc: immediate deferred */ 351 /* 352 * addresses are always longwords! 353 */ 354 tmp = get_long(ib); 355 add_off(ib, tmp); 356 break; 357 } 358 /* fall through */ 359 case 8: /* autoincrement */ 360 if (reg == 0x0F) { /* pc: immediate ==> special syntax */ 361 switch (size) { 362 case SIZE_BYTE: 363 tmp = (signed char) get_byte(ib); 364 break; 365 case SIZE_WORD: 366 tmp = (signed short) get_word(ib); 367 break; 368 case SIZE_LONG: 369 tmp = get_long(ib); 370 break; 371 default: 372 err_print("illegal op-type %d\n", size); 373 tmp = -1; 374 } 375 if (mode == 8) 376 add_char(ib, LITERAL); 377 add_int(ib, tmp); 378 break; 379 } 380 add_char(ib, '('); 381 add_str(ib, my_db_regs[reg].name); 382 add_char(ib, ')'); 383 add_char(ib, '+'); 384 break; 385 386 case 11: /* byte displacement deferred/ relative deferred */ 387 add_char(ib, DEFERRED); 388 case 10: /* byte displacement / relative mode */ 389 tmp = (signed char) get_byte(ib); 390 if (reg == 0x0F) { 391 add_off(ib, (u_int) ib->ppc + tmp); 392 break; 393 } 394 /* add_str (ib, "b^"); */ 395 add_int(ib, tmp); 396 add_char(ib, '('); 397 add_str(ib, my_db_regs[reg].name); 398 add_char(ib, ')'); 399 break; 400 401 case 13: /* word displacement deferred */ 402 add_char(ib, DEFERRED); 403 case 12: /* word displacement */ 404 tmp = (signed short) get_word(ib); 405 if (reg == 0x0F) { 406 add_off(ib, (u_int) ib->ppc + tmp); 407 break; 408 } 409 /* add_str (ib, "w^"); */ 410 add_int(ib, tmp); 411 add_char(ib, '('); 412 add_str(ib, my_db_regs[reg].name); 413 add_char(ib, ')'); 414 break; 415 416 case 15: /* long displacement referred */ 417 add_char(ib, DEFERRED); 418 case 14: /* long displacement */ 419 tmp = get_long(ib); 420 if (reg == 0x0F) { 421 add_off(ib, (u_int) ib->ppc + tmp); 422 break; 423 } 424 /* add_str (ib, "l^"); */ 425 add_int(ib, tmp); 426 add_char(ib, '('); 427 add_str(ib, my_db_regs[reg].name); 428 add_char(ib, ')'); 429 break; 430 431 default: 432 err_print("can\'t evaluate operand (%02X).\n", lit); 433 break; 434 } 435 436 return (0); 437 } 438 439 int 440 get_byte(ib) 441 inst_buffer *ib; 442 { 443 return ((unsigned char) *(ib->ppc++)); 444 } 445 446 int 447 get_word(ib) 448 inst_buffer *ib; 449 { 450 int tmp; 451 char *p = (void *) &tmp; 452 *p++ = get_byte(ib); 453 *p++ = get_byte(ib); 454 return (tmp); 455 } 456 457 int 458 get_long(ib) 459 inst_buffer *ib; 460 { 461 int tmp; 462 char *p = (void *) &tmp; 463 *p++ = get_byte(ib); 464 *p++ = get_byte(ib); 465 *p++ = get_byte(ib); 466 *p++ = get_byte(ib); 467 return (tmp); 468 } 469 470 void 471 add_char(ib, c) 472 inst_buffer *ib; 473 int c; 474 { 475 *ib->curp++ = c; 476 } 477 478 void 479 add_str(ib, s) 480 inst_buffer *ib; 481 char *s; 482 { 483 while (*ib->curp++ = *s++); 484 *--ib->curp = '\0'; 485 } 486 487 void 488 add_int(ib, i) 489 inst_buffer *ib; 490 int i; 491 { 492 char buf[32]; 493 if (i < 100 && i > -100) 494 sprintf(buf, "%d", i); 495 else 496 sprintf(buf, "0x%x", i); 497 add_str(ib, buf); 498 } 499 500 void 501 add_xint(ib, val) 502 inst_buffer *ib; 503 int val; 504 { 505 char buf[32]; 506 sprintf(buf, "0x%x", val); 507 add_str(ib, buf); 508 } 509 510 void 511 add_sym(ib, loc) 512 inst_buffer *ib; 513 int loc; 514 { 515 db_expr_t diff; 516 db_sym_t sym; 517 char *symname; 518 519 if (! loc) 520 return; 521 522 diff = INT_MAX; 523 symname = NULL; 524 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 525 db_symbol_values(sym, &symname, 0); 526 527 if (symname && !diff) { 528 /* add_char(ib, '<'); */ 529 add_str(ib, symname); 530 /* add_char(ib, '>'); */ 531 } 532 else 533 add_xint(ib, loc); 534 } 535 536 void 537 add_off(ib, loc) 538 inst_buffer *ib; 539 int loc; 540 { 541 db_expr_t diff; 542 db_sym_t sym; 543 char *symname; 544 545 if (!loc) 546 return; 547 548 diff = INT_MAX; 549 symname = NULL; 550 sym = db_search_symbol(loc, DB_STGY_ANY, &diff); 551 db_symbol_values(sym, &symname, 0); 552 553 if (symname) { 554 /* add_char(ib, '<'); */ 555 add_str(ib, symname); 556 if (diff) { 557 add_char(ib, '+'); 558 add_xint(ib, diff); 559 } 560 /* add_char(ib, '>'); */ 561 } 562 else 563 add_xint(ib, loc); 564 } 565