Fixed traceback for the following cases:

- legitimate null frames from idle() (traceback was aborted after a null
  pointer trap)
- second instruction of normal function prologue, and last instruction of
  a function (caller wasn't reported).

Reviewed by:	davidg
This commit is contained in:
Bruce Evans 1996-03-27 17:06:03 +00:00
parent ef46db020c
commit 6003d411e1
2 changed files with 98 additions and 42 deletions

View File

@ -23,7 +23,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: db_trace.c,v 1.13 1995/12/21 19:20:55 davidg Exp $
* $Id: db_trace.c,v 1.14 1995/12/22 07:09:24 davidg Exp $
*/
#include <sys/param.h>
@ -229,22 +229,27 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
db_expr_t count;
char *modif;
{
struct i386_frame *frame, *lastframe = NULL;
struct i386_frame *frame;
int *argp;
db_addr_t callpc;
boolean_t first;
if (count == -1)
count = 65535;
if (!have_addr) {
frame = (struct i386_frame *)ddb_regs.tf_ebp;
if (frame == NULL)
frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
callpc = (db_addr_t)ddb_regs.tf_eip;
} else {
frame = (struct i386_frame *)addr;
callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
}
first = TRUE;
while (count--) {
struct i386_frame *actframe;
int narg;
char * name;
db_expr_t offset;
@ -255,23 +260,47 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
db_symbol_values(sym, &name, NULL);
if (lastframe == NULL && sym == NULL) {
/* Symbol not found, peek at code */
int instr = db_get_value(callpc, 4, FALSE);
/*
* Attempt to determine a (possibly fake) frame that gives
* the caller's pc. It may differ from `frame' if the
* current function never sets up a standard frame or hasn't
* set one up yet or has just discarded one. The last two
* cases can be guessed fairly reliably for code generated
* by gcc. The first case is too much trouble to handle in
* general because the amount of junk on the stack depends
* on the pc (the special handling of "calltrap", etc. in
* db_nextframe() works because the `next' pc is special).
*/
actframe = frame;
if (first && !have_addr) {
int instr;
offset = 1;
/* enter: pushl %ebp, movl %esp, %ebp */
if ((instr & 0x00ffffff) == 0x00e58955 ||
/* enter+1: movl %esp, %ebp */
(instr & 0x0000ffff) == 0x0000e589) {
offset = 0;
instr = db_get_value(callpc, 4, FALSE);
if ((instr & 0x00ffffff) == 0x00e58955) {
/* pushl %ebp; movl %esp, %ebp */
actframe = (struct i386_frame *)
(ddb_regs.tf_esp - 4);
} else if ((instr & 0x0000ffff) == 0x0000e589) {
/* movl %esp, %ebp */
actframe = (struct i386_frame *)
ddb_regs.tf_esp;
if (ddb_regs.tf_ebp == 0) {
/* Fake the caller's frame better. */
frame = actframe;
}
} else if ((instr & 0x000000ff) == 0x000000c3) {
/* ret */
actframe = (struct i386_frame *)
(ddb_regs.tf_esp - 4);
} else if (offset == 0) {
/* Probably a symbol in assembler code. */
actframe = (struct i386_frame *)
(ddb_regs.tf_esp - 4);
}
}
if (lastframe == NULL && offset == 0 && !have_addr)
argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0;
else
argp = &frame->f_arg0;
}
first = FALSE;
argp = &actframe->f_arg0;
narg = MAXNARG;
if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
argnp = argnames;
@ -281,13 +310,12 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
db_print_stack_entry(name, narg, argnp, argp, callpc);
if (lastframe == NULL && offset == 0 && !have_addr) {
/* Frame really belongs to next callpc */
lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4);
callpc = (db_addr_t)db_get_value((int)&lastframe->f_retaddr, 4, FALSE);
if (actframe != frame) {
/* `frame' belongs to caller. */
callpc = (db_addr_t)
db_get_value((int)&actframe->f_retaddr, 4, FALSE);
continue;
}
lastframe = frame;
db_nextframe(&frame, &callpc);

View File

@ -23,7 +23,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: db_trace.c,v 1.13 1995/12/21 19:20:55 davidg Exp $
* $Id: db_trace.c,v 1.14 1995/12/22 07:09:24 davidg Exp $
*/
#include <sys/param.h>
@ -229,22 +229,27 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
db_expr_t count;
char *modif;
{
struct i386_frame *frame, *lastframe = NULL;
struct i386_frame *frame;
int *argp;
db_addr_t callpc;
boolean_t first;
if (count == -1)
count = 65535;
if (!have_addr) {
frame = (struct i386_frame *)ddb_regs.tf_ebp;
if (frame == NULL)
frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
callpc = (db_addr_t)ddb_regs.tf_eip;
} else {
frame = (struct i386_frame *)addr;
callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
}
first = TRUE;
while (count--) {
struct i386_frame *actframe;
int narg;
char * name;
db_expr_t offset;
@ -255,23 +260,47 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
db_symbol_values(sym, &name, NULL);
if (lastframe == NULL && sym == NULL) {
/* Symbol not found, peek at code */
int instr = db_get_value(callpc, 4, FALSE);
/*
* Attempt to determine a (possibly fake) frame that gives
* the caller's pc. It may differ from `frame' if the
* current function never sets up a standard frame or hasn't
* set one up yet or has just discarded one. The last two
* cases can be guessed fairly reliably for code generated
* by gcc. The first case is too much trouble to handle in
* general because the amount of junk on the stack depends
* on the pc (the special handling of "calltrap", etc. in
* db_nextframe() works because the `next' pc is special).
*/
actframe = frame;
if (first && !have_addr) {
int instr;
offset = 1;
/* enter: pushl %ebp, movl %esp, %ebp */
if ((instr & 0x00ffffff) == 0x00e58955 ||
/* enter+1: movl %esp, %ebp */
(instr & 0x0000ffff) == 0x0000e589) {
offset = 0;
instr = db_get_value(callpc, 4, FALSE);
if ((instr & 0x00ffffff) == 0x00e58955) {
/* pushl %ebp; movl %esp, %ebp */
actframe = (struct i386_frame *)
(ddb_regs.tf_esp - 4);
} else if ((instr & 0x0000ffff) == 0x0000e589) {
/* movl %esp, %ebp */
actframe = (struct i386_frame *)
ddb_regs.tf_esp;
if (ddb_regs.tf_ebp == 0) {
/* Fake the caller's frame better. */
frame = actframe;
}
} else if ((instr & 0x000000ff) == 0x000000c3) {
/* ret */
actframe = (struct i386_frame *)
(ddb_regs.tf_esp - 4);
} else if (offset == 0) {
/* Probably a symbol in assembler code. */
actframe = (struct i386_frame *)
(ddb_regs.tf_esp - 4);
}
}
if (lastframe == NULL && offset == 0 && !have_addr)
argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0;
else
argp = &frame->f_arg0;
}
first = FALSE;
argp = &actframe->f_arg0;
narg = MAXNARG;
if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
argnp = argnames;
@ -281,13 +310,12 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
db_print_stack_entry(name, narg, argnp, argp, callpc);
if (lastframe == NULL && offset == 0 && !have_addr) {
/* Frame really belongs to next callpc */
lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4);
callpc = (db_addr_t)db_get_value((int)&lastframe->f_retaddr, 4, FALSE);
if (actframe != frame) {
/* `frame' belongs to caller. */
callpc = (db_addr_t)
db_get_value((int)&actframe->f_retaddr, 4, FALSE);
continue;
}
lastframe = frame;
db_nextframe(&frame, &callpc);