diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kgdb.c | 68 |
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 | ||
57 | static int kgdb_break_asap; | 57 | static int kgdb_break_asap; |
58 | 58 | ||
59 | #define KGDB_MAX_THREAD_QUERY 17 | ||
59 | struct kgdb_state { | 60 | struct 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) | |||
527 | static struct task_struct *getthread(struct pt_regs *regs, int tid) | 537 | static 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 | */ |
742 | static inline int shadow_pid(int realpid) | 759 | static 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 | ||
750 | static char gdbmsgbuf[BUFMAX + 1]; | 767 | static 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 */ |
973 | static void gdb_cmd_query(struct kgdb_state *ks) | 990 | static 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; |