summaryrefslogtreecommitdiff
path: root/gdb/linux-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/linux-tdep.c')
-rw-r--r--gdb/linux-tdep.c361
1 files changed, 195 insertions, 166 deletions
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index b0056358cf9..4e728a06e7e 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -31,12 +31,12 @@
#include "inferior.h"
#include "cli/cli-utils.h"
#include "arch-utils.h"
-#include "gdb_obstack.h"
+#include "gdbsupport/gdb_obstack.h"
#include "observable.h"
#include "objfiles.h"
#include "infcall.h"
#include "gdbcmd.h"
-#include "gdb_regex.h"
+#include "gdbsupport/gdb_regex.h"
#include "gdbsupport/enum-flags.h"
#include "gdbsupport/gdb_optional.h"
#include "gcore.h"
@@ -44,6 +44,7 @@
#include "solib-svr4.h"
#include <ctype.h>
+#include <unordered_map>
/* This enum represents the values that the user can choose when
informing the Linux kernel about which memory mappings will be
@@ -441,42 +442,55 @@ linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
return normal_pid_to_str (ptid);
}
+/* Data from one mapping from /proc/PID/maps. */
+
+struct mapping
+{
+ ULONGEST addr;
+ ULONGEST endaddr;
+ gdb::string_view permissions;
+ ULONGEST offset;
+ gdb::string_view device;
+ ULONGEST inode;
+
+ /* This field is guaranteed to be NULL-terminated, hence it is not a
+ gdb::string_view. */
+ const char *filename;
+};
+
/* Service function for corefiles and info proc. */
-static void
-read_mapping (const char *line,
- ULONGEST *addr, ULONGEST *endaddr,
- const char **permissions, size_t *permissions_len,
- ULONGEST *offset,
- const char **device, size_t *device_len,
- ULONGEST *inode,
- const char **filename)
+static mapping
+read_mapping (const char *line)
{
+ struct mapping mapping;
const char *p = line;
- *addr = strtoulst (p, &p, 16);
+ mapping.addr = strtoulst (p, &p, 16);
if (*p == '-')
p++;
- *endaddr = strtoulst (p, &p, 16);
+ mapping.endaddr = strtoulst (p, &p, 16);
p = skip_spaces (p);
- *permissions = p;
+ const char *permissions_start = p;
while (*p && !isspace (*p))
p++;
- *permissions_len = p - *permissions;
+ mapping.permissions = {permissions_start, (size_t) (p - permissions_start)};
- *offset = strtoulst (p, &p, 16);
+ mapping.offset = strtoulst (p, &p, 16);
p = skip_spaces (p);
- *device = p;
+ const char *device_start = p;
while (*p && !isspace (*p))
p++;
- *device_len = p - *device;
+ mapping.device = {device_start, (size_t) (p - device_start)};
- *inode = strtoulst (p, &p, 10);
+ mapping.inode = strtoulst (p, &p, 10);
p = skip_spaces (p);
- *filename = p;
+ mapping.filename = p;
+
+ return mapping;
}
/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
@@ -824,7 +838,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
if (args && args[0])
error (_("Too many parameters: %s"), args);
- printf_filtered (_("process %ld\n"), pid);
+ gdb_printf (_("process %ld\n"), pid);
if (cmdline_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cmdline", pid);
@@ -842,7 +856,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
buffer[pos] = ' ';
}
buffer[len - 1] = '\0';
- printf_filtered ("cmdline = '%s'\n", buffer);
+ gdb_printf ("cmdline = '%s'\n", buffer);
}
else
warning (_("unable to open /proc file '%s'"), filename);
@@ -853,7 +867,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
gdb::optional<std::string> contents
= target_fileio_readlink (NULL, filename, &target_errno);
if (contents.has_value ())
- printf_filtered ("cwd = '%s'\n", contents->c_str ());
+ gdb_printf ("cwd = '%s'\n", contents->c_str ());
else
warning (_("unable to read link '%s'"), filename);
}
@@ -863,7 +877,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
gdb::optional<std::string> contents
= target_fileio_readlink (NULL, filename, &target_errno);
if (contents.has_value ())
- printf_filtered ("exe = '%s'\n", contents->c_str ());
+ gdb_printf ("exe = '%s'\n", contents->c_str ());
else
warning (_("unable to read link '%s'"), filename);
}
@@ -876,20 +890,18 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
{
char *line;
- printf_filtered (_("Mapped address spaces:\n\n"));
+ gdb_printf (_("Mapped address spaces:\n\n"));
if (gdbarch_addr_bit (gdbarch) == 32)
{
- printf_filtered ("\t%10s %10s %10s %10s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "objfile");
+ gdb_printf ("\t%10s %10s %10s %10s %s %s\n",
+ "Start Addr", " End Addr", " Size",
+ " Offset", "Perms ", "objfile");
}
else
{
- printf_filtered (" %18s %18s %10s %10s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "objfile");
+ gdb_printf (" %18s %18s %10s %10s %s %s\n",
+ "Start Addr", " End Addr", " Size",
+ " Offset", "Perms ", "objfile");
}
char *saveptr;
@@ -897,32 +909,29 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
line;
line = strtok_r (NULL, "\n", &saveptr))
{
- ULONGEST addr, endaddr, offset, inode;
- const char *permissions, *device, *mapping_filename;
- size_t permissions_len, device_len;
-
- read_mapping (line, &addr, &endaddr,
- &permissions, &permissions_len,
- &offset, &device, &device_len,
- &inode, &mapping_filename);
+ struct mapping m = read_mapping (line);
if (gdbarch_addr_bit (gdbarch) == 32)
{
- printf_filtered ("\t%10s %10s %10s %10s %s\n",
- paddress (gdbarch, addr),
- paddress (gdbarch, endaddr),
- hex_string (endaddr - addr),
- hex_string (offset),
- *mapping_filename ? mapping_filename : "");
+ gdb_printf ("\t%10s %10s %10s %10s %-5.*s %s\n",
+ paddress (gdbarch, m.addr),
+ paddress (gdbarch, m.endaddr),
+ hex_string (m.endaddr - m.addr),
+ hex_string (m.offset),
+ (int) m.permissions.size (),
+ m.permissions.data (),
+ m.filename);
}
else
{
- printf_filtered (" %18s %18s %10s %10s %s\n",
- paddress (gdbarch, addr),
- paddress (gdbarch, endaddr),
- hex_string (endaddr - addr),
- hex_string (offset),
- *mapping_filename ? mapping_filename : "");
+ gdb_printf (" %18s %18s %10s %10s %-5.*s %s\n",
+ paddress (gdbarch, m.addr),
+ paddress (gdbarch, m.endaddr),
+ hex_string (m.endaddr - m.addr),
+ hex_string (m.offset),
+ (int) m.permissions.size (),
+ m.permissions.data (),
+ m.filename);
}
}
}
@@ -935,7 +944,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
gdb::unique_xmalloc_ptr<char> status
= target_fileio_read_stralloc (NULL, filename);
if (status)
- puts_filtered (status.get ());
+ gdb_puts (status.get ());
else
warning (_("unable to open /proc file '%s'"), filename);
}
@@ -948,8 +957,8 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
{
const char *p = statstr.get ();
- printf_filtered (_("Process: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Process: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
p = skip_spaces (p);
if (*p == '(')
@@ -959,117 +968,117 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
const char *ep = strrchr (p, ')');
if (ep != NULL)
{
- printf_filtered ("Exec file: %.*s\n",
- (int) (ep - p - 1), p + 1);
+ gdb_printf ("Exec file: %.*s\n",
+ (int) (ep - p - 1), p + 1);
p = ep + 1;
}
}
p = skip_spaces (p);
if (*p)
- printf_filtered (_("State: %c\n"), *p++);
+ gdb_printf (_("State: %c\n"), *p++);
if (*p)
- printf_filtered (_("Parent process: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Parent process: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Process group: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Process group: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Session id: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Session id: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("TTY: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("TTY: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("TTY owner process group: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("TTY owner process group: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Flags: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Flags: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Minor faults (no memory page): %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Minor faults (no memory page): %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Minor faults, children: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Minor faults, children: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Major faults (memory page faults): %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Major faults (memory page faults): %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Major faults, children: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Major faults, children: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("utime: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("utime: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("stime: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("stime: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("utime, children: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("utime, children: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("stime, children: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("stime, children: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("jiffies remaining in current "
- "time slice: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("jiffies remaining in current "
+ "time slice: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("'nice' value: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("'nice' value: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("jiffies until next timeout: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("jiffies until next timeout: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("jiffies until next SIGALRM: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("jiffies until next SIGALRM: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("start time (jiffies since "
- "system boot): %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("start time (jiffies since "
+ "system boot): %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Virtual memory size: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Virtual memory size: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Resident set size: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("Resident set size: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("rlim: %s\n"),
- pulongest (strtoulst (p, &p, 10)));
+ gdb_printf (_("rlim: %s\n"),
+ pulongest (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Start of text: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Start of text: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("End of text: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("End of text: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Start of stack: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Start of stack: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
#if 0 /* Don't know how architecture-dependent the rest is...
Anyway the signal bitmap info is available from "status". */
if (*p)
- printf_filtered (_("Kernel stack pointer: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Kernel stack pointer: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Kernel instr pointer: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Kernel instr pointer: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Pending signals bitmap: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Pending signals bitmap: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Blocked signals bitmap: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Blocked signals bitmap: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Ignored signals bitmap: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Ignored signals bitmap: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("Catched signals bitmap: %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("Catched signals bitmap: %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
if (*p)
- printf_filtered (_("wchan (system call): %s\n"),
- hex_string (strtoulst (p, &p, 10)));
+ gdb_printf (_("wchan (system call): %s\n"),
+ hex_string (strtoulst (p, &p, 10)));
#endif
}
else
@@ -1177,6 +1186,22 @@ linux_read_core_file_mappings
if (f != descend)
warning (_("malformed note - filename area is too big"));
+ const bfd_build_id *orig_build_id = cbfd->build_id;
+ std::unordered_map<ULONGEST, const bfd_build_id *> vma_map;
+
+ /* Search for solib build-ids in the core file. Each time one is found,
+ map the start vma of the corresponding elf header to the build-id. */
+ for (bfd_section *sec = cbfd->sections; sec != nullptr; sec = sec->next)
+ {
+ cbfd->build_id = nullptr;
+
+ if (sec->flags & SEC_LOAD
+ && (get_elf_backend_data (cbfd)->elf_backend_core_find_build_id
+ (cbfd, (bfd_vma) sec->filepos)))
+ vma_map[sec->vma] = cbfd->build_id;
+ }
+
+ cbfd->build_id = orig_build_id;
pre_loop_cb (count);
for (int i = 0; i < count; i++)
@@ -1190,8 +1215,13 @@ linux_read_core_file_mappings
descdata += addr_size;
char * filename = filenames;
filenames += strlen ((char *) filenames) + 1;
+ const bfd_build_id *build_id = nullptr;
+ auto vma_map_it = vma_map.find (start);
- loop_cb (i, start, end, file_ofs, filename, nullptr);
+ if (vma_map_it != vma_map.end ())
+ build_id = vma_map_it->second;
+
+ loop_cb (i, start, end, file_ofs, filename, build_id);
}
}
@@ -1203,39 +1233,39 @@ linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
linux_read_core_file_mappings (gdbarch, core_bfd,
[=] (ULONGEST count)
{
- printf_filtered (_("Mapped address spaces:\n\n"));
+ gdb_printf (_("Mapped address spaces:\n\n"));
if (gdbarch_addr_bit (gdbarch) == 32)
{
- printf_filtered ("\t%10s %10s %10s %10s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "objfile");
+ gdb_printf ("\t%10s %10s %10s %10s %s\n",
+ "Start Addr",
+ " End Addr",
+ " Size", " Offset", "objfile");
}
else
{
- printf_filtered (" %18s %18s %10s %10s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "objfile");
+ gdb_printf (" %18s %18s %10s %10s %s\n",
+ "Start Addr",
+ " End Addr",
+ " Size", " Offset", "objfile");
}
},
[=] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
const char *filename, const bfd_build_id *build_id)
{
if (gdbarch_addr_bit (gdbarch) == 32)
- printf_filtered ("\t%10s %10s %10s %10s %s\n",
- paddress (gdbarch, start),
- paddress (gdbarch, end),
- hex_string (end - start),
- hex_string (file_ofs),
- filename);
+ gdb_printf ("\t%10s %10s %10s %10s %s\n",
+ paddress (gdbarch, start),
+ paddress (gdbarch, end),
+ hex_string (end - start),
+ hex_string (file_ofs),
+ filename);
else
- printf_filtered (" %18s %18s %10s %10s %s\n",
- paddress (gdbarch, start),
- paddress (gdbarch, end),
- hex_string (end - start),
- hex_string (file_ofs),
- filename);
+ gdb_printf (" %18s %18s %10s %10s %s\n",
+ paddress (gdbarch, start),
+ paddress (gdbarch, end),
+ hex_string (end - start),
+ hex_string (file_ofs),
+ filename);
});
}
@@ -1254,7 +1284,7 @@ linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
exe = bfd_core_file_failing_command (core_bfd);
if (exe != NULL)
- printf_filtered ("exe = '%s'\n", exe);
+ gdb_printf ("exe = '%s'\n", exe);
else
warning (_("unable to find command name in core file"));
}
@@ -1322,19 +1352,15 @@ parse_smaps_data (const char *data,
while (line != NULL)
{
- ULONGEST addr, endaddr, offset, inode;
- const char *permissions, *device, *filename;
struct smaps_vmflags v;
- size_t permissions_len, device_len;
int read, write, exec, priv;
int has_anonymous = 0;
int mapping_anon_p;
int mapping_file_p;
memset (&v, 0, sizeof (v));
- read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
- &offset, &device, &device_len, &inode, &filename);
- mapping_anon_p = mapping_is_anonymous_p (filename);
+ struct mapping m = read_mapping (line);
+ mapping_anon_p = mapping_is_anonymous_p (m.filename);
/* If the mapping is not anonymous, then we can consider it
to be file-backed. These two states (anonymous or
file-backed) seem to be exclusive, but they can actually
@@ -1347,9 +1373,12 @@ parse_smaps_data (const char *data,
mapping_file_p = !mapping_anon_p;
/* Decode permissions. */
- read = (memchr (permissions, 'r', permissions_len) != 0);
- write = (memchr (permissions, 'w', permissions_len) != 0);
- exec = (memchr (permissions, 'x', permissions_len) != 0);
+ auto has_perm = [&m] (char c)
+ { return m.permissions.find (c) != gdb::string_view::npos; };
+ read = has_perm ('r');
+ write = has_perm ('w');
+ exec = has_perm ('x');
+
/* 'private' here actually means VM_MAYSHARE, and not
VM_SHARED. In order to know if a mapping is really
private or not, we must check the flag "sh" in the
@@ -1359,7 +1388,7 @@ parse_smaps_data (const char *data,
not have the VmFlags there. In this case, there is
really no way to know if we are dealing with VM_SHARED,
so we just assume that VM_MAYSHARE is enough. */
- priv = memchr (permissions, 'p', permissions_len) != 0;
+ priv = has_perm ('p');
/* Try to detect if region should be dumped by parsing smaps
counters. */
@@ -1421,9 +1450,9 @@ parse_smaps_data (const char *data,
/* Save the smaps entry to the vector. */
struct smaps_data map;
- map.start_address = addr;
- map.end_address = endaddr;
- map.filename = filename;
+ map.start_address = m.addr;
+ map.end_address = m.endaddr;
+ map.filename = m.filename;
map.vmflags = v;
map.read = read? true : false;
map.write = write? true : false;
@@ -1432,8 +1461,8 @@ parse_smaps_data (const char *data,
map.has_anonymous = has_anonymous;
map.mapping_anon_p = mapping_anon_p? true : false;
map.mapping_file_p = mapping_file_p? true : false;
- map.offset = offset;
- map.inode = inode;
+ map.offset = m.offset;
+ map.inode = m.inode;
smaps.emplace_back (map);
}
@@ -2630,8 +2659,8 @@ static void
show_use_coredump_filter (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
- " corefiles is %s.\n"), value);
+ gdb_printf (file, _("Use of /proc/PID/coredump_filter file to generate"
+ " corefiles is %s.\n"), value);
}
/* Display whether the gcore command is dumping mappings marked with
@@ -2641,8 +2670,8 @@ 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);
+ gdb_printf (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