aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kgdb.c
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2008-08-01 09:39:35 -0400
committerJason Wessel <jason.wessel@windriver.com>2008-08-01 09:39:35 -0400
commit25fc999913839a45cbb48ac7872e67f7521e7ed9 (patch)
tree2785851665dccc753e9e6cf0de650be72e56d7de /kernel/kgdb.c
parenta9b60bf4c29e07a5a2f26a6f74937972fee9b58b (diff)
kgdb: fix gdb serial thread queries
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>
Diffstat (limited to 'kernel/kgdb.c')
-rw-r--r--kernel/kgdb.c68
1 files changed, 50 insertions, 18 deletions
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index c0d45b2c4d79..eaa21fc9ad1d 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -56,12 +56,14 @@
56 56
57static int kgdb_break_asap; 57static int kgdb_break_asap;
58 58
59#define KGDB_MAX_THREAD_QUERY 17
59struct kgdb_state { 60struct kgdb_state {
60 int ex_vector; 61 int ex_vector;
61 int signo; 62 int signo;
62 int err_code; 63 int err_code;
63 int cpu; 64 int cpu;
64 int pass_exception; 65 int pass_exception;
66 unsigned long thr_query;
65 unsigned long threadid; 67 unsigned long threadid;
66 long kgdb_usethreadid; 68 long kgdb_usethreadid;
67 struct pt_regs *linux_regs; 69 struct pt_regs *linux_regs;
@@ -445,9 +447,14 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
445{ 447{
446 int hex_val; 448 int hex_val;
447 int num = 0; 449 int num = 0;
450 int negate = 0;
448 451
449 *long_val = 0; 452 *long_val = 0;
450 453
454 if (**ptr == '-') {
455 negate = 1;
456 (*ptr)++;
457 }
451 while (**ptr) { 458 while (**ptr) {
452 hex_val = hex(**ptr); 459 hex_val = hex(**ptr);
453 if (hex_val < 0) 460 if (hex_val < 0)
@@ -458,6 +465,9 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
458 (*ptr)++; 465 (*ptr)++;
459 } 466 }
460 467
468 if (negate)
469 *long_val = -*long_val;
470
461 return num; 471 return num;
462} 472}
463 473
@@ -527,10 +537,16 @@ static void int_to_threadref(unsigned char *id, int value)
527static struct task_struct *getthread(struct pt_regs *regs, int tid) 537static struct task_struct *getthread(struct pt_regs *regs, int tid)
528{ 538{
529 /* 539 /*
530 * Non-positive TIDs are remapped idle tasks: 540 * Non-positive TIDs are remapped to the cpu shadow information
531 */ 541 */
532 if (tid <= 0) 542 if (tid == 0 || tid == -1)
533 return idle_task(-tid); 543 tid = -atomic_read(&kgdb_active) - 2;
544 if (tid < 0) {
545 if (kgdb_info[-tid - 2].task)
546 return kgdb_info[-tid - 2].task;
547 else
548 return idle_task(-tid - 2);
549 }
534 550
535 /* 551 /*
536 * find_task_by_pid_ns() does not take the tasklist lock anymore 552 * find_task_by_pid_ns() does not take the tasklist lock anymore
@@ -737,14 +753,15 @@ setundefined:
737} 753}
738 754
739/* 755/*
740 * Remap normal tasks to their real PID, idle tasks to -1 ... -NR_CPUs: 756 * Remap normal tasks to their real PID,
757 * CPU shadow threads are mapped to -CPU - 2
741 */ 758 */
742static inline int shadow_pid(int realpid) 759static inline int shadow_pid(int realpid)
743{ 760{
744 if (realpid) 761 if (realpid)
745 return realpid; 762 return realpid;
746 763
747 return -1-raw_smp_processor_id(); 764 return -raw_smp_processor_id() - 2;
748} 765}
749 766
750static char gdbmsgbuf[BUFMAX + 1]; 767static char gdbmsgbuf[BUFMAX + 1];
@@ -838,7 +855,7 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)
838 local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo; 855 local_debuggerinfo = kgdb_info[ks->cpu].debuggerinfo;
839 } else { 856 } else {
840 local_debuggerinfo = NULL; 857 local_debuggerinfo = NULL;
841 for (i = 0; i < NR_CPUS; i++) { 858 for_each_online_cpu(i) {
842 /* 859 /*
843 * Try to find the task on some other 860 * Try to find the task on some other
844 * or possibly this node if we do not 861 * or possibly this node if we do not
@@ -972,10 +989,13 @@ static int gdb_cmd_reboot(struct kgdb_state *ks)
972/* Handle the 'q' query packets */ 989/* Handle the 'q' query packets */
973static void gdb_cmd_query(struct kgdb_state *ks) 990static void gdb_cmd_query(struct kgdb_state *ks)
974{ 991{
975 struct task_struct *thread; 992 struct task_struct *g;
993 struct task_struct *p;
976 unsigned char thref[8]; 994 unsigned char thref[8];
977 char *ptr; 995 char *ptr;
978 int i; 996 int i;
997 int cpu;
998 int finished = 0;
979 999
980 switch (remcom_in_buffer[1]) { 1000 switch (remcom_in_buffer[1]) {
981 case 's': 1001 case 's':
@@ -985,22 +1005,34 @@ static void gdb_cmd_query(struct kgdb_state *ks)
985 break; 1005 break;
986 } 1006 }
987 1007
988 if (remcom_in_buffer[1] == 'f') 1008 i = 0;
989 ks->threadid = 1;
990
991 remcom_out_buffer[0] = 'm'; 1009 remcom_out_buffer[0] = 'm';
992 ptr = remcom_out_buffer + 1; 1010 ptr = remcom_out_buffer + 1;
993 1011 if (remcom_in_buffer[1] == 'f') {
994 for (i = 0; i < 17; ks->threadid++) { 1012 /* Each cpu is a shadow thread */
995 thread = getthread(ks->linux_regs, ks->threadid); 1013 for_each_online_cpu(cpu) {
996 if (thread) { 1014 ks->thr_query = 0;
997 int_to_threadref(thref, ks->threadid); 1015 int_to_threadref(thref, -cpu - 2);
998 pack_threadid(ptr, thref); 1016 pack_threadid(ptr, thref);
999 ptr += BUF_THREAD_ID_SIZE; 1017 ptr += BUF_THREAD_ID_SIZE;
1000 *(ptr++) = ','; 1018 *(ptr++) = ',';
1001 i++; 1019 i++;
1002 } 1020 }
1003 } 1021 }
1022
1023 do_each_thread(g, p) {
1024 if (i >= ks->thr_query && !finished) {
1025 int_to_threadref(thref, p->pid);
1026 pack_threadid(ptr, thref);
1027 ptr += BUF_THREAD_ID_SIZE;
1028 *(ptr++) = ',';
1029 ks->thr_query++;
1030 if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0)
1031 finished = 1;
1032 }
1033 i++;
1034 } while_each_thread(g, p);
1035
1004 *(--ptr) = '\0'; 1036 *(--ptr) = '\0';
1005 break; 1037 break;
1006 1038
@@ -1023,15 +1055,15 @@ static void gdb_cmd_query(struct kgdb_state *ks)
1023 error_packet(remcom_out_buffer, -EINVAL); 1055 error_packet(remcom_out_buffer, -EINVAL);
1024 break; 1056 break;
1025 } 1057 }
1026 if (ks->threadid > 0) { 1058 if ((int)ks->threadid > 0) {
1027 kgdb_mem2hex(getthread(ks->linux_regs, 1059 kgdb_mem2hex(getthread(ks->linux_regs,
1028 ks->threadid)->comm, 1060 ks->threadid)->comm,
1029 remcom_out_buffer, 16); 1061 remcom_out_buffer, 16);
1030 } else { 1062 } else {
1031 static char tmpstr[23 + BUF_THREAD_ID_SIZE]; 1063 static char tmpstr[23 + BUF_THREAD_ID_SIZE];
1032 1064
1033 sprintf(tmpstr, "Shadow task %d for pid 0", 1065 sprintf(tmpstr, "shadowCPU%d",
1034 (int)(-ks->threadid-1)); 1066 (int)(-ks->threadid - 2));
1035 kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr)); 1067 kgdb_mem2hex(tmpstr, remcom_out_buffer, strlen(tmpstr));
1036 } 1068 }
1037 break; 1069 break;