Skip to content

Commit

Permalink
kgdb: fix gdb serial thread queries
Browse files Browse the repository at this point in the history
The command "info threads" did not work correctly with kgdb.  It would
result in a silent kernel hang if used.

This patach addresses several problems.
 - Fix use of deprecated NR_CPUS
 - Fix kgdb to not walk linearly through the pid space
 - Correctly implement shadow pids
 - Change the threads per query to a #define
 - Fix kgdb_hex2long to work with negated values

The threads 0 and -1 are reserved to represent the current task.  That
means that CPU 0 will start with a shadow thread id of -2, and CPU 1
will have a shadow thread id of -3, etc...

From the debugger you can switch to a shadow thread to see what one of
the other cpus was doing, however it is not possible to execute run
control operations on any other cpu execept the cpu executing the
kgdb_handle_exception().

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
  • Loading branch information
Jason Wessel committed Aug 1, 2008
1 parent a9b60bf commit 25fc999
Showing 1 changed file with 50 additions and 18 deletions.
68 changes: 50 additions & 18 deletions kernel/kgdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@

static int kgdb_break_asap;

#define KGDB_MAX_THREAD_QUERY 17
struct kgdb_state {
int ex_vector;
int signo;
int err_code;
int cpu;
int pass_exception;
unsigned long thr_query;
unsigned long threadid;
long kgdb_usethreadid;
struct pt_regs *linux_regs;
Expand Down Expand Up @@ -445,9 +447,14 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
{
int hex_val;
int num = 0;
int negate = 0;

*long_val = 0;

if (**ptr == '-') {
negate = 1;
(*ptr)++;
}
while (**ptr) {
hex_val = hex(**ptr);
if (hex_val < 0)
Expand All @@ -458,6 +465,9 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
(*ptr)++;
}

if (negate)
*long_val = -*long_val;

return num;
}

Expand Down Expand Up @@ -527,10 +537,16 @@ static void int_to_threadref(unsigned char *id, int value)
static struct task_struct *getthread(struct pt_regs *regs, int tid)
{
/*
* Non-positive TIDs are remapped idle tasks:
* Non-positive TIDs are remapped to the cpu shadow information
*/
if (tid <= 0)
return idle_task(-tid);
if (tid == 0 || tid == -1)
tid = -atomic_read(&kgdb_active) - 2;
if (tid < 0) {
if (kgdb_info[-tid - 2].task)
return kgdb_info[-tid - 2].task;
else
return idle_task(-tid - 2);
}

/*
* find_task_by_pid_ns() does not take the tasklist lock anymore
Expand Down Expand Up @@ -737,14 +753,15 @@ static int remove_all_break(void)
}

/*
* Remap normal tasks to their real PID, idle tasks to -1 ... -NR_CPUs:
* Remap normal tasks to their real PID,
* CPU shadow threads are mapped to -CPU - 2
*/
static inline int shadow_pid(int realpid)
{
if (realpid)
return realpid;

return -1-raw_smp_processor_id();
return -raw_smp_processor_id() - 2;
}

static char gdbmsgbuf[BUFMAX + 1];
Expand Down Expand Up @@ -838,7 +855,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)
local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo;
} else {
local_debuggerinfo = NULL;
for (i = 0; i < NR_CPUS; i++) {
for_each_online_cpu(i) {
/*
* Try to find the task on some other
* or possibly this node if we do not
Expand Down Expand Up @@ -972,10 +989,13 @@ static int gdb_cmd_reboot(struct kgdb_state *ks)
/* Handle the 'q' query packets */
static void gdb_cmd_query(struct kgdb_state *ks)
{
struct task_struct *thread;
struct task_struct *g;
struct task_struct *p;
unsigned char thref[8];
char *ptr;
int i;
int cpu;
int finished = 0;

switch (remcom_in_buffer[1]) {
case 's':
Expand All @@ -985,22 +1005,34 @@ static void gdb_cmd_query(struct kgdb_state *ks)
break;
}

if (remcom_in_buffer[1] == 'f')
ks->threadid = 1;

i = 0;
remcom_out_buffer[0] = 'm';
ptr = remcom_out_buffer + 1;

for (i = 0; i < 17; ks->threadid++) {
thread = getthread(ks->linux_regs, ks->threadid);
if (thread) {
int_to_threadref(thref, ks->threadid);
if (remcom_in_buffer[1] == 'f') {
/* Each cpu is a shadow thread */
for_each_online_cpu(cpu) {
ks->thr_query = 0;
int_to_threadref(thref, -cpu - 2);
pack_threadid(ptr, thref);
ptr += BUF_THREAD_ID_SIZE;
*(ptr++) = ',';
i++;
}
}

do_each_thread(g, p) {
if (i >= ks->thr_query && !finished) {
int_to_threadref(thref, p->pid);
pack_threadid(ptr, thref);
ptr += BUF_THREAD_ID_SIZE;
*(ptr++) = ',';
ks->thr_query++;
if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0)
finished = 1;
}
i++;
} while_each_thread(g, p);

*(--ptr) = '\0';
break;

Expand All @@ -1023,15 +1055,15 @@ static void gdb_cmd_query(struct kgdb_state *ks)
error_packet(remcom_out_buffer, -EINVAL);
break;
}
if (ks->threadid > 0) {
if ((int)ks->threadid > 0) {
kgdb_mem2hex(getthread(ks->linux_regs,
ks->threadid)->comm,
remcom_out_buffer, 16);
} else {
static char tmpstr[23 + BUF_THREAD_ID_SIZE];

sprintf(tmpstr, "Shadow task %d for pid 0",
(int)(-ks->threadid-1));
sprintf(tmpstr, "shadowCPU%d",
(int)(-ks->threadid - 2));
kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr));
}
break;
Expand Down

0 comments on commit 25fc999

Please sign in to comment.