Enhancement of the X86_64 "bt" command to more correctly determine

the function frame that called into a function that was interrupted.
Without the patch, the first frame just above an IRQ exception frame
register dump may show an invalid/stale function.
(anderson@redhat.com)
This commit is contained in:
Dave Anderson 2014-01-29 15:20:47 -05:00
parent 8807d12cf0
commit 47a0fa259a
2 changed files with 59 additions and 0 deletions

1
defs.h
View File

@ -4829,6 +4829,7 @@ ulong cpu_map_addr(const char *type);
#define BT_USER_SPACE (0x100000000000ULL)
#define BT_KERNEL_SPACE (0x200000000000ULL)
#define BT_FULL_SYM_SLAB2 (0x400000000000ULL)
#define BT_EFRAME_TARGET (0x800000000000ULL)
#define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS)
#define BT_REF_HEXVAL (0x1)

View File

@ -107,6 +107,7 @@ static ulong x86_64_get_stacktop_hyper(ulong);
static int x86_64_framesize_cache_resize(void);
static int x86_64_framesize_cache_func(int, ulong, int *, int);
static ulong x86_64_get_framepointer(struct bt_info *, ulong);
int search_for_eframe_target_caller(struct bt_info *, ulong, int *);
static int x86_64_get_framesize(struct bt_info *, ulong, ulong);
static void x86_64_framesize_debug(struct bt_info *);
static void x86_64_get_active_set(void);
@ -3279,9 +3280,11 @@ in_exception_stack:
level++;
rsp += SIZE(pt_regs);
irq_eframe = 0;
bt->flags |= BT_EFRAME_TARGET;
if (bt->eframe_ip && ((framesize = x86_64_get_framesize(bt,
bt->eframe_ip, rsp)) >= 0))
rsp += framesize;
bt->flags &= ~BT_EFRAME_TARGET;
}
level++;
}
@ -7188,6 +7191,57 @@ x86_64_get_framepointer(struct bt_info *bt, ulong rsp)
return framepointer;
}
int
search_for_eframe_target_caller(struct bt_info *bt, ulong stkptr, int *framesize)
{
int i;
ulong *up, offset, rsp;
struct syment *sp1, *sp2;
char *called_function;
if ((sp1 = value_search(bt->eframe_ip, &offset)))
called_function = sp1->name;
else
return FALSE;
rsp = stkptr;
for (i = (rsp - bt->stackbase)/sizeof(ulong);
rsp < bt->stacktop; i++, rsp += sizeof(ulong)) {
up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]);
if (!is_kernel_text(*up))
continue;
if (!(sp1 = value_search(*up, &offset)))
continue;
if (!offset && !(bt->flags & BT_FRAMESIZE_DISABLE))
continue;
/*
* Get the syment of the function that the text
* routine above called before leaving its return
* address on the stack -- if it can be determined.
*/
if ((sp2 = x86_64_function_called_by((*up)-5))) {
if (STREQ(sp2->name, called_function)) {
if (CRASHDEBUG(1)) {
fprintf(fp,
"< %lx/%s rsp: %lx caller: %s >\n",
bt->eframe_ip, called_function,
stkptr, sp1->name);
}
*framesize = rsp - stkptr;
return TRUE;
}
}
}
return FALSE;
}
#define BT_FRAMESIZE_IGNORE_MASK \
(BT_OLD_BACK_TRACE|BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_ALL|BT_FRAMESIZE_DISABLE)
@ -7221,6 +7275,10 @@ x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp)
exception = bt->eframe_ip == textaddr ? TRUE : FALSE;
if ((bt->flags & BT_EFRAME_TARGET) &&
search_for_eframe_target_caller(bt, rsp, &framesize))
return framesize;
if (!(bt->flags & BT_FRAMESIZE_DEBUG) &&
x86_64_framesize_cache_func(FRAMESIZE_QUERY, textaddr, &framesize,
exception)) {