public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: Simon Marchi <simon.marchi@polymtl.ca>, gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@efficios.com>
Subject: Re: [PATCH 06/24] gdb: fix bugs in {get,put}_frame_register_bytes
Date: Mon, 13 Nov 2023 15:00:44 +0000	[thread overview]
Message-ID: <8734x9snoj.fsf@redhat.com> (raw)
In-Reply-To: <20231108051222.1275306-7-simon.marchi@polymtl.ca>

Simon Marchi <simon.marchi@polymtl.ca> writes:

> From: Simon Marchi <simon.marchi@efficios.com>
>
> I found this only by inspection: the myaddr pointer in
> {get,put}_frame_register_bytes is reset to `buffer.data ()` at each
> iteration.  This means that we will always use the bytes at the
> beginning of `buffer` to read or write to the registers, instead of
> progressing in `buffer`.
>
> Fix this by re-writing the functions to chip away the beginning of the
> buffer array_view as we progress in reading or writing the data.
>
> These bugs was introduced almost 3 years ago [1], and yet nobody
> complained.  I'm wondering which architecture relies on that register
> "overflow" behavior (reading or writing multiple consecutive registers
> with one {get,put}_frame_register_bytes calls), and in which situation.
> I find these functions a bit dangerous, if a caller mis-calculates
> things, it could end up silently reading or writing to the next
> register, even if it's not the intent.
>
> If I could change it, I would prefer to have functions specifically made
> for that ({get,put}_frame_register_bytes_consecutive or something like
> that) and make {get,put}_frame_register_bytes only able to write within
> a single register (which I presume represents most of the use cases of
> the current {get,put}_frame_register_bytes).  If a caller mis-calculates
> things and an overflow occurs while calling
> {get,put}_frame_register_bytes, it would hit an assert.  The problem is
> knowing which callers rely on the overflow behavior and which don't.

I agree that this overflow behaviour sucks.

I have a memory of being told (years ago now) that this was a result of
some older compilers not emitting correct DWARF for compound value
locations, instead the compiler would just emit a single register
location, and assume that the debugger would read from consecutive DWARF
registers.  Note, this code assumes that the DWARF register numbering is
the same as GDB's register numbering, which is not always the case.

Personally, I'd love for GDB to be more aggressive about removing some
of this legacy behaviour.  What I'd like to do is move things like this
behind a switch, say 'set maintenance deprecated-features on|off', which
would be off by default, but when it is turned on we'd print a message
saying:

  The feature you turned this on for is deprecated, and will be removed
  from future versions of GDB.  To avoid this feature removed, please
  file a bug report here <url> describing the deprecated feature that
  you are using.

Then if nobody complains after a couple of years, we can start deleting
things.

Anyway... just putting my thoughts down.  I think this patch is fine.

Approved-By: Andrew Burgess <aburgess@redhat.com>

Thanks,
Andrew


>
> [1] https://gitlab.com/gnutools/binutils-gdb/-/commit/bdec2917b1e94c7198ba39919f45060067952f43
>
> Change-Id: I43bd4a9f7fa8419d388a2b20bdc57d652688ddf8
> ---
>  gdb/frame.c | 63 +++++++++++++++++++----------------------------------
>  1 file changed, 23 insertions(+), 40 deletions(-)
>
> diff --git a/gdb/frame.c b/gdb/frame.c
> index afadb8ac4e73..b3d99163b4dc 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -1482,9 +1482,6 @@ get_frame_register_bytes (frame_info_ptr frame, int regnum,
>  			  int *optimizedp, int *unavailablep)
>  {
>    struct gdbarch *gdbarch = get_frame_arch (frame);
> -  int i;
> -  int maxsize;
> -  int numregs;
>  
>    /* Skip registers wholly inside of OFFSET.  */
>    while (offset >= register_size (gdbarch, regnum))
> @@ -1495,9 +1492,9 @@ get_frame_register_bytes (frame_info_ptr frame, int regnum,
>  
>    /* Ensure that we will not read beyond the end of the register file.
>       This can only ever happen if the debug information is bad.  */
> -  maxsize = -offset;
> -  numregs = gdbarch_num_cooked_regs (gdbarch);
> -  for (i = regnum; i < numregs; i++)
> +  int maxsize = -offset;
> +  int numregs = gdbarch_num_cooked_regs (gdbarch);
> +  for (int i = regnum; i < numregs; i++)
>      {
>        int thissize = register_size (gdbarch, i);
>  
> @@ -1506,20 +1503,15 @@ get_frame_register_bytes (frame_info_ptr frame, int regnum,
>        maxsize += thissize;
>      }
>  
> -  int len = buffer.size ();
> -  if (len > maxsize)
> +  if (buffer.size () > maxsize)
>      error (_("Bad debug information detected: "
> -	     "Attempt to read %d bytes from registers."), len);
> +	     "Attempt to read %zu bytes from registers."), buffer.size ());
>  
>    /* Copy the data.  */
> -  while (len > 0)
> +  while (!buffer.empty ())
>      {
> -      int curr_len = register_size (gdbarch, regnum) - offset;
> -
> -      if (curr_len > len)
> -	curr_len = len;
> -
> -      gdb_byte *myaddr = buffer.data ();
> +      int curr_len = std::min<int> (register_size (gdbarch, regnum) - offset,
> +				    buffer.size ());
>  
>        if (curr_len == register_size (gdbarch, regnum))
>  	{
> @@ -1527,8 +1519,8 @@ get_frame_register_bytes (frame_info_ptr frame, int regnum,
>  	  CORE_ADDR addr;
>  	  int realnum;
>  
> -	  frame_register (frame, regnum, optimizedp, unavailablep,
> -			  &lval, &addr, &realnum, myaddr);
> +	  frame_register (frame, regnum, optimizedp, unavailablep, &lval,
> +			  &addr, &realnum, buffer.data ());
>  	  if (*optimizedp || *unavailablep)
>  	    return false;
>  	}
> @@ -1547,13 +1539,12 @@ get_frame_register_bytes (frame_info_ptr frame, int regnum,
>  	      return false;
>  	    }
>  
> -	  memcpy (myaddr, value->contents_all ().data () + offset,
> -		  curr_len);
> +	  copy (value->contents_all ().slice (offset, curr_len),
> +		buffer.slice (0, curr_len));
>  	  release_value (value);
>  	}
>  
> -      myaddr += curr_len;
> -      len -= curr_len;
> +      buffer = buffer.slice (curr_len);
>        offset = 0;
>        regnum++;
>      }
> @@ -1578,36 +1569,28 @@ put_frame_register_bytes (frame_info_ptr frame, int regnum,
>        regnum++;
>      }
>  
> -  int len = buffer.size ();
>    /* Copy the data.  */
> -  while (len > 0)
> +  while (!buffer.empty ())
>      {
> -      int curr_len = register_size (gdbarch, regnum) - offset;
> +      int curr_len = std::min<int> (register_size (gdbarch, regnum) - offset,
> +				    buffer.size ());
>  
> -      if (curr_len > len)
> -	curr_len = len;
> -
> -      const gdb_byte *myaddr = buffer.data ();
>        if (curr_len == register_size (gdbarch, regnum))
> -	{
> -	  put_frame_register (frame, regnum, myaddr);
> -	}
> +	put_frame_register (frame, regnum, buffer.data ());
>        else
>  	{
> -	  struct value *value
> +	  value *value
>  	    = frame_unwind_register_value (frame_info_ptr (frame->next),
>  					   regnum);
> -	  gdb_assert (value != NULL);
> +	  gdb_assert (value != nullptr);
>  
> -	  memcpy ((char *) value->contents_writeable ().data () + offset,
> -		  myaddr, curr_len);
> -	  put_frame_register (frame, regnum,
> -			      value->contents_raw ().data ());
> +	  copy (buffer.slice (0, curr_len),
> +		value->contents_writeable ().slice (offset, curr_len));
> +	  put_frame_register (frame, regnum, value->contents_raw ().data ());
>  	  release_value (value);
>  	}
>  
> -      myaddr += curr_len;
> -      len -= curr_len;
> +      buffer = buffer.slice (curr_len);
>        offset = 0;
>        regnum++;
>      }
> -- 
> 2.42.1


  reply	other threads:[~2023-11-13 15:00 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-08  5:00 [PATCH 00/24] Fix reading and writing pseudo registers in non-current frames Simon Marchi
2023-11-08  5:00 ` [PATCH 01/24] gdb: don't handle i386 k registers as pseudo registers Simon Marchi
2023-11-11 19:29   ` John Baldwin
2023-11-08  5:00 ` [PATCH 02/24] gdb: use reg_buffer_common throughout gdbsupport/common-regcache.h Simon Marchi
2023-11-11 19:42   ` John Baldwin
2023-11-08  5:00 ` [PATCH 03/24] gdb: make store_integer take an array_view Simon Marchi
2023-11-08  5:00 ` [PATCH 04/24] gdb: simplify conditions in regcache::{read,write,raw_collect,raw_supply}_part Simon Marchi
2023-11-08  5:00 ` [PATCH 05/24] gdb: change regcache interface to use array_view Simon Marchi
2023-11-13 13:43   ` Andrew Burgess
2023-11-13 14:00     ` Andrew Burgess
2023-11-13 16:47       ` Simon Marchi
2023-11-08  5:00 ` [PATCH 06/24] gdb: fix bugs in {get,put}_frame_register_bytes Simon Marchi
2023-11-13 15:00   ` Andrew Burgess [this message]
2023-11-13 19:51     ` Simon Marchi
2023-11-08  5:00 ` [PATCH 07/24] gdb: make put_frame_register take an array_view Simon Marchi
2023-11-08  5:00 ` [PATCH 08/24] gdb: change value_of_register and value_of_register_lazy to take the next frame Simon Marchi
2023-11-08  5:00 ` [PATCH 09/24] gdb: remove frame_register Simon Marchi
2023-11-08  5:00 ` [PATCH 10/24] gdb: make put_frame_register take the next frame Simon Marchi
2023-11-08  5:00 ` [PATCH 11/24] gdb: make put_frame_register_bytes " Simon Marchi
2023-11-08  5:00 ` [PATCH 12/24] gdb: make get_frame_register_bytes " Simon Marchi
2023-11-08  5:00 ` [PATCH 13/24] gdb: add value::allocate_register Simon Marchi
2023-11-08  5:00 ` [PATCH 14/24] gdb: read pseudo register through frame Simon Marchi
2023-11-11 20:11   ` John Baldwin
2023-11-08  5:00 ` [PATCH 15/24] gdb: change parameter name in frame_unwind_register_unsigned declaration Simon Marchi
2023-11-08  5:01 ` [PATCH 16/24] gdb: rename gdbarch_pseudo_register_write to gdbarch_deprecated_pseudo_register_write Simon Marchi
2023-11-14 12:12   ` Andrew Burgess
2023-11-14 15:16     ` Simon Marchi
2023-11-08  5:01 ` [PATCH 17/24] gdb: add gdbarch_pseudo_register_write that takes a frame Simon Marchi
2023-11-14 12:20   ` Andrew Burgess
2023-11-14 15:20     ` Simon Marchi
2023-11-08  5:01 ` [PATCH 18/24] gdb: migrate i386 and amd64 to the new gdbarch_pseudo_register_write Simon Marchi
2023-11-11 20:16   ` John Baldwin
2023-11-13  2:59     ` Simon Marchi
2023-11-08  5:01 ` [PATCH 19/24] gdb: make aarch64_za_offsets_from_regnum return za_offsets Simon Marchi
2023-11-08  5:01 ` [PATCH 20/24] gdb: add missing raw register read in aarch64_sme_pseudo_register_write Simon Marchi
2023-11-08  5:01 ` [PATCH 21/24] gdb: migrate aarch64 to new gdbarch_pseudo_register_write Simon Marchi
2023-11-08  5:01 ` [PATCH 22/24] gdb: migrate arm to gdbarch_pseudo_register_read_value Simon Marchi
2023-11-08  5:01 ` [PATCH 23/24] gdb: migrate arm to new gdbarch_pseudo_register_write Simon Marchi
2023-11-08  5:01 ` [PATCH 24/24] gdb/testsuite: add tests for unwinding of pseudo registers Simon Marchi
2023-11-08  5:16 ` [PATCH 00/24] Fix reading and writing pseudo registers in non-current frames Simon Marchi
2023-11-09  3:05   ` Simon Marchi
2023-11-08 11:57 ` Luis Machado
2023-11-08 15:47   ` Simon Marchi
2023-11-08 17:08     ` Luis Machado
2023-11-08 19:34       ` Simon Marchi
2023-11-09 19:04         ` Simon Marchi
2023-11-13 13:10           ` Luis Machado
2023-11-13 15:08             ` Luis Machado
2023-11-11 20:26 ` John Baldwin
2023-11-13  3:03   ` Simon Marchi
2023-12-01 16:27 Simon Marchi
2023-12-01 16:27 ` [PATCH 06/24] gdb: fix bugs in {get,put}_frame_register_bytes Simon Marchi

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=8734x9snoj.fsf@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=simon.marchi@efficios.com \
    --cc=simon.marchi@polymtl.ca \
    /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).