|
|
1.1 ! root 1: /* ! 2: * db/i386/i386db1.c ! 3: * A debugger. ! 4: * i386-specific code. ! 5: * This file contains all the routines called by the machine-independent code ! 6: * except disassemble(), which is in i386db2.c. ! 7: */ ! 8: ! 9: #include <sys/ptrace.h> ! 10: #include <sys/sysi86.h> ! 11: #include <errno.h> ! 12: #include "i386db.h" ! 13: ! 14: /* ! 15: * Get the return pc and frame pointer to set a return breakpoint. ! 16: * Like traceback(), this knows some gory details about the calling sequence; ! 17: * see the comment there for elucidation. ! 18: * At a function entry point, ! 19: * %ebp is the caller's stack frame and *%esp contains the ra. ! 20: * Inside a function (after the frame save), ! 21: * *%ebp is the caller's stack frame and the ra is at a fixed offset from %ebp. ! 22: */ ! 23: int ! 24: bpt_setr(cmd) char *cmd; ! 25: { ! 26: register ADDR_T sp, myfp; ! 27: ADDR_T ra, fp; ! 28: unsigned char b; ! 29: ! 30: add = get_pc(); ! 31: fp = get_fp(); ! 32: sp = get_sp(); ! 33: dbprintf(("bpt_setr(%s) ip=%X bp=%X sp=%X\n", cmd, add, fp, sp)); ! 34: ! 35: /* Fetch the next opcode. */ ! 36: if (getb(ISEG, &b, sizeof(b)) == 0) ! 37: return 0; /* opcode fetch failed */ ! 38: ! 39: /* Find the return address and the caller's stack frame. */ ! 40: if ((IS_LOUT && b == PUSHESI) ! 41: || (!IS_LOUT && (b==ENTER || b==PUSHEBP))) ! 42: add = sp; /* sp points at ra, fp ok */ ! 43: else { ! 44: add = myfp = fp; /* fetch caller's fp */ ! 45: if (get_sized(DSEG, &fp) == 0) ! 46: return 0; ! 47: add = myfp + (IS_LOUT) ? 6 : 4; /* ra at known offset off fp */ ! 48: } ! 49: ! 50: /* Fetch the return address. */ ! 51: if (get_sized(DSEG, &ra) == 0) ! 52: return 0; /* ra fetch failed */ ! 53: dbprintf(("placing BRET breakpoint: ra=%X fp=%X cmd=%s\n", ra, fp, cmd)); ! 54: return bpt_set(BRET, ra, fp, cmd); /* set the return bpt */ ! 55: } ! 56: ! 57: /* ! 58: * See if the given instruction is a breakpoint. ! 59: */ ! 60: int ! 61: bpt_test(pc) ADDR_T pc; ! 62: { ! 63: unsigned char w; ! 64: ! 65: dbprintf(("bpt_test(%x)\n", pc)); ! 66: add = pc; ! 67: return getb(ISEG, &w, sizeof(w))!=0 && w==TRAP; ! 68: } ! 69: ! 70: /* ! 71: * Display registers. ! 72: * The 'flag' arg is R_GEN to get the general registers ! 73: * or R_ALL to get all the registers (including NDP). ! 74: */ ! 75: void ! 76: display_reg(flag) int flag; ! 77: { ! 78: register REGNAME *rp; ! 79: register ADDR_T val; ! 80: register char *name; ! 81: register int n; ! 82: ! 83: if (testint()) ! 84: return; ! 85: ! 86: if (get_regs(flag) == 0) ! 87: return; ! 88: ! 89: for (n = 0, rp = reg_name; rp < ®_name[NGREGS]; rp++) { ! 90: ! 91: if (testint()) ! 92: return; ! 93: ! 94: /* Print register name. */ ! 95: name = rp->r_name; ! 96: if (IS_LOUT) { ! 97: if (*name == 'e' && strlen(name) == 3) ! 98: ++name; ! 99: printx("%%%-2s=", name); ! 100: } else ! 101: printx("%%%-3s=", name); ! 102: ! 103: /* Print contents. */ ! 104: val = *(ADDR_T *)(((char *)&ureg) + rp->r_offset); ! 105: switch(rp->r_flag) { ! 106: case RF_1632: ! 107: if (!IS_LOUT) { ! 108: printx(ADDR_FMT, val); ! 109: break; ! 110: } ! 111: /* else fall through... */ ! 112: case RF_16: ! 113: printx(ADDR16_FMT, val&0xFFFF); ! 114: break; ! 115: default: ! 116: printr("<flag=%x>", rp->r_flag); ! 117: } ! 118: putchar(((++n % 4) == 0 || n == NGREGS) ? '\n' : '\t'); ! 119: } ! 120: ! 121: #ifndef NOFP ! 122: /* ! 123: * Dump the NDP state for :rN. ! 124: * Thanks to hal for this code, ! 125: * more detail than the average user needs... ! 126: */ ! 127: if (flag == R_ALL) { ! 128: register struct _fpstate *fstp; ! 129: register int i; ! 130: #if 0 ! 131: register int j; ! 132: #endif ! 133: int tagbits, tos; ! 134: unsigned char opfirst, opsecond; ! 135: unsigned int fcs, exp, sigzero; ! 136: double d; ! 137: ! 138: fstp = &ureg.ur_fpstate; ! 139: fcs = fstp->cssel; ! 140: tos = (fstp->sw >> 11) & 7; ! 141: #if 0 ! 142: printx("\nfstp=%08X\ttos=%d ", fstp, tos); ! 143: #endif ! 144: opfirst = 0xD8 | ((fcs >> 24) & 7); ! 145: opsecond = fcs >> 16; ! 146: #if 0 ! 147: printx("cw=%04X\tsw=%04X\ttag=%04X\n", ! 148: fstp->cw&0xFFFF, fstp->sw&0xFFFF, fstp->tag&0xFFFF); ! 149: printx("op=%02X\t%02X\tfcs=%04X\tfip=%08X\tfos=%04X\tfoo=%08X\n", ! 150: opfirst, opsecond, ! 151: fcs&0xFFFF, fstp->ipoff, fstp->datasel&0xFFFF, fstp->dataoff); ! 152: #endif ! 153: if (testint()) ! 154: return; ! 155: for (i = 0; i < 8; i++) { ! 156: tagbits = (fstp->tag >> (((tos + i) & 7) * 2)) & 3; ! 157: printx("%%st%d=", i); ! 158: #if 0 ! 159: printx("(%d) at %08X ", tagbits, fstp->_st + i); ! 160: #endif ! 161: switch(tagbits) { ! 162: case 0: /* Normal */ ! 163: if (get_fp_reg(&fstp->_st[i], &d) == 0) ! 164: printx("(none)"); /* no NDP */ ! 165: else ! 166: printx("%g", d); ! 167: #if 0 ! 168: for (j = 0; j < 4; j++) ! 169: printx("%04X ", fstp->_st[i].significand[j]); ! 170: printx(":%04X\n", fstp->_st[i].exponent); ! 171: #endif ! 172: break; ! 173: case 1: /* Zero */ ! 174: printx("0.0"); ! 175: break; ! 176: case 2: /* NaN, Infinity, Denormal */ ! 177: exp = fstp->_st[i].exponent; ! 178: sigzero = (fstp->_st[i].significand[0] == 0 ! 179: && fstp->_st[i].significand[1] == 0 ! 180: && fstp->_st[i].significand[2] == 0 ! 181: && fstp->_st[i].significand[3] == 0x8000); ! 182: putx((exp & 0x8000) ? '-' : '+'); ! 183: exp &= 0x7FFF; ! 184: if (exp == 0x7FFF) ! 185: printx(sigzero ? "Infinity" : "NaN"); ! 186: else if (exp == 0 && !sigzero) ! 187: printx("Denormal"); ! 188: else /* shouldn't happen */ ! 189: printx("Special: %08X %08X %08X %08X : %08X\n", ! 190: fstp->_st[i].significand[0], ! 191: fstp->_st[i].significand[1], ! 192: fstp->_st[i].significand[2], ! 193: fstp->_st[i].significand[3], ! 194: fstp->_st[i].exponent); ! 195: break; ! 196: case 3: /* Empty */ ! 197: printx("<Empty>"); ! 198: break; ! 199: } ! 200: if (i==3 || i==7) ! 201: putx('\n'); ! 202: else ! 203: putx('\t'); ! 204: } ! 205: } ! 206: #endif ! 207: } ! 208: ! 209: /* ! 210: * Find the segment in which an address resides. ! 211: * For COFF, the address implies a unique segment (or SEG_NONE). ! 212: * For l.out, the same address can represent an item in either DSEG or ISEG ! 213: * (i.e. the address->segment mapping is one->many), so this is does not ! 214: * necessarily give the right answer; it is even less right since the ! 215: * segmentation maps for the child process are at present set up incorrectly. ! 216: * Return SEG_NONE if not found. ! 217: */ ! 218: int ! 219: find_seg(addr) register ADDR_T addr; ! 220: { ! 221: register int s; ! 222: ! 223: if (IS_COFF) ! 224: return (addr < (ADDR_T)0x00400000) ? ISEG ! 225: : (addr < (ADDR_T)0x80000000) ? DSEG ! 226: : SEG_NONE; ! 227: for (s = 0; s < NSEGS; s++) ! 228: if (map_addr(s, addr) != (MAP *)NULL) ! 229: return s; ! 230: return SEG_NONE; ! 231: } ! 232: ! 233: /* ! 234: * Given a size character 't1' and a type 't2', ! 235: * return the appropriate format string. ! 236: */ ! 237: char * ! 238: get_format(t1, t2) register int t1, t2; ! 239: { ! 240: register char *cp, *sp; ! 241: ! 242: if (t1 == 'f' || t1 == 'F') ! 243: return "%g"; ! 244: if (t1 == 'h') ! 245: t1 = 'w'; ! 246: if ((cp = strchr(sp = "bwlv", t1)) == NULL) ! 247: return "?"; ! 248: t1 = cp - sp; ! 249: if ((cp = strchr(sp = "duox", t2)) == NULL) ! 250: return "?"; ! 251: t2 = cp - sp; ! 252: return formtab[t1][t2]; ! 253: } ! 254: ! 255: /* ! 256: * Return the frame pointer. ! 257: * Mask to 16-bit value for l.out. ! 258: */ ! 259: ADDR_T ! 260: get_fp() ! 261: { ! 262: return (IS_LOUT) ? ureg.ur_bp & 0xFFFF : ureg.ur_bp; ! 263: } ! 264: ! 265: /* ! 266: * Store the value from an NDP register into a double. ! 267: * If the machine has no NDP, fail and return 0. ! 268: * If the machine has an NDP (or NDP emulation), ! 269: * use the coprocessor instructions in _get_fp_reg() ! 270: * to convert the 80-bit arg to the 64-bit result ! 271: * and return 1. ! 272: */ ! 273: int ! 274: get_fp_reg(fpregp, dp) struct _fpreg *fpregp; double *dp; ! 275: { ! 276: if (!NDP_flag) ! 277: return 0; /* sorry */ ! 278: *dp = _get_fp_reg(fpregp); /* store converted result */ ! 279: return 1; ! 280: } ! 281: ! 282: /* ! 283: * Return the program counter. ! 284: * Mask to 16-bit value for l.out. ! 285: */ ! 286: ADDR_T ! 287: get_pc() ! 288: { ! 289: return (IS_LOUT) ? ureg.ur_ip & 0xFFFF : ureg.ur_ip; ! 290: } ! 291: ! 292: /* ! 293: * Read registers from the child process. ! 294: * The flag is: ! 295: * R_SOME read %eip, %ebp, %esp and signal number only ! 296: * R_GEN read the general registers ! 297: * R_ALL read all the registers, general and NDP ! 298: * This is for efficiency; the values of the registers other than ip/bp/sp ! 299: * are needed only for :r and ?, and because ptrace() only reads an int ! 300: * at a time it requires many system calls to read the complete register set. ! 301: * Return 1 on success, 0 on failure. ! 302: */ ! 303: int ! 304: get_regs(flag) int flag; ! 305: { ! 306: static char *nope = "Cannot read registers"; ! 307: ! 308: dbprintf(("get_regs(%d) reg_flag=%d\n", flag, reg_flag)); ! 309: ! 310: if (reg_flag != R_INVALID && reg_flag >= flag) ! 311: return 1; /* already read */ ! 312: reg_flag = R_INVALID; /* in case read fails */ ! 313: if (flag == R_SOME) { ! 314: add = PTRACE_EIP; ! 315: if (getb(USEG, (char *)&ureg.ur_ip, PTSIZE) == 0) ! 316: return printr(nope); ! 317: add = PTRACE_EBP; ! 318: if (getb(USEG, (char *)&ureg.ur_bp, PTSIZE) == 0) ! 319: return printr(nope); ! 320: add = PTRACE_UESP; ! 321: if (getb(USEG, (char *)&ureg.ur_sp, PTSIZE) == 0) ! 322: return printr(nope); ! 323: add = PTRACE_SIG; ! 324: if (getb(USEG, (char *)&ureg.ur_sig, PTSIZE) == 0) ! 325: return printr("Cannot read signal in traced process"); ! 326: dbprintf(("get_regs(R_SOME): ip=%x bp=%x sp=%x sig=%d\n", ureg.ur_ip, ureg.ur_bp, ureg.ur_sp, ureg.ur_sig)); ! 327: } else { /* R_GEN or R_ALL */ ! 328: add = UREG_BASE; /* pseudo-offset of ureg */ ! 329: if (getb(USEG, (char *)&ureg, ! 330: (flag==R_GEN) ? UREG_GEN_SIZE : UREG_ALL_SIZE) == 0) ! 331: return printr(nope); ! 332: } ! 333: reg_flag = flag; ! 334: return 1; ! 335: } ! 336: ! 337: /* ! 338: * Return the child program signal number. ! 339: */ ! 340: int ! 341: get_sig() ! 342: { ! 343: return ureg.ur_sig; ! 344: } ! 345: ! 346: /* ! 347: * Get a word or dword from segment s and store it in *lp. ! 348: */ ! 349: int ! 350: get_sized(s, lp) int s; ADDR_T *lp; ! 351: { ! 352: unsigned short i; ! 353: ! 354: if (IS_LOUT) { ! 355: if (getb(s, (char *)&i, sizeof(i)) == 0) /* get 2 bytes for l.out */ ! 356: return 0; ! 357: *lp = (ADDR_T)i; ! 358: return 1; ! 359: } ! 360: return getb(s, (char *)lp, sizeof(*lp)); /* get 4 bytes for COFF */ ! 361: ! 362: } ! 363: ! 364: /* ! 365: * Return the stack pointer. ! 366: * Mask to 16-bit value for l.out. ! 367: */ ! 368: ADDR_T ! 369: get_sp() ! 370: { ! 371: return (IS_LOUT) ? ureg.ur_sp & 0xFFFF : ureg.ur_sp; ! 372: } ! 373: ! 374: /* ! 375: * Perform i386-specific initialization. ! 376: * This checks whether NDP (or emulation) is present; ! 377: * get_fp_reg requires either NDP or emulation ! 378: * to convert an 80-bit NDP double to 64-bit format. ! 379: */ ! 380: void ! 381: init_mch() ! 382: { ! 383: int NDPstate; ! 384: ! 385: if (sysi86(SI86FPHW, &NDPstate) == -1) ! 386: panic("sysi86() call failed"); ! 387: NDP_flag = (NDPstate != FP_NO); ! 388: } ! 389: ! 390: /* ! 391: * Return true if instruction at %eip is a call. ! 392: */ ! 393: int ! 394: is_call() ! 395: { ! 396: unsigned char w[4]; ! 397: int i; ! 398: ! 399: add = get_pc(); ! 400: dbprintf(("is_call(): eip=%x\n", add)); ! 401: if (getb(ISEG, (char *)&i, sizeof(i)) == 0) ! 402: return; ! 403: w[0] = i & 0xff; ! 404: w[1] = (i>>8) & 0xff; ! 405: return (w[0] == CALL) /* Direct call */ ! 406: || (w[0]==ICALL1 && (w[1]&IC2MSK)==ICALL2); /* Indirect call */ ! 407: } ! 408: ! 409: /* ! 410: * If the given name matches a register, ! 411: * set up 'sp' with the address of a register in the user area. ! 412: */ ! 413: int ! 414: is_reg(sp) SYM *sp; ! 415: { ! 416: register char *cp, *np; ! 417: register REGNAME *rp; ! 418: ! 419: for (cp = sp->s_id, rp = reg_name; rp < ®_name[NREGS]; rp++) { ! 420: np = rp->r_name; ! 421: if (strcmp(cp, np) == 0) { ! 422: sp->s_addr = rp->r_offset; ! 423: sp->s_segn = USEG; ! 424: return 1; ! 425: } else if (*np == 'e' && strcmp(cp, np+1) == 0) { ! 426: /* Recognize e.g. "si" as word equivalent of "esi". */ ! 427: sp->s_addr = rp->r_offset; ! 428: sp->s_segn = USEG; ! 429: return 1; ! 430: } ! 431: } ! 432: return 0; ! 433: } ! 434: ! 435: /* ! 436: * Watch out for system calls if single stepping. ! 437: * If at system call, save the address (sys_add) and the contents (sys_in) ! 438: * of the replaced instruction and set *flagp to 2. ! 439: * Return 0 on error. ! 440: */ ! 441: int ! 442: is_syscall(flagp) int *flagp; ! 443: { ! 444: unsigned char w; ! 445: ! 446: if (*flagp == 0) ! 447: return 1; /* not single stepping */ ! 448: add = get_pc(); ! 449: dbprintf(("is_syscall(): pc=%X ", add)); ! 450: if (getb(ISEG, (char *)&w, sizeof(w)) == 0) ! 451: return 1; /* should this be 0? */ ! 452: ! 453: if (IS_LOUT) { /* l.out */ ! 454: if (w != INT) /* Interrupt (system call) */ ! 455: return 1; /* not at a system call */ ! 456: add = get_pc() + 2; ! 457: } else { /* COFF */ ! 458: if (w != LCALL) /* lcall (possibly system call) */ ! 459: return 1; /* not at a system call */ ! 460: add = get_pc() + 7; ! 461: } ! 462: sys_add = add; ! 463: if (getb(ISEG, (char *)sys_in, sizeof(sys_in)) == 0) ! 464: return printr("Cannot get breakpoint"); ! 465: add = sys_add; ! 466: dbprintf(("is_syscall: set system call bpt at %X replacing %X\n", add, sys_in[0])); ! 467: if (putb(ISEG, (char *)bin, sizeof(bin)) == 0) ! 468: return printr("Cannot set breakpoint"); ! 469: *flagp = 2; /* indicate system call seen */ ! 470: return 1; ! 471: } ! 472: ! 473: /* ! 474: * Print an address as a constant. ! 475: */ ! 476: void ! 477: print_const(buf, addr) register char *buf; ADDR_T addr; ! 478: { ! 479: sprintf(buf, (addr < (ADDR_T)0x10) ? "%ld" : "0x%lX", (long)addr); ! 480: } ! 481: ! 482: /* ! 483: * Restore after stepping past a system call. ! 484: * This basically undoes what is_syscall() does. ! 485: * Note that the system call may not return where you would expect, ! 486: * e.g. for sigreturn! ! 487: */ ! 488: int ! 489: rest_syscall(flagp) int *flagp; ! 490: { ! 491: ADDR_T pc; ! 492: ! 493: pc = get_pc() - sizeof(BIN); ! 494: if (pc == sys_add) ! 495: set_pc(pc); /* back up %eip */ ! 496: dbprintf(("rest_syscall(): step_flag=%d sys_add=%X pc=%X\n", *flagp, sys_add, pc)); ! 497: add = sys_add; /* restore instruction */ ! 498: if (putb(ISEG, (char *)sys_in, sizeof(sys_in)) == 0) ! 499: return printr("Cannot restore sys_in"); ! 500: *flagp = 1; /* restore step_mode==1 */ ! 501: return 1; ! 502: } ! 503: ! 504: /* ! 505: * Set up segmentation for COFF. ! 506: */ ! 507: void ! 508: setcoffseg() ! 509: { ! 510: register SCNHDR *shp, *oshp; ! 511: ADDR_T fbase, tbase, tsize, dbase, dsize, bbase, bsize; ! 512: off_t tsp, dsp, bsp; ! 513: int i; ! 514: ! 515: fbase = sizeof(FILEHDR) + coff_hdr.f_opthdr; ! 516: tbase = tsize = dbase = dsize = bbase = bsize = MIN_ADDR; ! 517: tsp = dsp = bsp = (off_t)0; ! 518: oshp = shp = (SCNHDR *)nalloc(coff_hdr.f_nscns*sizeof(SCNHDR), "COFF section headers"); ! 519: if (fseek(lfp, (long)fbase, SEEK_SET) == -1) ! 520: panic("COFF header seek failed"); ! 521: for (i = 0; i < coff_hdr.f_nscns; shp++, i++) { ! 522: /* Read a COFF section header. */ ! 523: if (fread(shp, sizeof(SCNHDR), 1, lfp) != 1) ! 524: panic("Cannot read COFF section header"); ! 525: ! 526: /* Set base and size info according to flags. */ ! 527: switch((int)shp->s_flags) { ! 528: case STYP_TEXT: ! 529: tbase = shp->s_vaddr; ! 530: tsize = shp->s_size; ! 531: tsp = shp->s_scnptr; ! 532: break; ! 533: case STYP_DATA: ! 534: dbase = shp->s_vaddr; ! 535: dsize = shp->s_size; ! 536: dsp = shp->s_scnptr; ! 537: break; ! 538: case STYP_BSS: ! 539: bbase = shp->s_vaddr; ! 540: bsize = shp->s_size; ! 541: bsp = shp->s_scnptr; ! 542: break; ! 543: default: ! 544: continue; /* ignore other section types */ ! 545: } ! 546: } ! 547: ! 548: endpure = (MAP *)NULL; /* no pure data */ ! 549: #if 0 ! 550: dbase = rup(dbase); /* round up? */ ! 551: #endif ! 552: #if 1 ! 553: /* Assume separate. */ ! 554: map_set(ISEG, tbase, tsize, tsp, MAP_PROG); ! 555: map_set(DSEG, dbase, dsize, dsp, MAP_PROG); ! 556: map_set(DSEG, bbase, bsize+4L, bsp, MAP_PROG); ! 557: #else ! 558: /* Assume NOT separate. */ ! 559: map_set(DSEG, tbase, tsize, tsp, MAP_PROG); ! 560: map_set(DSEG, dbase, dsize, dsp, MAP_PROG); ! 561: map_set(DSEG, bbase, bsize+4L, bsp, MAP_PROG); ! 562: ISPACE = DSPACE; ! 563: #endif ! 564: nfree(oshp); ! 565: } ! 566: ! 567: /* ! 568: * Set up segmentation for a system dump. ! 569: */ ! 570: void ! 571: setdump(name) char *name; ! 572: { ! 573: setkmem(name); ! 574: } ! 575: ! 576: /* ! 577: * Set up segmentation for kernel memory. ! 578: * FIX_ME This is much bogosity. "etext" is no more, for one thing... ! 579: */ ! 580: void ! 581: setkmem(name) char *name; ! 582: { ! 583: register off_t l; ! 584: unsigned int n; ! 585: static SYM *etextp; ! 586: ! 587: cfn = name; ! 588: cfp = openfile(name, rflag); ! 589: map_set(USEG, MIN_ADDR, MAX_ADDR, (off_t)0, MAP_CORE); ! 590: add = 2; ! 591: if (getb(USEG, (char *)&n, sizeof(n)) == 0) ! 592: panic("Bad memory file"); ! 593: l = (off_t)n << 4; ! 594: map_set(ISEG, MIN_ADDR, MAX_ADDR, (off_t)l, MAP_CORE); ! 595: if (etextp == (SYM *)NULL) { ! 596: /* Find the address of "etext". */ ! 597: etextp = (SYM *)nalloc(sizeof(SYM) + 6, "symbol \"etext\""); ! 598: strcpy(etextp->s_id, "etext"); ! 599: if (!is_symbol(etextp)) ! 600: etextp->s_addr = (off_t)1; ! 601: dbprintf(("main=%lX\n", etextp->s_addr)); ! 602: } ! 603: if (!is_symbol(etextp)) ! 604: DSPACE = ISPACE; ! 605: else { ! 606: n = rup(etextp->s_addr); ! 607: map_set(DSEG, MIN_ADDR, MAX_ADDR, (off_t)l+n, MAP_CORE); ! 608: } ! 609: } ! 610: ! 611: /* ! 612: * Set up segmentation for an l.out. ! 613: */ ! 614: void ! 615: setloutseg() ! 616: { ! 617: register off_t fbase; ! 618: register ADDR_T si, pi, bi, sd, pd, rs; ! 619: ! 620: fbase = (off_t)sizeof(ldh); ! 621: si = ldh.l_ssize[L_SHRI]; ! 622: pi = ldh.l_ssize[L_PRVI]; ! 623: bi = ldh.l_ssize[L_BSSI]; ! 624: sd = ldh.l_ssize[L_SHRD]; ! 625: pd = ldh.l_ssize[L_PRVD]; ! 626: dbprintf(("l.out sizes: si=%lX pi=%lX bi=%lX sd=%lX pd=%lX\n", si, pi, bi, sd, pd)); ! 627: endpure = (MAP *)NULL; /* no pure data */ ! 628: switch (ldh.l_flag & (LF_SEP|LF_SHR)) { ! 629: ! 630: case 0: /* not separate, not shared */ ! 631: map_set(DSEG, MIN_ADDR, si+pi, fbase, MAP_PROG); ! 632: map_set(DSEG, si+pi+bi, sd+pd, fbase+(off_t)(si+pi), MAP_PROG); ! 633: ISPACE = DSPACE; ! 634: break; ! 635: ! 636: case LF_SHR: /* not separate, shared */ ! 637: rs = rup(si+sd); ! 638: map_set(DSEG, MIN_ADDR, si, fbase, MAP_PROG); ! 639: map_set(DSEG, si, sd, fbase+(off_t)(si+pi), MAP_PROG); ! 640: map_set(DSEG, rs, pi, fbase+(off_t)si, MAP_PROG); ! 641: map_set(DSEG, rs+pi, pd, fbase+(off_t)(si+pi+sd), MAP_PROG); ! 642: ISPACE = DSPACE; ! 643: break; ! 644: ! 645: case LF_SEP: /* separate, not shared */ ! 646: map_set(ISEG, MIN_ADDR, si+pi, fbase, MAP_PROG); ! 647: map_set(DSEG, MIN_ADDR, sd+pd, fbase+(off_t)(si+pi), MAP_PROG); ! 648: break; ! 649: ! 650: case LF_SEP|LF_SHR: /* separate, shared */ ! 651: rs = rup(sd); ! 652: map_set(ISEG, MIN_ADDR, si+pi, fbase, MAP_PROG); ! 653: map_set(DSEG, MIN_ADDR, sd, fbase+(off_t)(si+pi), MAP_PROG); ! 654: map_set(DSEG, rs, pd, fbase+(off_t)(si+pi+sd), MAP_PROG); ! 655: break; ! 656: } ! 657: } ! 658: ! 659: /* ! 660: * Set the program counter. ! 661: */ ! 662: void ! 663: set_pc(ip) ADDR_T ip; ! 664: { ! 665: dbprintf(("set_pc(%lX)\n", ip)); ! 666: ureg.ur_ip = ip; ! 667: add = PTRACE_EIP; ! 668: putb(USEG, (char *)&ureg.ur_ip, sizeof(ureg.ur_ip)); ! 669: } ! 670: ! 671: /* ! 672: * Set a BSIN breakpoint at the return address given by %esp. ! 673: */ ! 674: void ! 675: set_ra_bpt() ! 676: { ! 677: ADDR_T ra; ! 678: ! 679: add = get_sp(); ! 680: dbprintf(("set_ra_bpt(): sp=%lX ", add)); ! 681: if (get_sized(DSEG, &ra) == 0) ! 682: return; ! 683: bpt_set(BSIN, ra, get_fp(), NULL); ! 684: dbprintf(("ra=%lX bp=%lX\n", ra, get_fp())); ! 685: } ! 686: ! 687: /* ! 688: * Set the signal number. ! 689: * This gets executed when a core file is read; ! 690: * dunno why the signal number in the register save is different. ! 691: */ ! 692: void ! 693: set_sig(sig) int sig; ! 694: { ! 695: dbprintf(("set_sig(%X)\n", sig)); ! 696: ureg.ur_sig = sig; ! 697: add = PTRACE_SIG; ! 698: putb(USEG, (char *)&ureg.ur_sig, sizeof(ureg.ur_sig)); ! 699: } ! 700: ! 701: /* ! 702: * Stack traceback. ! 703: * This code knows some gory details about the C calling sequence ! 704: * for code compiled by either the i8086 compiler or the i386 compiler. ! 705: * It must be changed if the calling sequence changes! ! 706: * ! 707: * i8086 stack frame: ! 708: * bp+6+(2*n)-> [argn] ! 709: * [...] ! 710: * bp+8-> [arg1] ! 711: * bp+6-> ra ! 712: * bp+4-> saved si ! 713: * bp+2-> saved di ! 714: * bp-> saved bp ! 715: * bp-n [locals] ! 716: * Here [] indicates optional; note that the registers are always saved. ! 717: * Arguments are popped after the call with "add %sp, $n". ! 718: * ! 719: * i386 stack frame: ! 720: * bp+4+(4*n)-> [argn] ! 721: * [...] ! 722: * bp+8-> [arg1] ! 723: * bp+4-> ra ! 724: * bp-> saved bp ! 725: * bp-x-> [locals] ! 726: * bp-x-4-> [saved esi] ! 727: * bp-x-8-> [saved edi] ! 728: * bp-x-12-> [saved ebx] ! 729: * Here the registers are saved only if required. ! 730: * The function entry sequence may begin with either "enter $n, $0" (if locals) ! 731: * or with "push %ebp; movl %ebp, %esp" (if no locals). ! 732: * Arguments are popped after the call with "pop %ecx" or "add %esp, $n". ! 733: */ ! 734: void ! 735: traceback(levels) int levels; ! 736: { ! 737: ADDR_T bp, pc, rpc; /* ebp, eip, return pc */ ! 738: register int argc; /* arg count */ ! 739: int at_start; /* at start, before ebp save */ ! 740: int qflag; /* quit flag */ ! 741: static SYM *mainp; /* "main" */ ! 742: int size; /* bytes per stack item */ ! 743: SYM *sp; ! 744: int i, n; ! 745: char *fmt; ! 746: unsigned char b[3], e[1]; /* opcode buffers */ ! 747: ! 748: fmt = (IS_LOUT) ? ADDR16_FMT : ADDR_FMT; ! 749: if (mainp == (SYM *)NULL) { ! 750: /* Find the address of "main". */ ! 751: mainp = (SYM *)nalloc(sizeof(SYM) + 5, "symbol \"main\""); ! 752: strcpy(mainp->s_id, "main"); ! 753: if (!is_symbol(mainp)) ! 754: mainp->s_addr = (off_t)1; ! 755: dbprintf(("main=%lX\n", mainp->s_addr)); ! 756: } ! 757: ! 758: /* Set operand size, get registers ip and bp. */ ! 759: size = (IS_LOUT) ? 2 : 4; /* word for l.out, dword for COFF */ ! 760: add = pc = get_pc(); ! 761: dbprintf(("ip=%lX\n", pc)); ! 762: if (getb(ISEG, b, 1) == 0) { /* fetch opcode at ip to b[] */ ! 763: printe("Illegal ip"); ! 764: return; ! 765: } ! 766: bp = get_fp(); ! 767: dbprintf(("bp=%lX\n", bp)); ! 768: ! 769: /* Fetch the first byte of the current routine. */ ! 770: if ((sp = findsym(1, pc)) != (SYM *)NULL) { ! 771: dbprintf(("findsym found %s, addr=%lX\n", sp->s_id, sp->s_addr)); ! 772: add = sp->s_addr; ! 773: getb(ISEG, (char *)e, 1); ! 774: dbprintf(("opcode fetched from %s: %x\n", sp->s_id, e[0])); ! 775: } else ! 776: e[0] = (IS_LOUT) ? PUSHESI : ENTER; /* take a guess... */ ! 777: ! 778: /* ! 779: * If we are right at the start of the routine, ! 780: * set at_start and kludge bp so that we can see this ! 781: * call in the traceback. ! 782: * sp currently must point to ra, ! 783: * so bp will be at sp-6 for l.out or sp-4 for COFF. ! 784: * Otherwise, use the current bp as is. ! 785: */ ! 786: if ((IS_LOUT && (b[0]==PUSHESI || e[0]!=PUSHESI)) ! 787: || (!IS_LOUT && (b[0]==ENTER || b[0]==PUSHEBP || (e[0]!=ENTER && e[0]!=PUSHEBP)))) { ! 788: at_start = 1; ! 789: bp = ureg.ur_sp - (8 - size); ! 790: if (IS_LOUT) ! 791: bp &= 0xFFFF; ! 792: } else ! 793: at_start = 0; ! 794: ! 795: for (qflag = 0; ; ) { ! 796: ! 797: /* Fetch the return PC. */ ! 798: add = (IS_LOUT) ? bp + 6 : bp + 4; ! 799: if (get_sized(DSEG, &rpc) == 0) ! 800: break; ! 801: dbprintf(("return pc=%lX\n", rpc)); ! 802: ! 803: /* ! 804: * Fetch code from return location and look for stack adjust. ! 805: * If present, calculate the argc from it. ! 806: * The i386 compiler deletes stack adjust before "leave"; ! 807: * these are currently printed with "(???)" args (argc==-1). ! 808: */ ! 809: argc = 0; ! 810: add = rpc; ! 811: if (getb(ISEG, b, 3) != 0) { ! 812: if (b[0]==ADDSP1 && b[1]==ADDSP2) /* add sp,$? */ ! 813: argc = b[2] / size; ! 814: else if (!IS_LOUT && b[0]==POPECX) /* pop %ecx */ ! 815: argc = 1; ! 816: else if (!IS_LOUT && b[0]==LEAVE) /* leave */ ! 817: argc = -1; ! 818: } ! 819: dbprintf(("argc=%d\n", argc)); ! 820: ! 821: /* ! 822: * Fetch the opcode preceding the return PC, presumably "call". ! 823: * Print a line like "bp pc name(arg1, ..., argn)\n". ! 824: */ ! 825: add = rpc - 1 - size; ! 826: if (getb(ISEG, b, 1) == 0) ! 827: break; ! 828: if (get_sized(ISEG, &n) == 0) ! 829: break; ! 830: printx(fmt, bp); ! 831: printx(" "); ! 832: printx(fmt, pc); ! 833: printx(" "); ! 834: if (b[0] == CALL) { ! 835: n += rpc; ! 836: putaddr(ISEG, (ADDR_T)n); ! 837: if (n == mainp->s_addr) { ! 838: qflag = 1; ! 839: argc = 3; ! 840: } ! 841: } else { ! 842: /* Not a call, e.g. icall. */ ! 843: if ((sp = findsym(1, pc)) == (SYM *)NULL) ! 844: printx("*"); ! 845: else { ! 846: putaddr(ISEG, pc); ! 847: if (strcmp(sp->s_id, "main") == 0) { ! 848: qflag = 1; ! 849: argc = 3; ! 850: } ! 851: } ! 852: } ! 853: ! 854: /* ! 855: * Splat the arg list. ! 856: * Offset 8 coincidently works for both file formats. ! 857: */ ! 858: putx('('); ! 859: add = bp + 8; ! 860: if (argc == -1) ! 861: printx("???"); ! 862: else for (i = 0; i < argc; i++) { ! 863: if (get_sized(DSEG, &n) == 0) ! 864: break; ! 865: if (i != 0) ! 866: printx(", "); ! 867: print_const(miscbuf, (ADDR_T)n); ! 868: printx("%s", miscbuf); ! 869: } ! 870: printx(")\n"); ! 871: ! 872: /* Move to the next frame and repeat ad nauseum. */ ! 873: if (testint()) ! 874: return; ! 875: if (qflag) ! 876: break; ! 877: if (at_start) { ! 878: at_start = 0; ! 879: bp = get_fp(); ! 880: } else { ! 881: add = bp; ! 882: if (get_sized(DSEG, &bp) == 0) ! 883: break; ! 884: } ! 885: if (--levels == 0) ! 886: return; ! 887: pc = rpc; ! 888: } ! 889: } ! 890: ! 891: /* end of db/i386/i386db1.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.