diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-09-29 11:30:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-09-29 11:30:11 -0400 |
| commit | 929675d58c5b4883050804f2b48de2293803862d (patch) | |
| tree | 038755ae54815d19d12873dcb9ac4662c8345ccd | |
| parent | 66120005e65eed8a05b14a36ab448bdec42f0d6b (diff) | |
| parent | 0dca0fd2bfeb99738708d6c9117994ebf398e72c (diff) | |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
kgdboc,tty: Fix tty polling search to use name correctly
kgdb, x86_64: fix PS CS SS registers in gdb serial
kgdb, x86_64: gdb serial has BX and DX reversed
kgdb, x86, arm, mips, powerpc: ignore user space single stepping
kgdb: could not write to the last of valid memory with kgdb
| -rw-r--r-- | arch/arm/kernel/kgdb.c | 2 | ||||
| -rw-r--r-- | arch/mips/kernel/kgdb.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/kernel/kgdb.c | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/kgdb.c | 43 | ||||
| -rw-r--r-- | drivers/char/tty_io.c | 14 | ||||
| -rw-r--r-- | include/asm-x86/kgdb.h | 24 | ||||
| -rw-r--r-- | kernel/kgdb.c | 10 |
7 files changed, 63 insertions, 38 deletions
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index aaffaecffcd1..ba8ccfede964 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
| @@ -111,8 +111,6 @@ int kgdb_arch_handle_exception(int exception_vector, int signo, | |||
| 111 | case 'D': | 111 | case 'D': |
| 112 | case 'k': | 112 | case 'k': |
| 113 | case 'c': | 113 | case 'c': |
| 114 | kgdb_contthread = NULL; | ||
| 115 | |||
| 116 | /* | 114 | /* |
| 117 | * Try to read optional parameter, pc unchanged if no parm. | 115 | * Try to read optional parameter, pc unchanged if no parm. |
| 118 | * If this was a compiled breakpoint, we need to move | 116 | * If this was a compiled breakpoint, we need to move |
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 8f6d58ede33c..6e152c80cd4a 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c | |||
| @@ -236,8 +236,7 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |||
| 236 | 236 | ||
| 237 | atomic_set(&kgdb_cpu_doing_single_step, -1); | 237 | atomic_set(&kgdb_cpu_doing_single_step, -1); |
| 238 | if (remcom_in_buffer[0] == 's') | 238 | if (remcom_in_buffer[0] == 's') |
| 239 | if (kgdb_contthread) | 239 | atomic_set(&kgdb_cpu_doing_single_step, cpu); |
| 240 | atomic_set(&kgdb_cpu_doing_single_step, cpu); | ||
| 241 | 240 | ||
| 242 | return 0; | 241 | return 0; |
| 243 | } | 242 | } |
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index b4fdf2f2743c..fe8f71dd0b3f 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c | |||
| @@ -347,9 +347,8 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |||
| 347 | linux_regs->msr |= MSR_SE; | 347 | linux_regs->msr |= MSR_SE; |
| 348 | #endif | 348 | #endif |
| 349 | kgdb_single_step = 1; | 349 | kgdb_single_step = 1; |
| 350 | if (kgdb_contthread) | 350 | atomic_set(&kgdb_cpu_doing_single_step, |
| 351 | atomic_set(&kgdb_cpu_doing_single_step, | 351 | raw_smp_processor_id()); |
| 352 | raw_smp_processor_id()); | ||
| 353 | } | 352 | } |
| 354 | return 0; | 353 | return 0; |
| 355 | } | 354 | } |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index f47f0eb886b8..8282a2139681 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
| @@ -69,6 +69,9 @@ static int gdb_x86vector = -1; | |||
| 69 | */ | 69 | */ |
| 70 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 70 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 71 | { | 71 | { |
| 72 | #ifndef CONFIG_X86_32 | ||
| 73 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
| 74 | #endif | ||
| 72 | gdb_regs[GDB_AX] = regs->ax; | 75 | gdb_regs[GDB_AX] = regs->ax; |
| 73 | gdb_regs[GDB_BX] = regs->bx; | 76 | gdb_regs[GDB_BX] = regs->bx; |
| 74 | gdb_regs[GDB_CX] = regs->cx; | 77 | gdb_regs[GDB_CX] = regs->cx; |
| @@ -76,9 +79,9 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 76 | gdb_regs[GDB_SI] = regs->si; | 79 | gdb_regs[GDB_SI] = regs->si; |
| 77 | gdb_regs[GDB_DI] = regs->di; | 80 | gdb_regs[GDB_DI] = regs->di; |
| 78 | gdb_regs[GDB_BP] = regs->bp; | 81 | gdb_regs[GDB_BP] = regs->bp; |
| 79 | gdb_regs[GDB_PS] = regs->flags; | ||
| 80 | gdb_regs[GDB_PC] = regs->ip; | 82 | gdb_regs[GDB_PC] = regs->ip; |
| 81 | #ifdef CONFIG_X86_32 | 83 | #ifdef CONFIG_X86_32 |
| 84 | gdb_regs[GDB_PS] = regs->flags; | ||
| 82 | gdb_regs[GDB_DS] = regs->ds; | 85 | gdb_regs[GDB_DS] = regs->ds; |
| 83 | gdb_regs[GDB_ES] = regs->es; | 86 | gdb_regs[GDB_ES] = regs->es; |
| 84 | gdb_regs[GDB_CS] = regs->cs; | 87 | gdb_regs[GDB_CS] = regs->cs; |
| @@ -94,6 +97,9 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 94 | gdb_regs[GDB_R13] = regs->r13; | 97 | gdb_regs[GDB_R13] = regs->r13; |
| 95 | gdb_regs[GDB_R14] = regs->r14; | 98 | gdb_regs[GDB_R14] = regs->r14; |
| 96 | gdb_regs[GDB_R15] = regs->r15; | 99 | gdb_regs[GDB_R15] = regs->r15; |
| 100 | gdb_regs32[GDB_PS] = regs->flags; | ||
| 101 | gdb_regs32[GDB_CS] = regs->cs; | ||
| 102 | gdb_regs32[GDB_SS] = regs->ss; | ||
| 97 | #endif | 103 | #endif |
| 98 | gdb_regs[GDB_SP] = regs->sp; | 104 | gdb_regs[GDB_SP] = regs->sp; |
| 99 | } | 105 | } |
| @@ -112,6 +118,9 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 112 | */ | 118 | */ |
| 113 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | 119 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) |
| 114 | { | 120 | { |
| 121 | #ifndef CONFIG_X86_32 | ||
| 122 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
| 123 | #endif | ||
| 115 | gdb_regs[GDB_AX] = 0; | 124 | gdb_regs[GDB_AX] = 0; |
| 116 | gdb_regs[GDB_BX] = 0; | 125 | gdb_regs[GDB_BX] = 0; |
| 117 | gdb_regs[GDB_CX] = 0; | 126 | gdb_regs[GDB_CX] = 0; |
| @@ -129,8 +138,10 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 129 | gdb_regs[GDB_FS] = 0xFFFF; | 138 | gdb_regs[GDB_FS] = 0xFFFF; |
| 130 | gdb_regs[GDB_GS] = 0xFFFF; | 139 | gdb_regs[GDB_GS] = 0xFFFF; |
| 131 | #else | 140 | #else |
| 132 | gdb_regs[GDB_PS] = *(unsigned long *)(p->thread.sp + 8); | 141 | gdb_regs32[GDB_PS] = *(unsigned long *)(p->thread.sp + 8); |
| 133 | gdb_regs[GDB_PC] = 0; | 142 | gdb_regs32[GDB_CS] = __KERNEL_CS; |
| 143 | gdb_regs32[GDB_SS] = __KERNEL_DS; | ||
| 144 | gdb_regs[GDB_PC] = p->thread.ip; | ||
| 134 | gdb_regs[GDB_R8] = 0; | 145 | gdb_regs[GDB_R8] = 0; |
| 135 | gdb_regs[GDB_R9] = 0; | 146 | gdb_regs[GDB_R9] = 0; |
| 136 | gdb_regs[GDB_R10] = 0; | 147 | gdb_regs[GDB_R10] = 0; |
| @@ -153,6 +164,9 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 153 | */ | 164 | */ |
| 154 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 165 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 155 | { | 166 | { |
| 167 | #ifndef CONFIG_X86_32 | ||
| 168 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
| 169 | #endif | ||
| 156 | regs->ax = gdb_regs[GDB_AX]; | 170 | regs->ax = gdb_regs[GDB_AX]; |
| 157 | regs->bx = gdb_regs[GDB_BX]; | 171 | regs->bx = gdb_regs[GDB_BX]; |
| 158 | regs->cx = gdb_regs[GDB_CX]; | 172 | regs->cx = gdb_regs[GDB_CX]; |
| @@ -160,9 +174,9 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 160 | regs->si = gdb_regs[GDB_SI]; | 174 | regs->si = gdb_regs[GDB_SI]; |
| 161 | regs->di = gdb_regs[GDB_DI]; | 175 | regs->di = gdb_regs[GDB_DI]; |
| 162 | regs->bp = gdb_regs[GDB_BP]; | 176 | regs->bp = gdb_regs[GDB_BP]; |
| 163 | regs->flags = gdb_regs[GDB_PS]; | ||
| 164 | regs->ip = gdb_regs[GDB_PC]; | 177 | regs->ip = gdb_regs[GDB_PC]; |
| 165 | #ifdef CONFIG_X86_32 | 178 | #ifdef CONFIG_X86_32 |
| 179 | regs->flags = gdb_regs[GDB_PS]; | ||
| 166 | regs->ds = gdb_regs[GDB_DS]; | 180 | regs->ds = gdb_regs[GDB_DS]; |
| 167 | regs->es = gdb_regs[GDB_ES]; | 181 | regs->es = gdb_regs[GDB_ES]; |
| 168 | regs->cs = gdb_regs[GDB_CS]; | 182 | regs->cs = gdb_regs[GDB_CS]; |
| @@ -175,6 +189,9 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 175 | regs->r13 = gdb_regs[GDB_R13]; | 189 | regs->r13 = gdb_regs[GDB_R13]; |
| 176 | regs->r14 = gdb_regs[GDB_R14]; | 190 | regs->r14 = gdb_regs[GDB_R14]; |
| 177 | regs->r15 = gdb_regs[GDB_R15]; | 191 | regs->r15 = gdb_regs[GDB_R15]; |
| 192 | regs->flags = gdb_regs32[GDB_PS]; | ||
| 193 | regs->cs = gdb_regs32[GDB_CS]; | ||
| 194 | regs->ss = gdb_regs32[GDB_SS]; | ||
| 178 | #endif | 195 | #endif |
| 179 | } | 196 | } |
| 180 | 197 | ||
| @@ -378,10 +395,8 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
| 378 | if (remcomInBuffer[0] == 's') { | 395 | if (remcomInBuffer[0] == 's') { |
| 379 | linux_regs->flags |= X86_EFLAGS_TF; | 396 | linux_regs->flags |= X86_EFLAGS_TF; |
| 380 | kgdb_single_step = 1; | 397 | kgdb_single_step = 1; |
| 381 | if (kgdb_contthread) { | 398 | atomic_set(&kgdb_cpu_doing_single_step, |
| 382 | atomic_set(&kgdb_cpu_doing_single_step, | 399 | raw_smp_processor_id()); |
| 383 | raw_smp_processor_id()); | ||
| 384 | } | ||
| 385 | } | 400 | } |
| 386 | 401 | ||
| 387 | get_debugreg(dr6, 6); | 402 | get_debugreg(dr6, 6); |
| @@ -466,9 +481,15 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) | |||
| 466 | 481 | ||
| 467 | case DIE_DEBUG: | 482 | case DIE_DEBUG: |
| 468 | if (atomic_read(&kgdb_cpu_doing_single_step) == | 483 | if (atomic_read(&kgdb_cpu_doing_single_step) == |
| 469 | raw_smp_processor_id() && | 484 | raw_smp_processor_id()) { |
| 470 | user_mode(regs)) | 485 | if (user_mode(regs)) |
| 471 | return single_step_cont(regs, args); | 486 | return single_step_cont(regs, args); |
| 487 | break; | ||
| 488 | } else if (test_thread_flag(TIF_SINGLESTEP)) | ||
| 489 | /* This means a user thread is single stepping | ||
| 490 | * a system call which should be ignored | ||
| 491 | */ | ||
| 492 | return NOTIFY_DONE; | ||
| 472 | /* fall through */ | 493 | /* fall through */ |
| 473 | default: | 494 | default: |
| 474 | if (user_mode(regs)) | 495 | if (user_mode(regs)) |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index daeb8f766971..e4dce8709541 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -695,13 +695,23 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) | |||
| 695 | { | 695 | { |
| 696 | struct tty_driver *p, *res = NULL; | 696 | struct tty_driver *p, *res = NULL; |
| 697 | int tty_line = 0; | 697 | int tty_line = 0; |
| 698 | int len; | ||
| 698 | char *str; | 699 | char *str; |
| 699 | 700 | ||
| 701 | for (str = name; *str; str++) | ||
| 702 | if ((*str >= '0' && *str <= '9') || *str == ',') | ||
| 703 | break; | ||
| 704 | if (!*str) | ||
| 705 | return NULL; | ||
| 706 | |||
| 707 | len = str - name; | ||
| 708 | tty_line = simple_strtoul(str, &str, 10); | ||
| 709 | |||
| 700 | mutex_lock(&tty_mutex); | 710 | mutex_lock(&tty_mutex); |
| 701 | /* Search through the tty devices to look for a match */ | 711 | /* Search through the tty devices to look for a match */ |
| 702 | list_for_each_entry(p, &tty_drivers, tty_drivers) { | 712 | list_for_each_entry(p, &tty_drivers, tty_drivers) { |
| 703 | str = name + strlen(p->name); | 713 | if (strncmp(name, p->name, len) != 0) |
| 704 | tty_line = simple_strtoul(str, &str, 10); | 714 | continue; |
| 705 | if (*str == ',') | 715 | if (*str == ',') |
| 706 | str++; | 716 | str++; |
| 707 | if (*str == '\0') | 717 | if (*str == '\0') |
diff --git a/include/asm-x86/kgdb.h b/include/asm-x86/kgdb.h index 484c47554f3b..94d63db10365 100644 --- a/include/asm-x86/kgdb.h +++ b/include/asm-x86/kgdb.h | |||
| @@ -39,12 +39,13 @@ enum regnames { | |||
| 39 | GDB_FS, /* 14 */ | 39 | GDB_FS, /* 14 */ |
| 40 | GDB_GS, /* 15 */ | 40 | GDB_GS, /* 15 */ |
| 41 | }; | 41 | }; |
| 42 | #define NUMREGBYTES ((GDB_GS+1)*4) | ||
| 42 | #else /* ! CONFIG_X86_32 */ | 43 | #else /* ! CONFIG_X86_32 */ |
| 43 | enum regnames { | 44 | enum regnames64 { |
| 44 | GDB_AX, /* 0 */ | 45 | GDB_AX, /* 0 */ |
| 45 | GDB_DX, /* 1 */ | 46 | GDB_BX, /* 1 */ |
| 46 | GDB_CX, /* 2 */ | 47 | GDB_CX, /* 2 */ |
| 47 | GDB_BX, /* 3 */ | 48 | GDB_DX, /* 3 */ |
| 48 | GDB_SI, /* 4 */ | 49 | GDB_SI, /* 4 */ |
| 49 | GDB_DI, /* 5 */ | 50 | GDB_DI, /* 5 */ |
| 50 | GDB_BP, /* 6 */ | 51 | GDB_BP, /* 6 */ |
| @@ -58,18 +59,15 @@ enum regnames { | |||
| 58 | GDB_R14, /* 14 */ | 59 | GDB_R14, /* 14 */ |
| 59 | GDB_R15, /* 15 */ | 60 | GDB_R15, /* 15 */ |
| 60 | GDB_PC, /* 16 */ | 61 | GDB_PC, /* 16 */ |
| 61 | GDB_PS, /* 17 */ | ||
| 62 | }; | 62 | }; |
| 63 | #endif /* CONFIG_X86_32 */ | ||
| 64 | 63 | ||
| 65 | /* | 64 | enum regnames32 { |
| 66 | * Number of bytes of registers: | 65 | GDB_PS = 34, |
| 67 | */ | 66 | GDB_CS, |
| 68 | #ifdef CONFIG_X86_32 | 67 | GDB_SS, |
| 69 | # define NUMREGBYTES 64 | 68 | }; |
| 70 | #else | 69 | #define NUMREGBYTES ((GDB_SS+1)*4) |
| 71 | # define NUMREGBYTES ((GDB_PS+1)*8) | 70 | #endif /* CONFIG_X86_32 */ |
| 72 | #endif | ||
| 73 | 71 | ||
| 74 | static inline void arch_kgdb_breakpoint(void) | 72 | static inline void arch_kgdb_breakpoint(void) |
| 75 | { | 73 | { |
diff --git a/kernel/kgdb.c b/kernel/kgdb.c index eaa21fc9ad1d..25d955dbb989 100644 --- a/kernel/kgdb.c +++ b/kernel/kgdb.c | |||
| @@ -488,7 +488,7 @@ static int write_mem_msg(int binary) | |||
| 488 | if (err) | 488 | if (err) |
| 489 | return err; | 489 | return err; |
| 490 | if (CACHE_FLUSH_IS_SAFE) | 490 | if (CACHE_FLUSH_IS_SAFE) |
| 491 | flush_icache_range(addr, addr + length + 1); | 491 | flush_icache_range(addr, addr + length); |
| 492 | return 0; | 492 | return 0; |
| 493 | } | 493 | } |
| 494 | 494 | ||
| @@ -1462,7 +1462,7 @@ acquirelock: | |||
| 1462 | * Get the passive CPU lock which will hold all the non-primary | 1462 | * Get the passive CPU lock which will hold all the non-primary |
| 1463 | * CPU in a spin state while the debugger is active | 1463 | * CPU in a spin state while the debugger is active |
| 1464 | */ | 1464 | */ |
| 1465 | if (!kgdb_single_step || !kgdb_contthread) { | 1465 | if (!kgdb_single_step) { |
| 1466 | for (i = 0; i < NR_CPUS; i++) | 1466 | for (i = 0; i < NR_CPUS; i++) |
| 1467 | atomic_set(&passive_cpu_wait[i], 1); | 1467 | atomic_set(&passive_cpu_wait[i], 1); |
| 1468 | } | 1468 | } |
| @@ -1475,7 +1475,7 @@ acquirelock: | |||
| 1475 | 1475 | ||
| 1476 | #ifdef CONFIG_SMP | 1476 | #ifdef CONFIG_SMP |
| 1477 | /* Signal the other CPUs to enter kgdb_wait() */ | 1477 | /* Signal the other CPUs to enter kgdb_wait() */ |
| 1478 | if ((!kgdb_single_step || !kgdb_contthread) && kgdb_do_roundup) | 1478 | if ((!kgdb_single_step) && kgdb_do_roundup) |
| 1479 | kgdb_roundup_cpus(flags); | 1479 | kgdb_roundup_cpus(flags); |
| 1480 | #endif | 1480 | #endif |
| 1481 | 1481 | ||
| @@ -1494,7 +1494,7 @@ acquirelock: | |||
| 1494 | kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code); | 1494 | kgdb_post_primary_code(ks->linux_regs, ks->ex_vector, ks->err_code); |
| 1495 | kgdb_deactivate_sw_breakpoints(); | 1495 | kgdb_deactivate_sw_breakpoints(); |
| 1496 | kgdb_single_step = 0; | 1496 | kgdb_single_step = 0; |
| 1497 | kgdb_contthread = NULL; | 1497 | kgdb_contthread = current; |
| 1498 | exception_level = 0; | 1498 | exception_level = 0; |
| 1499 | 1499 | ||
| 1500 | /* Talk to debugger with gdbserial protocol */ | 1500 | /* Talk to debugger with gdbserial protocol */ |
| @@ -1508,7 +1508,7 @@ acquirelock: | |||
| 1508 | kgdb_info[ks->cpu].task = NULL; | 1508 | kgdb_info[ks->cpu].task = NULL; |
| 1509 | atomic_set(&cpu_in_kgdb[ks->cpu], 0); | 1509 | atomic_set(&cpu_in_kgdb[ks->cpu], 0); |
| 1510 | 1510 | ||
| 1511 | if (!kgdb_single_step || !kgdb_contthread) { | 1511 | if (!kgdb_single_step) { |
| 1512 | for (i = NR_CPUS-1; i >= 0; i--) | 1512 | for (i = NR_CPUS-1; i >= 0; i--) |
| 1513 | atomic_set(&passive_cpu_wait[i], 0); | 1513 | atomic_set(&passive_cpu_wait[i], 0); |
| 1514 | /* | 1514 | /* |
