2013-02-04 Sergio Durigan Junior <sergiodj@redhat.com>

Denys Vlasenko  <dvlasenk@redhat.com>
	    Pedro Alves  <palves@redhat.com>

	* gdbarch.sh (elfcore_write_linux_prpsinfo): New F hook.
	(struct elf_internal_linux_prpsinfo): Forward declare.
	* gdbarch.h, gdbarch.c: Regenerate.
	* linux-tdep.c: Include `cli/cli-utils.h'.
	(linux_fill_prpsinfo): New function.
	(linux_make_corefile_notes): Use linux_fill_prpsinfo.  If there's
	an elfcore_write_linux_prpsinfo hook, use it, otherwise, use
	elfcore_write_linux_prpsinfo32 or elfcore_write_linux_prpsinfo64
	depending on gdbarch pointer bitness.
	* ppc-linux-tdep.c: Include elf-bfd.h.
	(ppc_linux_init_abi): Hook in elfcore_write_ppc_linux_prpsinfo32
	on 32-bit.
This commit is contained in:
Sergio Durigan Junior 2013-02-04 18:40:41 +00:00
parent 70a38d42c5
commit b3ac9c7756
6 changed files with 299 additions and 15 deletions

View File

@ -1,3 +1,20 @@
2013-02-04 Sergio Durigan Junior <sergiodj@redhat.com>
Denys Vlasenko <dvlasenk@redhat.com>
Pedro Alves <palves@redhat.com>
* gdbarch.sh (elfcore_write_linux_prpsinfo): New F hook.
(struct elf_internal_linux_prpsinfo): Forward declare.
* gdbarch.h, gdbarch.c: Regenerate.
* linux-tdep.c: Include `cli/cli-utils.h'.
(linux_fill_prpsinfo): New function.
(linux_make_corefile_notes): Use linux_fill_prpsinfo. If there's
an elfcore_write_linux_prpsinfo hook, use it, otherwise, use
elfcore_write_linux_prpsinfo32 or elfcore_write_linux_prpsinfo64
depending on gdbarch pointer bitness.
* ppc-linux-tdep.c: Include elf-bfd.h.
(ppc_linux_init_abi): Hook in elfcore_write_ppc_linux_prpsinfo32
on 32-bit.
2013-02-04 Jim MacArthur <jim.macarthur@arm.com>
Marcus Shawcroft <marcus.shawcroft@arm.com>
Nigel Stephens <nigel.stephens@arm.com>

View File

@ -238,6 +238,7 @@ struct gdbarch
gdbarch_regset_from_core_section_ftype *regset_from_core_section;
struct core_regset_section * core_regset_sections;
gdbarch_make_corefile_notes_ftype *make_corefile_notes;
gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo;
gdbarch_find_memory_regions_ftype *find_memory_regions;
gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries;
gdbarch_core_pid_to_str_ftype *core_pid_to_str;
@ -408,6 +409,7 @@ struct gdbarch startup_gdbarch =
0, /* regset_from_core_section */
0, /* core_regset_sections */
0, /* make_corefile_notes */
0, /* elfcore_write_linux_prpsinfo */
0, /* find_memory_regions */
0, /* core_xfer_shared_libraries */
0, /* core_pid_to_str */
@ -709,6 +711,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of fetch_pointer_argument, has predicate. */
/* Skip verify of regset_from_core_section, has predicate. */
/* Skip verify of make_corefile_notes, has predicate. */
/* Skip verify of elfcore_write_linux_prpsinfo, has predicate. */
/* Skip verify of find_memory_regions, has predicate. */
/* Skip verify of core_xfer_shared_libraries, has predicate. */
/* Skip verify of core_pid_to_str, has predicate. */
@ -954,6 +957,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: elf_make_msymbol_special = <%s>\n",
host_address_to_string (gdbarch->elf_make_msymbol_special));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_elfcore_write_linux_prpsinfo_p() = %d\n",
gdbarch_elfcore_write_linux_prpsinfo_p (gdbarch));
fprintf_unfiltered (file,
"gdbarch_dump: elfcore_write_linux_prpsinfo = <%s>\n",
host_address_to_string (gdbarch->elfcore_write_linux_prpsinfo));
fprintf_unfiltered (file,
"gdbarch_dump: fast_tracepoint_valid_at = <%s>\n",
host_address_to_string (gdbarch->fast_tracepoint_valid_at));
@ -3367,6 +3376,30 @@ set_gdbarch_make_corefile_notes (struct gdbarch *gdbarch,
gdbarch->make_corefile_notes = make_corefile_notes;
}
int
gdbarch_elfcore_write_linux_prpsinfo_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
return gdbarch->elfcore_write_linux_prpsinfo != NULL;
}
char *
gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch, bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prpsinfo *info)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->elfcore_write_linux_prpsinfo != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_elfcore_write_linux_prpsinfo called\n");
return gdbarch->elfcore_write_linux_prpsinfo (obfd, note_data, note_size, info);
}
void
set_gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch,
gdbarch_elfcore_write_linux_prpsinfo_ftype elfcore_write_linux_prpsinfo)
{
gdbarch->elfcore_write_linux_prpsinfo = elfcore_write_linux_prpsinfo;
}
int
gdbarch_find_memory_regions_p (struct gdbarch *gdbarch)
{

View File

@ -57,6 +57,7 @@ struct agent_expr;
struct axs_value;
struct stap_parse_info;
struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
/* The architecture associated with the inferior through the
connection to the target.
@ -736,6 +737,18 @@ typedef char * (gdbarch_make_corefile_notes_ftype) (struct gdbarch *gdbarch, bfd
extern char * gdbarch_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size);
extern void set_gdbarch_make_corefile_notes (struct gdbarch *gdbarch, gdbarch_make_corefile_notes_ftype *make_corefile_notes);
/* The elfcore writer hook to use to write Linux prpsinfo notes to core
files. Most Linux architectures use the same prpsinfo32 or
prpsinfo64 layouts, and so won't need to provide this hook, as we
call the Linux generic routines in bfd to write prpsinfo notes by
default. */
extern int gdbarch_elfcore_write_linux_prpsinfo_p (struct gdbarch *gdbarch);
typedef char * (gdbarch_elfcore_write_linux_prpsinfo_ftype) (bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prpsinfo *info);
extern char * gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch, bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prpsinfo *info);
extern void set_gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch, gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo);
/* Find core file memory regions */
extern int gdbarch_find_memory_regions_p (struct gdbarch *gdbarch);

View File

@ -641,6 +641,13 @@ v:struct core_regset_section *:core_regset_sections:const char *name, int len:::
# Create core file notes
M:char *:make_corefile_notes:bfd *obfd, int *note_size:obfd, note_size
# The elfcore writer hook to use to write Linux prpsinfo notes to core
# files. Most Linux architectures use the same prpsinfo32 or
# prpsinfo64 layouts, and so won't need to provide this hook, as we
# call the Linux generic routines in bfd to write prpsinfo notes by
# default.
F:char *:elfcore_write_linux_prpsinfo:bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prpsinfo *info:obfd, note_data, note_size, info
# Find core file memory regions
M:int:find_memory_regions:find_memory_region_ftype func, void *data:func, data
@ -1082,6 +1089,7 @@ struct agent_expr;
struct axs_value;
struct stap_parse_info;
struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
/* The architecture associated with the inferior through the
connection to the target.

View File

@ -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>
@ -1153,6 +1154,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 +1362,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. */

View File

@ -57,6 +57,7 @@
#include "parser-defs.h"
#include "user-regs.h"
#include <ctype.h>
#include "elf-bfd.h" /* for elfcore_write_* */
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
@ -1368,6 +1369,13 @@ ppc_linux_init_abi (struct gdbarch_info info,
set_gdbarch_core_regset_sections (gdbarch,
ppc64_linux_fp_regset_sections);
}
/* PPC32 uses a different prpsinfo32 compared to most other Linux
archs. */
if (tdep->wordsize == 4)
set_gdbarch_elfcore_write_linux_prpsinfo (gdbarch,
elfcore_write_ppc_linux_prpsinfo32);
set_gdbarch_regset_from_core_section (gdbarch,
ppc_linux_regset_from_core_section);
set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);