blob: 2484e3a9a67ae02819ca7c6fdf4f793ad686df17 [file] [log] [blame]
#include <string.h>
#include <assert.h>
#include <kdebug.h>
#include <pmap.h>
#include <process.h>
#include <kmalloc.h>
#include <arch/uaccess.h>
void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque)
{
uintptr_t pcs[MAX_BT_DEPTH];
size_t nr_pcs;
nr_pcs = backtrace_list(get_caller_pc(), get_caller_fp(), pcs,
MAX_BT_DEPTH);
print_backtrace_list(pcs, nr_pcs, pfunc, opaque);
}
static bool pc_is_asm_trampoline(uintptr_t pc)
{
extern char __asm_entry_points_start[], __asm_entry_points_end[];
extern char __asm_pop_hwtf_start[], __asm_pop_hwtf_end[];
extern char __asm_pop_swtf_start[], __asm_pop_swtf_end[];
extern char __asm_pop_vmtf_start[], __asm_pop_vmtf_end[];
if (((uintptr_t)__asm_entry_points_start <= pc) &&
(pc < (uintptr_t)__asm_entry_points_end))
return TRUE;
if (((uintptr_t)__asm_pop_hwtf_start <= pc) &&
(pc < (uintptr_t)__asm_pop_hwtf_end))
return TRUE;
if (((uintptr_t)__asm_pop_swtf_start <= pc) &&
(pc < (uintptr_t)__asm_pop_swtf_end))
return TRUE;
if (((uintptr_t)__asm_pop_vmtf_start <= pc) &&
(pc < (uintptr_t)__asm_pop_vmtf_end))
return TRUE;
return FALSE;
}
size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
size_t nr_slots)
{
size_t nr_pcs = 0;
while (nr_pcs < nr_slots) {
pcs[nr_pcs++] = pc;
printd("PC %p FP %p\n", pc, fp);
if (pc_is_asm_trampoline(pc))
break;
if (!fp)
break;
assert(KERNBASE <= fp);
/* We need to check the next FP before reading PC from beyond
* it. FP could be 0 and be at the top of the stack, and
* reading PC in that case will be a wild read. */
if (!*(uintptr_t*)fp)
break;
/* We used to set PC = retaddr - 1, where the -1 would put our
* PC back inside the function that called us. This was for
* obscure cases where a no-return function calls another
* function and has no other code after the function call. Or
* something. */
pc = *(uintptr_t*)(fp + sizeof(uintptr_t));
fp = *(uintptr_t*)fp;
}
return nr_pcs;
}
size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
size_t nr_slots)
{
int error;
size_t nr_pcs = 0;
uintptr_t frame[2];
while (nr_pcs < nr_slots) {
pcs[nr_pcs++] = pc;
if (!fp)
break;
error = copy_from_user(frame, (const void *) fp, 2 *
sizeof(uintptr_t));
if (unlikely(error))
break;
pc = frame[1];
fp = frame[0];
}
return nr_pcs;
}
/* Assumes 32-bit header */
void print_fpu_state(struct ancillary_state *fpu)
{
print_lock();
printk("fcw: 0x%04x\n", fpu->fp_head_n64.fcw);
printk("fsw: 0x%04x\n", fpu->fp_head_n64.fsw);
printk("ftw: 0x%02x\n", fpu->fp_head_n64.ftw);
printk("fop: 0x%04x\n", fpu->fp_head_n64.fop);
printk("fpu_ip: 0x%08x\n", fpu->fp_head_n64.fpu_ip);
printk("cs: 0x%04x\n", fpu->fp_head_n64.cs);
printk("fpu_dp: 0x%08x\n", fpu->fp_head_n64.fpu_dp);
printk("ds: 0x%04x\n", fpu->fp_head_n64.ds);
printk("mxcsr: 0x%08x\n", fpu->fp_head_n64.mxcsr);
printk("mxcsrm: 0x%08x\n", fpu->fp_head_n64.mxcsr_mask);
for (int i = 0; i < sizeof(struct ancillary_state); i++) {
if (i % 20 == 0)
printk("\n");
printk("%02x ", *((uint8_t*)fpu + i));
}
printk("\n");
print_unlock();
}