Hi,
Here is the updated patch. Changes from the previous version:
- implement kdb_follow_page in mm/memory.c itself to be able to
use follow_page() directly.
- support for writing into ("mm") user space addresses
- export kdb_get[put]userarea_size so that kdb modules will
be able to use kdb_get[put]word.
- implement this for ia64 along with i386.
Please apply.
Thanks,
Vamsi.
--
Vamsi Krishna S.
Linux Technology Center,
IBM Software Lab, Bangalore.
Ph: +91 80 5044959
Internet: vamsi@xxxxxxxxxx
-- description from previous mail --
Here is a patch to implement a command to switch the current
user process context whilst inside KDB to look at the stack,
disassemble code, display memory etc. of different processes.
Presently, KDB refuses to access user space addresses. A few
developers requested for a way to access process memory and
switch process contexts from within KDB. What it is required
for are those occasions where the system is hung and there
is no kernel panic. During hardware development it is not
uncommon for test to just stop and the server to be hung.
When this is caused by a process waiting for a resource to
be freed, it is essential to be able to see who is holding
the resource. Additionally, in a hang situation, the process
that is causing the problem may not be the current process
when you enter the debugger.
This patch (against 2.4.20 + KDB v4.1) provides:
- a way to switch the current process ("pid" command)
- a way to look at user space registers of the current
process ("rd u" command)
- a way to access user space addresses in the context of
a given process (normal md/mdr/id commands with
user space addresses)
Note that "bt" can be made to work unreliably in user
contexts too, but I have left it out for now.
--
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/arch/i386/kdb/kdbasupport.c
2420-kdb4.1/arch/i386/kdb/kdbasupport.c
--- 2420-kdb4.1-pure/arch/i386/kdb/kdbasupport.c 2003-04-16
18:00:58.000000000 +0530
+++ 2420-kdb4.1/arch/i386/kdb/kdbasupport.c 2003-04-16 18:02:14.000000000
+0530
@@ -723,7 +723,7 @@
/* User registers: %%e[a-c]x, etc */
regname++;
regs = (struct pt_regs *)
- (current->thread.esp0 - sizeof(struct pt_regs));
+ (kdb_current_task->thread.esp0 - sizeof(struct
pt_regs));
}
for (i=0; i<ndbreglist; i++) {
@@ -823,7 +823,7 @@
if (regname[0] == '%') {
regname++;
regs = (struct pt_regs *)
- (current->thread.esp0 - sizeof(struct pt_regs));
+ (kdb_current_task->thread.esp0 - sizeof(struct
pt_regs));
}
for (i=0; i<ndbreglist; i++) {
@@ -883,6 +883,7 @@
* d Debug registers
* c Control registers
* u User registers at most recent entry to kernel
+ * for the process currently selected with "pid" command.
* Following not yet implemented:
* m Model Specific Registers (extra defines register #)
* r Memory Type Range Registers (extra defines register)
@@ -900,7 +901,7 @@
&& (type[0] == 'u')) {
type = NULL;
regs = (struct pt_regs *)
- (current->thread.esp0 - sizeof(struct pt_regs));
+ (kdb_current_task->thread.esp0 - sizeof(struct
pt_regs));
}
if (type == NULL) {
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/arch/ia64/kdb/kdbasupport.c
2420-kdb4.1/arch/ia64/kdb/kdbasupport.c
--- 2420-kdb4.1-pure/arch/ia64/kdb/kdbasupport.c 2003-04-16
18:01:01.000000000 +0530
+++ 2420-kdb4.1/arch/ia64/kdb/kdbasupport.c 2003-04-16 18:02:18.000000000
+0530
@@ -672,7 +672,7 @@
if (regname[0] == '%') {
regname++;
regs = (struct pt_regs *)
- (current->thread.ksp - sizeof(struct pt_regs));
+ (kdb_current_task->thread.ksp - sizeof(struct pt_regs));
}
if (!regs) {
@@ -779,7 +779,7 @@
&& (type[0] == 'u')) {
type = NULL;
regs = (struct pt_regs *)
- (current->thread.ksp - sizeof(struct pt_regs));
+ (kdb_current_task->thread.ksp - sizeof(struct pt_regs));
}
if (type == NULL) {
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/include/asm-i386/kdb.h
2420-kdb4.1/include/asm-i386/kdb.h
--- 2420-kdb4.1-pure/include/asm-i386/kdb.h 2003-04-16 18:00:58.000000000
+0530
+++ 2420-kdb4.1/include/asm-i386/kdb.h 2003-04-16 19:06:49.000000000 +0530
@@ -78,6 +78,9 @@
#include <asm/uaccess.h>
+extern int kdb_getuserarea_size(void *, unsigned long, size_t);
+extern int kdb_putuserarea_size(unsigned long, void *, size_t);
+
static inline int
__kdba_putarea_size(unsigned long to_xxx, void *from, size_t size)
{
@@ -86,6 +89,11 @@
char c;
c = *((volatile char *)from);
c = *((volatile char *)from + size - 1);
+
+ if (to_xxx < PAGE_OFFSET) {
+ return kdb_putuserarea_size(to_xxx, from, size);
+ }
+
set_fs(KERNEL_DS);
r = __copy_to_user((void *)to_xxx, from, size);
set_fs(oldfs);
@@ -99,6 +107,11 @@
int r;
*((volatile char *)to) = '\0';
*((volatile char *)to + size - 1) = '\0';
+
+ if (from_xxx < PAGE_OFFSET) {
+ return kdb_getuserarea_size(to, from_xxx, size);
+ }
+
set_fs(KERNEL_DS);
switch (size) {
case 1:
diff -urN -X /home/vamsi/.dontdiff
2420-kdb4.1-pure/include/asm-i386/kmap_types.h
2420-kdb4.1/include/asm-i386/kmap_types.h
--- 2420-kdb4.1-pure/include/asm-i386/kmap_types.h 2003-04-16
18:35:03.000000000 +0530
+++ 2420-kdb4.1/include/asm-i386/kmap_types.h 2003-04-16 18:34:32.000000000
+0530
@@ -8,6 +8,7 @@
KM_USER0,
KM_USER1,
KM_BH_IRQ,
+ KM_KDB,
KM_TYPE_NR
};
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/include/asm-ia64/kdb.h
2420-kdb4.1/include/asm-ia64/kdb.h
--- 2420-kdb4.1-pure/include/asm-ia64/kdb.h 2003-04-16 18:01:01.000000000
+0530
+++ 2420-kdb4.1/include/asm-ia64/kdb.h 2003-04-16 18:57:58.000000000 +0530
@@ -76,6 +76,9 @@
#include <asm/uaccess.h>
+extern int kdb_getuserarea_size(void *, unsigned long, size_t);
+extern int kdb_putuserarea_size(void *, unsigned long, size_t);
+
static inline int
__kdba_putarea_size(unsigned long to_xxx, void *from, size_t size)
{
@@ -84,6 +87,11 @@
char c;
c = *((volatile char *)from);
c = *((volatile char *)from + size - 1);
+
+ if (to_xxx < PAGE_OFFSET) {
+ return kdb_putuserarea_size(to_xxx, from, size);
+ }
+
#ifdef VPERNODE_BASE /* if present, the new CONFIG_NUMA code */
if (to_xxx >= VPERNODE_BASE && to_xxx < VGLOBAL_BASE) {
to_xxx = __imva(to_xxx);
@@ -102,6 +110,11 @@
int r;
*((volatile char *)to) = '\0';
*((volatile char *)to + size - 1) = '\0';
+
+ if (from_xxx < PAGE_OFFSET) {
+ return kdb_getuserarea_size(to, from_xxx, size);
+ }
+
set_fs(KERNEL_DS);
switch (size) {
case 1:
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/include/linux/kdb.h
2420-kdb4.1/include/linux/kdb.h
--- 2420-kdb4.1-pure/include/linux/kdb.h 2003-04-16 18:00:50.000000000
+0530
+++ 2420-kdb4.1/include/linux/kdb.h 2003-04-16 19:07:42.000000000 +0530
@@ -333,4 +333,7 @@
#endif
}
+extern struct task_struct *kdb_current_task;
+extern struct page * kdb_follow_page(struct mm_struct *, unsigned long, int);
/* from mm/memory.c */
+
#endif /* !_KDB_H */
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/kdb/kdbmain.c
2420-kdb4.1/kdb/kdbmain.c
--- 2420-kdb4.1-pure/kdb/kdbmain.c 2003-04-16 18:00:50.000000000 +0530
+++ 2420-kdb4.1/kdb/kdbmain.c 2003-04-16 18:27:44.000000000 +0530
@@ -76,6 +76,8 @@
volatile int kdb_state[NR_CPUS]; /* Per cpu state */
+struct task_struct *kdb_current_task;
+
#ifdef CONFIG_KDB_OFF
int kdb_on = 0; /* Default is off */
#else
@@ -1067,6 +1069,8 @@
kdba_local_arch_setup();
+ kdb_current_task = current;
+
while (1) {
/*
* Initialize pager context.
@@ -2781,6 +2785,59 @@
}
/*
+ * kdb_pid
+ *
+ * This function implements the 'pid' command which switches
+ * the currently active process.
+ *
+ * pid [<pid>]
+ *
+ * Inputs:
+ * argc argument count
+ * argv argument vector
+ * envp environment vector
+ * regs registers at time kdb was entered.
+ * Outputs:
+ * None.
+ * Returns:
+ * zero for success, a kdb diagnostic if error
+ * Locking:
+ * none.
+ * Remarks:
+ */
+
+
+int
+kdb_pid(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+ struct task_struct *p;
+ unsigned long val;
+ int diag;
+
+ if (argc > 1)
+ return KDB_ARGCOUNT;
+
+ if (argc) {
+ diag = kdbgetularg(argv[1], &val);
+ if (diag)
+ return KDB_BADINT;
+
+ p = find_task_by_pid((pid_t)val);
+ if (!p) {
+ kdb_printf("No task with pid=%d\n", (pid_t)val);
+ return 0;
+ }
+
+ kdb_current_task = p;
+ }
+
+ kdb_printf("KDB current process is %s(pid=%d)\n",
kdb_current_task->comm,
+ kdb_current_task->pid);
+
+ return 0;
+}
+
+/*
* kdb_ll
*
* This function implements the 'll' command which follows a linked
@@ -3245,6 +3302,7 @@
kdb_register_repeat("?", kdb_help, "", "Display Help Message",
0, KDB_REPEAT_NONE);
kdb_register_repeat("cpu", kdb_cpu, "<cpunum>","Switch to new cpu", 0,
KDB_REPEAT_NONE);
kdb_register_repeat("ps", kdb_ps, "", "Display active task
list", 0, KDB_REPEAT_NONE);
+ kdb_register_repeat("pid", kdb_pid, "<pidnum>", "Switch to another
task", 0, KDB_REPEAT_NONE);
kdb_register_repeat("reboot", kdb_reboot, "", "Reboot the machine
immediately", 0, KDB_REPEAT_NONE);
kdb_register_repeat("sections", kdb_sections, "", "List kernel and
module sections", 0, KDB_REPEAT_NONE);
#if defined(CONFIG_MODULES)
@@ -3376,6 +3434,8 @@
EXPORT_SYMBOL(kdb_unregister);
EXPORT_SYMBOL(kdb_getarea_size);
EXPORT_SYMBOL(kdb_putarea_size);
+EXPORT_SYMBOL(kdb_getuserarea_size);
+EXPORT_SYMBOL(kdb_putuserarea_size);
EXPORT_SYMBOL(kdb_getword);
EXPORT_SYMBOL(kdb_putword);
EXPORT_SYMBOL(kdbgetularg);
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/kdb/kdbsupport.c
2420-kdb4.1/kdb/kdbsupport.c
--- 2420-kdb4.1-pure/kdb/kdbsupport.c 2003-04-16 18:00:50.000000000 +0530
+++ 2420-kdb4.1/kdb/kdbsupport.c 2003-04-16 19:11:44.000000000 +0530
@@ -40,6 +40,7 @@
#include <linux/kallsyms.h>
#include <linux/stddef.h>
#include <linux/vmalloc.h>
+#include <linux/highmem.h>
#include <asm/uaccess.h>
#include <linux/kdb.h>
@@ -800,3 +801,61 @@
else
kdb_printf("0x%lx\n", val);
}
+
+static struct page * kdb_get_one_user_page(struct task_struct *tsk, unsigned
long start,
+ int len, int write)
+{
+ struct mm_struct *mm = tsk->mm;
+ unsigned int flags;
+ struct vm_area_struct * vma;
+
+ /* shouldn't cross a page boundary. temporary restriction. */
+ if ((start & PAGE_MASK) != ((start+len) & PAGE_MASK)) {
+ kdb_printf("%s: crosses page boundary: addr=%08lx, len=%d\n",
+ __FUNCTION__, start, len);
+ return NULL;
+ }
+
+ start = PAGE_ALIGN(start);
+ flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+
+ vma = find_extend_vma(mm, start);
+
+ /* may be we can allow access to VM_IO pages inside KDB? */
+ if (!vma || (vma->vm_flags & VM_IO) || !(flags & vma->vm_flags))
+ return NULL;
+
+ return kdb_follow_page(mm, start, write);
+}
+
+int kdb_getuserarea_size(void *to, unsigned long from, size_t size)
+{
+ struct page *page;
+ void * vaddr;
+
+ page = kdb_get_one_user_page(kdb_current_task, from, size, 0);
+ if (!page)
+ return size;
+
+ vaddr = kmap_atomic(page, KM_KDB);
+ memcpy(to, vaddr+ (from & (PAGE_SIZE - 1)), size);
+ kunmap_atomic(vaddr, KM_KDB);
+
+ return 0;
+}
+
+int kdb_putuserarea_size(unsigned long to, void *from, size_t size)
+{
+ struct page *page;
+ void * vaddr;
+
+ page = kdb_get_one_user_page(kdb_current_task, to, size, 1);
+ if (!page)
+ return size;
+
+ vaddr = kmap_atomic(page, KM_KDB);
+ memcpy(vaddr+ (to & (PAGE_SIZE - 1)), from, size);
+ kunmap_atomic(vaddr, KM_KDB);
+
+ return 0;
+}
diff -urN -X /home/vamsi/.dontdiff 2420-kdb4.1-pure/mm/memory.c
2420-kdb4.1/mm/memory.c
--- 2420-kdb4.1-pure/mm/memory.c 2003-04-16 18:23:53.000000000 +0530
+++ 2420-kdb4.1/mm/memory.c 2003-04-16 18:44:28.000000000 +0530
@@ -1494,3 +1494,15 @@
}
return page;
}
+
+#ifdef CONFIG_KDB
+struct page * kdb_follow_page(struct mm_struct *mm, unsigned long address, int
write)
+{
+ struct page *page = follow_page(mm, address, write);
+
+ if (!page)
+ return get_page_map(page);
+
+ return page;
+}
+#endif
|