Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings
@ 2026-07-28 15:29 Matthieu Longo
  2026-07-28 15:30 ` Matthieu Longo
  2026-09-07  9:13 ` Matthieu Longo
  0 siblings, 2 replies; 5+ messages in thread
From: Matthieu Longo @ 2026-07-28 15:29 UTC (permalink / raw)
  To: gdb-patches
  Cc: Luis Machado, Luis Machado, Thiago Jung Bauermann,
	Srinath Parvathaneni, Matthieu Longo

Memory Protection Keys provide a mechanism for enforcing page-based
protections without requiring modification of the page tables
when an application changes protection domains. [1]

The "ProtectionKey" field may be present in /proc/PID/smaps on x86_64,
PowerPC, and AArch64 systems since Linux 4.9, when the kernel is built
with Memory Protection Keys support.

Store the parsed PKey in smaps_data as an optional value on systems
where the kernel reports memory protection keys.

Parse /proc/PID/smaps alongside /proc/PID/maps when printing 'info
proc mappings', and add a PKey column when at least one smaps entry
contains a "ProtectionKey" field.
This lets 'info proc mappings' show the protection key associated with
each mapped address range.

[1]: https://docs.kernel.org/core-api/protection-keys.html,
     https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/
     linux.git/commit/?id=c1192f842841
---
 gdb/linux-tdep.c | 93 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 78 insertions(+), 15 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 2e9cb14d5bf..2cdf93f3193 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -124,6 +124,7 @@ struct smaps_data
 
   ULONGEST rss;
   ULONGEST swap;
+  std::optional<int> pkey;
 };
 
 /* Whether to take the /proc/PID/coredump_filter into account when
@@ -907,6 +908,11 @@ extract_string_view_from_buffer (gdb::array_view<char> &buffer,
   return {gdb::array_view<char> (start, it), next_start};
 }
 
+/* Forward declaration of parse_smaps_data used in linux_info_proc below.  */
+
+static std::vector<struct smaps_data>
+parse_smaps_data (const file_reader_t<char> &freader);
+
 /* Implement the "info proc" command.  */
 
 static void
@@ -1010,33 +1016,69 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
     }
   if (mappings_f)
     {
+      /* Parse the content of /proc/PID/smaps.  */
+      bool pkey_column = false;
+      std::vector<struct smaps_data> smaps_data;
+      file_reader_t<char> smaps_freader
+	(string_printf ("/proc/%ld/smaps", ptid.lwp ()));
+      if (smaps_freader.error ())
+	warning (_("unable to open /proc file '%s'"),
+		 smaps_freader.c_filepath ());
+      else if (smaps_freader)
+	{
+	  smaps_data = parse_smaps_data (smaps_freader);
+
+	  /* Check whether "ProtectionKey" field is present.  */
+	  pkey_column
+	    = std::any_of (smaps_data.cbegin (), smaps_data.cend (),
+			   [] (const struct smaps_data &d) -> bool
+			   { return d.pkey.has_value (); });
+	}
+
+      /* Parse the content of /proc/PID/maps.  */
+      std::vector<struct mapping> maps_data;
       file_reader_t<char> map_freader
 	(string_printf ("/proc/%ld/maps", ptid.lwp ()));
-      if (map_freader)
+      if (map_freader.error ())
+	warning (_("unable to open /proc file '%s'"),
+		 map_freader.c_filepath ());
+      else if (map_freader)
+	{
+	  auto content = map_freader.view ();
+	  for (auto it = content.begin (); it != content.end ();)
+	    {
+	      auto [line, next_line_begin]
+		= extract_string_view_from_buffer (content, it, '\n');
+	      it = next_line_begin;
+
+	      /* read_mapping() expects a null-terminated string.  */
+	      *std::prev (it) = '\0';
+	      maps_data.emplace_back (read_mapping (line.data ()));
+	   }
+	}
+
+      gdb_assert (maps_data.size () == smaps_data.size ());
+
+      if (maps_data.size () > 0)
 	{
 	  gdb_printf (_("Mapped address spaces:\n\n"));
-	  ui_out_emit_table emitter (current_uiout, 6, -1, "ProcMappings");
+	  int n_cols = (pkey_column ? 7 : 6);
+	  ui_out_emit_table emitter (current_uiout, n_cols, -1, "ProcMappings");
 
 	  int width = gdbarch_addr_bit (gdbarch) == 32 ? 10 : 18;
 	  current_uiout->table_header (width, ui_left, "start", "Start Addr");
 	  current_uiout->table_header (width, ui_left, "end", "End Addr");
 	  current_uiout->table_header (width, ui_left, "size", "Size");
 	  current_uiout->table_header (width, ui_left, "offset", "Offset");
+	  if (pkey_column)
+	    current_uiout->table_header (4, ui_left, "pkey", "PKey");
 	  current_uiout->table_header (5, ui_left, "perms", "Perms");
 	  current_uiout->table_header (0, ui_left, "objfile", "File");
 	  current_uiout->table_body ();
 
-	  auto content = map_freader.view ();
-	  for (auto it = content.begin (); it != content.end ();)
+	  auto it_smaps = smaps_data.cbegin ();
+	  for (const auto &m: maps_data)
 	    {
-	      auto [line, next_line_begin]
-		= extract_string_view_from_buffer (content, it, '\n');
-	      it = next_line_begin;
-
-	      /* read_mapping() expects a null-terminated string.  */
-	      *std::prev (it) = '\0';
-	      struct mapping m = read_mapping (line.data ());
-
 	      ui_out_emit_tuple tuple_emitter (current_uiout, nullptr);
 	      current_uiout->field_core_addr ("start", gdbarch, m.addr);
 	      current_uiout->field_core_addr ("end", gdbarch, m.endaddr);
@@ -1047,15 +1089,21 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
 						     m.endaddr - m.addr));
 	      current_uiout->field_string ("offset",
 					   paddress (gdbarch, m.offset));
+	      if (pkey_column)
+		{
+		  if (it_smaps->pkey.has_value ())
+		    current_uiout->field_signed ("pkey",
+						 it_smaps->pkey.value ());
+		  else
+		    current_uiout->field_skip ("pkey");
+		}
 	      current_uiout->field_string ("perms", m.permissions);
 	      current_uiout->field_string ("objfile", m.filename,
 					   file_name_style.style ());
 	      current_uiout->text ("\n");
+	      ++it_smaps;
 	    }
 	}
-      else
-	warning (_("unable to open /proc file '%s'"),
-		 map_freader.c_filepath ());
     }
   if (status_f)
     {
@@ -1605,6 +1653,7 @@ parse_smaps_data (const file_reader_t<char> &freader)
       int mapping_file_p;
       ULONGEST rss = -1;
       ULONGEST swap = -1;
+      int pkey = -1;
 
       memset (&v, 0, sizeof (v));
       struct mapping m = read_mapping (line);
@@ -1705,6 +1754,18 @@ parse_smaps_data (const file_reader_t<char> &freader)
 		  mapping_anon_p = 1;
 		}
 	    }
+
+	  if (streq (keyword, "ProtectionKey:"))
+	    {
+	      if (sscanf (line, "%*s%d", &pkey) != 1)
+		{
+		  /* Remove the trailing column when printing the warning.  */
+		  keyword[sizeof ("ProtectionKey:") - 2] = '\0';
+		  warning (_("Error parsing %s's value in {s,}maps file '%s'"),
+			   keyword, freader.c_filepath ());
+		  break;
+		}
+	    }
 	}
       /* Save the smaps entry to the vector.  */
 	struct smaps_data map;
@@ -1724,6 +1785,8 @@ parse_smaps_data (const file_reader_t<char> &freader)
 	map.inode = m.inode;
 	map.rss = rss;
 	map.swap = swap;
+	if (pkey != -1)
+	  map.pkey.emplace (pkey);
 
 	smaps.emplace_back (map);
     }
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings
  2026-07-28 15:29 [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings Matthieu Longo
@ 2026-07-28 15:30 ` Matthieu Longo
  2026-09-07  9:13 ` Matthieu Longo
  1 sibling, 0 replies; 5+ messages in thread
From: Matthieu Longo @ 2026-07-28 15:30 UTC (permalink / raw)
  To: gdb-patches
  Cc: Luis Machado, Luis Machado, Thiago Jung Bauermann, Srinath Parvathaneni

On 28/07/2026 16:29, Matthieu Longo wrote:
> Memory Protection Keys provide a mechanism for enforcing page-based
> protections without requiring modification of the page tables
> when an application changes protection domains. [1]
> 
> The "ProtectionKey" field may be present in /proc/PID/smaps on x86_64,
> PowerPC, and AArch64 systems since Linux 4.9, when the kernel is built
> with Memory Protection Keys support.
> 
> Store the parsed PKey in smaps_data as an optional value on systems
> where the kernel reports memory protection keys.
> 
> Parse /proc/PID/smaps alongside /proc/PID/maps when printing 'info
> proc mappings', and add a PKey column when at least one smaps entry
> contains a "ProtectionKey" field.
> This lets 'info proc mappings' show the protection key associated with
> each mapped address range.
> 
> [1]: https://docs.kernel.org/core-api/protection-keys.html,
>      https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/
>      linux.git/commit/?id=c1192f842841
> ---
Please, note that this patch has a dependency on the new class file_reader_t introduced in
https://inbox.sourceware.org/gdb-patches/20260728151700.253720-1-matthieu.longo@arm.com/

Matthieu


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings
  2026-07-28 15:29 [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings Matthieu Longo
  2026-07-28 15:30 ` Matthieu Longo
@ 2026-09-07  9:13 ` Matthieu Longo
  2026-09-07 15:24   ` Andrew Burgess
  1 sibling, 1 reply; 5+ messages in thread
From: Matthieu Longo @ 2026-09-07  9:13 UTC (permalink / raw)
  To: gdb-patches
  Cc: Luis Machado, Luis Machado, Thiago Jung Bauermann, Srinath Parvathaneni

On 28/07/2026 16:29, Matthieu Longo wrote:
> Memory Protection Keys provide a mechanism for enforcing page-based
> protections without requiring modification of the page tables
> when an application changes protection domains. [1]
> 
> The "ProtectionKey" field may be present in /proc/PID/smaps on x86_64,
> PowerPC, and AArch64 systems since Linux 4.9, when the kernel is built
> with Memory Protection Keys support.
> 
> Store the parsed PKey in smaps_data as an optional value on systems
> where the kernel reports memory protection keys.
> 
> Parse /proc/PID/smaps alongside /proc/PID/maps when printing 'info
> proc mappings', and add a PKey column when at least one smaps entry
> contains a "ProtectionKey" field.
> This lets 'info proc mappings' show the protection key associated with
> each mapped address range.
> 
> [1]: https://docs.kernel.org/core-api/protection-keys.html,
>      https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/
>      linux.git/commit/?id=c1192f842841
> ---
>  gdb/linux-tdep.c | 93 ++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 78 insertions(+), 15 deletions(-)
> 
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index 2e9cb14d5bf..2cdf93f3193 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -124,6 +124,7 @@ struct smaps_data
>  
>    ULONGEST rss;
>    ULONGEST swap;
> +  std::optional<int> pkey;
>  };
>  
>  /* Whether to take the /proc/PID/coredump_filter into account when
> @@ -907,6 +908,11 @@ extract_string_view_from_buffer (gdb::array_view<char> &buffer,
>    return {gdb::array_view<char> (start, it), next_start};
>  }
>  
> +/* Forward declaration of parse_smaps_data used in linux_info_proc below.  */
> +
> +static std::vector<struct smaps_data>
> +parse_smaps_data (const file_reader_t<char> &freader);
> +
>  /* Implement the "info proc" command.  */
>  
>  static void
> @@ -1010,33 +1016,69 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
>      }
>    if (mappings_f)
>      {
> +      /* Parse the content of /proc/PID/smaps.  */
> +      bool pkey_column = false;
> +      std::vector<struct smaps_data> smaps_data;
> +      file_reader_t<char> smaps_freader
> +	(string_printf ("/proc/%ld/smaps", ptid.lwp ()));
> +      if (smaps_freader.error ())
> +	warning (_("unable to open /proc file '%s'"),
> +		 smaps_freader.c_filepath ());
> +      else if (smaps_freader)
> +	{
> +	  smaps_data = parse_smaps_data (smaps_freader);
> +
> +	  /* Check whether "ProtectionKey" field is present.  */
> +	  pkey_column
> +	    = std::any_of (smaps_data.cbegin (), smaps_data.cend (),
> +			   [] (const struct smaps_data &d) -> bool
> +			   { return d.pkey.has_value (); });
> +	}
> +
> +      /* Parse the content of /proc/PID/maps.  */
> +      std::vector<struct mapping> maps_data;
>        file_reader_t<char> map_freader
>  	(string_printf ("/proc/%ld/maps", ptid.lwp ()));
> -      if (map_freader)
> +      if (map_freader.error ())
> +	warning (_("unable to open /proc file '%s'"),
> +		 map_freader.c_filepath ());
> +      else if (map_freader)
> +	{
> +	  auto content = map_freader.view ();
> +	  for (auto it = content.begin (); it != content.end ();)
> +	    {
> +	      auto [line, next_line_begin]
> +		= extract_string_view_from_buffer (content, it, '\n');
> +	      it = next_line_begin;
> +
> +	      /* read_mapping() expects a null-terminated string.  */
> +	      *std::prev (it) = '\0';
> +	      maps_data.emplace_back (read_mapping (line.data ()));
> +	   }
> +	}
> +
> +      gdb_assert (maps_data.size () == smaps_data.size ());
> +
> +      if (maps_data.size () > 0)
>  	{
>  	  gdb_printf (_("Mapped address spaces:\n\n"));
> -	  ui_out_emit_table emitter (current_uiout, 6, -1, "ProcMappings");
> +	  int n_cols = (pkey_column ? 7 : 6);
> +	  ui_out_emit_table emitter (current_uiout, n_cols, -1, "ProcMappings");
>  
>  	  int width = gdbarch_addr_bit (gdbarch) == 32 ? 10 : 18;
>  	  current_uiout->table_header (width, ui_left, "start", "Start Addr");
>  	  current_uiout->table_header (width, ui_left, "end", "End Addr");
>  	  current_uiout->table_header (width, ui_left, "size", "Size");
>  	  current_uiout->table_header (width, ui_left, "offset", "Offset");
> +	  if (pkey_column)
> +	    current_uiout->table_header (4, ui_left, "pkey", "PKey");
>  	  current_uiout->table_header (5, ui_left, "perms", "Perms");
>  	  current_uiout->table_header (0, ui_left, "objfile", "File");
>  	  current_uiout->table_body ();
>  
> -	  auto content = map_freader.view ();
> -	  for (auto it = content.begin (); it != content.end ();)
> +	  auto it_smaps = smaps_data.cbegin ();
> +	  for (const auto &m: maps_data)
>  	    {
> -	      auto [line, next_line_begin]
> -		= extract_string_view_from_buffer (content, it, '\n');
> -	      it = next_line_begin;
> -
> -	      /* read_mapping() expects a null-terminated string.  */
> -	      *std::prev (it) = '\0';
> -	      struct mapping m = read_mapping (line.data ());
> -
>  	      ui_out_emit_tuple tuple_emitter (current_uiout, nullptr);
>  	      current_uiout->field_core_addr ("start", gdbarch, m.addr);
>  	      current_uiout->field_core_addr ("end", gdbarch, m.endaddr);
> @@ -1047,15 +1089,21 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
>  						     m.endaddr - m.addr));
>  	      current_uiout->field_string ("offset",
>  					   paddress (gdbarch, m.offset));
> +	      if (pkey_column)
> +		{
> +		  if (it_smaps->pkey.has_value ())
> +		    current_uiout->field_signed ("pkey",
> +						 it_smaps->pkey.value ());
> +		  else
> +		    current_uiout->field_skip ("pkey");
> +		}
>  	      current_uiout->field_string ("perms", m.permissions);
>  	      current_uiout->field_string ("objfile", m.filename,
>  					   file_name_style.style ());
>  	      current_uiout->text ("\n");
> +	      ++it_smaps;
>  	    }
>  	}
> -      else
> -	warning (_("unable to open /proc file '%s'"),
> -		 map_freader.c_filepath ());
>      }
>    if (status_f)
>      {
> @@ -1605,6 +1653,7 @@ parse_smaps_data (const file_reader_t<char> &freader)
>        int mapping_file_p;
>        ULONGEST rss = -1;
>        ULONGEST swap = -1;
> +      int pkey = -1;
>  
>        memset (&v, 0, sizeof (v));
>        struct mapping m = read_mapping (line);
> @@ -1705,6 +1754,18 @@ parse_smaps_data (const file_reader_t<char> &freader)
>  		  mapping_anon_p = 1;
>  		}
>  	    }
> +
> +	  if (streq (keyword, "ProtectionKey:"))
> +	    {
> +	      if (sscanf (line, "%*s%d", &pkey) != 1)
> +		{
> +		  /* Remove the trailing column when printing the warning.  */
> +		  keyword[sizeof ("ProtectionKey:") - 2] = '\0';
> +		  warning (_("Error parsing %s's value in {s,}maps file '%s'"),
> +			   keyword, freader.c_filepath ());
> +		  break;
> +		}
> +	    }
>  	}
>        /* Save the smaps entry to the vector.  */
>  	struct smaps_data map;
> @@ -1724,6 +1785,8 @@ parse_smaps_data (const file_reader_t<char> &freader)
>  	map.inode = m.inode;
>  	map.rss = rss;
>  	map.swap = swap;
> +	if (pkey != -1)
> +	  map.pkey.emplace (pkey);
>  
>  	smaps.emplace_back (map);
>      }

Ping.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings
  2026-09-07  9:13 ` Matthieu Longo
@ 2026-09-07 15:24   ` Andrew Burgess
  2026-09-07 16:00     ` Matthieu Longo
  0 siblings, 1 reply; 5+ messages in thread
From: Andrew Burgess @ 2026-09-07 15:24 UTC (permalink / raw)
  To: Matthieu Longo, gdb-patches
  Cc: Luis Machado, Luis Machado, Thiago Jung Bauermann, Srinath Parvathaneni

Matthieu Longo <matthieu.longo@arm.com> writes:

> On 28/07/2026 16:29, Matthieu Longo wrote:
>> Memory Protection Keys provide a mechanism for enforcing page-based
>> protections without requiring modification of the page tables
>> when an application changes protection domains. [1]
>> 
>> The "ProtectionKey" field may be present in /proc/PID/smaps on x86_64,
>> PowerPC, and AArch64 systems since Linux 4.9, when the kernel is built
>> with Memory Protection Keys support.
>> 
>> Store the parsed PKey in smaps_data as an optional value on systems
>> where the kernel reports memory protection keys.
>> 
>> Parse /proc/PID/smaps alongside /proc/PID/maps when printing 'info
>> proc mappings', and add a PKey column when at least one smaps entry
>> contains a "ProtectionKey" field.
>> This lets 'info proc mappings' show the protection key associated with
>> each mapped address range.
>> 
>> [1]: https://docs.kernel.org/core-api/protection-keys.html,
>>      https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/
>>      linux.git/commit/?id=c1192f842841
>> ---
>>  gdb/linux-tdep.c | 93 ++++++++++++++++++++++++++++++++++++++++--------
>>  1 file changed, 78 insertions(+), 15 deletions(-)
>> 
>> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
>> index 2e9cb14d5bf..2cdf93f3193 100644
>> --- a/gdb/linux-tdep.c
>> +++ b/gdb/linux-tdep.c
>> @@ -124,6 +124,7 @@ struct smaps_data
>>  
>>    ULONGEST rss;
>>    ULONGEST swap;
>> +  std::optional<int> pkey;
>>  };
>>  
>>  /* Whether to take the /proc/PID/coredump_filter into account when
>> @@ -907,6 +908,11 @@ extract_string_view_from_buffer (gdb::array_view<char> &buffer,
>>    return {gdb::array_view<char> (start, it), next_start};
>>  }
>>  
>> +/* Forward declaration of parse_smaps_data used in linux_info_proc below.  */
>> +
>> +static std::vector<struct smaps_data>
>> +parse_smaps_data (const file_reader_t<char> &freader);
>> +
>>  /* Implement the "info proc" command.  */
>>  
>>  static void
>> @@ -1010,33 +1016,69 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
>>      }
>>    if (mappings_f)
>>      {
>> +      /* Parse the content of /proc/PID/smaps.  */
>> +      bool pkey_column = false;
>> +      std::vector<struct smaps_data> smaps_data;
>> +      file_reader_t<char> smaps_freader
>> +	(string_printf ("/proc/%ld/smaps", ptid.lwp ()));
>> +      if (smaps_freader.error ())
>> +	warning (_("unable to open /proc file '%s'"),
>> +		 smaps_freader.c_filepath ());
>> +      else if (smaps_freader)
>> +	{
>> +	  smaps_data = parse_smaps_data (smaps_freader);
>> +
>> +	  /* Check whether "ProtectionKey" field is present.  */
>> +	  pkey_column
>> +	    = std::any_of (smaps_data.cbegin (), smaps_data.cend (),
>> +			   [] (const struct smaps_data &d) -> bool
>> +			   { return d.pkey.has_value (); });
>> +	}
>> +
>> +      /* Parse the content of /proc/PID/maps.  */
>> +      std::vector<struct mapping> maps_data;
>>        file_reader_t<char> map_freader
>>  	(string_printf ("/proc/%ld/maps", ptid.lwp ()));
>> -      if (map_freader)
>> +      if (map_freader.error ())
>> +	warning (_("unable to open /proc file '%s'"),
>> +		 map_freader.c_filepath ());
>> +      else if (map_freader)
>> +	{
>> +	  auto content = map_freader.view ();
>> +	  for (auto it = content.begin (); it != content.end ();)
>> +	    {
>> +	      auto [line, next_line_begin]
>> +		= extract_string_view_from_buffer (content, it, '\n');
>> +	      it = next_line_begin;
>> +
>> +	      /* read_mapping() expects a null-terminated string.  */
>> +	      *std::prev (it) = '\0';
>> +	      maps_data.emplace_back (read_mapping (line.data ()));
>> +	   }
>> +	}
>> +
>> +      gdb_assert (maps_data.size () == smaps_data.size ());
>> +
>> +      if (maps_data.size () > 0)
>>  	{
>>  	  gdb_printf (_("Mapped address spaces:\n\n"));
>> -	  ui_out_emit_table emitter (current_uiout, 6, -1, "ProcMappings");
>> +	  int n_cols = (pkey_column ? 7 : 6);
>> +	  ui_out_emit_table emitter (current_uiout, n_cols, -1, "ProcMappings");
>>  
>>  	  int width = gdbarch_addr_bit (gdbarch) == 32 ? 10 : 18;
>>  	  current_uiout->table_header (width, ui_left, "start", "Start Addr");
>>  	  current_uiout->table_header (width, ui_left, "end", "End Addr");
>>  	  current_uiout->table_header (width, ui_left, "size", "Size");
>>  	  current_uiout->table_header (width, ui_left, "offset", "Offset");
>> +	  if (pkey_column)
>> +	    current_uiout->table_header (4, ui_left, "pkey", "PKey");
>>  	  current_uiout->table_header (5, ui_left, "perms", "Perms");
>>  	  current_uiout->table_header (0, ui_left, "objfile", "File");
>>  	  current_uiout->table_body ();
>>  
>> -	  auto content = map_freader.view ();
>> -	  for (auto it = content.begin (); it != content.end ();)
>> +	  auto it_smaps = smaps_data.cbegin ();
>> +	  for (const auto &m: maps_data)
>>  	    {
>> -	      auto [line, next_line_begin]
>> -		= extract_string_view_from_buffer (content, it, '\n');
>> -	      it = next_line_begin;
>> -
>> -	      /* read_mapping() expects a null-terminated string.  */
>> -	      *std::prev (it) = '\0';
>> -	      struct mapping m = read_mapping (line.data ());
>> -
>>  	      ui_out_emit_tuple tuple_emitter (current_uiout, nullptr);
>>  	      current_uiout->field_core_addr ("start", gdbarch, m.addr);
>>  	      current_uiout->field_core_addr ("end", gdbarch, m.endaddr);
>> @@ -1047,15 +1089,21 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
>>  						     m.endaddr - m.addr));
>>  	      current_uiout->field_string ("offset",
>>  					   paddress (gdbarch, m.offset));
>> +	      if (pkey_column)
>> +		{
>> +		  if (it_smaps->pkey.has_value ())
>> +		    current_uiout->field_signed ("pkey",
>> +						 it_smaps->pkey.value ());
>> +		  else
>> +		    current_uiout->field_skip ("pkey");
>> +		}
>>  	      current_uiout->field_string ("perms", m.permissions);
>>  	      current_uiout->field_string ("objfile", m.filename,
>>  					   file_name_style.style ());
>>  	      current_uiout->text ("\n");
>> +	      ++it_smaps;
>>  	    }
>>  	}
>> -      else
>> -	warning (_("unable to open /proc file '%s'"),
>> -		 map_freader.c_filepath ());
>>      }
>>    if (status_f)
>>      {
>> @@ -1605,6 +1653,7 @@ parse_smaps_data (const file_reader_t<char> &freader)
>>        int mapping_file_p;
>>        ULONGEST rss = -1;
>>        ULONGEST swap = -1;
>> +      int pkey = -1;
>>  
>>        memset (&v, 0, sizeof (v));
>>        struct mapping m = read_mapping (line);
>> @@ -1705,6 +1754,18 @@ parse_smaps_data (const file_reader_t<char> &freader)
>>  		  mapping_anon_p = 1;
>>  		}
>>  	    }
>> +
>> +	  if (streq (keyword, "ProtectionKey:"))
>> +	    {
>> +	      if (sscanf (line, "%*s%d", &pkey) != 1)
>> +		{
>> +		  /* Remove the trailing column when printing the warning.  */
>> +		  keyword[sizeof ("ProtectionKey:") - 2] = '\0';
>> +		  warning (_("Error parsing %s's value in {s,}maps file '%s'"),
>> +			   keyword, freader.c_filepath ());
>> +		  break;
>> +		}
>> +	    }
>>  	}
>>        /* Save the smaps entry to the vector.  */
>>  	struct smaps_data map;
>> @@ -1724,6 +1785,8 @@ parse_smaps_data (const file_reader_t<char> &freader)
>>  	map.inode = m.inode;
>>  	map.rss = rss;
>>  	map.swap = swap;
>> +	if (pkey != -1)
>> +	  map.pkey.emplace (pkey);
>>  
>>  	smaps.emplace_back (map);
>>      }
>
> Ping.

Isn't this patch blocked on some other patches being merged?  I'm not
sure it needs to be pinged if it doesn't apply yet.  Apologies if I'm
wrong here.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings
  2026-09-07 15:24   ` Andrew Burgess
@ 2026-09-07 16:00     ` Matthieu Longo
  0 siblings, 0 replies; 5+ messages in thread
From: Matthieu Longo @ 2026-09-07 16:00 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches
  Cc: Luis Machado, Luis Machado, Thiago Jung Bauermann, Srinath Parvathaneni

On 07/09/2026 16:24, Andrew Burgess wrote:
> Matthieu Longo <matthieu.longo@arm.com> writes:
> 
>> On 28/07/2026 16:29, Matthieu Longo wrote:
>>> Memory Protection Keys provide a mechanism for enforcing page-based
>>> protections without requiring modification of the page tables
>>> when an application changes protection domains. [1]
>>>
>>> The "ProtectionKey" field may be present in /proc/PID/smaps on x86_64,
>>> PowerPC, and AArch64 systems since Linux 4.9, when the kernel is built
>>> with Memory Protection Keys support.
>>>
>>> Store the parsed PKey in smaps_data as an optional value on systems
>>> where the kernel reports memory protection keys.
>>>
>>> Parse /proc/PID/smaps alongside /proc/PID/maps when printing 'info
>>> proc mappings', and add a PKey column when at least one smaps entry
>>> contains a "ProtectionKey" field.
>>> This lets 'info proc mappings' show the protection key associated with
>>> each mapped address range.
>>>
>>> [1]: https://docs.kernel.org/core-api/protection-keys.html,
>>>      https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/
>>>      linux.git/commit/?id=c1192f842841
>>> ---
>>>  gdb/linux-tdep.c | 93 ++++++++++++++++++++++++++++++++++++++++--------
>>>  1 file changed, 78 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
>>> index 2e9cb14d5bf..2cdf93f3193 100644
>>> --- a/gdb/linux-tdep.c
>>> +++ b/gdb/linux-tdep.c
>>> @@ -124,6 +124,7 @@ struct smaps_data
>>>  
>>>    ULONGEST rss;
>>>    ULONGEST swap;
>>> +  std::optional<int> pkey;
>>>  };
>>>  
>>>  /* Whether to take the /proc/PID/coredump_filter into account when
>>> @@ -907,6 +908,11 @@ extract_string_view_from_buffer (gdb::array_view<char> &buffer,
>>>    return {gdb::array_view<char> (start, it), next_start};
>>>  }
>>>  
>>> +/* Forward declaration of parse_smaps_data used in linux_info_proc below.  */
>>> +
>>> +static std::vector<struct smaps_data>
>>> +parse_smaps_data (const file_reader_t<char> &freader);
>>> +
>>>  /* Implement the "info proc" command.  */
>>>  
>>>  static void
>>> @@ -1010,33 +1016,69 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
>>>      }
>>>    if (mappings_f)
>>>      {
>>> +      /* Parse the content of /proc/PID/smaps.  */
>>> +      bool pkey_column = false;
>>> +      std::vector<struct smaps_data> smaps_data;
>>> +      file_reader_t<char> smaps_freader
>>> +	(string_printf ("/proc/%ld/smaps", ptid.lwp ()));
>>> +      if (smaps_freader.error ())
>>> +	warning (_("unable to open /proc file '%s'"),
>>> +		 smaps_freader.c_filepath ());
>>> +      else if (smaps_freader)
>>> +	{
>>> +	  smaps_data = parse_smaps_data (smaps_freader);
>>> +
>>> +	  /* Check whether "ProtectionKey" field is present.  */
>>> +	  pkey_column
>>> +	    = std::any_of (smaps_data.cbegin (), smaps_data.cend (),
>>> +			   [] (const struct smaps_data &d) -> bool
>>> +			   { return d.pkey.has_value (); });
>>> +	}
>>> +
>>> +      /* Parse the content of /proc/PID/maps.  */
>>> +      std::vector<struct mapping> maps_data;
>>>        file_reader_t<char> map_freader
>>>  	(string_printf ("/proc/%ld/maps", ptid.lwp ()));
>>> -      if (map_freader)
>>> +      if (map_freader.error ())
>>> +	warning (_("unable to open /proc file '%s'"),
>>> +		 map_freader.c_filepath ());
>>> +      else if (map_freader)
>>> +	{
>>> +	  auto content = map_freader.view ();
>>> +	  for (auto it = content.begin (); it != content.end ();)
>>> +	    {
>>> +	      auto [line, next_line_begin]
>>> +		= extract_string_view_from_buffer (content, it, '\n');
>>> +	      it = next_line_begin;
>>> +
>>> +	      /* read_mapping() expects a null-terminated string.  */
>>> +	      *std::prev (it) = '\0';
>>> +	      maps_data.emplace_back (read_mapping (line.data ()));
>>> +	   }
>>> +	}
>>> +
>>> +      gdb_assert (maps_data.size () == smaps_data.size ());
>>> +
>>> +      if (maps_data.size () > 0)
>>>  	{
>>>  	  gdb_printf (_("Mapped address spaces:\n\n"));
>>> -	  ui_out_emit_table emitter (current_uiout, 6, -1, "ProcMappings");
>>> +	  int n_cols = (pkey_column ? 7 : 6);
>>> +	  ui_out_emit_table emitter (current_uiout, n_cols, -1, "ProcMappings");
>>>  
>>>  	  int width = gdbarch_addr_bit (gdbarch) == 32 ? 10 : 18;
>>>  	  current_uiout->table_header (width, ui_left, "start", "Start Addr");
>>>  	  current_uiout->table_header (width, ui_left, "end", "End Addr");
>>>  	  current_uiout->table_header (width, ui_left, "size", "Size");
>>>  	  current_uiout->table_header (width, ui_left, "offset", "Offset");
>>> +	  if (pkey_column)
>>> +	    current_uiout->table_header (4, ui_left, "pkey", "PKey");
>>>  	  current_uiout->table_header (5, ui_left, "perms", "Perms");
>>>  	  current_uiout->table_header (0, ui_left, "objfile", "File");
>>>  	  current_uiout->table_body ();
>>>  
>>> -	  auto content = map_freader.view ();
>>> -	  for (auto it = content.begin (); it != content.end ();)
>>> +	  auto it_smaps = smaps_data.cbegin ();
>>> +	  for (const auto &m: maps_data)
>>>  	    {
>>> -	      auto [line, next_line_begin]
>>> -		= extract_string_view_from_buffer (content, it, '\n');
>>> -	      it = next_line_begin;
>>> -
>>> -	      /* read_mapping() expects a null-terminated string.  */
>>> -	      *std::prev (it) = '\0';
>>> -	      struct mapping m = read_mapping (line.data ());
>>> -
>>>  	      ui_out_emit_tuple tuple_emitter (current_uiout, nullptr);
>>>  	      current_uiout->field_core_addr ("start", gdbarch, m.addr);
>>>  	      current_uiout->field_core_addr ("end", gdbarch, m.endaddr);
>>> @@ -1047,15 +1089,21 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
>>>  						     m.endaddr - m.addr));
>>>  	      current_uiout->field_string ("offset",
>>>  					   paddress (gdbarch, m.offset));
>>> +	      if (pkey_column)
>>> +		{
>>> +		  if (it_smaps->pkey.has_value ())
>>> +		    current_uiout->field_signed ("pkey",
>>> +						 it_smaps->pkey.value ());
>>> +		  else
>>> +		    current_uiout->field_skip ("pkey");
>>> +		}
>>>  	      current_uiout->field_string ("perms", m.permissions);
>>>  	      current_uiout->field_string ("objfile", m.filename,
>>>  					   file_name_style.style ());
>>>  	      current_uiout->text ("\n");
>>> +	      ++it_smaps;
>>>  	    }
>>>  	}
>>> -      else
>>> -	warning (_("unable to open /proc file '%s'"),
>>> -		 map_freader.c_filepath ());
>>>      }
>>>    if (status_f)
>>>      {
>>> @@ -1605,6 +1653,7 @@ parse_smaps_data (const file_reader_t<char> &freader)
>>>        int mapping_file_p;
>>>        ULONGEST rss = -1;
>>>        ULONGEST swap = -1;
>>> +      int pkey = -1;
>>>  
>>>        memset (&v, 0, sizeof (v));
>>>        struct mapping m = read_mapping (line);
>>> @@ -1705,6 +1754,18 @@ parse_smaps_data (const file_reader_t<char> &freader)
>>>  		  mapping_anon_p = 1;
>>>  		}
>>>  	    }
>>> +
>>> +	  if (streq (keyword, "ProtectionKey:"))
>>> +	    {
>>> +	      if (sscanf (line, "%*s%d", &pkey) != 1)
>>> +		{
>>> +		  /* Remove the trailing column when printing the warning.  */
>>> +		  keyword[sizeof ("ProtectionKey:") - 2] = '\0';
>>> +		  warning (_("Error parsing %s's value in {s,}maps file '%s'"),
>>> +			   keyword, freader.c_filepath ());
>>> +		  break;
>>> +		}
>>> +	    }
>>>  	}
>>>        /* Save the smaps entry to the vector.  */
>>>  	struct smaps_data map;
>>> @@ -1724,6 +1785,8 @@ parse_smaps_data (const file_reader_t<char> &freader)
>>>  	map.inode = m.inode;
>>>  	map.rss = rss;
>>>  	map.swap = swap;
>>> +	if (pkey != -1)
>>> +	  map.pkey.emplace (pkey);
>>>  
>>>  	smaps.emplace_back (map);
>>>      }
>>
>> Ping.
> 
> Isn't this patch blocked on some other patches being merged?  I'm not
> sure it needs to be pinged if it doesn't apply yet.  Apologies if I'm
> wrong here.
> 
> Thanks,
> Andrew

You are correct.
Sorry for the noise.

Matthieu

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-07 16:02 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-28 15:29 [PATCH v1] gdb/linux-tdep: display ProtectionKey in info proc mappings Matthieu Longo
2026-07-28 15:30 ` Matthieu Longo
2026-09-07  9:13 ` Matthieu Longo
2026-09-07 15:24   ` Andrew Burgess
2026-09-07 16:00     ` Matthieu Longo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox