Message ID | 20241102025635.586759-5-thiago.bauermann@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | gdbserver improvements for AArch64 SVE support | expand |
> diff --git a/gdb/regcache.h b/gdb/regcache.h > index 65e9f7bb79da..739172a249b8 100644 > --- a/gdb/regcache.h > +++ b/gdb/regcache.h > @@ -177,7 +177,7 @@ using register_read_ftype > struct cached_reg_t > { > int num; > - gdb::unique_xmalloc_ptr<gdb_byte> data; > + gdb::byte_vector data; > > cached_reg_t () = default; > cached_reg_t (cached_reg_t &&rhs) = default; You can remove these last two lines now. > diff --git a/gdb/remote.c b/gdb/remote.c > index 6ffc51e4e2f5..2da2c5a4789a 100644 > --- a/gdb/remote.c > +++ b/gdb/remote.c > @@ -8225,13 +8225,12 @@ Packet: '%s'\n"), > hex_string (pnum), p, buf); > > cached_reg.num = reg->regnum; > - cached_reg.data.reset ((gdb_byte *) > - xmalloc (register_size (event->arch, > - reg->regnum))); > + cached_reg.data.resize (register_size (event->arch, > + reg->regnum)); > > p = p1 + 1; > - fieldsize = hex2bin (p, cached_reg.data.get (), > - register_size (event->arch, reg->regnum)); > + fieldsize = hex2bin (p, cached_reg.data.data (), > + cached_reg.data.size ()); > p += 2 * fieldsize; > if (fieldsize < register_size (event->arch, reg->regnum)) > warning (_("Remote reply is too short: %s"), buf); Could you please factor out the register_size calls, saving the result to a reg_size local? That would help readability. LGTM with those fixed. Approved-By: Simon Marchi <simon.marchi@efficios.com> Simon
Simon Marchi <simark@simark.ca> writes: >> diff --git a/gdb/regcache.h b/gdb/regcache.h >> index 65e9f7bb79da..739172a249b8 100644 >> --- a/gdb/regcache.h >> +++ b/gdb/regcache.h >> @@ -177,7 +177,7 @@ using register_read_ftype >> struct cached_reg_t >> { >> int num; >> - gdb::unique_xmalloc_ptr<gdb_byte> data; >> + gdb::byte_vector data; >> >> cached_reg_t () = default; >> cached_reg_t (cached_reg_t &&rhs) = default; > > You can remove these last two lines now. Ah, thanks. Removed. >> diff --git a/gdb/remote.c b/gdb/remote.c >> index 6ffc51e4e2f5..2da2c5a4789a 100644 >> --- a/gdb/remote.c >> +++ b/gdb/remote.c >> @@ -8225,13 +8225,12 @@ Packet: '%s'\n"), >> hex_string (pnum), p, buf); >> >> cached_reg.num = reg->regnum; >> - cached_reg.data.reset ((gdb_byte *) >> - xmalloc (register_size (event->arch, >> - reg->regnum))); >> + cached_reg.data.resize (register_size (event->arch, >> + reg->regnum)); >> >> p = p1 + 1; >> - fieldsize = hex2bin (p, cached_reg.data.get (), >> - register_size (event->arch, reg->regnum)); >> + fieldsize = hex2bin (p, cached_reg.data.data (), >> + cached_reg.data.size ()); > >> p += 2 * fieldsize; >> if (fieldsize < register_size (event->arch, reg->regnum)) >> warning (_("Remote reply is too short: %s"), buf); > > Could you please factor out the register_size calls, saving the result > to a reg_size local? That would help readability. Good idea. Done. > LGTM with those fixed. > > Approved-By: Simon Marchi <simon.marchi@efficios.com> Thanks! Pushed as commit ad59259604f0 ("GDB: trad-frame: Store length of value_bytes in trad_frame_saved_reg"). -- Thiago
Hi Thiago, Looked at this and tried to implement something for our purposes. There I saw little issue when we collect the expedite registers. If an expedited register itself is a variable size register, register_size() requires a frame and none is supplied here. Not sure we could get around this by getting the current thread's regcache if no frame is supplied? Thanks Klaus > -----Original Message----- > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org> > Sent: Friday, January 10, 2025 3:08 AM > To: Simon Marchi <simark@simark.ca> > Cc: gdb-patches@sourceware.org > Subject: Re: [RFC PATCH v4 04/15] GDB: trad-frame: Store length of > value_bytes in trad_frame_saved_reg > > > Simon Marchi <simark@simark.ca> writes: > > >> diff --git a/gdb/regcache.h b/gdb/regcache.h > >> index 65e9f7bb79da..739172a249b8 100644 > >> --- a/gdb/regcache.h > >> +++ b/gdb/regcache.h > >> @@ -177,7 +177,7 @@ using register_read_ftype > >> struct cached_reg_t > >> { > >> int num; > >> - gdb::unique_xmalloc_ptr<gdb_byte> data; > >> + gdb::byte_vector data; > >> > >> cached_reg_t () = default; > >> cached_reg_t (cached_reg_t &&rhs) = default; > > > > You can remove these last two lines now. > > Ah, thanks. Removed. > > >> diff --git a/gdb/remote.c b/gdb/remote.c > >> index 6ffc51e4e2f5..2da2c5a4789a 100644 > >> --- a/gdb/remote.c > >> +++ b/gdb/remote.c > >> @@ -8225,13 +8225,12 @@ Packet: '%s'\n"), > >> hex_string (pnum), p, buf); > >> > >> cached_reg.num = reg->regnum; > >> - cached_reg.data.reset ((gdb_byte *) > >> - xmalloc (register_size (event->arch, > >> - reg- > >regnum))); > >> + cached_reg.data.resize (register_size (event->arch, > >> + reg->regnum)); > >> > >> p = p1 + 1; > >> - fieldsize = hex2bin (p, cached_reg.data.get (), > >> - register_size (event->arch, reg->regnum)); > >> + fieldsize = hex2bin (p, cached_reg.data.data (), > >> + cached_reg.data.size ()); > > > >> p += 2 * fieldsize; > >> if (fieldsize < register_size (event->arch, reg->regnum)) > >> warning (_("Remote reply is too short: %s"), buf); > > > > Could you please factor out the register_size calls, saving the result > > to a reg_size local? That would help readability. > > Good idea. Done. > > > LGTM with those fixed. > > > > Approved-By: Simon Marchi <simon.marchi@efficios.com> > > Thanks! Pushed as commit ad59259604f0 ("GDB: trad-frame: Store length of > value_bytes in trad_frame_saved_reg"). > > -- > Thiago Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928
Hello Klaus, "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes: > Looked at this and tried to implement something for our > purposes. There I saw little issue when we collect the expedite > registers. > > If an expedited register itself is a variable size register, Ah, this is one thing I don't have to worry about. Do you require that any expedited register that has variable size needs to come after the register(s) it depends on in the response packet? > register_size() requires a frame and none is supplied here. Where is "here" in the code? > Not sure we could get around this by getting the current thread's > regcache if no frame is supplied? That would be possible, but with the drawback of possibly resulting in the wrong register size if the user is currently inspecting an older frame in the stack. -- Thiago
Hi Thiago, > Hello Klaus, > > "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes: > > > Looked at this and tried to implement something for our > > purposes. There I saw little issue when we collect the expedite > > registers. > > > > If an expedited register itself is a variable size register, > > Ah, this is one thing I don't have to worry about. Do you require that > any expedited register that has variable size needs to come after the > register(s) it depends on in the response packet? > > > register_size() requires a frame and none is supplied here. > > Where is "here" in the code? > The code I'm referring to is in remote.c, ~line #8316, where we process the expedites: packet_reg *reg = packet_reg_from_pnum (event->arch, rsa, pnum); cached_reg_t cached_reg; if (reg == NULL) error (_("Remote sent bad register number %s: %s\n\ Packet: '%s'\n"), hex_string (pnum), p, buf); cached_reg.num = reg->regnum; cached_reg.data.resize (register_size (event->arch, reg->regnum)); p = p1 + 1; fieldsize = hex2bin (p, cached_reg.data.data (), cached_reg.data.size ()); p += 2 * fieldsize; if (fieldsize < register_size (event->arch, reg->regnum)) warning (_("Remote reply is too short: %s"), buf); event->regcache.push_back (std::move (cached_reg)); If one the expedite regs is a var len register, then we are in trouble. 1) Because we would usually need a frame and 2) fetching load early here would overwrite the currently processed packet. Of course I assume we could move this defer this decoding to process_stop_reply(), where we can first get the load early registers and the decode the XX:XXXXXXX expedite packets. The other road that I took in trying out your patches in our GPU product is to not have any of the expedites be var length, which would mean just a little extra data in the GDBserver transfer. Not very problematic IMHO. > > Not sure we could get around this by getting the current thread's > > regcache if no frame is supplied? > > That would be possible, but with the drawback of possibly resulting in the > wrong register size if the user is currently inspecting an older frame > in the stack. Is that a big issue? I fail to see all the implications. Could you give me an example? > > -- > Thiago Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928
"Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes: >> "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes: >> >> > Looked at this and tried to implement something for our >> > purposes. There I saw little issue when we collect the expedite >> > registers. >> > >> > If an expedited register itself is a variable size register, >> >> Ah, this is one thing I don't have to worry about. Do you require that >> any expedited register that has variable size needs to come after the >> register(s) it depends on in the response packet? >> >> > register_size() requires a frame and none is supplied here. >> >> Where is "here" in the code? > > The code I'm referring to is in remote.c, ~line #8316, where we > process the expedites: > > packet_reg *reg > = packet_reg_from_pnum (event->arch, rsa, pnum); > cached_reg_t cached_reg; > > if (reg == NULL) > error (_("Remote sent bad register number %s: %s\n\ > Packet: '%s'\n"), > hex_string (pnum), p, buf); > > cached_reg.num = reg->regnum; > cached_reg.data.resize (register_size (event->arch, > reg->regnum)); > > p = p1 + 1; > fieldsize = hex2bin (p, cached_reg.data.data (), > cached_reg.data.size ()); > p += 2 * fieldsize; > if (fieldsize < register_size (event->arch, reg->regnum)) > warning (_("Remote reply is too short: %s"), buf); > > event->regcache.push_back (std::move (cached_reg)); > > If one the expedite regs is a var len register, then we are in > trouble. 1) Because we would usually need a frame and The code above is in remote_target::remote_parse_stop_reply, in which case the inferior has just stopped and we can just get the current thread's regcache as you suggested. The user isn't inspecting an older frame in the stack. > 2) fetching load early here would overwrite the currently processed > packet. > > Of course I assume we could move this defer this decoding to > process_stop_reply(), where we can first get the load early registers > and the decode the XX:XXXXXXX expedite packets. I agree that it would make sense to move the parsing of the expedited registers to process_stop_reply, but I don't think there should be an additional fetching of the load early registers when processing the expedited registers. The load early registers are a subset of expedited registers, so they will already be present in the stop reply that is being processed. What should happen is that the load early registers need to be supplied to the regcache before the other expedited registers during processing of the stop reply. Or are you considering a case where a load early register is also variable-size? In that case it can probably also be made to work, if we require that any load early register required to compute the size of another load early register should precede the latter in the stop reply. Though if we can avoid this case it would be simpler. > The other road that I took in trying out your patches in our GPU > product is to not have any of the expedites be var length, which would > mean just a little extra data in the GDBserver transfer. Not very > problematic IMHO. In case the variable length expedited register isn't also a load early register it shouldn't be too hard to support it as I mentioned above. But if it is, then it's indeed probably better to avoid this scenario. >> > Not sure we could get around this by getting the current thread's >> > regcache if no frame is supplied? >> >> That would be possible, but with the drawback of possibly resulting in the >> wrong register size if the user is currently inspecting an older frame >> in the stack. > > Is that a big issue? I fail to see all the implications. Could you > give me an example? It won't happen in the case of remote_parse_stop_reply and process_stop_reply as I mention above, but the scenario I was thinking was something like: Breakpoint 1, function3 (arg3=3) at hello.c:6 6 printf ("function3: arg3 = %d\n", arg3); (gdb) p $vg $1 = 8 (gdb) p sizeof $z0 $2 = 64 (gdb) up #1 0x0000aaaaaaaa0994 in function2 (arg2=2) at hello.c:10 10 function3(arg2 + 1); (gdb) p $vg $3 = 4 (gdb) p sizeof $z0 $4 = 32 In the example above, the current thread's regcache contains $vg = 8, but if the user goes to frame #1, $vg has a different value there and thus the SVE register $z0 has a different size. If the user is in the context of frame #1 and GDB uses the current regcache for something, then it will mistakenly use the wrong $vg size of 8 and consequently the wrong $z0 size of 64. -- Thiago
> -----Original Message----- > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org> > Sent: Wednesday, February 19, 2025 5:58 AM > To: Gerlicher, Klaus <klaus.gerlicher@intel.com> > Cc: Simon Marchi <simark@simark.ca>; gdb-patches@sourceware.org > Subject: Re: [RFC PATCH v4 04/15] GDB: trad-frame: Store length of value_bytes > in trad_frame_saved_reg > > "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes: > > >> "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes: > >> > >> > Looked at this and tried to implement something for our purposes. > >> > There I saw little issue when we collect the expedite registers. > >> > > >> > If an expedited register itself is a variable size register, > >> > >> Ah, this is one thing I don't have to worry about. Do you require > >> that any expedited register that has variable size needs to come > >> after the > >> register(s) it depends on in the response packet? > >> > >> > register_size() requires a frame and none is supplied here. > >> > >> Where is "here" in the code? > > > > The code I'm referring to is in remote.c, ~line #8316, where we > > process the expedites: > > > > packet_reg *reg > > = packet_reg_from_pnum (event->arch, rsa, pnum); > > cached_reg_t cached_reg; > > > > if (reg == NULL) > > error (_("Remote sent bad register number %s: %s\n\ > > Packet: '%s'\n"), > > hex_string (pnum), p, buf); > > > > cached_reg.num = reg->regnum; > > cached_reg.data.resize (register_size (event->arch, > > reg->regnum)); > > > > p = p1 + 1; > > fieldsize = hex2bin (p, cached_reg.data.data (), > > cached_reg.data.size ()); > > p += 2 * fieldsize; > > if (fieldsize < register_size (event->arch, reg->regnum)) > > warning (_("Remote reply is too short: %s"), buf); > > > > event->regcache.push_back (std::move (cached_reg)); > > > > If one the expedite regs is a var len register, then we are in > > trouble. 1) Because we would usually need a frame and > > The code above is in remote_target::remote_parse_stop_reply, in which case > the inferior has just stopped and we can just get the current thread's regcache > as you suggested. The user isn't inspecting an older frame in the stack. > > > 2) fetching load early here would overwrite the currently processed > > packet. > > > > Of course I assume we could move this defer this decoding to > > process_stop_reply(), where we can first get the load early registers > > and the decode the XX:XXXXXXX expedite packets. > > I agree that it would make sense to move the parsing of the expedited registers > to process_stop_reply, but I don't think there should be an additional fetching of > the load early registers when processing the expedited registers. The load early > registers are a subset of expedited registers, so they will already be present in > the stop reply that is being processed. > > What should happen is that the load early registers need to be supplied to the > regcache before the other expedited registers during processing of the stop > reply. > > Or are you considering a case where a load early register is also variable-size? > In that case it can probably also be made to work, if we require that any load > early register required to compute the size of another load early register should > precede the latter in the stop reply. > > Though if we can avoid this case it would be simpler. > > > The other road that I took in trying out your patches in our GPU > > product is to not have any of the expedites be var length, which would > > mean just a little extra data in the GDBserver transfer. Not very > > problematic IMHO. > > In case the variable length expedited register isn't also a load early register it > shouldn't be too hard to support it as I mentioned above. But if it is, then it's > indeed probably better to avoid this scenario. > > >> > Not sure we could get around this by getting the current thread's > >> > regcache if no frame is supplied? > >> > >> That would be possible, but with the drawback of possibly resulting > >> in the wrong register size if the user is currently inspecting an > >> older frame in the stack. > > > > Is that a big issue? I fail to see all the implications. Could you > > give me an example? > > It won't happen in the case of remote_parse_stop_reply and process_stop_reply > as I mention above, but the scenario I was thinking was something like: > > Breakpoint 1, function3 (arg3=3) at hello.c:6 > 6 printf ("function3: arg3 = %d\n", arg3); > (gdb) p $vg > $1 = 8 > (gdb) p sizeof $z0 > $2 = 64 > (gdb) up > #1 0x0000aaaaaaaa0994 in function2 (arg2=2) at hello.c:10 > 10 function3(arg2 + 1); > (gdb) p $vg > $3 = 4 > (gdb) p sizeof $z0 > $4 = 32 > > In the example above, the current thread's regcache contains $vg = 8, but if the > user goes to frame #1, $vg has a different value there and thus the SVE register > $z0 has a different size. > > If the user is in the context of frame #1 and GDB uses the current regcache for > something, then it will mistakenly use the wrong $vg size of 8 and consequently > the wrong $z0 size of 64. Hi Thiago, we did a quick check and could not see that vg is being unwound. Could you give us a more detailed example ? Thanks Christina + Klaus Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928
diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c index fecd1070e912..ad8ebb29d736 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -313,14 +313,26 @@ frame_unwind_got_constant (const frame_info_ptr &frame, int regnum, } struct value * -frame_unwind_got_bytes (const frame_info_ptr &frame, int regnum, const gdb_byte *buf) +frame_unwind_got_bytes (const frame_info_ptr &frame, int regnum, + gdb::array_view<const gdb_byte> buf) { struct gdbarch *gdbarch = frame_unwind_arch (frame); struct value *reg_val; reg_val = value::zero (register_type (gdbarch, regnum), not_lval); - memcpy (reg_val->contents_raw ().data (), buf, - register_size (gdbarch, regnum)); + gdb::array_view<gdb_byte> val_contents = reg_val->contents_raw (); + + /* The value's contents buffer is zeroed on allocation so if buf is + smaller, the remaining space will be filled with zero. + + This can happen when unwinding through signal frames. For example, if + an AArch64 program doesn't use SVE, then the Linux kernel will only + save in the signal frame the first 128 bits of the vector registers, + which is their minimum size, even if the vector length says they're + bigger. */ + gdb_assert (buf.size () <= val_contents.size ()); + + memcpy (val_contents.data (), buf.data (), buf.size ()); return reg_val; } diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h index 53fcd6869e95..36e7fbdb4f9c 100644 --- a/gdb/frame-unwind.h +++ b/gdb/frame-unwind.h @@ -226,7 +226,7 @@ value *frame_unwind_got_constant (const frame_info_ptr &frame, int regnum, inside BUF. */ value *frame_unwind_got_bytes (const frame_info_ptr &frame, int regnum, - const gdb_byte *buf); + gdb::array_view<const gdb_byte> buf); /* Return a value which indicates that FRAME's saved version of REGNUM has a known constant (computed) value of ADDR. Convert the diff --git a/gdb/jit.c b/gdb/jit.c index ed3b26cd4bd1..e068b0a4b572 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -1094,7 +1094,7 @@ jit_frame_prev_register (const frame_info_ptr &this_frame, void **cache, int reg return frame_unwind_got_optimized (this_frame, reg); gdbarch = priv->regcache->arch (); - gdb_byte *buf = (gdb_byte *) alloca (register_size (gdbarch, reg)); + gdb::byte_vector buf (register_size (gdbarch, reg)); enum register_status status = priv->regcache->cooked_read (reg, buf); if (status == REG_VALID) diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c index 68deaf98d81f..c1a01bf7cfe4 100644 --- a/gdb/python/py-unwind.c +++ b/gdb/python/py-unwind.c @@ -812,7 +812,7 @@ pyuw_prev_register (const frame_info_ptr &this_frame, void **cache_ptr, for (; reg_info < reg_info_end; ++reg_info) { if (regnum == reg_info->num) - return frame_unwind_got_bytes (this_frame, regnum, reg_info->data.get ()); + return frame_unwind_got_bytes (this_frame, regnum, reg_info->data); } return frame_unwind_got_optimized (this_frame, regnum); @@ -936,8 +936,9 @@ pyuw_sniffer (const struct frame_unwind *self, const frame_info_ptr &this_frame, cached_reg_t *cached = new (&cached_frame->reg[i]) cached_reg_t (); cached->num = reg->number; - cached->data.reset ((gdb_byte *) xmalloc (data_size)); - memcpy (cached->data.get (), value->contents ().data (), data_size); + cached->data.resize (data_size); + gdb::array_view<const gdb_byte> contents = value->contents (); + cached->data.assign (contents.begin (), contents.end ()); } } diff --git a/gdb/regcache.h b/gdb/regcache.h index 65e9f7bb79da..739172a249b8 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -177,7 +177,7 @@ using register_read_ftype struct cached_reg_t { int num; - gdb::unique_xmalloc_ptr<gdb_byte> data; + gdb::byte_vector data; cached_reg_t () = default; cached_reg_t (cached_reg_t &&rhs) = default; diff --git a/gdb/remote.c b/gdb/remote.c index 6ffc51e4e2f5..2da2c5a4789a 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -8225,13 +8225,12 @@ Packet: '%s'\n"), hex_string (pnum), p, buf); cached_reg.num = reg->regnum; - cached_reg.data.reset ((gdb_byte *) - xmalloc (register_size (event->arch, - reg->regnum))); + cached_reg.data.resize (register_size (event->arch, + reg->regnum)); p = p1 + 1; - fieldsize = hex2bin (p, cached_reg.data.get (), - register_size (event->arch, reg->regnum)); + fieldsize = hex2bin (p, cached_reg.data.data (), + cached_reg.data.size ()); p += 2 * fieldsize; if (fieldsize < register_size (event->arch, reg->regnum)) warning (_("Remote reply is too short: %s"), buf); @@ -8572,7 +8571,7 @@ remote_target::process_stop_reply (stop_reply_up stop_reply, for (cached_reg_t ® : stop_reply->regcache) { - regcache->raw_supply (reg.num, reg.data.get ()); + regcache->raw_supply (reg.num, reg.data); rs->last_seen_expedited_registers.insert (reg.num); } } diff --git a/gdb/trad-frame.h b/gdb/trad-frame.h index ca8792baa17d..ef84a24c0bc7 100644 --- a/gdb/trad-frame.h +++ b/gdb/trad-frame.h @@ -122,6 +122,7 @@ struct trad_frame_saved_reg m_kind = trad_frame_saved_reg_kind::VALUE_BYTES; m_reg.value_bytes = data; + m_reg.bytes_len = bytes.size (); } /* Getters */ @@ -144,10 +145,10 @@ struct trad_frame_saved_reg return m_reg.addr; } - const gdb_byte *value_bytes () const + gdb::array_view<const gdb_byte> value_bytes () const { gdb_assert (m_kind == trad_frame_saved_reg_kind::VALUE_BYTES); - return m_reg.value_bytes; + return { m_reg.value_bytes, m_reg.bytes_len }; } /* Convenience functions, return true if the register has been @@ -185,7 +186,10 @@ struct trad_frame_saved_reg LONGEST value; int realreg; LONGEST addr; - const gdb_byte *value_bytes; + struct { + const gdb_byte *value_bytes; + size_t bytes_len; + }; } m_reg; };