From 5090e82cca377dd12046a4bb7dc1922f363348b4 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Fri, 5 Nov 1993 19:27:49 +0000 Subject: [PATCH] * inflow.c (terminal_init_inferior): Temporarily use Lynx PIDGET macro to set process groups. * infptrace.c (child_resume): Temporarily use Lynx PIDGET to specify resumption of all threads. * infrun.c (wait_for_inferior): Fix handling of thread-specific breakpoints for systems where DECR_PC_AFTER_BREAK > 0 (ie: backup PC by the right amount when continuing the thread). * thread.c (thread_apply_command): Add the `thread apply' command to apply a given GDB command to a list of threads. --- gdb/ChangeLog | 12 ++++++ gdb/inflow.c | 4 ++ gdb/infptrace.c | 118 ++++++++++++++++++++++++++------------------------ gdb/thread.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 205 insertions(+), 59 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3851696..8ff804b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +Fri Nov 5 09:49:22 1993 Stu Grossman (grossman at cygnus.com) + + * inflow.c (terminal_init_inferior): Temporarily use Lynx PIDGET + macro to set process groups. + * infptrace.c (child_resume): Temporarily use Lynx PIDGET to + specify resumption of all threads. + * infrun.c (wait_for_inferior): Fix handling of thread-specific + breakpoints for systems where DECR_PC_AFTER_BREAK > 0 (ie: backup + PC by the right amount when continuing the thread). + * thread.c (thread_apply_command): Add the `thread apply' + command to apply a given GDB command to a list of threads. + Fri Nov 5 05:58:03 1993 Jim Kingdon (kingdon@cygnus.com) * Makefile.in (init.c): Don't call sed if filename is empty. diff --git a/gdb/inflow.c b/gdb/inflow.c index cd0105e..f3757d5 100644 --- a/gdb/inflow.c +++ b/gdb/inflow.c @@ -176,8 +176,12 @@ terminal_init_inferior () free (inferior_ttystate); inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); #ifdef PROCESS_GROUP_TYPE +#ifdef PIDGET /* XXX Lynx */ + inferior_process_group = PIDGET (inferior_pid); +#else inferior_process_group = inferior_pid; #endif +#endif /* Make sure that next time we call terminal_inferior (which will be before the program runs, as it needs to be), we install the new diff --git a/gdb/infptrace.c b/gdb/infptrace.c index aafbd85..26f7be3 100644 --- a/gdb/infptrace.c +++ b/gdb/infptrace.c @@ -41,6 +41,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if !defined (PT_KILL) #define PT_KILL 8 +#endif + +#if !defined (PT_STEP) #define PT_STEP 9 #define PT_CONTINUE 7 #define PT_READ_U 3 @@ -49,7 +52,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define PT_READ_D 2 #define PT_WRITE_I 4 #define PT_WRITE_D 5 -#endif /* No PT_KILL. */ +#endif /* No PT_STEP. */ #ifndef PT_ATTACH #define PT_ATTACH PTRACE_ATTACH @@ -62,11 +65,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef NO_SYS_FILE #include #endif +#if 0 +/* Don't think this is used anymore. On the sequent (not sure whether it's + dynix or ptx or both), it is included unconditionally by sys/user.h and + not protected against multiple inclusion. */ #include - -#if defined (FIVE_ARG_PTRACE -/* Deal with HPUX 8.0 braindamage. */ -#define ptrace(a,b,c,d) ptrace(a,b,c,d,0) #endif #if !defined (FETCH_INFERIOR_REGISTERS) @@ -86,10 +89,16 @@ call_ptrace (request, pid, addr, data) PTRACE_ARG3_TYPE addr; int data; { - return ptrace (request, pid, addr, data); + return ptrace (request, pid, addr, data +#if defined (FIVE_ARG_PTRACE) + /* Deal with HPUX 8.0 braindamage. We never use the + calls which require the fifth argument. */ + , 0 +#endif + ); } -#ifdef DEBUG_PTRACE +#if defined (DEBUG_PTRACE) || defined (FIVE_ARG_PTRACE) /* For the rest of the file, use an extra level of indirection */ /* This lets us breakpoint usefully on call_ptrace. */ #define ptrace call_ptrace @@ -113,12 +122,20 @@ kill_inferior () If SIGNAL is nonzero, give it that signal. */ void -child_resume (step, signal) +child_resume (pid, step, signal) + int pid; int step; int signal; { errno = 0; + if (pid == -1) +#ifdef PIDGET /* XXX Lynx */ + pid = PIDGET (inferior_pid); +#else + pid = inferior_pid; +#endif + /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where it was. (If GDB wanted it to start some other way, we have already written a new PC value to the child.) @@ -129,9 +146,9 @@ child_resume (step, signal) instructions), so we don't have to worry about that here. */ if (step) - ptrace (PT_STEP, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, signal); else - ptrace (PT_CONTINUE, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1, signal); if (errno) perror_with_name ("ptrace"); @@ -167,17 +184,22 @@ detach (signal) } #endif /* ATTACH_DETACH */ -#if !defined (FETCH_INFERIOR_REGISTERS) +/* Default the type of the ptrace transfer to int. */ +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif /* KERNEL_U_ADDR is the amount to subtract from u.u_ar0 to get the offset in the core file of the register values. */ -#if defined (KERNEL_U_ADDR_BSD) +#if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS) /* Get kernel_u_addr using BSD-style nlist(). */ CORE_ADDR kernel_u_addr; +#endif /* KERNEL_U_ADDR_BSD. */ void _initialize_kernel_u_addr () { +#if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS) struct nlist names[2]; names[0].n_un.n_name = "_u"; @@ -186,30 +208,10 @@ _initialize_kernel_u_addr () kernel_u_addr = names[0].n_value; else fatal ("Unable to get kernel u area address."); -} #endif /* KERNEL_U_ADDR_BSD. */ - -#if defined (KERNEL_U_ADDR_HPUX) -/* Get kernel_u_addr using HPUX-style nlist(). */ -CORE_ADDR kernel_u_addr; - -struct hpnlist { - char * n_name; - long n_value; - unsigned char n_type; - unsigned char n_length; - short n_almod; - short n_unused; -}; -static struct hpnlist nl[] = {{ "_u", -1, }, { (char *) 0, }}; - -/* read the value of the u area from the hp-ux kernel */ -void _initialize_kernel_u_addr () -{ - nlist ("/hp-ux", &nl); - kernel_u_addr = nl[0].n_value; } -#endif /* KERNEL_U_ADDR_HPUX. */ + +#if !defined (FETCH_INFERIOR_REGISTERS) #if !defined (offsetof) #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) @@ -244,7 +246,7 @@ fetch_register (regno) if (CANNOT_FETCH_REGISTER (regno)) { - bzero (buf, REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ supply_register (regno, buf); return; } @@ -252,12 +254,12 @@ fetch_register (regno) offset = U_REGS_OFFSET; regaddr = register_addr (regno, offset); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - *(int *) &buf[i] = ptrace (PT_READ_U, inferior_pid, - (PTRACE_ARG3_TYPE) regaddr, 0); - regaddr += sizeof (int); + *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); if (errno != 0) { sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); @@ -296,7 +298,6 @@ store_inferior_registers (regno) { register unsigned int regaddr; char buf[80]; - extern char registers[]; register int i; unsigned int offset = U_REGS_OFFSET; @@ -304,17 +305,17 @@ store_inferior_registers (regno) if (regno >= 0) { regaddr = register_addr (regno, offset); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) { errno = 0; ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, - *(int *) ®isters[REGISTER_BYTE (regno) + i]); + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); if (errno != 0) { sprintf (buf, "writing register number %d(%d)", regno, i); perror_with_name (buf); } - regaddr += sizeof(int); + regaddr += sizeof(PTRACE_XFER_TYPE); } } else @@ -324,17 +325,17 @@ store_inferior_registers (regno) if (CANNOT_STORE_REGISTER (regno)) continue; regaddr = register_addr (regno, offset); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) { errno = 0; ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, - *(int *) ®isters[REGISTER_BYTE (regno) + i]); + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); if (errno != 0) { sprintf (buf, "writing register number %d(%d)", regno, i); perror_with_name (buf); } - regaddr += sizeof(int); + regaddr += sizeof(PTRACE_XFER_TYPE); } } } @@ -366,18 +367,20 @@ child_xfer_memory (memaddr, myaddr, len, write, target) { register int i; /* Round starting address down to longword boundary. */ - register CORE_ADDR addr = memaddr & - sizeof (int); + register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE); /* Round ending address up; get number of longwords that makes. */ register int count - = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ - register int *buffer = (int *) alloca (count * sizeof (int)); + register PTRACE_XFER_TYPE *buffer + = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); if (write) { /* Fill start and end extra bytes of buffer with existing memory data. */ - if (addr != memaddr || len < (int)sizeof (int)) { + if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) { /* Need part of initial word -- fetch it. */ buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); @@ -387,17 +390,20 @@ child_xfer_memory (memaddr, myaddr, len, write, target) { buffer[count - 1] = ptrace (PT_READ_I, inferior_pid, - (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (int)), + ((PTRACE_ARG3_TYPE) + (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))), 0); } /* Copy data to be written over corresponding part of buffer */ - memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + myaddr, + len); /* Write the entire buffer. */ - for (i = 0; i < count; i++, addr += sizeof (int)) + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, @@ -417,7 +423,7 @@ child_xfer_memory (memaddr, myaddr, len, write, target) else { /* Read all the longwords */ - for (i = 0; i < count; i++, addr += sizeof (int)) + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; buffer[i] = ptrace (PT_READ_I, inferior_pid, @@ -428,7 +434,9 @@ child_xfer_memory (memaddr, myaddr, len, write, target) } /* Copy appropriate bytes out of the buffer. */ - memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + memcpy (myaddr, + (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + len); } return len; } diff --git a/gdb/thread.c b/gdb/thread.c index f14b41f..a060bec 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -211,18 +211,124 @@ thread_switch (pid) } static void +restore_current_thread (pid) + int pid; +{ + if (pid != inferior_pid) + thread_switch (pid); +} + +/* Apply a GDB command to a list of threads. List syntax is a whitespace + seperated list of numbers, or ranges, or the keyword `all'. Ranges consist + of two numbers seperated by a hyphen. Examples: + + thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4 + thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9 + thread apply all p x/i $pc Apply x/i $pc cmd to all threads +*/ + +static void +thread_apply_all_command (cmd, from_tty) + char *cmd; + int from_tty; +{ + struct thread_info *tp; + struct cleanup *old_chain; + + if (cmd == NULL || *cmd == '\000') + error ("Please specify a command following the thread ID list"); + + old_chain = make_cleanup (restore_current_thread, inferior_pid); + + for (tp = thread_list; tp; tp = tp->next) + { + thread_switch (tp->pid); + printf_filtered ("\nThread %d (%s):\n", tp->num, + target_pid_to_str (inferior_pid)); + execute_command (cmd, from_tty); + } +} + +static void +thread_apply_command (tidlist, from_tty) + char *tidlist; + int from_tty; +{ + char *cmd; + char *p; + struct cleanup *old_chain; + + if (tidlist == NULL || *tidlist == '\000') + error ("Please specify a thread ID list"); + + for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++); + + if (*cmd == '\000') + error ("Please specify a command following the thread ID list"); + + old_chain = make_cleanup (restore_current_thread, inferior_pid); + + while (tidlist < cmd) + { + struct thread_info *tp; + int start, end; + + start = strtol (tidlist, &p, 10); + if (p == tidlist) + error ("Error parsing %s", tidlist); + tidlist = p; + + while (*tidlist == ' ' || *tidlist == '\t') + tidlist++; + + if (*tidlist == '-') /* Got a range of IDs? */ + { + tidlist++; /* Skip the - */ + end = strtol (tidlist, &p, 10); + if (p == tidlist) + error ("Error parsing %s", tidlist); + tidlist = p; + + while (*tidlist == ' ' || *tidlist == '\t') + tidlist++; + } + else + end = start; + + for (; start <= end; start++) + { + tp = find_thread_id (start); + + if (!tp) + { + warning ("Unknown thread %d.", start); + continue; + } + + thread_switch (tp->pid); + printf_filtered ("\nThread %d (%s):\n", tp->num, + target_pid_to_str (inferior_pid)); + execute_command (cmd, from_tty); + } + } +} + +/* Switch to the specified thread. Will dispatch off to thread_apply_command + if prefix of arg is `apply'. */ + +static void thread_command (tidstr, from_tty) char *tidstr; int from_tty; { int num; struct thread_info *tp; + char *p; if (!tidstr) error ("Please specify a thread ID. Use the \"info threads\" command to\n\ see the IDs of currently known threads."); - num = atoi (tidstr); tp = find_thread_id (num); @@ -240,9 +346,25 @@ see the IDs of currently known threads.", num); void _initialize_thread () { + static struct cmd_list_element *thread_cmd_list = NULL; + static struct cmd_list_element *thread_apply_list = NULL; + extern struct cmd_list_element *cmdlist; + add_info ("threads", info_threads_command, "IDs of currently known threads."); - add_com ("thread", class_info, thread_command, - "Use this command to switch between threads.\n\ -The new thread ID must be currently known."); + + add_prefix_cmd ("thread", class_run, thread_command, + "Use this command to switch between threads.\n\ +The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1, + &cmdlist); + + add_prefix_cmd ("apply", class_run, thread_apply_command, + "Apply a command to a list of threads.", + &thread_apply_list, "apply ", 1, &thread_cmd_list); + + add_cmd ("all", class_run, thread_apply_all_command, + "Apply a command to all threads.", + &thread_apply_list); + + add_com_alias ("t", "thread", class_run, 1); } -- 2.7.4