diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-03-08 03:33:24 -0500 |
---|---|---|
committer | Paul Mundt <lethal@hera.kernel.org> | 2007-05-06 22:10:51 -0400 |
commit | fc31b80957a14a60513d953cc67a55519a2b09c7 (patch) | |
tree | 0ec4b686bc0f05dc26dd46c8f38866818775ca86 | |
parent | fa5da2f7bdcf885efe65a37df13907c7d72296f6 (diff) |
sh: Rip out broken kgdb thread support.
The kgdb thread support is woefully out of date (it predates
the pidhash), and needs a complete rewrite before it's useful
again. Just rip it out entirely.
Updating the unified kgdb stub is a more worthwhile endeavour
for anyone that happens to be interested in this, at present
it's just limping along.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/Kconfig.debug | 4 | ||||
-rw-r--r-- | arch/sh/kernel/kgdb_stub.c | 386 |
2 files changed, 4 insertions, 386 deletions
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 6be2385c1ad2..931c620dbc24 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug | |||
@@ -104,10 +104,6 @@ config KGDB_NMI | |||
104 | bool "Enter KGDB on NMI" | 104 | bool "Enter KGDB on NMI" |
105 | default n | 105 | default n |
106 | 106 | ||
107 | config KGDB_THREAD | ||
108 | bool "Include KGDB thread support" | ||
109 | default y | ||
110 | |||
111 | config SH_KGDB_CONSOLE | 107 | config SH_KGDB_CONSOLE |
112 | bool "Console messages through GDB" | 108 | bool "Console messages through GDB" |
113 | depends on !SERIAL_SH_SCI_CONSOLE | 109 | depends on !SERIAL_SH_SCI_CONSOLE |
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c index 737eadc8ce0f..a5323364cbca 100644 --- a/arch/sh/kernel/kgdb_stub.c +++ b/arch/sh/kernel/kgdb_stub.c | |||
@@ -243,14 +243,6 @@ static char out_buffer[OUTBUFMAX]; | |||
243 | 243 | ||
244 | static void kgdb_to_gdb(const char *s); | 244 | static void kgdb_to_gdb(const char *s); |
245 | 245 | ||
246 | #ifdef CONFIG_KGDB_THREAD | ||
247 | static struct task_struct *trapped_thread; | ||
248 | static struct task_struct *current_thread; | ||
249 | typedef unsigned char threadref[8]; | ||
250 | #define BUF_THREAD_ID_SIZE 16 | ||
251 | #endif | ||
252 | |||
253 | |||
254 | /* Convert ch to hex */ | 246 | /* Convert ch to hex */ |
255 | static int hex(const char ch) | 247 | static int hex(const char ch) |
256 | { | 248 | { |
@@ -346,66 +338,6 @@ static char *pack_hex_byte(char *pkt, int byte) | |||
346 | return pkt; | 338 | return pkt; |
347 | } | 339 | } |
348 | 340 | ||
349 | #ifdef CONFIG_KGDB_THREAD | ||
350 | |||
351 | /* Pack a thread ID */ | ||
352 | static char *pack_threadid(char *pkt, threadref * id) | ||
353 | { | ||
354 | char *limit; | ||
355 | unsigned char *altid; | ||
356 | |||
357 | altid = (unsigned char *) id; | ||
358 | |||
359 | limit = pkt + BUF_THREAD_ID_SIZE; | ||
360 | while (pkt < limit) | ||
361 | pkt = pack_hex_byte(pkt, *altid++); | ||
362 | return pkt; | ||
363 | } | ||
364 | |||
365 | /* Convert an integer into our threadref */ | ||
366 | static void int_to_threadref(threadref * id, const int value) | ||
367 | { | ||
368 | unsigned char *scan = (unsigned char *) id; | ||
369 | int i = 4; | ||
370 | |||
371 | while (i--) | ||
372 | *scan++ = 0; | ||
373 | |||
374 | *scan++ = (value >> 24) & 0xff; | ||
375 | *scan++ = (value >> 16) & 0xff; | ||
376 | *scan++ = (value >> 8) & 0xff; | ||
377 | *scan++ = (value & 0xff); | ||
378 | } | ||
379 | |||
380 | /* Return a task structure ptr for a particular pid */ | ||
381 | static struct task_struct *get_thread(int pid) | ||
382 | { | ||
383 | struct task_struct *thread; | ||
384 | |||
385 | /* Use PID_MAX w/gdb for pid 0 */ | ||
386 | if (pid == PID_MAX) pid = 0; | ||
387 | |||
388 | /* First check via PID */ | ||
389 | thread = find_task_by_pid(pid); | ||
390 | |||
391 | if (thread) | ||
392 | return thread; | ||
393 | |||
394 | /* Start at the start */ | ||
395 | thread = init_tasks[0]; | ||
396 | |||
397 | /* Walk along the linked list of tasks */ | ||
398 | do { | ||
399 | if (thread->pid == pid) | ||
400 | return thread; | ||
401 | thread = thread->next_task; | ||
402 | } while (thread != init_tasks[0]); | ||
403 | |||
404 | return NULL; | ||
405 | } | ||
406 | |||
407 | #endif /* CONFIG_KGDB_THREAD */ | ||
408 | |||
409 | /* Scan for the start char '$', read the packet and check the checksum */ | 341 | /* Scan for the start char '$', read the packet and check the checksum */ |
410 | static void get_packet(char *buffer, int buflen) | 342 | static void get_packet(char *buffer, int buflen) |
411 | { | 343 | { |
@@ -608,74 +540,6 @@ static void gdb_regs_to_kgdb_regs(const int *gdb_regs, | |||
608 | regs->vbr = gdb_regs[VBR]; | 540 | regs->vbr = gdb_regs[VBR]; |
609 | } | 541 | } |
610 | 542 | ||
611 | #ifdef CONFIG_KGDB_THREAD | ||
612 | /* Make a local copy of registers from the specified thread */ | ||
613 | asmlinkage void ret_from_fork(void); | ||
614 | static void thread_regs_to_gdb_regs(const struct task_struct *thread, | ||
615 | int *gdb_regs) | ||
616 | { | ||
617 | int regno; | ||
618 | int *tregs; | ||
619 | |||
620 | /* Initialize to zero */ | ||
621 | for (regno = 0; regno < MAXREG; regno++) | ||
622 | gdb_regs[regno] = 0; | ||
623 | |||
624 | /* Just making sure... */ | ||
625 | if (thread == NULL) | ||
626 | return; | ||
627 | |||
628 | /* A new fork has pt_regs on the stack from a fork() call */ | ||
629 | if (thread->thread.pc == (unsigned long)ret_from_fork) { | ||
630 | |||
631 | int vbr_val; | ||
632 | struct pt_regs *kregs; | ||
633 | kregs = (struct pt_regs*)thread->thread.sp; | ||
634 | |||
635 | gdb_regs[R0] = kregs->regs[R0]; | ||
636 | gdb_regs[R1] = kregs->regs[R1]; | ||
637 | gdb_regs[R2] = kregs->regs[R2]; | ||
638 | gdb_regs[R3] = kregs->regs[R3]; | ||
639 | gdb_regs[R4] = kregs->regs[R4]; | ||
640 | gdb_regs[R5] = kregs->regs[R5]; | ||
641 | gdb_regs[R6] = kregs->regs[R6]; | ||
642 | gdb_regs[R7] = kregs->regs[R7]; | ||
643 | gdb_regs[R8] = kregs->regs[R8]; | ||
644 | gdb_regs[R9] = kregs->regs[R9]; | ||
645 | gdb_regs[R10] = kregs->regs[R10]; | ||
646 | gdb_regs[R11] = kregs->regs[R11]; | ||
647 | gdb_regs[R12] = kregs->regs[R12]; | ||
648 | gdb_regs[R13] = kregs->regs[R13]; | ||
649 | gdb_regs[R14] = kregs->regs[R14]; | ||
650 | gdb_regs[R15] = kregs->regs[R15]; | ||
651 | gdb_regs[PC] = kregs->pc; | ||
652 | gdb_regs[PR] = kregs->pr; | ||
653 | gdb_regs[GBR] = kregs->gbr; | ||
654 | gdb_regs[MACH] = kregs->mach; | ||
655 | gdb_regs[MACL] = kregs->macl; | ||
656 | gdb_regs[SR] = kregs->sr; | ||
657 | |||
658 | asm("stc vbr, %0":"=r"(vbr_val)); | ||
659 | gdb_regs[VBR] = vbr_val; | ||
660 | return; | ||
661 | } | ||
662 | |||
663 | /* Otherwise, we have only some registers from switch_to() */ | ||
664 | tregs = (int *)thread->thread.sp; | ||
665 | gdb_regs[R15] = (int)tregs; | ||
666 | gdb_regs[R14] = *tregs++; | ||
667 | gdb_regs[R13] = *tregs++; | ||
668 | gdb_regs[R12] = *tregs++; | ||
669 | gdb_regs[R11] = *tregs++; | ||
670 | gdb_regs[R10] = *tregs++; | ||
671 | gdb_regs[R9] = *tregs++; | ||
672 | gdb_regs[R8] = *tregs++; | ||
673 | gdb_regs[PR] = *tregs++; | ||
674 | gdb_regs[GBR] = *tregs++; | ||
675 | gdb_regs[PC] = thread->thread.pc; | ||
676 | } | ||
677 | #endif /* CONFIG_KGDB_THREAD */ | ||
678 | |||
679 | /* Calculate the new address for after a step */ | 543 | /* Calculate the new address for after a step */ |
680 | static short *get_step_address(void) | 544 | static short *get_step_address(void) |
681 | { | 545 | { |
@@ -794,37 +658,11 @@ static void undo_single_step(void) | |||
794 | /* Send a signal message */ | 658 | /* Send a signal message */ |
795 | static void send_signal_msg(const int signum) | 659 | static void send_signal_msg(const int signum) |
796 | { | 660 | { |
797 | #ifndef CONFIG_KGDB_THREAD | ||
798 | out_buffer[0] = 'S'; | 661 | out_buffer[0] = 'S'; |
799 | out_buffer[1] = highhex(signum); | 662 | out_buffer[1] = highhex(signum); |
800 | out_buffer[2] = lowhex(signum); | 663 | out_buffer[2] = lowhex(signum); |
801 | out_buffer[3] = 0; | 664 | out_buffer[3] = 0; |
802 | put_packet(out_buffer); | 665 | put_packet(out_buffer); |
803 | #else /* CONFIG_KGDB_THREAD */ | ||
804 | int threadid; | ||
805 | threadref thref; | ||
806 | char *out = out_buffer; | ||
807 | const char *tstring = "thread"; | ||
808 | |||
809 | *out++ = 'T'; | ||
810 | *out++ = highhex(signum); | ||
811 | *out++ = lowhex(signum); | ||
812 | |||
813 | while (*tstring) { | ||
814 | *out++ = *tstring++; | ||
815 | } | ||
816 | *out++ = ':'; | ||
817 | |||
818 | threadid = trapped_thread->pid; | ||
819 | if (threadid == 0) threadid = PID_MAX; | ||
820 | int_to_threadref(&thref, threadid); | ||
821 | pack_threadid(out, &thref); | ||
822 | out += BUF_THREAD_ID_SIZE; | ||
823 | *out++ = ';'; | ||
824 | |||
825 | *out = 0; | ||
826 | put_packet(out_buffer); | ||
827 | #endif /* CONFIG_KGDB_THREAD */ | ||
828 | } | 666 | } |
829 | 667 | ||
830 | /* Reply that all was well */ | 668 | /* Reply that all was well */ |
@@ -959,15 +797,7 @@ static void step_with_sig_msg(void) | |||
959 | /* Send register contents */ | 797 | /* Send register contents */ |
960 | static void send_regs_msg(void) | 798 | static void send_regs_msg(void) |
961 | { | 799 | { |
962 | #ifdef CONFIG_KGDB_THREAD | ||
963 | if (!current_thread) | ||
964 | kgdb_regs_to_gdb_regs(&trap_registers, registers); | ||
965 | else | ||
966 | thread_regs_to_gdb_regs(current_thread, registers); | ||
967 | #else | ||
968 | kgdb_regs_to_gdb_regs(&trap_registers, registers); | 800 | kgdb_regs_to_gdb_regs(&trap_registers, registers); |
969 | #endif | ||
970 | |||
971 | mem_to_hex((char *) registers, out_buffer, NUMREGBYTES); | 801 | mem_to_hex((char *) registers, out_buffer, NUMREGBYTES); |
972 | put_packet(out_buffer); | 802 | put_packet(out_buffer); |
973 | } | 803 | } |
@@ -975,198 +805,11 @@ static void send_regs_msg(void) | |||
975 | /* Set register contents - currently can't set other thread's registers */ | 805 | /* Set register contents - currently can't set other thread's registers */ |
976 | static void set_regs_msg(void) | 806 | static void set_regs_msg(void) |
977 | { | 807 | { |
978 | #ifdef CONFIG_KGDB_THREAD | 808 | kgdb_regs_to_gdb_regs(&trap_registers, registers); |
979 | if (!current_thread) { | 809 | hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES); |
980 | #endif | 810 | gdb_regs_to_kgdb_regs(registers, &trap_registers); |
981 | kgdb_regs_to_gdb_regs(&trap_registers, registers); | 811 | send_ok_msg(); |
982 | hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES); | ||
983 | gdb_regs_to_kgdb_regs(registers, &trap_registers); | ||
984 | send_ok_msg(); | ||
985 | #ifdef CONFIG_KGDB_THREAD | ||
986 | } else | ||
987 | send_err_msg(); | ||
988 | #endif | ||
989 | } | ||
990 | |||
991 | |||
992 | #ifdef CONFIG_KGDB_THREAD | ||
993 | |||
994 | /* Set the status for a thread */ | ||
995 | void set_thread_msg(void) | ||
996 | { | ||
997 | int threadid; | ||
998 | struct task_struct *thread = NULL; | ||
999 | char *ptr; | ||
1000 | |||
1001 | switch (in_buffer[1]) { | ||
1002 | /* To select which thread for gG etc messages, i.e. supported */ | ||
1003 | case 'g': | ||
1004 | ptr = &in_buffer[2]; | ||
1005 | hex_to_int(&ptr, &threadid); | ||
1006 | thread = get_thread(threadid); | ||
1007 | |||
1008 | /* If we haven't found it */ | ||
1009 | if (!thread) { | ||
1010 | send_err_msg(); | ||
1011 | break; | ||
1012 | } | ||
1013 | |||
1014 | /* Set current_thread (or not) */ | ||
1015 | if (thread == trapped_thread) | ||
1016 | current_thread = NULL; | ||
1017 | else | ||
1018 | current_thread = thread; | ||
1019 | send_ok_msg(); | ||
1020 | break; | ||
1021 | |||
1022 | /* To select which thread for cCsS messages, i.e. unsupported */ | ||
1023 | case 'c': | ||
1024 | send_ok_msg(); | ||
1025 | break; | ||
1026 | |||
1027 | default: | ||
1028 | send_empty_msg(); | ||
1029 | break; | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | /* Is a thread alive? */ | ||
1034 | static void thread_status_msg(void) | ||
1035 | { | ||
1036 | char *ptr; | ||
1037 | int threadid; | ||
1038 | struct task_struct *thread = NULL; | ||
1039 | |||
1040 | ptr = &in_buffer[1]; | ||
1041 | hex_to_int(&ptr, &threadid); | ||
1042 | thread = get_thread(threadid); | ||
1043 | if (thread) | ||
1044 | send_ok_msg(); | ||
1045 | else | ||
1046 | send_err_msg(); | ||
1047 | } | ||
1048 | /* Send the current thread ID */ | ||
1049 | static void thread_id_msg(void) | ||
1050 | { | ||
1051 | int threadid; | ||
1052 | threadref thref; | ||
1053 | |||
1054 | out_buffer[0] = 'Q'; | ||
1055 | out_buffer[1] = 'C'; | ||
1056 | |||
1057 | if (current_thread) | ||
1058 | threadid = current_thread->pid; | ||
1059 | else if (trapped_thread) | ||
1060 | threadid = trapped_thread->pid; | ||
1061 | else /* Impossible, but just in case! */ | ||
1062 | { | ||
1063 | send_err_msg(); | ||
1064 | return; | ||
1065 | } | ||
1066 | |||
1067 | /* Translate pid 0 to PID_MAX for gdb */ | ||
1068 | if (threadid == 0) threadid = PID_MAX; | ||
1069 | |||
1070 | int_to_threadref(&thref, threadid); | ||
1071 | pack_threadid(out_buffer + 2, &thref); | ||
1072 | out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0'; | ||
1073 | put_packet(out_buffer); | ||
1074 | } | ||
1075 | |||
1076 | /* Send thread info */ | ||
1077 | static void thread_info_msg(void) | ||
1078 | { | ||
1079 | struct task_struct *thread = NULL; | ||
1080 | int threadid; | ||
1081 | char *pos; | ||
1082 | threadref thref; | ||
1083 | |||
1084 | /* Start with 'm' */ | ||
1085 | out_buffer[0] = 'm'; | ||
1086 | pos = &out_buffer[1]; | ||
1087 | |||
1088 | /* For all possible thread IDs - this will overrun if > 44 threads! */ | ||
1089 | /* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */ | ||
1090 | for (threadid = 1; threadid <= PID_MAX; threadid++) { | ||
1091 | |||
1092 | read_lock(&tasklist_lock); | ||
1093 | thread = get_thread(threadid); | ||
1094 | read_unlock(&tasklist_lock); | ||
1095 | |||
1096 | /* If it's a valid thread */ | ||
1097 | if (thread) { | ||
1098 | int_to_threadref(&thref, threadid); | ||
1099 | pack_threadid(pos, &thref); | ||
1100 | pos += BUF_THREAD_ID_SIZE; | ||
1101 | *pos++ = ','; | ||
1102 | } | ||
1103 | } | ||
1104 | *--pos = 0; /* Lose final comma */ | ||
1105 | put_packet(out_buffer); | ||
1106 | |||
1107 | } | ||
1108 | |||
1109 | /* Return printable info for gdb's 'info threads' command */ | ||
1110 | static void thread_extra_info_msg(void) | ||
1111 | { | ||
1112 | int threadid; | ||
1113 | struct task_struct *thread = NULL; | ||
1114 | char buffer[20], *ptr; | ||
1115 | int i; | ||
1116 | |||
1117 | /* Extract thread ID */ | ||
1118 | ptr = &in_buffer[17]; | ||
1119 | hex_to_int(&ptr, &threadid); | ||
1120 | thread = get_thread(threadid); | ||
1121 | |||
1122 | /* If we don't recognise it, say so */ | ||
1123 | if (thread == NULL) | ||
1124 | strcpy(buffer, "(unknown)"); | ||
1125 | else | ||
1126 | strcpy(buffer, thread->comm); | ||
1127 | |||
1128 | /* Construct packet */ | ||
1129 | for (i = 0, ptr = out_buffer; buffer[i]; i++) | ||
1130 | ptr = pack_hex_byte(ptr, buffer[i]); | ||
1131 | |||
1132 | if (thread->thread.pc == (unsigned long)ret_from_fork) { | ||
1133 | strcpy(buffer, "<new fork>"); | ||
1134 | for (i = 0; buffer[i]; i++) | ||
1135 | ptr = pack_hex_byte(ptr, buffer[i]); | ||
1136 | } | ||
1137 | |||
1138 | *ptr = '\0'; | ||
1139 | put_packet(out_buffer); | ||
1140 | } | ||
1141 | |||
1142 | /* Handle all qFooBarBaz messages - have to use an if statement as | ||
1143 | opposed to a switch because q messages can have > 1 char id. */ | ||
1144 | static void query_msg(void) | ||
1145 | { | ||
1146 | const char *q_start = &in_buffer[1]; | ||
1147 | |||
1148 | /* qC = return current thread ID */ | ||
1149 | if (strncmp(q_start, "C", 1) == 0) | ||
1150 | thread_id_msg(); | ||
1151 | |||
1152 | /* qfThreadInfo = query all threads (first) */ | ||
1153 | else if (strncmp(q_start, "fThreadInfo", 11) == 0) | ||
1154 | thread_info_msg(); | ||
1155 | |||
1156 | /* qsThreadInfo = query all threads (subsequent). We know we have sent | ||
1157 | them all after the qfThreadInfo message, so there are no to send */ | ||
1158 | else if (strncmp(q_start, "sThreadInfo", 11) == 0) | ||
1159 | put_packet("l"); /* el = last */ | ||
1160 | |||
1161 | /* qThreadExtraInfo = supply printable information per thread */ | ||
1162 | else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0) | ||
1163 | thread_extra_info_msg(); | ||
1164 | |||
1165 | /* Unsupported - empty message as per spec */ | ||
1166 | else | ||
1167 | send_empty_msg(); | ||
1168 | } | 812 | } |
1169 | #endif /* CONFIG_KGDB_THREAD */ | ||
1170 | 813 | ||
1171 | #ifdef CONFIG_SH_KGDB_CONSOLE | 814 | #ifdef CONFIG_SH_KGDB_CONSOLE |
1172 | /* | 815 | /* |
@@ -1206,12 +849,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) | |||
1206 | if (!kgdb_enabled) | 849 | if (!kgdb_enabled) |
1207 | return; | 850 | return; |
1208 | 851 | ||
1209 | #ifdef CONFIG_KGDB_THREAD | ||
1210 | /* Until GDB specifies a thread */ | ||
1211 | current_thread = NULL; | ||
1212 | trapped_thread = current; | ||
1213 | #endif | ||
1214 | |||
1215 | /* Enter GDB mode (e.g. after detach) */ | 852 | /* Enter GDB mode (e.g. after detach) */ |
1216 | if (!kgdb_in_gdb_mode) { | 853 | if (!kgdb_in_gdb_mode) { |
1217 | /* Do serial setup, notify user, issue preemptive ack */ | 854 | /* Do serial setup, notify user, issue preemptive ack */ |
@@ -1284,21 +921,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) | |||
1284 | step_msg(); | 921 | step_msg(); |
1285 | return; | 922 | return; |
1286 | 923 | ||
1287 | #ifdef CONFIG_KGDB_THREAD | ||
1288 | |||
1289 | case 'H': /* Task related */ | ||
1290 | set_thread_msg(); | ||
1291 | break; | ||
1292 | |||
1293 | case 'T': /* Query thread status */ | ||
1294 | thread_status_msg(); | ||
1295 | break; | ||
1296 | |||
1297 | case 'q': /* Handle query - currently thread-related */ | ||
1298 | query_msg(); | ||
1299 | break; | ||
1300 | #endif | ||
1301 | |||
1302 | case 'k': /* 'Kill the program' with a kernel ? */ | 924 | case 'k': /* 'Kill the program' with a kernel ? */ |
1303 | break; | 925 | break; |
1304 | 926 | ||