|
|
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.