From: Matthieu Longo <matthieu.longo@arm.com>
To: <gdb-patches@sourceware.org>
Cc: Andrew Burgess <aburgess@redhat.com>, Tom Tromey <tom@tromey.com>,
Matthieu Longo <matthieu.longo@arm.com>
Subject: [PATCH v3 5/8] gdb/linux: refactor /proc mapping parsing to use array_view
Date: Tue, 22 Sep 2026 14:50:47 +0100 [thread overview]
Message-ID: <20260922135050.236941-6-matthieu.longo@arm.com> (raw)
In-Reply-To: <20260922135050.236941-1-matthieu.longo@arm.com>
Refactor read_mapping and smaps parsing to operate on gdb::array_view<char>
instead of relying on NUL-terminated strings and strtok_r to split mapping
headers.
Track the amount of data returned by target_fileio_read_stralloc and use
extract_next_field to iterate over mapping lines.
Update read_mapping to parse fields using bounded iterators and diagnose
malformed addresses, separators, offsets, and inode values.
Adjust the callers of parse_smaps_data accordingly.
---
gdb/linux-tdep.c | 167 +++++++++++++++++++++++++++++------------------
1 file changed, 103 insertions(+), 64 deletions(-)
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index bd4c1d5540f..772b561eb96 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -510,35 +510,60 @@ struct mapping
/* Service function for corefiles and info proc. */
static mapping
-read_mapping (const char *line)
+read_mapping (gdb::array_view<char> line)
{
struct mapping mapping;
- const char *p = line;
- mapping.addr = strtoulst (p, &p, 16);
- if (*p == '-')
- p++;
- mapping.endaddr = strtoulst (p, &p, 16);
+ decltype(line)::const_iterator it = line.begin ();
+ decltype(line)::const_iterator it_next;
- p = skip_spaces (p);
- const char *permissions_start = p;
- while (*p && !c_isspace (*p))
- p++;
- mapping.permissions = std::string (permissions_start,
- (size_t) (p - permissions_start));
+ mapping.addr = strtoulst (it, &it_next, 16);
+ if (it == it_next)
+ error (_("failed to parse start address"));
+ else
+ it = it_next;
- mapping.offset = strtoulst (p, &p, 16);
+ if (*it++ != '-')
+ error (_("expected separator '-'"));
- p = skip_spaces (p);
- const char *device_start = p;
- while (*p && !c_isspace (*p))
- p++;
- mapping.device = {device_start, (size_t) (p - device_start)};
+ mapping.endaddr = strtoulst (it, &it_next, 16);
+ if (it == it_next)
+ error (_("failed to parse end address"));
+ else
+ it = it_next;
- mapping.inode = strtoulst (p, &p, 10);
+ /* Skip spaces. */
+ it = std::find_if_not (it, line.cend (), c_isspace);
- p = skip_spaces (p);
- mapping.filename = p;
+ it_next = std::find_if (it, line.cend (), c_isspace);
+ mapping.permissions = std::string (it, it_next);
+ it = it_next;
+
+ mapping.offset = strtoulst (it, &it_next, 16);
+ if (it == it_next)
+ error (_("failed to parse offset"));
+ else
+ it = it_next;
+
+ /* Skip spaces. */
+ it = std::find_if_not (it, line.cend (), c_isspace);
+
+ it_next = std::find_if (it, line.cend (), c_isspace);
+ mapping.device = std::string (it, it_next);
+ it = it_next;
+
+ mapping.inode = strtoulst (it, &it_next, 10);
+ if (it == it_next)
+ error (_("failed to parse inode"));
+ else
+ it = it_next;
+
+ /* Skip spaces. */
+ it = std::find_if_not (it, line.cend (), c_isspace);
+
+ mapping.filename = it;
+ /* Ensure that the line ends with '0'. */
+ *line.end () = '\0';
return mapping;
}
@@ -985,8 +1010,9 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
if (mappings_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/maps", ptid.lwp ());
+ LONGEST len = 0;
gdb::unique_xmalloc_ptr<char> map
- = target_fileio_read_stralloc (NULL, filename);
+ = target_fileio_read_stralloc (NULL, filename, &len);
if (map != NULL)
{
gdb_printf (_("Mapped address spaces:\n\n"));
@@ -1001,12 +1027,13 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
current_uiout->table_header (0, ui_left, "objfile", "File");
current_uiout->table_body ();
- char *saveptr;
- for (const char *line = strtok_r (map.get (), "\n", &saveptr);
- line != nullptr;
- line = strtok_r (nullptr, "\n", &saveptr))
+ gdb::array_view<char> content (map.get (), len);
+ for (auto it = content.begin (); it != content.end ();)
{
- struct mapping m = read_mapping (line);
+ auto [line, next_line_begin]
+ = extract_next_field (content, it, '\n');
+ it = next_line_begin;
+ mapping m = read_mapping (line);
ui_out_emit_tuple tuple_emitter (current_uiout);
current_uiout->field_core_addr ("start", gdbarch, m.addr);
@@ -1559,20 +1586,22 @@ parse_smaps_key_value (const char *keyword, const char *line,
into the SMAPS vector. */
static std::vector<smaps_data>
-parse_smaps_data (const char *data,
+parse_smaps_data (gdb::array_view<char> data,
const std::string &maps_filename)
{
- char *line, *t;
-
- gdb_assert (data != nullptr);
-
- line = strtok_r ((char *) data, "\n", &t);
-
std::vector<smaps_data> smaps;
- while (line != NULL)
+ for (auto it = data.begin (); it != data.end ();)
{
+ auto [region_header_line, next_line_begin]
+ = extract_next_field (data, it, '\n');
+ it = next_line_begin;
+
+ /* Parse a region's header. */
+ mapping m = read_mapping (region_header_line);
+
struct smaps_vmflags v;
+ memset (&v, 0, sizeof (v));
int read, write, exec, priv;
int has_anonymous = 0;
int mapping_anon_p;
@@ -1580,8 +1609,6 @@ parse_smaps_data (const char *data,
ULONGEST rss = -1;
ULONGEST swap = -1;
- memset (&v, 0, sizeof (v));
- 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
@@ -1614,7 +1641,8 @@ parse_smaps_data (const char *data,
/* Try to detect if region should be dumped by parsing smaps
counters. */
- for (line = strtok_r (NULL, "\n", &t);
+ char *line, *t;
+ for (line = strtok_r (it, "\n", &t);
line != NULL && line[0] >= 'A' && line[0] <= 'Z';
line = strtok_r (NULL, "\n", &t))
{
@@ -1679,26 +1707,31 @@ parse_smaps_data (const char *data,
}
}
}
+
/* Save the smaps entry to the vector. */
- smaps_data map;
-
- 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;
- 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 = m.offset;
- map.inode = m.inode;
- map.rss = rss;
- map.swap = swap;
-
- smaps.emplace_back (map);
+ smaps_data map;
+
+ 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;
+ 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 = m.offset;
+ map.inode = m.inode;
+ map.rss = rss;
+ map.swap = swap;
+
+ smaps.emplace_back (map);
+
+ if (line == nullptr)
+ break;
+ it = line;
}
return smaps;
@@ -1716,15 +1749,17 @@ linux_process_address_in_memtag_page (CORE_ADDR address)
ptid_t ptid = get_ptid_for_slash_proc ();
std::string smaps_file = string_printf ("/proc/%ld/smaps", ptid.lwp ());
+ LONGEST len = 0;
gdb::unique_xmalloc_ptr<char> data
- = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
+ = target_fileio_read_stralloc (NULL, smaps_file.c_str (), &len);
if (data == nullptr)
return false;
/* Parse the contents of smaps into a vector. */
+ gdb::array_view<char> content (data.get (), len);
std::vector<smaps_data> smaps
- = parse_smaps_data (data.get (), smaps_file);
+ = parse_smaps_data (content, smaps_file);
for (const smaps_data &map : smaps)
{
@@ -1805,22 +1840,24 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
std::string maps_filename = string_printf ("/proc/%ld/smaps", ptid.lwp ());
+ LONGEST len = 0;
gdb::unique_xmalloc_ptr<char> data
- = target_fileio_read_stralloc (NULL, maps_filename.c_str ());
+ = target_fileio_read_stralloc (NULL, maps_filename.c_str (), &len);
if (data == NULL)
{
/* Older Linux kernels did not support /proc/PID/smaps. */
maps_filename = string_printf ("/proc/%ld/maps", ptid.lwp ());
- data = target_fileio_read_stralloc (NULL, maps_filename.c_str ());
+ data = target_fileio_read_stralloc (NULL, maps_filename.c_str (), &len);
if (data == nullptr)
return false;
}
/* Parse the contents of smaps into a vector. */
+ gdb::array_view<char> content (data.get (), len);
std::vector<smaps_data> smaps
- = parse_smaps_data (data.get (), maps_filename);
+ = parse_smaps_data (content, maps_filename);
for (const smaps_data &map : smaps)
{
@@ -3263,14 +3300,16 @@ linux_address_in_shadow_stack_mem_range
ptid_t ptid = get_ptid_for_slash_proc ();
std::string smaps_file = string_printf ("/proc/%ld/smaps", ptid.lwp ());
+ LONGEST len = 0;
gdb::unique_xmalloc_ptr<char> data
- = target_fileio_read_stralloc (nullptr, smaps_file.c_str ());
+ = target_fileio_read_stralloc (nullptr, smaps_file.c_str (), &len);
if (data == nullptr)
return false;
+ gdb::array_view<char> content (data.get (), len);
const std::vector<smaps_data> smaps
- = parse_smaps_data (data.get (), smaps_file);
+ = parse_smaps_data (content, smaps_file);
auto find_addr_mem_range = [&addr] (const smaps_data &map)
{
--
2.55.0
next prev parent reply other threads:[~2026-09-22 14:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 13:50 [PATCH v3 0/8] gdb: introduce file_reader_t to read procfs files Matthieu Longo
2026-09-22 13:50 ` [PATCH v3 1/8] gdb support: add gdb::ranges::replace algorithm Matthieu Longo
2026-09-22 13:50 ` [PATCH v3 2/8] gdb/linux: remove redundant struct prefixes from smaps_data Matthieu Longo
2026-09-22 13:50 ` [PATCH v3 3/8] gdb/linux: style filenames in /proc warning messages Matthieu Longo
2026-09-22 13:50 ` [PATCH v3 4/8] gdbsupport: add extract_next_field helper Matthieu Longo
2026-09-22 13:50 ` Matthieu Longo [this message]
2026-09-22 13:50 ` [PATCH v3 6/8] gdb: introduce helper class target_file_reader Matthieu Longo
2026-09-22 13:50 ` [PATCH v3 7/8] gdb/linux-tdep: use target_file_reader for procfs parsing Matthieu Longo
2026-09-22 13:50 ` [PATCH v3 8/8] gdb/linux-tdep: remove legacy parse_smaps_data overload Matthieu Longo
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=20260922135050.236941-6-matthieu.longo@arm.com \
--to=matthieu.longo@arm.com \
--cc=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=tom@tromey.com \
/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