[Kgdb-bugreport] [PATCH] kgdb_roundup_cpus() with 'O' packets
Status: Beta
Brought to you by:
jwessel
From: Tom R. <tr...@ke...> - 2004-11-30 16:17:14
|
So, here's what I'd like to commit. We always call kgdb_roundup_cpus(), we provide a weak version, and a send_IPI_allbutself(...) version on i386/x86_64, which can be expanded to be more robust if needed, wait 'a bit' to try and catch NR_CPUS and if we fail, we send an 'O' packet, and only an 'O' packet, once. This doesn't get lost by GDB since we've waited for GDB to make a request, and the protocol says that on a '?' GDB must parse O packets and wait for a real answer to come, so it's protocol-safe. I've changed my mind about printk'ing, since it's too much of a headache to make sure we don't accidently goof the machine, and printk isn't 'reliable' here. --- linux-2.6.10-rc2/include/linux/kgdb.h +++ linux-2.6.10-rc2/include/linux/kgdb.h @@ -115,7 +115,7 @@ * kgdb hook. */ extern int kgdb_arch_handle_exception(int vector, int signo, int err_code, - char *InBuffer, char *outBuffer, + char *inBuffer, char *outBuffer, struct pt_regs *regs); /* Optional functions. */ @@ -123,6 +123,7 @@ extern void kgdb_disable_hw_debug(struct pt_regs *regs); extern void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code); +extern void kgdb_roundup_cpus(void); extern int kgdb_set_hw_break(unsigned long addr); extern int kgdb_remove_hw_break(unsigned long addr); extern void kgdb_remove_all_hw_break(void); --- linux-2.6.10-rc2/kernel/kgdb.c +++ linux-2.6.10-rc2/kernel/kgdb.c @@ -59,6 +59,8 @@ extern int pid_max; extern int pidhash_init_done; +/* How many times to count all of the waiting CPUs */ +#define ROUNDUP_WAIT 64000 #define BUF_THREAD_ID_SIZE 16 /* @@ -195,6 +197,18 @@ } /** + * kgdb_roundup_cpus - Get other CPUs into a holding pattern + * + * On SMP systems, we need to get the attention of the other CPUs + * and get them be in a known state. This should do what is needed + * to get the other CPUs to call kgdb_wait(). + */ +void __attribute__ ((weak)) + kgdb_roundup_cpus(void) +{ +} + +/** * kgdb_shadowinfo - Get shadowed information on @threadid. * @regs: The &struct pt_regs of the current process. * @buffer: A buffer of %BUFMAX size. @@ -543,7 +557,7 @@ } /* Wait till master processor is done with debugging */ - spin_lock(slavecpulocks + processor); + spin_lock(slavecpulocks[processor]); /* This has been taken from x86 kgdb implementation and * will be needed by architectures that have SMP support @@ -555,7 +569,7 @@ /* Signal the master processor that we are done */ procindebug[processor] = 0; - spin_unlock(slavecpulocks + processor); + spin_unlock(slavecpulocks[processor]); local_irq_restore(flags); } #endif @@ -697,6 +711,42 @@ return pid_max + smp_processor_id(); } +#define MAXOUT ((BUFMAX - 2) / 2) + +static char gdbmsgbuf[BUFMAX + 1]; +static void kgdb_msg_write(const char *s) +{ + int i; + int wcount, len; + char *bufptr; + + /* 'O'utput */ + gdbmsgbuf[0] = 'O'; + + /* How long of a string. */ + len = strlen(s); + + /* Fill and send buffers... */ + while (len > 0) { + bufptr = gdbmsgbuf + 1; + + /* Calculate how many this time */ + wcount = (len > MAXOUT) ? MAXOUT : len; + + /* Pack in hex chars */ + for (i = 0; i < wcount; i++) + bufptr = pack_hex_byte(bufptr, s[i]); + *bufptr = '\0'; + + /* Move up */ + s += wcount; + len -= wcount; + + /* Write packet */ + put_packet(gdbmsgbuf); + } +} + /* * This function does all command procesing for interfacing to gdb. * @@ -704,6 +754,10 @@ * interface locks, if any (begin_session) * kgdb lock (debugger_active) * + * Note that since we can be in here prior to our cpumask being filled + * out, which err on the side of caution and loop over NR_CPUS instead + * of a for_each_online_cpu. + * */ int kgdb_handle_exception(int exVector, int signo, int err_code, struct pt_regs *linux_regs) @@ -718,7 +772,7 @@ unsigned procid; int numshadowth = num_online_cpus() + kgdb_ops->shadowth; long kgdb_usethreadid = 0; - int error = 0; + int error = 0, all_cpus_rounded = 0; struct pt_regs *shadowregs; int processor = smp_processor_id(); void * local_debuggerinfo; @@ -753,20 +807,37 @@ goto acquirelock; } - kgdb_info[processor].debuggerinfo = linux_regs; + kgdb_info[processor].debuggerinfo = linux_regs; kgdb_info[processor].task = current; kgdb_disable_hw_debug(linux_regs); - if(!debugger_step || !kgdb_contthread) { - for (i = 0; i < num_online_cpus(); i++) + if (!debugger_step || !kgdb_contthread) + for (i = 0; i < NR_CPUS; i++) spin_lock(&slavecpulocks[i]); - } + + /* Make sure we get the other CPUs */ + kgdb_roundup_cpus(); /* spin_lock code is good enough as a barrier so we don't * need one here */ procindebug[smp_processor_id()] = 1; + /* Wait a reasonable time for the other CPUs to be notified and + * be waiting for us. Very early on this could be imperfect + * as num_online_cpus() could be 0.*/ + for (i = 0; i < ROUNDUP_WAIT; i++) { + int cpu, num = 0; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (procindebug[cpu]) + num++; + } + if (num >= num_online_cpus()) { + all_cpus_rounded = 1; + break; + } + } + /* Clear the out buffer. */ memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); @@ -809,6 +880,12 @@ * we clear out our breakpoints now incase * GDB is reconnecting. */ remove_all_break(); + /* Also, if we haven't been able to roundup all + * CPUs, send an 'O' packet informing the user + * as much. Only need to do this once. */ + if (!all_cpus_rounded) + kgdb_msg_write("Not all CPUs have been" + "synced for KGDB\n"); remcom_out_buffer[0] = 'S'; remcom_out_buffer[1] = hexchars[signo >> 4]; remcom_out_buffer[2] = hexchars[signo % 16]; @@ -915,12 +992,14 @@ kgdb_connected = 0; } put_packet(remcom_out_buffer); + all_cpus_rounded = 0; goto default_handle; case 'k': /* Don't care about error from remove_all_break */ remove_all_break(); kgdb_connected = 0; + all_cpus_rounded = 0; goto default_handle; /* query */ @@ -1144,12 +1223,12 @@ procindebug[smp_processor_id()] = 0; if (!debugger_step || !kgdb_contthread) { - for (i = 0; i < num_online_cpus(); i++) - spin_unlock(&slavecpulocks[i]); + for (i = 0; i < NR_CPUS; i++) + spin_unlock(&slavecpulocks[i]); /* Wait till all the processors have quit - * from the debugger - */ - for_each_online_cpu (i) { + * from the debugger. + */ + for (i = 0; i < NR_CPUS; i++) { while (procindebug[i]) { int j = 10; /* an arbitrary number */ --- linux-2.6.10-rc2/arch/i386/kernel/kgdb.c +++ linux-2.6.10-rc2/arch/i386/kernel/kgdb.c @@ -37,9 +37,12 @@ #include <asm/ptrace.h> /* for linux pt_regs struct */ #include <linux/kgdb.h> #include <linux/init.h> +#include <asm/apicdef.h> #include <asm/desc.h> #include <asm/kdebug.h> +#include "mach_ipi.h" + /* Put the error code here just in case the user cares. */ int gdb_i386errcode; /* Likewise, the vector number here (since GDB only gets the signal @@ -194,6 +197,11 @@ gdb_i386errcode = err_code; } +void kgdb_roundup_cpus(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + int kgdb_arch_handle_exception(int exceptionVector, int signo, int err_code, char *remcom_in_buffer, char *remcom_out_buffer, --- linux-2.6.10-rc2/arch/x86_64/kernel/kgdb.c +++ linux-2.6.10-rc2/arch/x86_64/kernel/kgdb.c @@ -39,6 +39,7 @@ #include <asm/ptrace.h> /* for linux pt_regs struct */ #include <linux/kgdb.h> #include <linux/init.h> +#include <asm/mach_apic.h> #include <asm/kdebug.h> /* Put the error code here just in case the user cares. */ @@ -260,6 +261,11 @@ gdb_x86_64errcode = err_code; } +void kgdb_roundup_cpus(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + int kgdb_arch_handle_exception(int exceptionVector, int signo, int err_code, char *remcomInBuffer, char *remcomOutBuffer, struct pt_regs *linux_regs) -- Tom Rini http://gate.crashing.org/~trini/ |