x86/LDT: Print the real LDT base address
[pandora-kernel.git] / arch / x86 / kernel / process_64.c
index e361095..ee2e70c 100644 (file)
@@ -218,11 +218,11 @@ void __show_regs(struct pt_regs *regs, int all)
 void release_thread(struct task_struct *dead_task)
 {
        if (dead_task->mm) {
-               if (dead_task->mm->context.size) {
+               if (dead_task->mm->context.ldt) {
                        printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
                                        dead_task->comm,
-                                       dead_task->mm->context.ldt,
-                                       dead_task->mm->context.size);
+                                       dead_task->mm->context.ldt->entries,
+                                       dead_task->mm->context.ldt->size);
                        BUG();
                }
        }
@@ -555,27 +555,59 @@ void set_personality_ia32(void)
        current_thread_info()->status |= TS_COMPAT;
 }
 
+/*
+ * Called from fs/proc with a reference on @p to find the function
+ * which called into schedule(). This needs to be done carefully
+ * because the task might wake up and we might look at a stack
+ * changing under us.
+ */
 unsigned long get_wchan(struct task_struct *p)
 {
-       unsigned long stack;
-       u64 fp, ip;
+       unsigned long start, bottom, top, sp, fp, ip;
        int count = 0;
 
        if (!p || p == current || p->state == TASK_RUNNING)
                return 0;
-       stack = (unsigned long)task_stack_page(p);
-       if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE)
+
+       start = (unsigned long)task_stack_page(p);
+       if (!start)
+               return 0;
+
+       /*
+        * Layout of the stack page:
+        *
+        * ----------- topmax = start + THREAD_SIZE - sizeof(unsigned long)
+        * PADDING
+        * ----------- top = topmax - TOP_OF_KERNEL_STACK_PADDING
+        * stack
+        * ----------- bottom = start + sizeof(thread_info)
+        * thread_info
+        * ----------- start
+        *
+        * The tasks stack pointer points at the location where the
+        * framepointer is stored. The data on the stack is:
+        * ... IP FP ... IP FP
+        *
+        * We need to read FP and IP, so we need to adjust the upper
+        * bound by another unsigned long.
+        */
+       top = start + THREAD_SIZE;
+       top -= 2 * sizeof(unsigned long);
+       bottom = start + sizeof(struct thread_info);
+
+       sp = ACCESS_ONCE(p->thread.sp);
+       if (sp < bottom || sp > top)
                return 0;
-       fp = *(u64 *)(p->thread.sp);
+
+       fp = ACCESS_ONCE(*(unsigned long *)sp);
        do {
-               if (fp < (unsigned long)stack ||
-                   fp >= (unsigned long)stack+THREAD_SIZE)
+               if (fp < bottom || fp > top)
                        return 0;
-               ip = *(u64 *)(fp+8);
+               ip = ACCESS_ONCE(*(unsigned long *)(fp + sizeof(unsigned long)));
                if (!in_sched_functions(ip))
                        return ip;
-               fp = *(u64 *)fp;
-       } while (count++ < 16);
+               fp = ACCESS_ONCE(*(unsigned long *)fp);
+       } while (count++ < 16 && p->state != TASK_RUNNING);
        return 0;
 }