From: Luis Machado <luis.machado@linaro.org>
To: gdb-patches@sourceware.org, Alan.Hayward@arm.com
Cc: omair.javaid@linaro.org, catalin.marinas@arm.com,
david.spickett@linaro.org, jose.marchesi@oracle.com
Subject: [PATCH 13/23] Refactor parsing of /proc/<pid>/smaps
Date: Wed, 15 Jul 2020 16:45:03 -0300 [thread overview]
Message-ID: <20200715194513.16641-14-luis.machado@linaro.org> (raw)
In-Reply-To: <20200715194513.16641-1-luis.machado@linaro.org>
The Linux kernel exposes the information about MTE-protected pages via the
proc filesystem, more specifically through the smaps file.
What we're looking for is a mapping with the 'mt' flag, which tells us that
mapping was created with a PROT_MTE flag and, thus, is capable of using memory
tagging.
We already parse that file for other purposes (core file
generation/filtering), so this patch refactors the code to make the parsing
of the smaps file reusable for memory tagging.
The function linux_address_in_memtag_page uses the refactored code to allow
querying for memory tag support in a particular address, and it gets used in the
next patch.
gdb/ChangeLog:
YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
* linux-tdep.c (struct smaps_vmflags) <memory_tagging>: New flag
bit.
(struct smaps_data): New struct.
(decode_vmflags): Handle the 'mt' flag.
(parse_smaps_data): New function, refactored from
linux_find_memory_regions_full.
(linux_address_in_memtag_page): New function.
(linux_find_memory_regions_full): Refactor into parse_smaps_data.
* linux-tdep.h (linux_address_in_memtag_page): New prototype.
---
gdb/linux-tdep.c | 356 +++++++++++++++++++++++++++++++----------------
gdb/linux-tdep.h | 4 +
2 files changed, 240 insertions(+), 120 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index fd4337f100..daab1761a9 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -86,8 +86,33 @@ struct smaps_vmflags
/* Is this a MAP_SHARED mapping (VM_SHARED, "sh"). */
unsigned int shared_mapping : 1;
+
+ /* Memory map has memory tagging enabled. */
+
+ unsigned int memory_tagging : 1;
};
+/* Data structure that holds the information contained in the
+ /proc/<pid>/smaps file. */
+
+struct smaps_data
+{
+ ULONGEST start_address;
+ ULONGEST end_address;
+ std::string filename;
+ struct smaps_vmflags vmflags;
+ bool read;
+ bool write;
+ bool exec;
+ bool priv;
+ bool has_anonymous;
+ bool mapping_anon_p;
+ bool mapping_file_p;
+
+ ULONGEST inode;
+ ULONGEST offset;
+};
+
/* Whether to take the /proc/PID/coredump_filter into account when
generating a corefile. */
@@ -472,6 +497,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
v->exclude_coredump = 1;
else if (strcmp (s, "sh") == 0)
v->shared_mapping = 1;
+ else if (strcmp (s, "mt") == 0)
+ v->memory_tagging = 1;
}
}
@@ -1172,6 +1199,185 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
const char *filename,
void *data);
+/* Helper function to parse the contents of /proc/<pid>/smaps into a data
+ structure, for easy access.
+
+ DATA is the contents of the smaps file. The parsed contents are stored
+ into the SMAPS vector. */
+
+static int
+parse_smaps_data (const char *data,
+ std::vector<struct smaps_data> &smaps,
+ const char *mapsfilename)
+{
+ char *line, *t;
+
+ gdb_assert (data != nullptr);
+
+ smaps.clear ();
+
+ line = strtok_r ((char *) data, "\n", &t);
+
+ 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);
+ /* 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
+ coexist. For example, if a file-backed mapping has
+ "Anonymous:" pages (see more below), then the Linux
+ kernel will dump this mapping when the user specified
+ that she only wants anonymous mappings in the corefile
+ (*even* when she explicitly disabled the dumping of
+ file-backed mappings). */
+ 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);
+ /* '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
+ VmFlags field. This is done by decode_vmflags. However,
+ if we are using a Linux kernel released before the commit
+ 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+ 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;
+
+ /* Try to detect if region should be dumped by parsing smaps
+ counters. */
+ for (line = strtok_r (NULL, "\n", &t);
+ line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+ line = strtok_r (NULL, "\n", &t))
+ {
+ char keyword[64 + 1];
+
+ if (sscanf (line, "%64s", keyword) != 1)
+ {
+ warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
+ break;
+ }
+
+ if (strcmp (keyword, "Anonymous:") == 0)
+ {
+ /* Older Linux kernels did not support the
+ "Anonymous:" counter. Check it here. */
+ has_anonymous = 1;
+ }
+ else if (strcmp (keyword, "VmFlags:") == 0)
+ decode_vmflags (line, &v);
+
+ if (strcmp (keyword, "AnonHugePages:") == 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)
+ {
+ /* Even if we are dealing with a file-backed
+ mapping, if it contains anonymous pages we
+ consider it to be *also* an anonymous
+ mapping, because this is what the Linux
+ kernel does:
+
+ // Dump segments that have been written to.
+ if (vma->anon_vma && FILTER(ANON_PRIVATE))
+ goto whole;
+
+ Note that if the mapping is already marked as
+ file-backed (i.e., mapping_file_p is
+ non-zero), then this is a special case, and
+ this mapping will be dumped either when the
+ user wants to dump file-backed *or* anonymous
+ mappings. */
+ mapping_anon_p = 1;
+ }
+ }
+ }
+ /* Save the smaps entry to the vector. */
+ struct smaps_data map;
+ std::string fname (filename);
+
+ map.start_address = addr;
+ map.end_address = endaddr;
+ map.filename = fname;
+ map.vmflags = v;
+ map.read = read? true : false;
+ map.write = write? true : false;
+ map.exec = exec? true : false;
+ map.priv = priv? true : false;
+ 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;
+
+ smaps.emplace_back (map);
+ }
+
+ return 0;
+}
+
+/* See linux-tdep.h. */
+
+bool
+linux_address_in_memtag_page (CORE_ADDR address)
+{
+ if (current_inferior ()->fake_pid_p)
+ return false;
+
+ pid_t pid = current_inferior ()->pid;
+
+ std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
+
+ gdb::unique_xmalloc_ptr<char> data
+ = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
+
+ if (data == nullptr)
+ return false;
+
+ std::vector<struct smaps_data> smaps;
+
+ /* Parse the contents of smaps into a vector. */
+ parse_smaps_data (data.get (), smaps, smaps_file.c_str ());
+
+ if (!smaps.empty ())
+ {
+ for (struct smaps_data map : smaps)
+ {
+ /* Is the address within [start_address, end_address) in a page
+ mapped with memory tagging? */
+ if (address >= map.start_address
+ && address < map.end_address
+ && map.vmflags.memory_tagging)
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* List memory regions in the inferior for a corefile. */
static int
@@ -1179,8 +1385,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
linux_find_memory_region_ftype *func,
void *obfd)
{
- char mapsfilename[100];
- char coredumpfilter_name[100];
+ std::string coredumpfilter_name;
pid_t pid;
/* Default dump behavior of coredump_filter (0x33), according to
Documentation/filesystems/proc.txt from the Linux kernel
@@ -1198,10 +1403,9 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
if (use_coredump_filter)
{
- xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
- "/proc/%d/coredump_filter", pid);
+ coredumpfilter_name = string_printf ("/proc/%d/coredump_filter", pid);
gdb::unique_xmalloc_ptr<char> coredumpfilterdata
- = target_fileio_read_stralloc (NULL, coredumpfilter_name);
+ = target_fileio_read_stralloc (NULL, coredumpfilter_name.c_str ());
if (coredumpfilterdata != NULL)
{
unsigned int flags;
@@ -1211,124 +1415,37 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
}
}
- xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
+ std::string mapsfilename = string_printf ("/proc/%d/smaps", pid);
gdb::unique_xmalloc_ptr<char> data
- = target_fileio_read_stralloc (NULL, mapsfilename);
+ = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
if (data == NULL)
{
/* Older Linux kernels did not support /proc/PID/smaps. */
- xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
- data = target_fileio_read_stralloc (NULL, mapsfilename);
+ mapsfilename = string_printf ("/proc/%d/maps", pid);
+ data = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
}
- if (data != NULL)
- {
- char *line, *t;
-
- line = strtok_r (data.get (), "\n", &t);
- 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 should_dump_p = 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);
- /* 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
- coexist. For example, if a file-backed mapping has
- "Anonymous:" pages (see more below), then the Linux
- kernel will dump this mapping when the user specified
- that she only wants anonymous mappings in the corefile
- (*even* when she explicitly disabled the dumping of
- file-backed mappings). */
- 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);
- /* '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
- VmFlags field. This is done by decode_vmflags. However,
- if we are using a Linux kernel released before the commit
- 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
- 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;
-
- /* Try to detect if region should be dumped by parsing smaps
- counters. */
- for (line = strtok_r (NULL, "\n", &t);
- line != NULL && line[0] >= 'A' && line[0] <= 'Z';
- line = strtok_r (NULL, "\n", &t))
- {
- char keyword[64 + 1];
+ if (data == nullptr)
+ return 1;
- if (sscanf (line, "%64s", keyword) != 1)
- {
- warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
- break;
- }
+ std::vector<struct smaps_data> smaps;
- if (strcmp (keyword, "Anonymous:") == 0)
- {
- /* Older Linux kernels did not support the
- "Anonymous:" counter. Check it here. */
- has_anonymous = 1;
- }
- else if (strcmp (keyword, "VmFlags:") == 0)
- decode_vmflags (line, &v);
+ /* Parse the contents of smaps into a vector. */
+ parse_smaps_data (data.get (), smaps, mapsfilename.c_str ());
- if (strcmp (keyword, "AnonHugePages:") == 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)
- {
- /* Even if we are dealing with a file-backed
- mapping, if it contains anonymous pages we
- consider it to be *also* an anonymous
- mapping, because this is what the Linux
- kernel does:
-
- // Dump segments that have been written to.
- if (vma->anon_vma && FILTER(ANON_PRIVATE))
- goto whole;
-
- Note that if the mapping is already marked as
- file-backed (i.e., mapping_file_p is
- non-zero), then this is a special case, and
- this mapping will be dumped either when the
- user wants to dump file-backed *or* anonymous
- mappings. */
- mapping_anon_p = 1;
- }
- }
- }
+ if (!smaps.empty ())
+ {
+ for (struct smaps_data map : smaps)
+ {
+ int should_dump_p = 0;
- if (has_anonymous)
- should_dump_p = dump_mapping_p (filterflags, &v, priv,
- mapping_anon_p, mapping_file_p,
- filename, addr, offset);
+ if (map.has_anonymous)
+ should_dump_p = dump_mapping_p (filterflags, &map.vmflags, map.priv,
+ map.mapping_anon_p,
+ map.mapping_file_p,
+ map.filename.c_str (),
+ map.start_address,
+ map.offset);
else
{
/* Older Linux kernels did not support the "Anonymous:" counter.
@@ -1338,16 +1455,15 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
/* Invoke the callback function to create the corefile segment. */
if (should_dump_p)
- func (addr, endaddr - addr, offset, inode,
- read, write, exec, 1, /* MODIFIED is true because we
- want to dump the mapping. */
- filename, obfd);
+ func (map.start_address, map.end_address - map.start_address,
+ map.offset, map.inode, map.read, map.write, map.exec,
+ 1, /* MODIFIED is true because we want to dump
+ the mapping. */
+ map.filename.c_str (), obfd);
}
-
- return 0;
}
- return 1;
+ return 0;
}
/* A structure for passing information through
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index 91c28738f5..32c9c03835 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -41,6 +41,10 @@ DEF_ENUM_FLAGS_TYPE (enum linux_siginfo_extra_field_values,
struct type *linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch,
linux_siginfo_extra_fields);
+ /* Return true if ADDRESS is within the boundaries of a page mapped with
+ memory tagging protection. */
+bool linux_address_in_memtag_page (CORE_ADDR address);
+
typedef char *(*linux_collect_thread_registers_ftype) (const struct regcache *,
ptid_t,
bfd *, char *, int *,
--
2.17.1
next prev parent reply other threads:[~2020-07-15 19:48 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-15 19:44 [PATCH 00/23] Memory Tagging Support + AArch64 Linux implementation Luis Machado
2020-07-15 19:44 ` [PATCH 01/23] New target methods for memory tagging support Luis Machado
2020-07-15 19:44 ` [PATCH 02/23] New gdbarch memory tagging hooks Luis Machado
2020-07-15 19:44 ` [PATCH 03/23] Add GDB-side remote target support for memory tagging Luis Machado
2020-07-15 19:44 ` [PATCH 04/23] Unit testing for GDB-side remote memory tagging handling Luis Machado
2020-07-15 19:44 ` [PATCH 05/23] GDBserver remote packet support for memory tagging Luis Machado
2020-07-15 19:44 ` [PATCH 06/23] Unit tests for gdbserver memory tagging remote packets Luis Machado
2020-07-15 19:44 ` [PATCH 07/23] Documentation for " Luis Machado
2020-07-17 5:54 ` Eli Zaretskii
2020-07-17 14:20 ` Luis Machado
2020-07-15 19:44 ` [PATCH 08/23] AArch64: Add MTE CPU feature check support Luis Machado
2020-07-15 19:44 ` [PATCH 09/23] AArch64: Add target description/feature for MTE registers Luis Machado
2020-07-15 19:45 ` [PATCH 10/23] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
2020-07-15 19:45 ` [PATCH 11/23] AArch64: Add MTE ptrace requests Luis Machado
2020-07-15 19:45 ` [PATCH 12/23] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
2020-07-15 19:45 ` Luis Machado [this message]
2020-07-15 19:45 ` [PATCH 14/23] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
2020-07-15 19:45 ` [PATCH 15/23] AArch64: Add unit testing for logical tag set/get operations Luis Machado
2020-07-15 19:45 ` [PATCH 16/23] AArch64: Report tag violation error information Luis Machado
2020-07-15 19:45 ` [PATCH 17/23] AArch64: Add gdbserver MTE support Luis Machado
2020-07-15 19:45 ` [PATCH 18/23] New mtag commands Luis Machado
2020-07-15 19:45 ` [PATCH 19/23] Documentation for the new " Luis Machado
2020-07-17 6:11 ` Eli Zaretskii
2020-07-17 14:20 ` Luis Machado
2020-07-17 14:29 ` Eli Zaretskii
2020-07-17 15:08 ` Luis Machado
2020-07-15 19:45 ` [PATCH 20/23] Extend "x" and "print" commands to support memory tagging Luis Machado
2020-07-15 19:45 ` [PATCH 21/23] Document new "x" and "print" memory tagging extensions Luis Machado
2020-07-17 6:16 ` Eli Zaretskii
2020-07-17 14:20 ` Luis Machado
2020-07-17 14:31 ` Eli Zaretskii
2020-07-15 19:45 ` [PATCH 22/23] Add NEWS entry Luis Machado
2020-07-17 6:18 ` Eli Zaretskii
2020-07-17 14:20 ` Luis Machado
2020-07-15 19:45 ` [PATCH 23/23] Add memory tagging testcases Luis Machado
2020-07-16 16:49 ` [PATCH 00/23] Memory Tagging Support + AArch64 Linux implementation Alan Hayward
2020-07-17 12:33 ` Luis Machado
2020-07-17 22:02 ` John Baldwin
2020-07-23 13:59 ` Luis Machado
2020-07-23 16:48 ` John Baldwin
2020-07-24 16:10 ` David Spickett
2020-07-23 14:59 ` Luis Machado
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200715194513.16641-14-luis.machado@linaro.org \
--to=luis.machado@linaro.org \
--cc=Alan.Hayward@arm.com \
--cc=catalin.marinas@arm.com \
--cc=david.spickett@linaro.org \
--cc=gdb-patches@sourceware.org \
--cc=jose.marchesi@oracle.com \
--cc=omair.javaid@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).