* v850-tdep.c (elf-bfd.h, elf/v850.h): Include.
[deliverable/binutils-gdb.git] / gdb / linux-tdep.c
index d5ad6e3c34a1805124aca4366de612d28148d892..bfb64049bc45cadd81a1ad0c5706598a0ec85c52 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux, architecture independent.
 
-   Copyright (C) 2009-2012 Free Software Foundation, Inc.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -32,6 +32,7 @@
 #include "cli/cli-utils.h"
 #include "arch-utils.h"
 #include "gdb_obstack.h"
+#include "cli/cli-utils.h"
 
 #include <ctype.h>
 
@@ -224,8 +225,7 @@ read_mapping (const char *line,
     p++;
   *endaddr = strtoulst (p, &p, 16);
 
-  while (*p && isspace (*p))
-    p++;
+  p = skip_spaces_const (p);
   *permissions = p;
   while (*p && !isspace (*p))
     p++;
@@ -233,8 +233,7 @@ read_mapping (const char *line,
 
   *offset = strtoulst (p, &p, 16);
 
-  while (*p && isspace (*p))
-    p++;
+  p = skip_spaces_const (p);
   *device = p;
   while (*p && !isspace (*p))
     p++;
@@ -242,8 +241,7 @@ read_mapping (const char *line,
 
   *inode = strtoulst (p, &p, 10);
 
-  while (*p && isspace (*p))
-    p++;
+  p = skip_spaces_const (p);
   *filename = p;
 }
 
@@ -263,7 +261,7 @@ linux_info_proc (struct gdbarch *gdbarch, char *args,
   int status_f = (what == IP_STATUS || what == IP_ALL);
   int stat_f = (what == IP_STAT || what == IP_ALL);
   char filename[100];
-  gdb_byte *data;
+  char *data;
   int target_errno;
 
   if (args && isdigit (args[0]))
@@ -408,8 +406,7 @@ linux_info_proc (struct gdbarch *gdbarch, char *args,
          printf_filtered (_("Process: %s\n"),
                           pulongest (strtoulst (p, &p, 10)));
 
-         while (*p && isspace (*p))
-           p++;
+         p = skip_spaces_const (p);
          if (*p == '(')
            {
              const char *ep = strchr (p, ')');
@@ -421,8 +418,7 @@ linux_info_proc (struct gdbarch *gdbarch, char *args,
                }
            }
 
-         while (*p && isspace (*p))
-           p++;
+         p = skip_spaces_const (p);
          if (*p)
            printf_filtered (_("State: %c\n"), *p++);
 
@@ -679,22 +675,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
                                linux_find_memory_region_ftype *func,
                                void *obfd)
 {
-  char filename[100];
-  gdb_byte *data;
+  char mapsfilename[100];
+  char *data;
 
   /* We need to know the real target PID to access /proc.  */
   if (current_inferior ()->fake_pid_p)
     return 1;
 
-  xsnprintf (filename, sizeof filename,
+  xsnprintf (mapsfilename, sizeof mapsfilename,
             "/proc/%d/smaps", current_inferior ()->pid);
-  data = target_fileio_read_stralloc (filename);
+  data = target_fileio_read_stralloc (mapsfilename);
   if (data == NULL)
     {
       /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (filename, sizeof filename,
+      xsnprintf (mapsfilename, sizeof mapsfilename,
                 "/proc/%d/maps", current_inferior ()->pid);
-      data = target_fileio_read_stralloc (filename);
+      data = target_fileio_read_stralloc (mapsfilename);
     }
   if (data)
     {
@@ -724,20 +720,30 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
               line = strtok (NULL, "\n"))
            {
              char keyword[64 + 1];
-             unsigned long number;
 
-             if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
+             if (sscanf (line, "%64s", keyword) != 1)
                {
-                 warning (_("Error parsing {s,}maps file '%s'"), filename);
+                 warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
                  break;
                }
              if (strcmp (keyword, "Anonymous:") == 0)
                has_anonymous = 1;
-             if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
-                                 || strcmp (keyword, "Private_Dirty:") == 0
-                                 || strcmp (keyword, "Swap:") == 0
-                                 || strcmp (keyword, "Anonymous:") == 0))
-               modified = 1;
+             if (strcmp (keyword, "Shared_Dirty:") == 0
+                 || strcmp (keyword, "Private_Dirty:") == 0
+                 || strcmp (keyword, "Swap:") == 0
+                 || strcmp (keyword, "Anonymous:") == 0)
+               {
+                 unsigned long number;
+
+                 if (sscanf (line, "%*s%lu", &number) != 1)
+                   {
+                     warning (_("Error parsing {s,}maps file '%s' number"),
+                              mapsfilename);
+                     break;
+                   }
+                 if (number != 0)
+                   modified = 1;
+               }
            }
 
          /* Older Linux kernels did not support the "Anonymous:" counter.
@@ -987,8 +993,8 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
   if (mapping_data.file_count != 0)
     {
       /* Write the count to the obstack.  */
-      pack_long (obstack_base (&data_obstack), long_type,
-                mapping_data.file_count);
+      pack_long ((gdb_byte *) obstack_base (&data_obstack),
+                long_type, mapping_data.file_count);
 
       /* Copy the filenames to the data obstack.  */
       obstack_grow (&data_obstack, obstack_base (&filename_obstack),
@@ -1153,6 +1159,206 @@ linux_corefile_thread_callback (struct thread_info *info, void *data)
   return !args->note_data;
 }
 
+/* Fill the PRPSINFO structure with information about the process being
+   debugged.  Returns 1 in case of success, 0 for failures.  Please note that
+   even if the structure cannot be entirely filled (e.g., GDB was unable to
+   gather information about the process UID/GID), this function will still
+   return 1 since some information was already recorded.  It will only return
+   0 iff nothing can be gathered.  */
+
+static int
+linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
+{
+  /* The filename which we will use to obtain some info about the process.
+     We will basically use this to store the `/proc/PID/FILENAME' file.  */
+  char filename[100];
+  /* The full name of the program which generated the corefile.  */
+  char *fname;
+  /* The basename of the executable.  */
+  const char *basename;
+  /* The arguments of the program.  */
+  char *psargs;
+  char *infargs;
+  /* The contents of `/proc/PID/stat' and `/proc/PID/status' files.  */
+  char *proc_stat, *proc_status;
+  /* Temporary buffer.  */
+  char *tmpstr;
+  /* The valid states of a process, according to the Linux kernel.  */
+  const char valid_states[] = "RSDTZW";
+  /* The program state.  */
+  const char *prog_state;
+  /* The state of the process.  */
+  char pr_sname;
+  /* The PID of the program which generated the corefile.  */
+  pid_t pid;
+  /* Process flags.  */
+  unsigned int pr_flag;
+  /* Process nice value.  */
+  long pr_nice;
+  /* The number of fields read by `sscanf'.  */
+  int n_fields = 0;
+  /* Cleanups.  */
+  struct cleanup *c;
+  int i;
+
+  gdb_assert (p != NULL);
+
+  /* Obtaining PID and filename.  */
+  pid = ptid_get_pid (inferior_ptid);
+  xsnprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid);
+  fname = target_fileio_read_stralloc (filename);
+
+  if (fname == NULL || *fname == '\0')
+    {
+      /* No program name was read, so we won't be able to retrieve more
+        information about the process.  */
+      xfree (fname);
+      return 0;
+    }
+
+  c = make_cleanup (xfree, fname);
+  memset (p, 0, sizeof (*p));
+
+  /* Defining the PID.  */
+  p->pr_pid = pid;
+
+  /* Copying the program name.  Only the basename matters.  */
+  basename = lbasename (fname);
+  strncpy (p->pr_fname, basename, sizeof (p->pr_fname));
+  p->pr_fname[sizeof (p->pr_fname) - 1] = '\0';
+
+  infargs = get_inferior_args ();
+
+  psargs = xstrdup (fname);
+  if (infargs != NULL)
+    psargs = reconcat (psargs, psargs, " ", infargs, NULL);
+
+  make_cleanup (xfree, psargs);
+
+  strncpy (p->pr_psargs, psargs, sizeof (p->pr_psargs));
+  p->pr_psargs[sizeof (p->pr_psargs) - 1] = '\0';
+
+  xsnprintf (filename, sizeof (filename), "/proc/%d/stat", (int) pid);
+  proc_stat = target_fileio_read_stralloc (filename);
+  make_cleanup (xfree, proc_stat);
+
+  if (proc_stat == NULL || *proc_stat == '\0')
+    {
+      /* Despite being unable to read more information about the
+        process, we return 1 here because at least we have its
+        command line, PID and arguments.  */
+      do_cleanups (c);
+      return 1;
+    }
+
+  /* Ok, we have the stats.  It's time to do a little parsing of the
+     contents of the buffer, so that we end up reading what we want.
+
+     The following parsing mechanism is strongly based on the
+     information generated by the `fs/proc/array.c' file, present in
+     the Linux kernel tree.  More details about how the information is
+     displayed can be obtained by seeing the manpage of proc(5),
+     specifically under the entry of `/proc/[pid]/stat'.  */
+
+  /* Getting rid of the PID, since we already have it.  */
+  while (isdigit (*proc_stat))
+    ++proc_stat;
+
+  proc_stat = skip_spaces (proc_stat);
+
+  /* Getting rid of the executable name, since we already have it.  We
+     know that this name will be in parentheses, so we can safely look
+     for the close-paren.  */
+  while (*proc_stat != ')')
+    ++proc_stat;
+  ++proc_stat;
+
+  proc_stat = skip_spaces (proc_stat);
+
+  n_fields = sscanf (proc_stat,
+                    "%c"               /* Process state.  */
+                    "%d%d%d"           /* Parent PID, group ID, session ID.  */
+                    "%*d%*d"           /* tty_nr, tpgid (not used).  */
+                    "%u"               /* Flags.  */
+                    "%*s%*s%*s%*s"     /* minflt, cminflt, majflt,
+                                          cmajflt (not used).  */
+                    "%*s%*s%*s%*s"     /* utime, stime, cutime,
+                                          cstime (not used).  */
+                    "%*s"              /* Priority (not used).  */
+                    "%ld",             /* Nice.  */
+                    &pr_sname,
+                    &p->pr_ppid, &p->pr_pgrp, &p->pr_sid,
+                    &pr_flag,
+                    &pr_nice);
+
+  if (n_fields != 6)
+    {
+      /* Again, we couldn't read the complementary information about
+        the process state.  However, we already have minimal
+        information, so we just return 1 here.  */
+      do_cleanups (c);
+      return 1;
+    }
+
+  /* Filling the structure fields.  */
+  prog_state = strchr (valid_states, pr_sname);
+  if (prog_state != NULL)
+    p->pr_state = prog_state - valid_states;
+  else
+    {
+      /* Zero means "Running".  */
+      p->pr_state = 0;
+    }
+
+  p->pr_sname = p->pr_state > 5 ? '.' : pr_sname;
+  p->pr_zomb = p->pr_sname == 'Z';
+  p->pr_nice = pr_nice;
+  p->pr_flag = pr_flag;
+
+  /* Finally, obtaining the UID and GID.  For that, we read and parse the
+     contents of the `/proc/PID/status' file.  */
+  xsnprintf (filename, sizeof (filename), "/proc/%d/status", (int) pid);
+  proc_status = target_fileio_read_stralloc (filename);
+  make_cleanup (xfree, proc_status);
+
+  if (proc_status == NULL || *proc_status == '\0')
+    {
+      /* Returning 1 since we already have a bunch of information.  */
+      do_cleanups (c);
+      return 1;
+    }
+
+  /* Extracting the UID.  */
+  tmpstr = strstr (proc_status, "Uid:");
+  if (tmpstr != NULL)
+    {
+      /* Advancing the pointer to the beginning of the UID.  */
+      tmpstr += sizeof ("Uid:");
+      while (*tmpstr != '\0' && !isdigit (*tmpstr))
+       ++tmpstr;
+
+      if (isdigit (*tmpstr))
+       p->pr_uid = strtol (tmpstr, &tmpstr, 10);
+    }
+
+  /* Extracting the GID.  */
+  tmpstr = strstr (proc_status, "Gid:");
+  if (tmpstr != NULL)
+    {
+      /* Advancing the pointer to the beginning of the GID.  */
+      tmpstr += sizeof ("Gid:");
+      while (*tmpstr != '\0' && !isdigit (*tmpstr))
+       ++tmpstr;
+
+      if (isdigit (*tmpstr))
+       p->pr_gid = strtol (tmpstr, &tmpstr, 10);
+    }
+
+  do_cleanups (c);
+
+  return 1;
+}
+
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
    section for a corefile, and returns it in a malloc buffer.  */
 
@@ -1161,26 +1367,30 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
                           linux_collect_thread_registers_ftype collect)
 {
   struct linux_corefile_thread_data thread_args;
+  struct elf_internal_linux_prpsinfo prpsinfo;
   char *note_data = NULL;
   gdb_byte *auxv;
   int auxv_len;
 
-  /* Process information.  */
-  if (get_exec_file (0))
+  if (linux_fill_prpsinfo (&prpsinfo))
     {
-      const char *fname = lbasename (get_exec_file (0));
-      char *psargs = xstrdup (fname);
-
-      if (get_inferior_args ())
-        psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
-                          (char *) NULL);
-
-      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
-                                          fname, psargs);
-      xfree (psargs);
-
-      if (!note_data)
-       return NULL;
+      if (gdbarch_elfcore_write_linux_prpsinfo_p (gdbarch))
+       {
+         note_data = gdbarch_elfcore_write_linux_prpsinfo (gdbarch, obfd,
+                                                           note_data, note_size,
+                                                           &prpsinfo);
+       }
+      else
+       {
+         if (gdbarch_ptr_bit (gdbarch) == 64)
+           note_data = elfcore_write_linux_prpsinfo64 (obfd,
+                                                       note_data, note_size,
+                                                       &prpsinfo);
+         else
+           note_data = elfcore_write_linux_prpsinfo32 (obfd,
+                                                       note_data, note_size,
+                                                       &prpsinfo);
+       }
     }
 
   /* Thread register information.  */
This page took 0.029143 seconds and 4 git commands to generate.