#include <linux/module.h>
#include <linux/sched.h>
#include <asm/sysrq.h>
+#include <os.h>
struct stack_frame {
struct stack_frame *next_frame;
/*Stolen from arch/i386/kernel/traps.c */
static const int kstack_depth_to_print = 24;
-static unsigned long get_frame_pointer(struct task_struct *task)
+static unsigned long get_frame_pointer(struct task_struct *task,
+ struct pt_regs *segv_regs)
{
if (!task || task == current)
- return current_bp();
+ return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
else
return KSTK_EBP(task);
}
+static unsigned long *get_stack_pointer(struct task_struct *task,
+ struct pt_regs *segv_regs)
+{
+ if (!task || task == current)
+ return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
+ else
+ return (unsigned long *)KSTK_ESP(task);
+}
+
void show_stack(struct task_struct *task, unsigned long *stack)
{
unsigned long *sp = stack, bp = 0;
+ struct pt_regs *segv_regs = current->thread.segv_regs;
int i;
+ if (!segv_regs && os_is_signal_stack()) {
+ printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler,"
+ " aborting stack trace!\n");
+ return;
+ }
+
#ifdef CONFIG_FRAME_POINTER
- bp = get_frame_pointer(task);
+ bp = get_frame_pointer(task, segv_regs);
#endif
- if (!stack) {
- if (!task || task == current)
- sp = current_sp();
- else
- sp = (unsigned long *)KSTK_ESP(task);
- }
+ if (!stack)
+ sp = get_stack_pointer(task, segv_regs);
printk(KERN_INFO "Stack:\n");
stack = sp;
int is_write = FAULT_WRITE(fi);
unsigned long address = FAULT_ADDRESS(fi);
+ if (regs)
+ current->thread.segv_regs = container_of(regs, struct pt_regs, regs);
+
if (!is_user && (address >= start_vm) && (address < end_vm)) {
flush_tlb_kernel_vm();
- return 0;
+ goto out;
}
else if (current->mm == NULL) {
show_regs(container_of(regs, struct pt_regs, regs));
catcher = current->thread.fault_catcher;
if (!err)
- return 0;
+ goto out;
else if (catcher != NULL) {
current->thread.fault_addr = (void *) address;
UML_LONGJMP(catcher, 1);
else if (current->thread.fault_addr != NULL)
panic("fault_addr set but no fault catcher");
else if (!is_user && arch_fixup(ip, regs))
- return 0;
+ goto out;
if (!is_user) {
show_regs(container_of(regs, struct pt_regs, regs));
current->thread.arch.faultinfo = fi;
force_sig_info(SIGSEGV, &si, current);
}
+
+out:
+ if (regs)
+ current->thread.segv_regs = NULL;
+
return 0;
}