1 /* Multi-process/thread control for GDB, the GNU debugger. 2 Copyright 1986, 1987, 1988, 1993 3 4 Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. 5 Free Software Foundation, Inc. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 22 23 #include "defs.h" 24 #include "symtab.h" 25 #include "frame.h" 26 #include "inferior.h" 27 #include "environ.h" 28 #include "value.h" 29 #include "target.h" 30 #include "gdbthread.h" 31 #include "command.h" 32 #include "gdbcmd.h" 33 34 #include <ctype.h> 35 #include <sys/types.h> 36 #include <signal.h> 37 38 /*#include "lynxos-core.h"*/ 39 40 struct thread_info 41 { 42 struct thread_info *next; 43 int pid; /* Actual process id */ 44 int num; /* Convenient handle */ 45 CORE_ADDR prev_pc; /* State from wait_for_inferior */ 46 CORE_ADDR prev_func_start; 47 char *prev_func_name; 48 struct breakpoint *step_resume_breakpoint; 49 struct breakpoint *through_sigtramp_breakpoint; 50 CORE_ADDR step_range_start; 51 CORE_ADDR step_range_end; 52 CORE_ADDR step_frame_address; 53 int trap_expected; 54 int handling_longjmp; 55 int another_trap; 56 }; 57 58 static struct thread_info *thread_list = NULL; 59 static int highest_thread_num; 60 61 static void 62 thread_command PARAMS ((char * tidstr, int from_tty)); 63 64 static void 65 prune_threads PARAMS ((void)); 66 67 static void 68 thread_switch PARAMS ((int pid)); 69 70 static struct thread_info * 71 find_thread_id PARAMS ((int num)); 72 73 static void 74 info_threads_command PARAMS ((char *, int)); 75 76 static void 77 restore_current_thread PARAMS ((int)); 78 79 static void 80 thread_apply_all_command PARAMS ((char *, int)); 81 82 static void 83 thread_apply_command PARAMS ((char *, int)); 84 85 void 86 init_thread_list () 87 { 88 struct thread_info *tp, *tpnext; 89 90 if (!thread_list) 91 return; 92 93 for (tp = thread_list; tp; tp = tpnext) 94 { 95 tpnext = tp->next; 96 free (tp); 97 } 98 99 thread_list = NULL; 100 highest_thread_num = 0; 101 } 102 103 void 104 add_thread (pid) 105 int pid; 106 { 107 struct thread_info *tp; 108 109 tp = (struct thread_info *) xmalloc (sizeof (struct thread_info)); 110 111 tp->pid = pid; 112 tp->num = ++highest_thread_num; 113 tp->prev_pc = 0; 114 tp->prev_func_start = 0; 115 tp->prev_func_name = NULL; 116 tp->step_range_start = 0; 117 tp->step_range_end = 0; 118 tp->step_frame_address =0; 119 tp->step_resume_breakpoint = 0; 120 tp->through_sigtramp_breakpoint = 0; 121 tp->handling_longjmp = 0; 122 tp->trap_expected = 0; 123 tp->another_trap = 0; 124 tp->next = thread_list; 125 thread_list = tp; 126 } 127 128 static struct thread_info * 129 find_thread_id (num) 130 int num; 131 { 132 struct thread_info *tp; 133 134 for (tp = thread_list; tp; tp = tp->next) 135 if (tp->num == num) 136 return tp; 137 138 return NULL; 139 } 140 141 int 142 valid_thread_id (num) 143 int num; 144 { 145 struct thread_info *tp; 146 147 for (tp = thread_list; tp; tp = tp->next) 148 if (tp->num == num) 149 return 1; 150 151 return 0; 152 } 153 154 int 155 pid_to_thread_id (pid) 156 int pid; 157 { 158 struct thread_info *tp; 159 160 for (tp = thread_list; tp; tp = tp->next) 161 if (tp->pid == pid) 162 return tp->num; 163 164 return 0; 165 } 166 167 int 168 in_thread_list (pid) 169 int pid; 170 { 171 struct thread_info *tp; 172 173 for (tp = thread_list; tp; tp = tp->next) 174 if (tp->pid == pid) 175 return 1; 176 177 return 0; /* Never heard of 'im */ 178 } 179 180 /* Load infrun state for the thread PID. */ 181 182 void load_infrun_state (pid, prev_pc, prev_func_start, prev_func_name, 183 trap_expected, step_resume_breakpoint, 184 through_sigtramp_breakpoint, step_range_start, 185 step_range_end, step_frame_address, 186 handling_longjmp, another_trap) 187 int pid; 188 CORE_ADDR *prev_pc; 189 CORE_ADDR *prev_func_start; 190 char **prev_func_name; 191 int *trap_expected; 192 struct breakpoint **step_resume_breakpoint; 193 struct breakpoint **through_sigtramp_breakpoint; 194 CORE_ADDR *step_range_start; 195 CORE_ADDR *step_range_end; 196 CORE_ADDR *step_frame_address; 197 int *handling_longjmp; 198 int *another_trap; 199 { 200 struct thread_info *tp; 201 202 /* If we can't find the thread, then we're debugging a single threaded 203 process. No need to do anything in that case. */ 204 tp = find_thread_id (pid_to_thread_id (pid)); 205 if (tp == NULL) 206 return; 207 208 *prev_pc = tp->prev_pc; 209 *prev_func_start = tp->prev_func_start; 210 *prev_func_name = tp->prev_func_name; 211 *step_resume_breakpoint = tp->step_resume_breakpoint; 212 *step_range_start = tp->step_range_start; 213 *step_range_end = tp->step_range_end; 214 *step_frame_address = tp->step_frame_address; 215 *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint; 216 *handling_longjmp = tp->handling_longjmp; 217 *trap_expected = tp->trap_expected; 218 *another_trap = tp->another_trap; 219 } 220 221 /* Save infrun state for the thread PID. */ 222 223 void save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name, 224 trap_expected, step_resume_breakpoint, 225 through_sigtramp_breakpoint, step_range_start, 226 step_range_end, step_frame_address, 227 handling_longjmp, another_trap) 228 int pid; 229 CORE_ADDR prev_pc; 230 CORE_ADDR prev_func_start; 231 char *prev_func_name; 232 int trap_expected; 233 struct breakpoint *step_resume_breakpoint; 234 struct breakpoint *through_sigtramp_breakpoint; 235 CORE_ADDR step_range_start; 236 CORE_ADDR step_range_end; 237 CORE_ADDR step_frame_address; 238 int handling_longjmp; 239 int another_trap; 240 { 241 struct thread_info *tp; 242 243 /* If we can't find the thread, then we're debugging a single-threaded 244 process. Nothing to do in that case. */ 245 tp = find_thread_id (pid_to_thread_id (pid)); 246 if (tp == NULL) 247 return; 248 249 tp->prev_pc = prev_pc; 250 tp->prev_func_start = prev_func_start; 251 tp->prev_func_name = prev_func_name; 252 tp->step_resume_breakpoint = step_resume_breakpoint; 253 tp->step_range_start = step_range_start; 254 tp->step_range_end = step_range_end; 255 tp->step_frame_address = step_frame_address; 256 tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint; 257 tp->handling_longjmp = handling_longjmp; 258 tp->trap_expected = trap_expected; 259 tp->another_trap = another_trap; 260 } 261 262 static void 263 prune_threads () 264 { 265 struct thread_info *tp, *tpprev; 266 267 tpprev = 0; 268 269 for (tp = thread_list; tp; tp = tp->next) 270 if (tp->pid == -1) 271 { 272 if (tpprev) 273 tpprev->next = tp->next; 274 else 275 thread_list = NULL; 276 277 free (tp); 278 } 279 else 280 tpprev = tp; 281 } 282 283 /* Print information about currently known threads */ 284 285 static void 286 info_threads_command (arg, from_tty) 287 char *arg; 288 int from_tty; 289 { 290 struct thread_info *tp; 291 int current_pid = inferior_pid; 292 293 /* Avoid coredumps which would happen if we tried to access a NULL 294 selected_frame. */ 295 if (!target_has_stack) error ("No stack."); 296 297 for (tp = thread_list; tp; tp = tp->next) 298 { 299 if (! target_thread_alive (tp->pid)) 300 { 301 tp->pid = -1; /* Mark it as dead */ 302 continue; 303 } 304 305 if (tp->pid == current_pid) 306 printf_filtered ("* "); 307 else 308 printf_filtered (" "); 309 310 printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid)); 311 312 thread_switch (tp->pid); 313 print_stack_frame (selected_frame, -1, 0); 314 } 315 316 thread_switch (current_pid); 317 prune_threads (); 318 } 319 320 /* Switch from one thread to another. */ 321 322 static void 323 thread_switch (pid) 324 int pid; 325 { 326 if (pid == inferior_pid) 327 return; 328 329 inferior_pid = pid; 330 flush_cached_frames (); 331 registers_changed (); 332 stop_pc = read_pc(); 333 select_frame (get_current_frame (), 0); 334 } 335 336 static void 337 restore_current_thread (pid) 338 int pid; 339 { 340 if (pid != inferior_pid) 341 thread_switch (pid); 342 } 343 344 /* Apply a GDB command to a list of threads. List syntax is a whitespace 345 seperated list of numbers, or ranges, or the keyword `all'. Ranges consist 346 of two numbers seperated by a hyphen. Examples: 347 348 thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4 349 thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9 350 thread apply all p x/i $pc Apply x/i $pc cmd to all threads 351 */ 352 353 static void 354 thread_apply_all_command (cmd, from_tty) 355 char *cmd; 356 int from_tty; 357 { 358 struct thread_info *tp; 359 struct cleanup *old_chain; 360 361 if (cmd == NULL || *cmd == '\000') 362 error ("Please specify a command following the thread ID list"); 363 364 old_chain = make_cleanup (restore_current_thread, inferior_pid); 365 366 for (tp = thread_list; tp; tp = tp->next) 367 { 368 thread_switch (tp->pid); 369 printf_filtered ("\nThread %d (%s):\n", tp->num, 370 target_pid_to_str (inferior_pid)); 371 execute_command (cmd, from_tty); 372 } 373 } 374 375 static void 376 thread_apply_command (tidlist, from_tty) 377 char *tidlist; 378 int from_tty; 379 { 380 char *cmd; 381 char *p; 382 struct cleanup *old_chain; 383 384 if (tidlist == NULL || *tidlist == '\000') 385 error ("Please specify a thread ID list"); 386 387 for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++); 388 389 if (*cmd == '\000') 390 error ("Please specify a command following the thread ID list"); 391 392 old_chain = make_cleanup (restore_current_thread, inferior_pid); 393 394 while (tidlist < cmd) 395 { 396 struct thread_info *tp; 397 int start, end; 398 399 start = strtol (tidlist, &p, 10); 400 if (p == tidlist) 401 error ("Error parsing %s", tidlist); 402 tidlist = p; 403 404 while (*tidlist == ' ' || *tidlist == '\t') 405 tidlist++; 406 407 if (*tidlist == '-') /* Got a range of IDs? */ 408 { 409 tidlist++; /* Skip the - */ 410 end = strtol (tidlist, &p, 10); 411 if (p == tidlist) 412 error ("Error parsing %s", tidlist); 413 tidlist = p; 414 415 while (*tidlist == ' ' || *tidlist == '\t') 416 tidlist++; 417 } 418 else 419 end = start; 420 421 for (; start <= end; start++) 422 { 423 tp = find_thread_id (start); 424 425 if (!tp) 426 { 427 warning ("Unknown thread %d.", start); 428 continue; 429 } 430 431 thread_switch (tp->pid); 432 printf_filtered ("\nThread %d (%s):\n", tp->num, 433 target_pid_to_str (inferior_pid)); 434 execute_command (cmd, from_tty); 435 } 436 } 437 } 438 439 /* Switch to the specified thread. Will dispatch off to thread_apply_command 440 if prefix of arg is `apply'. */ 441 442 static void 443 thread_command (tidstr, from_tty) 444 char *tidstr; 445 int from_tty; 446 { 447 int num; 448 struct thread_info *tp; 449 450 if (!tidstr) 451 error ("Please specify a thread ID. Use the \"info threads\" command to\n\ 452 see the IDs of currently known threads."); 453 454 num = atoi (tidstr); 455 456 tp = find_thread_id (num); 457 458 if (!tp) 459 error ("Thread ID %d not known. Use the \"info threads\" command to\n\ 460 see the IDs of currently known threads.", num); 461 462 thread_switch (tp->pid); 463 464 printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid)); 465 print_stack_frame (selected_frame, selected_frame_level, 1); 466 } 467 468 void 469 _initialize_thread () 470 { 471 static struct cmd_list_element *thread_cmd_list = NULL; 472 static struct cmd_list_element *thread_apply_list = NULL; 473 extern struct cmd_list_element *cmdlist; 474 475 add_info ("threads", info_threads_command, 476 "IDs of currently known threads."); 477 478 add_prefix_cmd ("thread", class_run, thread_command, 479 "Use this command to switch between threads.\n\ 480 The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1, 481 &cmdlist); 482 483 add_prefix_cmd ("apply", class_run, thread_apply_command, 484 "Apply a command to a list of threads.", 485 &thread_apply_list, "apply ", 1, &thread_cmd_list); 486 487 add_cmd ("all", class_run, thread_apply_all_command, 488 "Apply a command to all threads.", 489 &thread_apply_list); 490 491 add_com_alias ("t", "thread", class_run, 1); 492 } 493