119370Spst/* Multi-process/thread control for GDB, the GNU debugger. 219370Spst 398948Sobrien Copyright 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998, 4130809Smarcel 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. 598948Sobrien 619370Spst Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. 719370Spst 898948Sobrien This file is part of GDB. 919370Spst 1098948Sobrien This program is free software; you can redistribute it and/or modify 1198948Sobrien it under the terms of the GNU General Public License as published by 1298948Sobrien the Free Software Foundation; either version 2 of the License, or 1398948Sobrien (at your option) any later version. 1419370Spst 1598948Sobrien This program is distributed in the hope that it will be useful, 1698948Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1798948Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1898948Sobrien GNU General Public License for more details. 1919370Spst 2098948Sobrien You should have received a copy of the GNU General Public License 2198948Sobrien along with this program; if not, write to the Free Software 2298948Sobrien Foundation, Inc., 59 Temple Place - Suite 330, 2398948Sobrien Boston, MA 02111-1307, USA. */ 2419370Spst 2519370Spst#include "defs.h" 2619370Spst#include "symtab.h" 2719370Spst#include "frame.h" 2819370Spst#include "inferior.h" 2919370Spst#include "environ.h" 3019370Spst#include "value.h" 3119370Spst#include "target.h" 3246283Sdfr#include "gdbthread.h" 3319370Spst#include "command.h" 3419370Spst#include "gdbcmd.h" 3598948Sobrien#include "regcache.h" 3698948Sobrien#include "gdb.h" 37130809Smarcel#include "gdb_string.h" 3819370Spst 3919370Spst#include <ctype.h> 4019370Spst#include <sys/types.h> 4119370Spst#include <signal.h> 4298948Sobrien#include "ui-out.h" 4319370Spst 4498948Sobrien/*#include "lynxos-core.h" */ 4519370Spst 4698948Sobrien/* Definition of struct thread_info exported to gdbthread.h */ 4746283Sdfr 4846283Sdfr/* Prototypes for exported functions. */ 4946283Sdfr 5098948Sobrienvoid _initialize_thread (void); 5146283Sdfr 5246283Sdfr/* Prototypes for local functions. */ 5346283Sdfr 5419370Spststatic struct thread_info *thread_list = NULL; 5519370Spststatic int highest_thread_num; 5619370Spst 5798948Sobrienstatic struct thread_info *find_thread_id (int num); 5846283Sdfr 5998948Sobrienstatic void thread_command (char *tidstr, int from_tty); 6098948Sobrienstatic void thread_apply_all_command (char *, int); 6198948Sobrienstatic int thread_alive (struct thread_info *); 6298948Sobrienstatic void info_threads_command (char *, int); 6398948Sobrienstatic void thread_apply_command (char *, int); 6498948Sobrienstatic void restore_current_thread (ptid_t); 6598948Sobrienstatic void switch_to_thread (ptid_t ptid); 6698948Sobrienstatic void prune_threads (void); 6719370Spst 6898948Sobrienvoid 6998948Sobriendelete_step_resume_breakpoint (void *arg) 7098948Sobrien{ 7198948Sobrien struct breakpoint **breakpointp = (struct breakpoint **) arg; 7298948Sobrien struct thread_info *tp; 7319370Spst 7498948Sobrien if (*breakpointp != NULL) 7598948Sobrien { 7698948Sobrien delete_breakpoint (*breakpointp); 7798948Sobrien for (tp = thread_list; tp; tp = tp->next) 7898948Sobrien if (tp->step_resume_breakpoint == *breakpointp) 7998948Sobrien tp->step_resume_breakpoint = NULL; 8019370Spst 8198948Sobrien *breakpointp = NULL; 8298948Sobrien } 8346283Sdfr} 8446283Sdfr 8598948Sobrienstatic void 8698948Sobrienfree_thread (struct thread_info *tp) 8746283Sdfr{ 8898948Sobrien /* NOTE: this will take care of any left-over step_resume breakpoints, 8998948Sobrien but not any user-specified thread-specific breakpoints. */ 9098948Sobrien if (tp->step_resume_breakpoint) 9198948Sobrien delete_breakpoint (tp->step_resume_breakpoint); 9246283Sdfr 9398948Sobrien /* FIXME: do I ever need to call the back-end to give it a 9498948Sobrien chance at this private data before deleting the thread? */ 9598948Sobrien if (tp->private) 9698948Sobrien xfree (tp->private); 9746283Sdfr 9898948Sobrien xfree (tp); 9946283Sdfr} 10046283Sdfr 10146283Sdfrvoid 10298948Sobrieninit_thread_list (void) 10319370Spst{ 10419370Spst struct thread_info *tp, *tpnext; 10519370Spst 10698948Sobrien highest_thread_num = 0; 10719370Spst if (!thread_list) 10819370Spst return; 10919370Spst 11019370Spst for (tp = thread_list; tp; tp = tpnext) 11119370Spst { 11219370Spst tpnext = tp->next; 11398948Sobrien free_thread (tp); 11419370Spst } 11519370Spst 11619370Spst thread_list = NULL; 11719370Spst} 11819370Spst 11998948Sobrien/* add_thread now returns a pointer to the new thread_info, 12098948Sobrien so that back_ends can initialize their private data. */ 12198948Sobrien 12298948Sobrienstruct thread_info * 12398948Sobrienadd_thread (ptid_t ptid) 12419370Spst{ 12519370Spst struct thread_info *tp; 12619370Spst 12798948Sobrien tp = (struct thread_info *) xmalloc (sizeof (*tp)); 12898948Sobrien memset (tp, 0, sizeof (*tp)); 12998948Sobrien tp->ptid = ptid; 13019370Spst tp->num = ++highest_thread_num; 13119370Spst tp->next = thread_list; 13219370Spst thread_list = tp; 13398948Sobrien return tp; 13419370Spst} 13519370Spst 13646283Sdfrvoid 13798948Sobriendelete_thread (ptid_t ptid) 13846283Sdfr{ 13946283Sdfr struct thread_info *tp, *tpprev; 14046283Sdfr 14146283Sdfr tpprev = NULL; 14246283Sdfr 14346283Sdfr for (tp = thread_list; tp; tpprev = tp, tp = tp->next) 14498948Sobrien if (ptid_equal (tp->ptid, ptid)) 14546283Sdfr break; 14646283Sdfr 14746283Sdfr if (!tp) 14846283Sdfr return; 14946283Sdfr 15046283Sdfr if (tpprev) 15146283Sdfr tpprev->next = tp->next; 15246283Sdfr else 15346283Sdfr thread_list = tp->next; 15446283Sdfr 15598948Sobrien free_thread (tp); 15646283Sdfr} 15746283Sdfr 15819370Spststatic struct thread_info * 15998948Sobrienfind_thread_id (int num) 16019370Spst{ 16119370Spst struct thread_info *tp; 16219370Spst 16319370Spst for (tp = thread_list; tp; tp = tp->next) 16419370Spst if (tp->num == num) 16519370Spst return tp; 16619370Spst 16719370Spst return NULL; 16819370Spst} 16919370Spst 17098948Sobrien/* Find a thread_info by matching PTID. */ 17198948Sobrienstruct thread_info * 17298948Sobrienfind_thread_pid (ptid_t ptid) 17398948Sobrien{ 17498948Sobrien struct thread_info *tp; 17598948Sobrien 17698948Sobrien for (tp = thread_list; tp; tp = tp->next) 17798948Sobrien if (ptid_equal (tp->ptid, ptid)) 17898948Sobrien return tp; 17998948Sobrien 18098948Sobrien return NULL; 18198948Sobrien} 18298948Sobrien 18398948Sobrien/* 18498948Sobrien * Thread iterator function. 18598948Sobrien * 18698948Sobrien * Calls a callback function once for each thread, so long as 18798948Sobrien * the callback function returns false. If the callback function 18898948Sobrien * returns true, the iteration will end and the current thread 18998948Sobrien * will be returned. This can be useful for implementing a 19098948Sobrien * search for a thread with arbitrary attributes, or for applying 19198948Sobrien * some operation to every thread. 19298948Sobrien * 19398948Sobrien * FIXME: some of the existing functionality, such as 19498948Sobrien * "Thread apply all", might be rewritten using this functionality. 19598948Sobrien */ 19698948Sobrien 19798948Sobrienstruct thread_info * 19898948Sobrieniterate_over_threads (int (*callback) (struct thread_info *, void *), 19998948Sobrien void *data) 20098948Sobrien{ 20198948Sobrien struct thread_info *tp; 20298948Sobrien 20398948Sobrien for (tp = thread_list; tp; tp = tp->next) 20498948Sobrien if ((*callback) (tp, data)) 20598948Sobrien return tp; 20698948Sobrien 20798948Sobrien return NULL; 20898948Sobrien} 20998948Sobrien 21019370Spstint 21198948Sobrienvalid_thread_id (int num) 21219370Spst{ 21319370Spst struct thread_info *tp; 21419370Spst 21519370Spst for (tp = thread_list; tp; tp = tp->next) 21619370Spst if (tp->num == num) 21719370Spst return 1; 21819370Spst 21919370Spst return 0; 22019370Spst} 22119370Spst 22219370Spstint 22398948Sobrienpid_to_thread_id (ptid_t ptid) 22419370Spst{ 22519370Spst struct thread_info *tp; 22619370Spst 22719370Spst for (tp = thread_list; tp; tp = tp->next) 22898948Sobrien if (ptid_equal (tp->ptid, ptid)) 22919370Spst return tp->num; 23019370Spst 23119370Spst return 0; 23219370Spst} 23319370Spst 23498948Sobrienptid_t 23598948Sobrienthread_id_to_pid (int num) 23646283Sdfr{ 23746283Sdfr struct thread_info *thread = find_thread_id (num); 23846283Sdfr if (thread) 23998948Sobrien return thread->ptid; 24046283Sdfr else 24198948Sobrien return pid_to_ptid (-1); 24246283Sdfr} 24346283Sdfr 24446283Sdfrint 24598948Sobrienin_thread_list (ptid_t ptid) 24619370Spst{ 24719370Spst struct thread_info *tp; 24819370Spst 24919370Spst for (tp = thread_list; tp; tp = tp->next) 25098948Sobrien if (ptid_equal (tp->ptid, ptid)) 25119370Spst return 1; 25219370Spst 25319370Spst return 0; /* Never heard of 'im */ 25419370Spst} 25519370Spst 25698948Sobrien/* Print a list of thread ids currently known, and the total number of 25798948Sobrien threads. To be used from within catch_errors. */ 258130809Smarcelstatic int 259130809Smarceldo_captured_list_thread_ids (struct ui_out *uiout, void *arg) 26098948Sobrien{ 26198948Sobrien struct thread_info *tp; 26298948Sobrien int num = 0; 263130809Smarcel struct cleanup *cleanup_chain; 26498948Sobrien 265130809Smarcel prune_threads (); 266130809Smarcel target_find_new_threads (); 26798948Sobrien 268130809Smarcel cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "thread-ids"); 269130809Smarcel 27098948Sobrien for (tp = thread_list; tp; tp = tp->next) 27198948Sobrien { 27298948Sobrien num++; 27398948Sobrien ui_out_field_int (uiout, "thread-id", tp->num); 27498948Sobrien } 27598948Sobrien 276130809Smarcel do_cleanups (cleanup_chain); 27798948Sobrien ui_out_field_int (uiout, "number-of-threads", num); 27898948Sobrien return GDB_RC_OK; 27998948Sobrien} 28098948Sobrien 28198948Sobrien/* Official gdblib interface function to get a list of thread ids and 28298948Sobrien the total number. */ 28398948Sobrienenum gdb_rc 28498948Sobriengdb_list_thread_ids (struct ui_out *uiout) 28598948Sobrien{ 28698948Sobrien return catch_exceptions (uiout, do_captured_list_thread_ids, NULL, 28798948Sobrien NULL, RETURN_MASK_ALL); 28898948Sobrien} 28998948Sobrien 29019370Spst/* Load infrun state for the thread PID. */ 29119370Spst 29298948Sobrienvoid 293130809Smarcelload_infrun_state (ptid_t ptid, 294130809Smarcel CORE_ADDR *prev_pc, 29598948Sobrien int *trap_expected, 29698948Sobrien struct breakpoint **step_resume_breakpoint, 29798948Sobrien struct breakpoint **through_sigtramp_breakpoint, 298130809Smarcel CORE_ADDR *step_range_start, 29998948Sobrien CORE_ADDR *step_range_end, 300130809Smarcel struct frame_id *step_frame_id, 30198948Sobrien int *handling_longjmp, 302130809Smarcel int *another_trap, 30398948Sobrien int *stepping_through_solib_after_catch, 30498948Sobrien bpstat *stepping_through_solib_catchpoints, 30598948Sobrien int *stepping_through_sigtramp, 306130809Smarcel int *current_line, 307130809Smarcel struct symtab **current_symtab, CORE_ADDR *step_sp) 30819370Spst{ 30919370Spst struct thread_info *tp; 31019370Spst 31119370Spst /* If we can't find the thread, then we're debugging a single threaded 31219370Spst process. No need to do anything in that case. */ 31398948Sobrien tp = find_thread_id (pid_to_thread_id (ptid)); 31419370Spst if (tp == NULL) 31519370Spst return; 31619370Spst 31719370Spst *prev_pc = tp->prev_pc; 31898948Sobrien *trap_expected = tp->trap_expected; 31919370Spst *step_resume_breakpoint = tp->step_resume_breakpoint; 32098948Sobrien *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint; 32119370Spst *step_range_start = tp->step_range_start; 32219370Spst *step_range_end = tp->step_range_end; 323130809Smarcel *step_frame_id = tp->step_frame_id; 32419370Spst *handling_longjmp = tp->handling_longjmp; 32519370Spst *another_trap = tp->another_trap; 326130809Smarcel *stepping_through_solib_after_catch = 327130809Smarcel tp->stepping_through_solib_after_catch; 328130809Smarcel *stepping_through_solib_catchpoints = 329130809Smarcel tp->stepping_through_solib_catchpoints; 33046283Sdfr *stepping_through_sigtramp = tp->stepping_through_sigtramp; 33198948Sobrien *current_line = tp->current_line; 33298948Sobrien *current_symtab = tp->current_symtab; 33398948Sobrien *step_sp = tp->step_sp; 33419370Spst} 33519370Spst 33619370Spst/* Save infrun state for the thread PID. */ 33719370Spst 33898948Sobrienvoid 339130809Smarcelsave_infrun_state (ptid_t ptid, 340130809Smarcel CORE_ADDR prev_pc, 34198948Sobrien int trap_expected, 34298948Sobrien struct breakpoint *step_resume_breakpoint, 34398948Sobrien struct breakpoint *through_sigtramp_breakpoint, 344130809Smarcel CORE_ADDR step_range_start, 34598948Sobrien CORE_ADDR step_range_end, 346130809Smarcel const struct frame_id *step_frame_id, 34798948Sobrien int handling_longjmp, 348130809Smarcel int another_trap, 34998948Sobrien int stepping_through_solib_after_catch, 35098948Sobrien bpstat stepping_through_solib_catchpoints, 351130809Smarcel int stepping_through_sigtramp, 35298948Sobrien int current_line, 353130809Smarcel struct symtab *current_symtab, CORE_ADDR step_sp) 35419370Spst{ 35519370Spst struct thread_info *tp; 35619370Spst 35719370Spst /* If we can't find the thread, then we're debugging a single-threaded 35819370Spst process. Nothing to do in that case. */ 35998948Sobrien tp = find_thread_id (pid_to_thread_id (ptid)); 36019370Spst if (tp == NULL) 36119370Spst return; 36219370Spst 36319370Spst tp->prev_pc = prev_pc; 36498948Sobrien tp->trap_expected = trap_expected; 36519370Spst tp->step_resume_breakpoint = step_resume_breakpoint; 36698948Sobrien tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint; 36719370Spst tp->step_range_start = step_range_start; 36819370Spst tp->step_range_end = step_range_end; 369130809Smarcel tp->step_frame_id = (*step_frame_id); 37019370Spst tp->handling_longjmp = handling_longjmp; 37119370Spst tp->another_trap = another_trap; 37246283Sdfr tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch; 37346283Sdfr tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints; 37446283Sdfr tp->stepping_through_sigtramp = stepping_through_sigtramp; 37598948Sobrien tp->current_line = current_line; 37698948Sobrien tp->current_symtab = current_symtab; 37798948Sobrien tp->step_sp = step_sp; 37819370Spst} 37919370Spst 38046283Sdfr/* Return true if TP is an active thread. */ 38146283Sdfrstatic int 38298948Sobrienthread_alive (struct thread_info *tp) 38346283Sdfr{ 38498948Sobrien if (PIDGET (tp->ptid) == -1) 38546283Sdfr return 0; 38698948Sobrien if (!target_thread_alive (tp->ptid)) 38746283Sdfr { 38898948Sobrien tp->ptid = pid_to_ptid (-1); /* Mark it as dead */ 38946283Sdfr return 0; 39046283Sdfr } 39146283Sdfr return 1; 39246283Sdfr} 39346283Sdfr 39419370Spststatic void 39598948Sobrienprune_threads (void) 39619370Spst{ 39798948Sobrien struct thread_info *tp, *next; 39819370Spst 39946283Sdfr for (tp = thread_list; tp; tp = next) 40046283Sdfr { 40146283Sdfr next = tp->next; 40246283Sdfr if (!thread_alive (tp)) 40398948Sobrien delete_thread (tp->ptid); 40446283Sdfr } 40519370Spst} 40619370Spst 40746283Sdfr/* Print information about currently known threads 40898948Sobrien 40946283Sdfr * Note: this has the drawback that it _really_ switches 41046283Sdfr * threads, which frees the frame cache. A no-side 41146283Sdfr * effects info-threads command would be nicer. 41246283Sdfr */ 41319370Spst 41419370Spststatic void 41598948Sobrieninfo_threads_command (char *arg, int from_tty) 41619370Spst{ 41719370Spst struct thread_info *tp; 41898948Sobrien ptid_t current_ptid; 41998948Sobrien struct frame_info *cur_frame; 420130809Smarcel int saved_frame_level = frame_relative_level (get_selected_frame ()); 42198948Sobrien int counter; 42298948Sobrien char *extra_info; 42319370Spst 424130809Smarcel /* Check that there really is a frame. This happens when a simulator 425130809Smarcel is connected but not loaded or running, for instance. */ 426130809Smarcel if (legacy_frame_p (current_gdbarch) && saved_frame_level < 0) 427130809Smarcel error ("No frame."); 42819370Spst 42946283Sdfr prune_threads (); 43098948Sobrien target_find_new_threads (); 43198948Sobrien current_ptid = inferior_ptid; 43219370Spst for (tp = thread_list; tp; tp = tp->next) 43319370Spst { 43498948Sobrien if (ptid_equal (tp->ptid, current_ptid)) 43519370Spst printf_filtered ("* "); 43619370Spst else 43719370Spst printf_filtered (" "); 43819370Spst 43946283Sdfr#ifdef HPUXHPPA 44098948Sobrien printf_filtered ("%d %s", tp->num, target_tid_to_str (tp->ptid)); 44146283Sdfr#else 44298948Sobrien printf_filtered ("%d %s", tp->num, target_pid_to_str (tp->ptid)); 44346283Sdfr#endif 44498948Sobrien 44598948Sobrien extra_info = target_extra_thread_info (tp); 44698948Sobrien if (extra_info) 44798948Sobrien printf_filtered (" (%s)", extra_info); 44898948Sobrien puts_filtered (" "); 44998948Sobrien 45098948Sobrien switch_to_thread (tp->ptid); 451130809Smarcel print_stack_frame (get_selected_frame (), -1, 0); 45246283Sdfr } 45319370Spst 45498948Sobrien switch_to_thread (current_ptid); 45546283Sdfr 45646283Sdfr /* Code below copied from "up_silently_base" in "stack.c". 45746283Sdfr * It restores the frame set by the user before the "info threads" 45846283Sdfr * command. We have finished the info-threads display by switching 45946283Sdfr * back to the current thread. That switch has put us at the top 46046283Sdfr * of the stack (leaf frame). 46146283Sdfr */ 46298948Sobrien counter = saved_frame_level; 463130809Smarcel cur_frame = find_relative_frame (get_selected_frame (), &counter); 46446283Sdfr if (counter != 0) 46546283Sdfr { 46646283Sdfr /* Ooops, can't restore, tell user where we are. */ 46746283Sdfr warning ("Couldn't restore frame in current thread, at frame 0"); 468130809Smarcel print_stack_frame (get_selected_frame (), -1, 0); 46919370Spst } 47046283Sdfr else 47146283Sdfr { 472130809Smarcel select_frame (cur_frame); 47346283Sdfr } 47419370Spst 47546283Sdfr /* re-show current frame. */ 47698948Sobrien show_stack_frame (cur_frame); 47719370Spst} 47819370Spst 47919370Spst/* Switch from one thread to another. */ 48019370Spst 48119370Spststatic void 48298948Sobrienswitch_to_thread (ptid_t ptid) 48319370Spst{ 48498948Sobrien if (ptid_equal (ptid, inferior_ptid)) 48519370Spst return; 48619370Spst 48798948Sobrien inferior_ptid = ptid; 48819370Spst flush_cached_frames (); 48919370Spst registers_changed (); 49098948Sobrien stop_pc = read_pc (); 491130809Smarcel select_frame (get_current_frame ()); 49219370Spst} 49319370Spst 49419370Spststatic void 49598948Sobrienrestore_current_thread (ptid_t ptid) 49619370Spst{ 497130809Smarcel if (!ptid_equal (ptid, inferior_ptid)) 49846283Sdfr { 49998948Sobrien switch_to_thread (ptid); 50098948Sobrien print_stack_frame (get_current_frame (), 0, -1); 50146283Sdfr } 50219370Spst} 50319370Spst 50498948Sobrienstruct current_thread_cleanup 50598948Sobrien{ 50698948Sobrien ptid_t inferior_ptid; 50798948Sobrien}; 50898948Sobrien 50998948Sobrienstatic void 51098948Sobriendo_restore_current_thread_cleanup (void *arg) 51198948Sobrien{ 51298948Sobrien struct current_thread_cleanup *old = arg; 51398948Sobrien restore_current_thread (old->inferior_ptid); 51498948Sobrien xfree (old); 51598948Sobrien} 51698948Sobrien 51798948Sobrienstatic struct cleanup * 51898948Sobrienmake_cleanup_restore_current_thread (ptid_t inferior_ptid) 51998948Sobrien{ 52098948Sobrien struct current_thread_cleanup *old 52198948Sobrien = xmalloc (sizeof (struct current_thread_cleanup)); 52298948Sobrien old->inferior_ptid = inferior_ptid; 52398948Sobrien return make_cleanup (do_restore_current_thread_cleanup, old); 52498948Sobrien} 52598948Sobrien 52619370Spst/* Apply a GDB command to a list of threads. List syntax is a whitespace 52719370Spst seperated list of numbers, or ranges, or the keyword `all'. Ranges consist 52819370Spst of two numbers seperated by a hyphen. Examples: 52919370Spst 53098948Sobrien thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4 53198948Sobrien thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9 53298948Sobrien thread apply all p x/i $pc Apply x/i $pc cmd to all threads 53398948Sobrien */ 53419370Spst 53519370Spststatic void 53698948Sobrienthread_apply_all_command (char *cmd, int from_tty) 53719370Spst{ 53819370Spst struct thread_info *tp; 53919370Spst struct cleanup *old_chain; 54098948Sobrien struct cleanup *saved_cmd_cleanup_chain; 54198948Sobrien char *saved_cmd; 54219370Spst 54319370Spst if (cmd == NULL || *cmd == '\000') 54419370Spst error ("Please specify a command following the thread ID list"); 54519370Spst 54698948Sobrien old_chain = make_cleanup_restore_current_thread (inferior_ptid); 54719370Spst 54898948Sobrien /* It is safe to update the thread list now, before 54998948Sobrien traversing it for "thread apply all". MVS */ 55098948Sobrien target_find_new_threads (); 55198948Sobrien 55298948Sobrien /* Save a copy of the command in case it is clobbered by 55398948Sobrien execute_command */ 55498948Sobrien saved_cmd = xstrdup (cmd); 55598948Sobrien saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd); 55619370Spst for (tp = thread_list; tp; tp = tp->next) 55746283Sdfr if (thread_alive (tp)) 55846283Sdfr { 55998948Sobrien switch_to_thread (tp->ptid); 56046283Sdfr#ifdef HPUXHPPA 56146283Sdfr printf_filtered ("\nThread %d (%s):\n", 562130809Smarcel tp->num, target_tid_to_str (inferior_ptid)); 56346283Sdfr#else 56446283Sdfr printf_filtered ("\nThread %d (%s):\n", tp->num, 56598948Sobrien target_pid_to_str (inferior_ptid)); 56646283Sdfr#endif 56746283Sdfr execute_command (cmd, from_tty); 568130809Smarcel strcpy (cmd, saved_cmd); /* Restore exact command used previously */ 56946283Sdfr } 57098948Sobrien 57198948Sobrien do_cleanups (saved_cmd_cleanup_chain); 57298948Sobrien do_cleanups (old_chain); 57319370Spst} 57419370Spst 57519370Spststatic void 57698948Sobrienthread_apply_command (char *tidlist, int from_tty) 57719370Spst{ 57819370Spst char *cmd; 57919370Spst char *p; 58019370Spst struct cleanup *old_chain; 58198948Sobrien struct cleanup *saved_cmd_cleanup_chain; 58298948Sobrien char *saved_cmd; 58319370Spst 58419370Spst if (tidlist == NULL || *tidlist == '\000') 58519370Spst error ("Please specify a thread ID list"); 58619370Spst 58798948Sobrien for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++); 58819370Spst 58919370Spst if (*cmd == '\000') 59019370Spst error ("Please specify a command following the thread ID list"); 59119370Spst 59298948Sobrien old_chain = make_cleanup_restore_current_thread (inferior_ptid); 59319370Spst 59498948Sobrien /* Save a copy of the command in case it is clobbered by 59598948Sobrien execute_command */ 59698948Sobrien saved_cmd = xstrdup (cmd); 59798948Sobrien saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd); 59819370Spst while (tidlist < cmd) 59919370Spst { 60019370Spst struct thread_info *tp; 60119370Spst int start, end; 60219370Spst 60319370Spst start = strtol (tidlist, &p, 10); 60419370Spst if (p == tidlist) 60519370Spst error ("Error parsing %s", tidlist); 60619370Spst tidlist = p; 60719370Spst 60819370Spst while (*tidlist == ' ' || *tidlist == '\t') 60919370Spst tidlist++; 61019370Spst 61119370Spst if (*tidlist == '-') /* Got a range of IDs? */ 61219370Spst { 61398948Sobrien tidlist++; /* Skip the - */ 61419370Spst end = strtol (tidlist, &p, 10); 61519370Spst if (p == tidlist) 61619370Spst error ("Error parsing %s", tidlist); 61719370Spst tidlist = p; 61819370Spst 61919370Spst while (*tidlist == ' ' || *tidlist == '\t') 62019370Spst tidlist++; 62119370Spst } 62219370Spst else 62319370Spst end = start; 62419370Spst 62519370Spst for (; start <= end; start++) 62619370Spst { 62719370Spst tp = find_thread_id (start); 62819370Spst 62919370Spst if (!tp) 63046283Sdfr warning ("Unknown thread %d.", start); 63146283Sdfr else if (!thread_alive (tp)) 63246283Sdfr warning ("Thread %d has terminated.", start); 63346283Sdfr else 63419370Spst { 63598948Sobrien switch_to_thread (tp->ptid); 63646283Sdfr#ifdef HPUXHPPA 63746283Sdfr printf_filtered ("\nThread %d (%s):\n", tp->num, 63898948Sobrien target_tid_to_str (inferior_ptid)); 63946283Sdfr#else 64046283Sdfr printf_filtered ("\nThread %d (%s):\n", tp->num, 64198948Sobrien target_pid_to_str (inferior_ptid)); 64246283Sdfr#endif 64346283Sdfr execute_command (cmd, from_tty); 64498948Sobrien strcpy (cmd, saved_cmd); /* Restore exact command used previously */ 64519370Spst } 64619370Spst } 64719370Spst } 64898948Sobrien 64998948Sobrien do_cleanups (saved_cmd_cleanup_chain); 65098948Sobrien do_cleanups (old_chain); 65119370Spst} 65219370Spst 65319370Spst/* Switch to the specified thread. Will dispatch off to thread_apply_command 65419370Spst if prefix of arg is `apply'. */ 65519370Spst 65619370Spststatic void 65798948Sobrienthread_command (char *tidstr, int from_tty) 65819370Spst{ 65919370Spst if (!tidstr) 66046283Sdfr { 66146283Sdfr /* Don't generate an error, just say which thread is current. */ 66246283Sdfr if (target_has_stack) 66346283Sdfr printf_filtered ("[Current thread is %d (%s)]\n", 66498948Sobrien pid_to_thread_id (inferior_ptid), 66546283Sdfr#if defined(HPUXHPPA) 66698948Sobrien target_tid_to_str (inferior_ptid) 66746283Sdfr#else 66898948Sobrien target_pid_to_str (inferior_ptid) 66946283Sdfr#endif 67098948Sobrien ); 67146283Sdfr else 67246283Sdfr error ("No stack."); 67346283Sdfr return; 67446283Sdfr } 67519370Spst 67698948Sobrien gdb_thread_select (uiout, tidstr); 67798948Sobrien} 67898948Sobrien 67998948Sobrienstatic int 680130809Smarceldo_captured_thread_select (struct ui_out *uiout, void *tidstr) 68198948Sobrien{ 68298948Sobrien int num; 68398948Sobrien struct thread_info *tp; 68498948Sobrien 68598948Sobrien num = value_as_long (parse_and_eval (tidstr)); 68698948Sobrien 68719370Spst tp = find_thread_id (num); 68819370Spst 68919370Spst if (!tp) 69098948Sobrien error ("Thread ID %d not known.", num); 69119370Spst 69246283Sdfr if (!thread_alive (tp)) 69346283Sdfr error ("Thread ID %d has terminated.\n", num); 69419370Spst 69598948Sobrien switch_to_thread (tp->ptid); 69646283Sdfr 69798948Sobrien ui_out_text (uiout, "[Switching to thread "); 69898948Sobrien ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid)); 69998948Sobrien ui_out_text (uiout, " ("); 70046283Sdfr#if defined(HPUXHPPA) 70198948Sobrien ui_out_text (uiout, target_tid_to_str (inferior_ptid)); 70246283Sdfr#else 70398948Sobrien ui_out_text (uiout, target_pid_to_str (inferior_ptid)); 70446283Sdfr#endif 70598948Sobrien ui_out_text (uiout, ")]"); 70698948Sobrien 707130809Smarcel print_stack_frame (deprecated_selected_frame, 708130809Smarcel frame_relative_level (deprecated_selected_frame), 1); 70998948Sobrien return GDB_RC_OK; 71019370Spst} 71119370Spst 71298948Sobrienenum gdb_rc 713130809Smarcelgdb_thread_select (struct ui_out *uiout, char *tidstr) 71498948Sobrien{ 71598948Sobrien return catch_exceptions (uiout, do_captured_thread_select, tidstr, 71698948Sobrien NULL, RETURN_MASK_ALL); 71798948Sobrien} 71898948Sobrien 71946283Sdfr/* Commands with a prefix of `thread'. */ 72046283Sdfrstruct cmd_list_element *thread_cmd_list = NULL; 72146283Sdfr 72219370Spstvoid 72398948Sobrien_initialize_thread (void) 72419370Spst{ 72519370Spst static struct cmd_list_element *thread_apply_list = NULL; 72619370Spst 72719370Spst add_info ("threads", info_threads_command, 72819370Spst "IDs of currently known threads."); 72919370Spst 73019370Spst add_prefix_cmd ("thread", class_run, thread_command, 73119370Spst "Use this command to switch between threads.\n\ 732130809SmarcelThe new thread ID must be currently known.", &thread_cmd_list, "thread ", 1, &cmdlist); 73319370Spst 73419370Spst add_prefix_cmd ("apply", class_run, thread_apply_command, 73519370Spst "Apply a command to a list of threads.", 73619370Spst &thread_apply_list, "apply ", 1, &thread_cmd_list); 73719370Spst 73819370Spst add_cmd ("all", class_run, thread_apply_all_command, 739130809Smarcel "Apply a command to all threads.", &thread_apply_list); 74019370Spst 74146283Sdfr if (!xdb_commands) 74246283Sdfr add_com_alias ("t", "thread", class_run, 1); 74319370Spst} 744