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