* linux-nat.c (linux_nat_make_corefile_notes): Fixed a buffer overflow.
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 80771a7cc7ed60786de59d81ef0fded238ded0f3..90b8a3b84502e261963d48c450d7b28400944174 100644 (file)
@@ -7,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "inferior.h"
@@ -335,8 +333,8 @@ linux_enable_event_reporting (ptid_t ptid)
   ptrace (PTRACE_SETOPTIONS, pid, 0, options);
 }
 
-void
-child_post_attach (int pid)
+static void
+linux_child_post_attach (int pid)
 {
   linux_enable_event_reporting (pid_to_ptid (pid));
   check_for_thread_db ();
@@ -349,8 +347,8 @@ linux_child_post_startup_inferior (ptid_t ptid)
   check_for_thread_db ();
 }
 
-int
-child_follow_fork (struct target_ops *ops, int follow_child)
+static int
+linux_child_follow_fork (struct target_ops *ops, int follow_child)
 {
   ptid_t last_ptid;
   struct target_waitstatus last_status;
@@ -520,22 +518,22 @@ child_follow_fork (struct target_ops *ops, int follow_child)
 }
 
 \f
-void
-child_insert_fork_catchpoint (int pid)
+static void
+linux_child_insert_fork_catchpoint (int pid)
 {
   if (! linux_supports_tracefork (pid))
     error (_("Your system does not support fork catchpoints."));
 }
 
-void
-child_insert_vfork_catchpoint (int pid)
+static void
+linux_child_insert_vfork_catchpoint (int pid)
 {
   if (!linux_supports_tracefork (pid))
     error (_("Your system does not support vfork catchpoints."));
 }
 
-void
-child_insert_exec_catchpoint (int pid)
+static void
+linux_child_insert_exec_catchpoint (int pid)
 {
   if (!linux_supports_tracefork (pid))
     error (_("Your system does not support exec catchpoints."));
@@ -616,6 +614,7 @@ static sigset_t blocked_mask;
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
+static char *linux_child_pid_to_exec_file (int pid);
 \f
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
@@ -1325,7 +1324,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
     {
       ourstatus->kind = TARGET_WAITKIND_EXECD;
       ourstatus->value.execd_pathname
-       = xstrdup (child_pid_to_exec_file (pid));
+       = xstrdup (linux_child_pid_to_exec_file (pid));
 
       if (linux_parent_pid)
        {
@@ -1766,7 +1765,8 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
   if (lp->status != 0
       && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
       && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
-                                    DECR_PC_AFTER_BREAK))
+                                    gdbarch_decr_pc_after_break
+                                      (current_gdbarch)))
     {
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -1774,8 +1774,10 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
                            target_pid_to_str (lp->ptid));
 
       /* Back up the PC if necessary.  */
-      if (DECR_PC_AFTER_BREAK)
-       write_pc_pid (read_pc_pid (lp->ptid) - DECR_PC_AFTER_BREAK, lp->ptid);
+      if (gdbarch_decr_pc_after_break (current_gdbarch))
+       write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
+                                                (current_gdbarch),
+                     lp->ptid);
 
       /* Throw away the SIGTRAP.  */
       lp->status = 0;
@@ -2463,8 +2465,8 @@ sigchld_handler (int signo)
 /* Accepts an integer PID; Returns a string representing a file that
    can be opened to get the symbols for the child process.  */
 
-char *
-child_pid_to_exec_file (int pid)
+static char *
+linux_child_pid_to_exec_file (int pid)
 {
   char *name1, *name2;
 
@@ -2579,19 +2581,26 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
   gdb_fpxregset_t fpxregs;
 #endif
   unsigned long lwp = ptid_get_lwp (ptid);
-  struct gdbarch *gdbarch = current_gdbarch;
+  struct regcache *regcache = get_thread_regcache (ptid);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   const struct regset *regset;
   int core_regset_p;
+  struct cleanup *old_chain;
+
+  old_chain = save_inferior_ptid ();
+  inferior_ptid = ptid;
+  target_fetch_registers (regcache, -1);
+  do_cleanups (old_chain);
 
   core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
   if (core_regset_p
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
                                                     sizeof (gregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, current_regcache, -1,
+    regset->collect_regset (regset, regcache, -1,
                            &gregs, sizeof (gregs));
   else
-    fill_gregset (&gregs, -1);
+    fill_gregset (regcache, &gregs, -1);
 
   note_data = (char *) elfcore_write_prstatus (obfd,
                                               note_data,
@@ -2603,10 +2612,10 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
                                                     sizeof (fpregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, current_regcache, -1,
+    regset->collect_regset (regset, regcache, -1,
                            &fpregs, sizeof (fpregs));
   else
-    fill_fpregset (&fpregs, -1);
+    fill_fpregset (regcache, &fpregs, -1);
 
   note_data = (char *) elfcore_write_prfpreg (obfd,
                                              note_data,
@@ -2618,10 +2627,10 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg-xfp",
                                                     sizeof (fpxregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, current_regcache, -1,
+    regset->collect_regset (regset, regcache, -1,
                            &fpxregs, sizeof (fpxregs));
   else
-    fill_fpxregset (&fpxregs, -1);
+    fill_fpxregset (regcache, &fpxregs, -1);
 
   note_data = (char *) elfcore_write_prxfpreg (obfd,
                                               note_data,
@@ -2646,21 +2655,13 @@ static int
 linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
 {
   struct linux_nat_corefile_thread_data *args = data;
-  ptid_t saved_ptid = inferior_ptid;
 
-  inferior_ptid = ti->ptid;
-  registers_changed ();
-  target_fetch_registers (-1); /* FIXME should not be necessary;
-                                  fill_gregset should do it automatically. */
   args->note_data = linux_nat_do_thread_registers (args->obfd,
                                                   ti->ptid,
                                                   args->note_data,
                                                   args->note_size);
   args->num_notes++;
-  inferior_ptid = saved_ptid;
-  registers_changed ();
-  target_fetch_registers (-1); /* FIXME should not be necessary;
-                                  fill_gregset should do it automatically. */
+
   return 0;
 }
 
@@ -2670,15 +2671,11 @@ static char *
 linux_nat_do_registers (bfd *obfd, ptid_t ptid,
                        char *note_data, int *note_size)
 {
-  registers_changed ();
-  target_fetch_registers (-1); /* FIXME should not be necessary;
-                                  fill_gregset should do it automatically. */
   return linux_nat_do_thread_registers (obfd,
                                        ptid_build (ptid_get_pid (inferior_ptid),
                                                    ptid_get_pid (inferior_ptid),
                                                    0),
                                        note_data, note_size);
-  return note_data;
 }
 
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
@@ -2689,7 +2686,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 {
   struct linux_nat_corefile_thread_data thread_args;
   struct cleanup *old_chain;
+  /* The variable size must be >= sizeof (prpsinfo_t.pr_fname).  */
   char fname[16] = { '\0' };
+  /* The variable size must be >= sizeof (prpsinfo_t.pr_psargs).  */
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
@@ -2702,9 +2701,18 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       strncpy (psargs, get_exec_file (0), sizeof (psargs));
       if (get_inferior_args ())
        {
-         strncat (psargs, " ", sizeof (psargs) - strlen (psargs));
-         strncat (psargs, get_inferior_args (),
-                  sizeof (psargs) - strlen (psargs));
+         char *string_end;
+         char *psargs_end = psargs + sizeof (psargs);
+
+         /* linux_elfcore_write_prpsinfo () handles zero unterminated
+            strings fine.  */
+         string_end = memchr (psargs, 0, sizeof (psargs));
+         if (string_end != NULL)
+           {
+             *string_end++ = ' ';
+             strncpy (string_end, get_inferior_args (),
+                      psargs_end - string_end);
+           }
        }
       note_data = (char *) elfcore_write_prpsinfo (obfd,
                                                   note_data,
@@ -2857,7 +2865,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          char permissions[8], device[8], filename[MAXPATHLEN];
 
          printf_filtered (_("Mapped address spaces:\n\n"));
-         if (TARGET_ADDR_BIT == 32)
+         if (gdbarch_addr_bit (current_gdbarch) == 32)
            {
              printf_filtered ("\t%10s %10s %10s %10s %7s\n",
                           "Start Addr",
@@ -2883,7 +2891,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
                 a generic local_address_string instead to print out
                 the addresses; that makes sense to me, too.  */
 
-             if (TARGET_ADDR_BIT == 32)
+             if (gdbarch_addr_bit (current_gdbarch) == 32)
                {
                  printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
                               (unsigned long) addr,    /* FIXME: pr_addr */
@@ -2927,10 +2935,11 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
        {
          int itmp;
          char ctmp;
+         long ltmp;
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
-         if (fscanf (procfile, "%s ", &buffer[0]) > 0)
+         if (fscanf (procfile, "(%[^)]) ", &buffer[0]) > 0)
            printf_filtered (_("Exec file: %s\n"), buffer);
          if (fscanf (procfile, "%c ", &ctmp) > 0)
            printf_filtered (_("State: %c\n"), ctmp);
@@ -2944,71 +2953,71 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
            printf_filtered (_("TTY: %d\n"), itmp);
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("TTY owner process group: %d\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Flags: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Minor faults (no memory page): %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Minor faults, children: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Major faults (memory page faults): %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Major faults, children: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("utime: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("stime: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("utime, children: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("stime, children: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("jiffies remaining in current time slice: %d\n"),
-                            itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("'nice' value: %d\n", itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("jiffies until next timeout: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered ("jiffies until next SIGALRM: %u\n",
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("start time (jiffies since system boot): %d\n"),
-                            itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Virtual memory size: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Resident set size: %u\n"), (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered ("rlim: %u\n", (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Start of text: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("End of text: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Start of stack: 0x%x\n"), itmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Flags: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Minor faults (no memory page): %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Minor faults, children: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Major faults (memory page faults): %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Major faults, children: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("utime: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("stime: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("utime, children: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("stime, children: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("jiffies remaining in current time slice: %ld\n"),
+                            ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("'nice' value: %ld\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("jiffies until next timeout: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("jiffies until next SIGALRM: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("start time (jiffies since system boot): %ld\n"),
+                            ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Virtual memory size: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Resident set size: %lu\n"), (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("rlim: %lu\n"), (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Start of text: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("End of text: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Start of stack: 0x%lx\n"), ltmp);
 #if 0                          /* Don't know how architecture-dependent the rest is...
                                   Anyway the signal bitmap info is available from "status".  */
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("Kernel stack pointer: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("Kernel instr pointer: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Pending signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Blocked signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Ignored signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Catched signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("wchan (system call): 0x%x\n"), itmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("Kernel stack pointer: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("Kernel instr pointer: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Pending signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Blocked signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Ignored signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Catched signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
 #endif
          fclose (procfile);
        }
@@ -3164,47 +3173,44 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
                             offset, len);
 }
 
-#ifndef FETCH_INFERIOR_REGISTERS
-
-/* Return the address in the core dump or inferior of register
-   REGNO.  */
+/* Create a prototype generic Linux target.  The client can override
+   it with local methods.  */
 
-static CORE_ADDR
-linux_register_u_offset (int regno)
+static void
+linux_target_install_ops (struct target_ops *t)
 {
-  /* FIXME drow/2005-09-04: The hardcoded use of register_addr should go
-     away.  This requires disentangling the various definitions of it
-     (particularly alpha-nat.c's).  */
-  return register_addr (regno, 0);
-}
-
-#endif
+  t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
+  t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
+  t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
+  t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
+  t->to_post_startup_inferior = linux_child_post_startup_inferior;
+  t->to_post_attach = linux_child_post_attach;
+  t->to_follow_fork = linux_child_follow_fork;
+  t->to_find_memory_regions = linux_nat_find_memory_regions;
+  t->to_make_corefile_notes = linux_nat_make_corefile_notes;
 
-/* Create a prototype generic Linux target.  The client can override
-   it with local methods.  */
+  super_xfer_partial = t->to_xfer_partial;
+  t->to_xfer_partial = linux_xfer_partial;
+}
 
 struct target_ops *
 linux_target (void)
 {
   struct target_ops *t;
 
-#ifdef FETCH_INFERIOR_REGISTERS
   t = inf_ptrace_target ();
-#else
-  t = inf_ptrace_trad_target (linux_register_u_offset);
-#endif
-  t->to_insert_fork_catchpoint = child_insert_fork_catchpoint;
-  t->to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
-  t->to_insert_exec_catchpoint = child_insert_exec_catchpoint;
-  t->to_pid_to_exec_file = child_pid_to_exec_file;
-  t->to_post_startup_inferior = linux_child_post_startup_inferior;
-  t->to_post_attach = child_post_attach;
-  t->to_follow_fork = child_follow_fork;
-  t->to_find_memory_regions = linux_nat_find_memory_regions;
-  t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+  linux_target_install_ops (t);
 
-  super_xfer_partial = t->to_xfer_partial;
-  t->to_xfer_partial = linux_xfer_partial;
+  return t;
+}
+
+struct target_ops *
+linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int))
+{
+  struct target_ops *t;
+
+  t = inf_ptrace_trad_target (register_u_offset);
+  linux_target_install_ops (t);
 
   return t;
 }
This page took 0.033741 seconds and 4 git commands to generate.