/* Target-dependent code for GNU/Linux, architecture independent.
- Copyright (C) 2009-2016 Free Software Foundation, Inc.
+ Copyright (C) 2009-2018 Free Software Foundation, Inc.
This file is part of GDB.
#include "cli/cli-utils.h"
#include "arch-utils.h"
#include "gdb_obstack.h"
-#include "observer.h"
+#include "observable.h"
#include "objfiles.h"
#include "infcall.h"
#include "gdbcmd.h"
#include "gdb_regex.h"
#include "common/enum-flags.h"
+#include "common/gdb_optional.h"
#include <ctype.h>
static int use_coredump_filter = 1;
+/* Whether the value of smaps_vmflags->exclude_coredump should be
+ ignored, including mappings marked with the VM_DONTDUMP flag in
+ the dump. */
+static int dump_excluded_mappings = 0;
+
/* This enum represents the signals' numbers on a generic architecture
running the Linux kernel. The definition of "generic" comes from
the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
/* __pid_t */
pid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
- TYPE_LENGTH (int_type), "__pid_t");
+ TYPE_LENGTH (int_type) * TARGET_CHAR_BIT, "__pid_t");
TYPE_TARGET_TYPE (pid_type) = int_type;
TYPE_TARGET_STUB (pid_type) = 1;
/* __uid_t */
uid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
- TYPE_LENGTH (uint_type), "__uid_t");
+ TYPE_LENGTH (uint_type) * TARGET_CHAR_BIT, "__uid_t");
TYPE_TARGET_TYPE (uid_type) = uint_type;
TYPE_TARGET_STUB (uid_type) = 1;
/* __clock_t */
clock_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
- TYPE_LENGTH (long_type), "__clock_t");
+ TYPE_LENGTH (long_type) * TARGET_CHAR_BIT,
+ "__clock_t");
TYPE_TARGET_TYPE (clock_type) = long_type;
TYPE_TARGET_STUB (clock_type) = 1;
/* This is how we want PTIDs from core files to be printed. */
-static char *
+static const char *
linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
{
static char buf[80];
p++;
*endaddr = strtoulst (p, &p, 16);
- p = skip_spaces_const (p);
+ p = skip_spaces (p);
*permissions = p;
while (*p && !isspace (*p))
p++;
*offset = strtoulst (p, &p, 16);
- p = skip_spaces_const (p);
+ p = skip_spaces (p);
*device = p;
while (*p && !isspace (*p))
p++;
*inode = strtoulst (p, &p, 10);
- p = skip_spaces_const (p);
+ p = skip_spaces (p);
*filename = p;
}
}
}
+/* Regexes used by mapping_is_anonymous_p. Put in a structure because
+ they're initialized lazily. */
+
+struct mapping_regexes
+{
+ /* Matches "/dev/zero" filenames (with or without the "(deleted)"
+ string in the end). We know for sure, based on the Linux kernel
+ code, that memory mappings whose associated filename is
+ "/dev/zero" are guaranteed to be MAP_ANONYMOUS. */
+ compiled_regex dev_zero
+ {"^/dev/zero\\( (deleted)\\)\\?$", REG_NOSUB,
+ _("Could not compile regex to match /dev/zero filename")};
+
+ /* Matches "/SYSV%08x" filenames (with or without the "(deleted)"
+ string in the end). These filenames refer to shared memory
+ (shmem), and memory mappings associated with them are
+ MAP_ANONYMOUS as well. */
+ compiled_regex shmem_file
+ {"^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$", REG_NOSUB,
+ _("Could not compile regex to match shmem filenames")};
+
+ /* A heuristic we use to try to mimic the Linux kernel's 'n_link ==
+ 0' code, which is responsible to decide if it is dealing with a
+ 'MAP_SHARED | MAP_ANONYMOUS' mapping. In other words, if
+ FILE_DELETED matches, it does not necessarily mean that we are
+ dealing with an anonymous shared mapping. However, there is no
+ easy way to detect this currently, so this is the best
+ approximation we have.
+
+ As a result, GDB will dump readonly pages of deleted executables
+ when using the default value of coredump_filter (0x33), while the
+ Linux kernel will not dump those pages. But we can live with
+ that. */
+ compiled_regex file_deleted
+ {" (deleted)$", REG_NOSUB,
+ _("Could not compile regex to match '<file> (deleted)'")};
+};
+
/* Return 1 if the memory mapping is anonymous, 0 otherwise.
FILENAME is the name of the file present in the first line of the
static int
mapping_is_anonymous_p (const char *filename)
{
- static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
+ static gdb::optional<mapping_regexes> regexes;
static int init_regex_p = 0;
if (!init_regex_p)
{
- struct cleanup *c = make_cleanup (null_cleanup, NULL);
-
/* Let's be pessimistic and assume there will be an error while
compiling the regex'es. */
init_regex_p = -1;
- /* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
- without the "(deleted)" string in the end). We know for
- sure, based on the Linux kernel code, that memory mappings
- whose associated filename is "/dev/zero" are guaranteed to be
- MAP_ANONYMOUS. */
- compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
- _("Could not compile regex to match /dev/zero "
- "filename"));
- /* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
- without the "(deleted)" string in the end). These filenames
- refer to shared memory (shmem), and memory mappings
- associated with them are MAP_ANONYMOUS as well. */
- compile_rx_or_error (&shmem_file_regex,
- "^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
- _("Could not compile regex to match shmem "
- "filenames"));
- /* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
- Linux kernel's 'n_link == 0' code, which is responsible to
- decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
- mapping. In other words, if FILE_DELETED_REGEX matches, it
- does not necessarily mean that we are dealing with an
- anonymous shared mapping. However, there is no easy way to
- detect this currently, so this is the best approximation we
- have.
-
- As a result, GDB will dump readonly pages of deleted
- executables when using the default value of coredump_filter
- (0x33), while the Linux kernel will not dump those pages.
- But we can live with that. */
- compile_rx_or_error (&file_deleted_regex, " (deleted)$",
- _("Could not compile regex to match "
- "'<file> (deleted)'"));
- /* We will never release these regexes, so just discard the
- cleanups. */
- discard_cleanups (c);
+ regexes.emplace ();
/* If we reached this point, then everything succeeded. */
init_regex_p = 1;
}
if (*filename == '\0'
- || regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
- || regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
- || regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
+ || regexes->dev_zero.exec (filename, 0, NULL, 0) == 0
+ || regexes->shmem_file.exec (filename, 0, NULL, 0) == 0
+ || regexes->file_deleted.exec (filename, 0, NULL, 0) == 0)
return 1;
return 0;
return 0;
/* Check if we should exclude this mapping. */
- if (v->exclude_coredump)
+ if (!dump_excluded_mappings && v->exclude_coredump)
return 0;
/* Update our notion of whether this mapping is shared or
pid = current_inferior ()->pid;
}
- args = skip_spaces_const (args);
+ args = skip_spaces (args);
if (args && args[0])
error (_("Too many parameters: %s"), args);
if (cmdline_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cmdline", pid);
- data = target_fileio_read_stralloc (NULL, filename);
- if (data)
+ gdb_byte *buffer;
+ ssize_t len = target_fileio_read_alloc (NULL, filename, &buffer);
+
+ if (len > 0)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
- printf_filtered ("cmdline = '%s'\n", data);
- do_cleanups (cleanup);
+ gdb::unique_xmalloc_ptr<char> cmdline ((char *) buffer);
+ ssize_t pos;
+
+ for (pos = 0; pos < len - 1; pos++)
+ {
+ if (buffer[pos] == '\0')
+ buffer[pos] = ' ';
+ }
+ buffer[len - 1] = '\0';
+ printf_filtered ("cmdline = '%s'\n", buffer);
}
else
warning (_("unable to open /proc file '%s'"), filename);
if (cwd_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cwd", pid);
- data = target_fileio_readlink (NULL, filename, &target_errno);
- if (data)
- {
- struct cleanup *cleanup = make_cleanup (xfree, data);
- printf_filtered ("cwd = '%s'\n", data);
- do_cleanups (cleanup);
- }
+ gdb::optional<std::string> contents
+ = target_fileio_readlink (NULL, filename, &target_errno);
+ if (contents.has_value ())
+ printf_filtered ("cwd = '%s'\n", contents->c_str ());
else
warning (_("unable to read link '%s'"), filename);
}
if (exe_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/exe", pid);
- data = target_fileio_readlink (NULL, filename, &target_errno);
- if (data)
- {
- struct cleanup *cleanup = make_cleanup (xfree, data);
- printf_filtered ("exe = '%s'\n", data);
- do_cleanups (cleanup);
- }
+ gdb::optional<std::string> contents
+ = target_fileio_readlink (NULL, filename, &target_errno);
+ if (contents.has_value ())
+ printf_filtered ("exe = '%s'\n", contents->c_str ());
else
warning (_("unable to read link '%s'"), filename);
}
if (mappings_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/maps", pid);
- data = target_fileio_read_stralloc (NULL, filename);
- if (data)
+ gdb::unique_xmalloc_ptr<char> map
+ = target_fileio_read_stralloc (NULL, filename);
+ if (map != NULL)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line;
printf_filtered (_("Mapped address spaces:\n\n"));
" Size", " Offset", "objfile");
}
- for (line = strtok (data, "\n"); line; line = strtok (NULL, "\n"))
+ for (line = strtok (map.get (), "\n");
+ line;
+ line = strtok (NULL, "\n"))
{
ULONGEST addr, endaddr, offset, inode;
const char *permissions, *device, *filename;
*filename? filename : "");
}
}
-
- do_cleanups (cleanup);
}
else
warning (_("unable to open /proc file '%s'"), filename);
if (status_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/status", pid);
- data = target_fileio_read_stralloc (NULL, filename);
- if (data)
- {
- struct cleanup *cleanup = make_cleanup (xfree, data);
- puts_filtered (data);
- do_cleanups (cleanup);
- }
+ gdb::unique_xmalloc_ptr<char> status
+ = target_fileio_read_stralloc (NULL, filename);
+ if (status)
+ puts_filtered (status.get ());
else
warning (_("unable to open /proc file '%s'"), filename);
}
if (stat_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/stat", pid);
- data = target_fileio_read_stralloc (NULL, filename);
- if (data)
+ gdb::unique_xmalloc_ptr<char> statstr
+ = target_fileio_read_stralloc (NULL, filename);
+ if (statstr)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
- const char *p = data;
+ const char *p = statstr.get ();
printf_filtered (_("Process: %s\n"),
pulongest (strtoulst (p, &p, 10)));
- p = skip_spaces_const (p);
+ p = skip_spaces (p);
if (*p == '(')
{
/* ps command also relies on no trailing fields
}
}
- p = skip_spaces_const (p);
+ p = skip_spaces (p);
if (*p)
printf_filtered (_("State: %c\n"), *p++);
printf_filtered (_("wchan (system call): %s\n"),
hex_string (strtoulst (p, &p, 10)));
#endif
- do_cleanups (cleanup);
}
else
warning (_("unable to open /proc file '%s'"), filename);
{
asection *section;
ULONGEST count, page_size;
- unsigned char *descdata, *filenames, *descend, *contents;
+ unsigned char *descdata, *filenames, *descend;
size_t note_size;
unsigned int addr_size_bits, addr_size;
- struct cleanup *cleanup;
struct gdbarch *core_gdbarch = gdbarch_from_bfd (core_bfd);
/* We assume this for reading 64-bit core files. */
gdb_static_assert (sizeof (ULONGEST) >= 8);
if (note_size < 2 * addr_size)
error (_("malformed core note - too short for header"));
- contents = (unsigned char *) xmalloc (note_size);
- cleanup = make_cleanup (xfree, contents);
- if (!bfd_get_section_contents (core_bfd, section, contents, 0, note_size))
+ gdb::def_vector<unsigned char> contents (note_size);
+ if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
error (_("could not get core note contents"));
- descdata = contents;
+ descdata = contents.data ();
descend = descdata + note_size;
if (descdata[note_size - 1] != '\0')
filenames += 1 + strlen ((char *) filenames);
}
-
- do_cleanups (cleanup);
}
/* Implement "info proc" for a corefile. */
error (_("unable to handle request"));
}
+/* Read siginfo data from the core, if possible. Returns -1 on
+ failure. Otherwise, returns the number of bytes read. READBUF,
+ OFFSET, and LEN are all as specified by the to_xfer_partial
+ interface. */
+
+static LONGEST
+linux_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf,
+ ULONGEST offset, ULONGEST len)
+{
+ thread_section_name section_name (".note.linuxcore.siginfo", inferior_ptid);
+ asection *section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
+ if (section == NULL)
+ return -1;
+
+ if (!bfd_get_section_contents (core_bfd, section, readbuf, offset, len))
+ return -1;
+
+ return len;
+}
+
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
{
char mapsfilename[100];
char coredumpfilter_name[100];
- char *data, *coredumpfilterdata;
pid_t pid;
/* Default dump behavior of coredump_filter (0x33), according to
Documentation/filesystems/proc.txt from the Linux kernel
{
xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
"/proc/%d/coredump_filter", pid);
- coredumpfilterdata = target_fileio_read_stralloc (NULL,
- coredumpfilter_name);
+ gdb::unique_xmalloc_ptr<char> coredumpfilterdata
+ = target_fileio_read_stralloc (NULL, coredumpfilter_name);
if (coredumpfilterdata != NULL)
{
unsigned int flags;
- sscanf (coredumpfilterdata, "%x", &flags);
+ sscanf (coredumpfilterdata.get (), "%x", &flags);
filterflags = (enum filter_flag) flags;
- xfree (coredumpfilterdata);
}
}
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
- data = target_fileio_read_stralloc (NULL, mapsfilename);
+ gdb::unique_xmalloc_ptr<char> data
+ = target_fileio_read_stralloc (NULL, mapsfilename);
if (data == NULL)
{
/* Older Linux kernels did not support /proc/PID/smaps. */
if (data != NULL)
{
- struct cleanup *cleanup = make_cleanup (xfree, data);
char *line, *t;
- line = strtok_r (data, "\n", &t);
+ line = strtok_r (data.get (), "\n", &t);
while (line != NULL)
{
ULONGEST addr, endaddr, offset, inode;
filename, obfd);
}
- do_cleanups (cleanup);
return 0;
}
};
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
- gdb_byte *spu_ids;
- LONGEST i, j, size;
/* Determine list of SPU ids. */
- size = target_read_alloc (¤t_target, TARGET_OBJECT_SPU,
- NULL, &spu_ids);
+ gdb::optional<gdb::byte_vector>
+ spu_ids = target_read_alloc (¤t_target, TARGET_OBJECT_SPU, NULL);
+
+ if (!spu_ids)
+ return note_data;
/* Generate corefile notes for each SPU file. */
- for (i = 0; i < size; i += 4)
+ for (size_t i = 0; i < spu_ids->size (); i += 4)
{
- int fd = extract_unsigned_integer (spu_ids + i, 4, byte_order);
+ int fd = extract_unsigned_integer (spu_ids->data () + i, 4, byte_order);
- for (j = 0; j < sizeof (spu_files) / sizeof (spu_files[0]); j++)
+ for (size_t j = 0; j < sizeof (spu_files) / sizeof (spu_files[0]); j++)
{
char annex[32], note_name[32];
- gdb_byte *spu_data;
- LONGEST spu_len;
xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[j]);
- spu_len = target_read_alloc (¤t_target, TARGET_OBJECT_SPU,
- annex, &spu_data);
- if (spu_len > 0)
+ gdb::optional<gdb::byte_vector> spu_data
+ = target_read_alloc (¤t_target, TARGET_OBJECT_SPU, annex);
+
+ if (spu_data && !spu_data->empty ())
{
xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
note_data = elfcore_write_note (obfd, note_data, note_size,
note_name, NT_SPU,
- spu_data, spu_len);
- xfree (spu_data);
+ spu_data->data (),
+ spu_data->size ());
if (!note_data)
- {
- xfree (spu_ids);
- return NULL;
- }
+ return nullptr;
}
}
}
- if (size > 0)
- xfree (spu_ids);
-
return note_data;
}
linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
char *note_data, int *note_size)
{
- struct cleanup *cleanup;
- struct obstack data_obstack, filename_obstack;
struct linux_make_mappings_data mapping_data;
struct type *long_type
= arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), 0, "long");
gdb_byte buf[sizeof (ULONGEST)];
- obstack_init (&data_obstack);
- cleanup = make_cleanup_obstack_free (&data_obstack);
- obstack_init (&filename_obstack);
- make_cleanup_obstack_free (&filename_obstack);
+ auto_obstack data_obstack, filename_obstack;
mapping_data.file_count = 0;
mapping_data.data_obstack = &data_obstack;
obstack_object_size (&data_obstack));
}
- do_cleanups (cleanup);
return note_data;
}
char *note_data, int *note_size,
enum gdb_signal stop_signal)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct linux_collect_regset_section_cb_data data;
data.gdbarch = gdbarch;
return data.note_data;
}
-/* Fetch the siginfo data for the current thread, if it exists. If
- there is no data, or we could not read it, return NULL. Otherwise,
- return a newly malloc'd buffer holding the data and fill in *SIZE
- with the size of the data. The caller is responsible for freeing
- the data. */
+/* Fetch the siginfo data for the specified thread, if it exists. If
+ there is no data, or we could not read it, return an empty
+ buffer. */
-static gdb_byte *
-linux_get_siginfo_data (struct gdbarch *gdbarch, LONGEST *size)
+static gdb::byte_vector
+linux_get_siginfo_data (thread_info *thread, struct gdbarch *gdbarch)
{
struct type *siginfo_type;
- gdb_byte *buf;
LONGEST bytes_read;
- struct cleanup *cleanups;
if (!gdbarch_get_siginfo_type_p (gdbarch))
- return NULL;
-
+ return gdb::byte_vector ();
+
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+ inferior_ptid = thread->ptid;
+
siginfo_type = gdbarch_get_siginfo_type (gdbarch);
- buf = (gdb_byte *) xmalloc (TYPE_LENGTH (siginfo_type));
- cleanups = make_cleanup (xfree, buf);
+ gdb::byte_vector buf (TYPE_LENGTH (siginfo_type));
bytes_read = target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
- buf, 0, TYPE_LENGTH (siginfo_type));
- if (bytes_read == TYPE_LENGTH (siginfo_type))
- {
- discard_cleanups (cleanups);
- *size = bytes_read;
- }
- else
- {
- do_cleanups (cleanups);
- buf = NULL;
- }
+ buf.data (), 0, TYPE_LENGTH (siginfo_type));
+ if (bytes_read != TYPE_LENGTH (siginfo_type))
+ buf.clear ();
return buf;
}
linux_corefile_thread (struct thread_info *info,
struct linux_corefile_thread_data *args)
{
- struct cleanup *old_chain;
struct regcache *regcache;
- gdb_byte *siginfo_data;
- LONGEST siginfo_size = 0;
regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
- old_chain = save_inferior_ptid ();
- inferior_ptid = info->ptid;
target_fetch_registers (regcache, -1);
- siginfo_data = linux_get_siginfo_data (args->gdbarch, &siginfo_size);
- do_cleanups (old_chain);
-
- old_chain = make_cleanup (xfree, siginfo_data);
+ gdb::byte_vector siginfo_data = linux_get_siginfo_data (info, args->gdbarch);
args->note_data = linux_collect_thread_registers
(regcache, info->ptid, args->obfd, args->note_data,
/* Don't return anything if we got no register information above,
such a core file is useless. */
if (args->note_data != NULL)
- if (siginfo_data != NULL)
+ if (!siginfo_data.empty ())
args->note_data = elfcore_write_note (args->obfd,
args->note_data,
args->note_size,
"CORE", NT_SIGINFO,
- siginfo_data, siginfo_size);
-
- do_cleanups (old_chain);
+ siginfo_data.data (),
+ siginfo_data.size ());
}
/* Fill the PRPSINFO structure with information about the process being
/* 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. */
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 (NULL, filename);
+ /* The full name of the program which generated the corefile. */
+ gdb::unique_xmalloc_ptr<char> fname
+ = target_fileio_read_stralloc (NULL, filename);
- if (fname == NULL || *fname == '\0')
+ if (fname == NULL || fname.get ()[0] == '\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);
+ basename = lbasename (fname.get ());
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);
+ /* The arguments of the program. */
+ std::string psargs = fname.get ();
if (infargs != NULL)
- psargs = reconcat (psargs, psargs, " ", infargs, (char *) NULL);
+ psargs = psargs + " " + infargs;
- make_cleanup (xfree, psargs);
-
- strncpy (p->pr_psargs, psargs, sizeof (p->pr_psargs));
+ strncpy (p->pr_psargs, psargs.c_str (), 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 (NULL, filename);
- make_cleanup (xfree, proc_stat);
+ /* The contents of `/proc/PID/stat'. */
+ gdb::unique_xmalloc_ptr<char> proc_stat_contents
+ = target_fileio_read_stralloc (NULL, filename);
+ char *proc_stat = proc_stat_contents.get ();
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;
}
/* ps command also relies on no trailing fields ever contain ')'. */
proc_stat = strrchr (proc_stat, ')');
if (proc_stat == NULL)
- {
- do_cleanups (c);
- return 1;
- }
+ return 1;
proc_stat++;
proc_stat = skip_spaces (proc_stat);
/* 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;
}
/* 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 (NULL, filename);
- make_cleanup (xfree, proc_status);
+ /* The contents of `/proc/PID/status'. */
+ gdb::unique_xmalloc_ptr<char> proc_status_contents
+ = target_fileio_read_stralloc (NULL, filename);
+ char *proc_status = proc_status_contents.get ();
if (proc_status == NULL || *proc_status == '\0')
{
/* Returning 1 since we already have a bunch of information. */
- do_cleanups (c);
return 1;
}
p->pr_gid = strtol (tmpstr, &tmpstr, 10);
}
- do_cleanups (c);
-
return 1;
}
struct linux_corefile_thread_data thread_args;
struct elf_internal_linux_prpsinfo prpsinfo;
char *note_data = NULL;
- gdb_byte *auxv;
- int auxv_len;
struct thread_info *curr_thr, *signalled_thr, *thr;
if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
if (linux_fill_prpsinfo (&prpsinfo))
{
- if (gdbarch_elfcore_write_linux_prpsinfo_p (gdbarch))
- {
- note_data = gdbarch_elfcore_write_linux_prpsinfo (gdbarch, obfd,
- note_data, note_size,
- &prpsinfo);
- }
+ if (gdbarch_ptr_bit (gdbarch) == 64)
+ note_data = elfcore_write_linux_prpsinfo64 (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);
- }
+ note_data = elfcore_write_linux_prpsinfo32 (obfd,
+ note_data, note_size,
+ &prpsinfo);
}
/* Thread register information. */
return NULL;
/* Auxillary vector. */
- auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV,
- NULL, &auxv);
- if (auxv_len > 0)
+ gdb::optional<gdb::byte_vector> auxv =
+ target_read_alloc (¤t_target, TARGET_OBJECT_AUXV, NULL);
+ if (auxv && !auxv->empty ())
{
note_data = elfcore_write_note (obfd, note_data, note_size,
- "CORE", NT_AUXV, auxv, auxv_len);
- xfree (auxv);
+ "CORE", NT_AUXV, auxv->data (),
+ auxv->size ());
if (!note_data)
return NULL;
return -1;
}
-/* Rummage through mappings to find a mapping's size. */
-
-static int
-find_mapping_size (CORE_ADDR vaddr, unsigned long size,
- int read, int write, int exec, int modified,
- void *data)
-{
- struct mem_range *range = (struct mem_range *) data;
-
- if (vaddr == range->start)
- {
- range->length = size;
- return 1;
- }
- return 0;
-}
-
/* Helper for linux_vsyscall_range that does the real work of finding
the vsyscall's address range. */
static int
linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
{
+ char filename[100];
+ long pid;
+
if (target_auxv_search (¤t_target, AT_SYSINFO_EHDR, &range->start) <= 0)
return 0;
- /* This is installed by linux_init_abi below, so should always be
- available. */
- gdb_assert (gdbarch_find_memory_regions_p (target_gdbarch ()));
+ /* It doesn't make sense to access the host's /proc when debugging a
+ core file. Instead, look for the PT_LOAD segment that matches
+ the vDSO. */
+ if (!target_has_execution)
+ {
+ Elf_Internal_Phdr *phdrs;
+ long phdrs_size;
+ int num_phdrs, i;
- range->length = 0;
- gdbarch_find_memory_regions (gdbarch, find_mapping_size, range);
- return 1;
+ phdrs_size = bfd_get_elf_phdr_upper_bound (core_bfd);
+ if (phdrs_size == -1)
+ return 0;
+
+ phdrs = (Elf_Internal_Phdr *) alloca (phdrs_size);
+ num_phdrs = bfd_get_elf_phdrs (core_bfd, phdrs);
+ if (num_phdrs == -1)
+ return 0;
+
+ for (i = 0; i < num_phdrs; i++)
+ if (phdrs[i].p_type == PT_LOAD
+ && phdrs[i].p_vaddr == range->start)
+ {
+ range->length = phdrs[i].p_memsz;
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /* We need to know the real target PID to access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 0;
+
+ pid = current_inferior ()->pid;
+
+ /* Note that reading /proc/PID/task/PID/maps (1) is much faster than
+ reading /proc/PID/maps (2). The later identifies thread stacks
+ in the output, which requires scanning every thread in the thread
+ group to check whether a VMA is actually a thread's stack. With
+ Linux 4.4 on an Intel i7-4810MQ @ 2.80GHz, with an inferior with
+ a few thousand threads, (1) takes a few miliseconds, while (2)
+ takes several seconds. Also note that "smaps", what we read for
+ determining core dump mappings, is even slower than "maps". */
+ xsnprintf (filename, sizeof filename, "/proc/%ld/task/%ld/maps", pid, pid);
+ gdb::unique_xmalloc_ptr<char> data
+ = target_fileio_read_stralloc (NULL, filename);
+ if (data != NULL)
+ {
+ char *line;
+ char *saveptr = NULL;
+
+ for (line = strtok_r (data.get (), "\n", &saveptr);
+ line != NULL;
+ line = strtok_r (NULL, "\n", &saveptr))
+ {
+ ULONGEST addr, endaddr;
+ const char *p = line;
+
+ addr = strtoulst (p, &p, 16);
+ if (addr == range->start)
+ {
+ if (*p == '-')
+ p++;
+ endaddr = strtoulst (p, &p, 16);
+ range->length = endaddr - addr;
+ return 1;
+ }
+ }
+ }
+ else
+ warning (_("unable to open /proc file '%s'"), filename);
+
+ return 0;
}
/* Implementation of the "vsyscall_range" gdbarch hook. Handles
arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
0);
- addr_val = call_function_by_hand (mmap_val, ARG_LAST, arg);
+ addr_val = call_function_by_hand (mmap_val, NULL, ARG_LAST, arg);
retval = value_as_address (addr_val);
if (retval == (CORE_ADDR) -1)
error (_("Failed inferior mmap call for %s bytes, errno is changed."),
/* Assuming sizeof (unsigned long) == sizeof (size_t). */
arg[ARG_LENGTH] = value_from_ulongest
(builtin_type (gdbarch)->builtin_unsigned_long, size);
- retval_val = call_function_by_hand (munmap_val, ARG_LAST, arg);
+ retval_val = call_function_by_hand (munmap_val, NULL, ARG_LAST, arg);
retval = value_as_long (retval_val);
if (retval != 0)
warning (_("Failed inferior munmap call at %s for %s bytes, "
" corefiles is %s.\n"), value);
}
+/* Display whether the gcore command is dumping mappings marked with
+ the VM_DONTDUMP flag. */
+
+static void
+show_dump_excluded_mappings (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Dumping of mappings marked with the VM_DONTDUMP"
+ " flag is %s.\n"), value);
+}
+
/* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types. */
set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
set_gdbarch_info_proc (gdbarch, linux_info_proc);
set_gdbarch_core_info_proc (gdbarch, linux_core_info_proc);
+ set_gdbarch_core_xfer_siginfo (gdbarch, linux_core_xfer_siginfo);
set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes);
set_gdbarch_has_shared_address_space (gdbarch,
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_linux_tdep;
-
void
_initialize_linux_tdep (void)
{
linux_inferior_data
= register_inferior_data_with_cleanup (NULL, linux_inferior_data_cleanup);
/* Observers used to invalidate the cache when needed. */
- observer_attach_inferior_exit (invalidate_linux_cache_inf);
- observer_attach_inferior_appeared (invalidate_linux_cache_inf);
+ gdb::observers::inferior_exit.attach (invalidate_linux_cache_inf);
+ gdb::observers::inferior_appeared.attach (invalidate_linux_cache_inf);
add_setshow_boolean_cmd ("use-coredump-filter", class_files,
&use_coredump_filter, _("\
about this file, refer to the manpage of core(5)."),
NULL, show_use_coredump_filter,
&setlist, &showlist);
+
+ add_setshow_boolean_cmd ("dump-excluded-mappings", class_files,
+ &dump_excluded_mappings, _("\
+Set whether gcore should dump mappings marked with the VM_DONTDUMP flag."),
+ _("\
+Show whether gcore should dump mappings marked with the VM_DONTDUMP flag."),
+ _("\
+Use this command to set whether gcore should dump mappings marked with the\n\
+VM_DONTDUMP flag (\"dd\" in /proc/PID/smaps) when generating the corefile. For\n\
+more information about this file, refer to the manpage of proc(5) and core(5)."),
+ NULL, show_dump_excluded_mappings,
+ &setlist, &showlist);
}