From: Hirokazu Takata <takata@linux-m32r.org> This patch updates ptrace.c to support multithread debugging. So far, only one breakpoint's location was kept by kernel, however, in the multithreaded application's debug, it is required to kept multi-point breakpoint locations by kernel. In this implementation, maximum number of MAX_TRAPS(=10 (by default)) breakpoint's information will be kept in the "debug_trap" member of the thread_struct for each thread. * include/asm-m32r/processor.h: Modify debug_trap struct to keep multipoint breakpoint locations for multithread debugging. * arch/m32r/kernel/ptrace.c: - Update to support multithread debugging. - Remove unused functions, withdraw_debug_trap_for_signal() and embed_debug_trap_for_signal(). Signed-off-by: Kei Sakamoto <ksakamot@linux-m32r.org> Signed-off-by: Hirokazu Takata <takata@linux-m32r.org> Signed-off-by: Andrew Morton <akpm@osdl.org> --- 25-akpm/arch/m32r/kernel/ptrace.c | 89 +++++++++++------------------------ 25-akpm/include/asm-m32r/processor.h | 6 +- 2 files changed, 34 insertions(+), 61 deletions(-) diff -puN arch/m32r/kernel/ptrace.c~m32r-update-ptracec-for-multithread arch/m32r/kernel/ptrace.c --- 25/arch/m32r/kernel/ptrace.c~m32r-update-ptracec-for-multithread Thu Dec 16 15:18:33 2004 +++ 25-akpm/arch/m32r/kernel/ptrace.c Thu Dec 16 15:18:33 2004 @@ -2,7 +2,7 @@ * linux/arch/m32r/kernel/ptrace.c * * Copyright (C) 2002 Hirokazu Takata, Takeo Takahashi - * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> + * Copyright (C) 2004 Hirokazu Takata, Kei Sakamoto * * Original x86 implementation: * By Ross Biro 1/23/92 @@ -450,13 +450,13 @@ register_debug_trap(struct task_struct * struct debug_trap *p = &child->thread.debug_trap; unsigned long addr = next_pc & ~3; - if (p->nr_trap != 0) { + if (p->nr_trap == MAX_TRAPS) { printk("kernel BUG at %s %d: p->nr_trap = %d\n", __FILE__, __LINE__, p->nr_trap); return -1; } - p->addr = addr; - p->insn = next_insn; + p->addr[p->nr_trap] = addr; + p->insn[p->nr_trap] = next_insn; p->nr_trap++; if (next_pc & 3) { *code = (next_insn & 0xffff0000) | 0x10f1; @@ -473,35 +473,34 @@ register_debug_trap(struct task_struct * return 0; } -int withdraw_debug_trap_for_signal(struct task_struct *child) -{ - struct debug_trap *p = &child->thread.debug_trap; - int nr_trap = p->nr_trap; - - if (nr_trap) { - access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1); - p->nr_trap = 0; - p->addr = 0; - p->insn = 0; - } - return nr_trap; -} - static int unregister_debug_trap(struct task_struct *child, unsigned long addr, unsigned long *code) { struct debug_trap *p = &child->thread.debug_trap; + int i; - if (p->nr_trap != 1 || p->addr != addr) { + /* Search debug trap entry. */ + for (i = 0; i < p->nr_trap; i++) { + if (p->addr[i] == addr) + break; + } + if (i >= p->nr_trap) { /* The trap may be requested from debugger. * ptrace should do nothing in this case. */ return 0; } - *code = p->insn; - p->insn = 0; - p->addr = 0; + + /* Recover orignal instruction code. */ + *code = p->insn[i]; + + /* Shift debug trap entries. */ + while (i < p->nr_trap - 1) { + p->insn[i] = p->insn[i + 1]; + p->addr[i] = p->addr[i + 1]; + i++; + } p->nr_trap--; return 1; } @@ -510,13 +509,11 @@ static void unregister_all_debug_traps(struct task_struct *child) { struct debug_trap *p = &child->thread.debug_trap; + int i; - if (p->nr_trap) { - access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1); - p->addr = 0; - p->insn = 0; - p->nr_trap = 0; - } + for (i = 0; i < p->nr_trap; i++) + access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1); + p->nr_trap = 0; } static inline void @@ -576,34 +573,6 @@ embed_debug_trap(struct task_struct *chi } void -embed_debug_trap_for_signal(struct task_struct *child) -{ - unsigned long next_pc; - unsigned long pc, insn; - int ret; - - pc = get_stack_long(child, PT_BPC); - ret = access_process_vm(child, pc&~3, &insn, sizeof(insn), 0); - if (ret != sizeof(insn)) { - printk("kernel BUG at %s %d: access_process_vm returns %d\n", - __FILE__, __LINE__, ret); - return; - } - compute_next_pc(insn, pc, &next_pc, child); - if (next_pc & 0x80000000) { - printk("kernel BUG at %s %d: next_pc = 0x%08x\n", - __FILE__, __LINE__, (int)next_pc); - return; - } - if (embed_debug_trap(child, next_pc)) { - printk("kernel BUG at %s %d: embed_debug_trap error\n", - __FILE__, __LINE__); - return; - } - invalidate_cache(); -} - -void withdraw_debug_trap(struct pt_regs *regs) { unsigned long addr; @@ -621,9 +590,12 @@ static void init_debug_traps(struct task_struct *child) { struct debug_trap *p = &child->thread.debug_trap; + int i; p->nr_trap = 0; - p->addr = 0; - p->insn = 0; + for (i = 0; i < MAX_TRAPS; i++) { + p->addr[i] = 0; + p->insn[i] = 0; + } } @@ -855,4 +827,3 @@ void do_syscall_trace(void) current->exit_code = 0; } } - diff -puN include/asm-m32r/processor.h~m32r-update-ptracec-for-multithread include/asm-m32r/processor.h --- 25/include/asm-m32r/processor.h~m32r-update-ptracec-for-multithread Thu Dec 16 15:18:33 2004 +++ 25-akpm/include/asm-m32r/processor.h Thu Dec 16 15:18:33 2004 @@ -70,10 +70,12 @@ typedef struct { unsigned long seg; } mm_segment_t; +#define MAX_TRAPS 10 + struct debug_trap { int nr_trap; - unsigned long addr; - unsigned long insn; + unsigned long addr[MAX_TRAPS]; + unsigned long insn[MAX_TRAPS]; }; struct thread_struct { _