From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 64510 invoked by alias); 26 May 2018 00:24:54 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 64303 invoked by uid 89); 26 May 2018 00:24:32 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.2 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=AVR, avr, tdep, involve X-HELO: barracuda.ebox.ca Received: from barracuda.ebox.ca (HELO barracuda.ebox.ca) (96.127.255.19) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 26 May 2018 00:24:25 +0000 X-ASG-Debug-ID: 1527294247-0c856e5f355a36c0001-fS2M51 Received: from smtp.ebox.ca (smtp.electronicbox.net [96.127.255.82]) by barracuda.ebox.ca with ESMTP id hwUWjjPIEn0mbi2U (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 25 May 2018 20:24:07 -0400 (EDT) X-Barracuda-Envelope-From: simon.marchi@polymtl.ca X-Barracuda-RBL-Trusted-Forwarder: 96.127.255.82 Received: from simark.lan (unknown [192.222.164.54]) by smtp.ebox.ca (Postfix) with ESMTP id 8E72C441B21; Fri, 25 May 2018 20:24:07 -0400 (EDT) From: Simon Marchi X-Barracuda-Effective-Source-IP: 192-222-164-54.qc.cable.ebox.net[192.222.164.54] X-Barracuda-Apparent-Source-IP: 192.222.164.54 X-Barracuda-RBL-IP: 192.222.164.54 To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [RFC PATCH] Read pseudo registers from frame instead of regcache Date: Sat, 26 May 2018 01:14:00 -0000 X-ASG-Orig-Subj: [RFC PATCH] Read pseudo registers from frame instead of regcache Message-Id: <20180526002406.18166-1-simon.marchi@polymtl.ca> X-Barracuda-Connect: smtp.electronicbox.net[96.127.255.82] X-Barracuda-Start-Time: 1527294247 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://96.127.255.19:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 48216 X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.50 X-Barracuda-Spam-Status: No, SCORE=0.50 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=8.0 tests=BSF_RULE7568M X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.51266 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.50 BSF_RULE7568M Custom Rule 7568M X-IsSubscribed: yes X-SW-Source: 2018-05/txt/msg00707.txt.bz2 From: Simon Marchi I would like to fix the problem described below. The solution I currently have would require me to change some gdbarch hooks and therefore touch every architecture. It will take quite some time and it's not always trivial, so before doing this, I'd like to gather comments to know if my approach looks right or wrong. NOTE: Don't use you --enable-targets=all build for this, it will only build for x86-64, i386, ARM and AVR. The problem: Reading pseudo registers from an upper stack frame does not work. The raw registers needed to compose the pseudo registers are always read from the current thread's regcache, which is effectively frame #0's registers. Here's an example using the x86-64 test included in this patch (with some output remove for brevity): (gdb) tb break_here_asm (gdb) r (gdb) info registers rbx ebx rbx 0x2021222324252627 2315169217770759719 ebx 0x24252627 606414375 (gdb) up (gdb) info registers rbx ebx rbx 0x1011121314151617 1157726452361532951 ebx 0x24252627 606414375 We would expect the last ebx value to be 0x14151617, half of the rbx value in the same frame. The gdbarch hooks - pseudo_register_read - pseudo_register_read_value - pseudo_register_write receive a regcache as a parameter, as a way to get the values of the raw registers required to compute the pseudo register value. However, the regcache object always contains the current register values, not the values unwound to the frame we're interested in. That's why ebx in frame #1 appears to have the value it has in frame #0. Instead, I think the "read" hooks should take the "next frame" and read the register values it needs from it. In the example above, amd64_pseudo_register_read_value would properly get the value of rbx for frame #1 (which is at that point saved on the stack). Similarly, the write hook would receive a frame and read/write raw registers through that. Another thing I'm wondering about is error handling. In amd64_pseudo_register_read_value, I changed functions that returned a register_status for functions that throw errors when values are unavailable. I'm not sure if we should keep handling unavailable/optimized out values in each arch hook, or let the hooks throw and handle it in the callers. Finally, this change affected the cooked_write_test and cooked_read_test tests. I had to set up a bit more fake global state to get them to pass. This is because reading/writing pseudo registers now involve frames, and in particular the sentinel frame, which was not created before. Comments on any of this are very welcome! --- gdb/amd64-tdep.c | 60 ++--- gdb/arm-tdep.c | 20 +- gdb/avr-tdep.c | 19 +- gdb/frame.c | 83 ++++--- gdb/gdbarch.c | 8 +- gdb/gdbarch.h | 8 +- gdb/gdbarch.sh | 4 +- gdb/i386-tdep.c | 209 ++++++------------ gdb/i386-tdep.h | 4 +- gdb/regcache.c | 45 +++- .../gdb.arch/amd64-pseudo-unwind-asm.S | 43 ++++ gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c | 33 +++ .../gdb.arch/amd64-pseudo-unwind.exp | 81 +++++++ gdb/value.c | 16 +- gdb/value.h | 3 + 15 files changed, 397 insertions(+), 239 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S create mode 100644 gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c create mode 100644 gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index d555465c2f96..12ec8294e4ee 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -349,19 +349,15 @@ amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum) static struct value * amd64_pseudo_register_read_value (struct gdbarch *gdbarch, - readable_regcache *regcache, + frame_info *next_frame, int regnum) { gdb_byte *raw_buf = (gdb_byte *) alloca (register_size (gdbarch, regnum)); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - enum register_status status; - struct value *result_value; - gdb_byte *buf; - - result_value = allocate_value (register_type (gdbarch, regnum)); - VALUE_LVAL (result_value) = lval_register; - VALUE_REGNUM (result_value) = regnum; - buf = value_contents_raw (result_value); + value *result_value + = allocate_register_value (gdbarch, regnum, next_frame); + gdb_byte *buf = value_contents_raw (result_value); + set_value_lazy (result_value, 0); if (i386_byte_regnum_p (gdbarch, regnum)) { @@ -371,37 +367,25 @@ amd64_pseudo_register_read_value (struct gdbarch *gdbarch, if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS) { /* Special handling for AH, BH, CH, DH. */ - status = regcache->raw_read (gpnum - AMD64_NUM_LOWER_BYTE_REGS, - raw_buf); - if (status == REG_VALID) - memcpy (buf, raw_buf + 1, 1); - else - mark_value_bytes_unavailable (result_value, 0, - TYPE_LENGTH (value_type (result_value))); + frame_unwind_register (next_frame, gpnum - AMD64_NUM_LOWER_BYTE_REGS, + raw_buf); + memcpy (buf, raw_buf + 1, 1); } else { - status = regcache->raw_read (gpnum, raw_buf); - if (status == REG_VALID) - memcpy (buf, raw_buf, 1); - else - mark_value_bytes_unavailable (result_value, 0, - TYPE_LENGTH (value_type (result_value))); + frame_unwind_register (next_frame, gpnum, raw_buf); + memcpy (buf, raw_buf, 1); } } else if (i386_dword_regnum_p (gdbarch, regnum)) { int gpnum = regnum - tdep->eax_regnum; /* Extract (always little endian). */ - status = regcache->raw_read (gpnum, raw_buf); - if (status == REG_VALID) - memcpy (buf, raw_buf, 4); - else - mark_value_bytes_unavailable (result_value, 0, - TYPE_LENGTH (value_type (result_value))); + frame_unwind_register (next_frame, gpnum, raw_buf); + memcpy (buf, raw_buf, 4); } else - i386_pseudo_register_read_into_value (gdbarch, regcache, regnum, + i386_pseudo_register_read_into_value (gdbarch, next_frame, regnum, result_value); return result_value; @@ -409,7 +393,7 @@ amd64_pseudo_register_read_value (struct gdbarch *gdbarch, static void amd64_pseudo_register_write (struct gdbarch *gdbarch, - struct regcache *regcache, + frame_info *this_frame, int regnum, const gdb_byte *buf) { gdb_byte *raw_buf = (gdb_byte *) alloca (register_size (gdbarch, regnum)); @@ -422,22 +406,20 @@ amd64_pseudo_register_write (struct gdbarch *gdbarch, if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS) { /* Read ... AH, BH, CH, DH. */ - regcache_raw_read (regcache, - gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf); + get_frame_register (this_frame, gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf); /* ... Modify ... (always little endian). */ memcpy (raw_buf + 1, buf, 1); /* ... Write. */ - regcache_raw_write (regcache, - gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf); + put_frame_register (this_frame, gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf); } else { /* Read ... */ - regcache_raw_read (regcache, gpnum, raw_buf); + get_frame_register (this_frame, gpnum, raw_buf); /* ... Modify ... (always little endian). */ memcpy (raw_buf, buf, 1); /* ... Write. */ - regcache_raw_write (regcache, gpnum, raw_buf); + put_frame_register (this_frame, gpnum, raw_buf); } } else if (i386_dword_regnum_p (gdbarch, regnum)) @@ -445,14 +427,14 @@ amd64_pseudo_register_write (struct gdbarch *gdbarch, int gpnum = regnum - tdep->eax_regnum; /* Read ... */ - regcache_raw_read (regcache, gpnum, raw_buf); + get_frame_register (this_frame, gpnum, raw_buf); /* ... Modify ... (always little endian). */ memcpy (raw_buf, buf, 4); /* ... Write. */ - regcache_raw_write (regcache, gpnum, raw_buf); + put_frame_register (this_frame, gpnum, raw_buf); } else - i386_pseudo_register_write (gdbarch, regcache, regnum, buf); + i386_pseudo_register_write (gdbarch, this_frame, regnum, buf); } /* Implement the 'ax_pseudo_register_collect' gdbarch method. */ diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 382080a714b6..123ab9e2a03d 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -230,7 +230,7 @@ static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch, readable_regcache *regcache, int regnum, gdb_byte *buf); static void arm_neon_quad_write (struct gdbarch *gdbarch, - struct regcache *regcache, + frame_info *this_frame, int regnum, const gdb_byte *buf); static CORE_ADDR @@ -3796,7 +3796,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function, char name_buf[4]; int regnum; if (reg_char == 'q') - arm_neon_quad_write (gdbarch, regcache, reg_scaled + i, + arm_neon_quad_write (gdbarch, get_current_frame (), reg_scaled + i, val + i * unit_length); else { @@ -8198,7 +8198,7 @@ arm_return_value (struct gdbarch *gdbarch, struct value *function, if (reg_char == 'q') { if (writebuf) - arm_neon_quad_write (gdbarch, regcache, i, + arm_neon_quad_write (gdbarch, get_current_frame (), i, writebuf + i * unit_length); if (readbuf) @@ -8749,7 +8749,7 @@ arm_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache, of the quad register, in [0, 15]. */ static void -arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache, +arm_neon_quad_write (struct gdbarch *gdbarch, frame_info *this_frame, int regnum, const gdb_byte *buf) { char name_buf[4]; @@ -8765,13 +8765,13 @@ arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache, else offset = 0; - regcache_raw_write (regcache, double_regnum, buf + offset); + put_frame_register (this_frame, double_regnum, buf + offset); offset = 8 - offset; - regcache_raw_write (regcache, double_regnum + 1, buf + offset); + put_frame_register (this_frame, double_regnum + 1, buf + offset); } static void -arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache, +arm_pseudo_write (struct gdbarch *gdbarch, frame_info *this_frame, int regnum, const gdb_byte *buf) { const int num_regs = gdbarch_num_regs (gdbarch); @@ -8784,7 +8784,7 @@ arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache, if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48) /* Quad-precision register. */ - arm_neon_quad_write (gdbarch, regcache, regnum - 32, buf); + arm_neon_quad_write (gdbarch, this_frame, regnum - 32, buf); else { /* Single-precision register. */ @@ -8800,9 +8800,9 @@ arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache, double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf, strlen (name_buf)); - regcache_raw_read (regcache, double_regnum, reg_buf); + get_frame_register (this_frame, double_regnum, reg_buf); memcpy (reg_buf + offset, buf, 4); - regcache_raw_write (regcache, double_regnum, reg_buf); + put_frame_register (this_frame, double_regnum, reg_buf); } } diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c index 5aa61ba2d9e7..d1addbad72b3 100644 --- a/gdb/avr-tdep.c +++ b/gdb/avr-tdep.c @@ -404,18 +404,23 @@ avr_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, } static void -avr_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, +avr_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame, int regnum, const gdb_byte *buf) { - ULONGEST val; - switch (regnum) { case AVR_PSEUDO_PC_REGNUM: - val = extract_unsigned_integer (buf, 4, gdbarch_byte_order (gdbarch)); - val <<= 1; - regcache_raw_write_unsigned (regcache, AVR_PC_REGNUM, val); - break; + { + bfd_endian endianness = gdbarch_byte_order (gdbarch); + ULONGEST val = extract_unsigned_integer (buf, 4, endianness); + val <<= 1; + + int pc_size = register_size (gdbarch, AVR_PC_REGNUM); + gdb_byte pc_buf[pc_size]; + store_unsigned_integer (pc_buf, pc_size, endianness, val); + put_frame_register (this_frame, AVR_PC_REGNUM, pc_buf); + break; + } default: internal_error (__FILE__, __LINE__, _("invalid regnum")); } diff --git a/gdb/frame.c b/gdb/frame.c index c0f6e64dfc25..0181655b2d60 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1183,29 +1183,48 @@ get_frame_register (struct frame_info *frame, } struct value * -frame_unwind_register_value (struct frame_info *frame, int regnum) +frame_unwind_register_value (struct frame_info *next_frame, int regnum) { - struct gdbarch *gdbarch; - struct value *value; + gdb_assert (next_frame != NULL); - gdb_assert (frame != NULL); - gdbarch = frame_unwind_arch (frame); + struct gdbarch *gdbarch = frame_unwind_arch (next_frame); + + gdb_assert (regnum >= 0); + gdb_assert (regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))); if (frame_debug) { fprintf_unfiltered (gdb_stdlog, "{ frame_unwind_register_value " "(frame=%d,regnum=%d(%s),...) ", - frame->level, regnum, + next_frame->level, regnum, user_reg_map_regnum_to_name (gdbarch, regnum)); } /* Find the unwinder. */ - if (frame->unwind == NULL) - frame_unwind_find_by_frame (frame, &frame->prologue_cache); + if (next_frame->unwind == NULL) + frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache); - /* Ask this frame to unwind its register. */ - value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum); + struct value *value; + if (regnum < gdbarch_num_regs (gdbarch)) + { + /* This is a raw register, we can directly ask the next frame to unwind + the register. */ + value = next_frame->unwind->prev_register (next_frame, + &next_frame->prologue_cache, + regnum); + } + else if (gdbarch_pseudo_register_read_value_p (gdbarch)) + { + /* This is a pseudo register, we don't know how how what raw registers + this pseudo register is made of. Ask the gdbarch to read the value, + it will itself ask the next frame to unwind the values of the raw + registers it needs to compose the value of the pseudo register. */ + value = gdbarch_pseudo_register_read_value (gdbarch, next_frame, regnum); + } + else + error (_("Can't unwind value of register %d (%s)"), regnum, + user_reg_map_regnum_to_name (gdbarch, regnum)); if (frame_debug) { @@ -1353,22 +1372,36 @@ put_frame_register (struct frame_info *frame, int regnum, enum lval_type lval; CORE_ADDR addr; - frame_register (frame, regnum, &optim, &unavail, - &lval, &addr, &realnum, NULL); - if (optim) - error (_("Attempt to assign to a register that was not saved.")); - switch (lval) + gdb_assert (regnum >= 0); + gdb_assert (regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))); + + if (regnum < gdbarch_num_regs (gdbarch)) { - case lval_memory: - { - write_memory (addr, buf, register_size (gdbarch, regnum)); - break; - } - case lval_register: - regcache_cooked_write (get_current_regcache (), realnum, buf); - break; - default: - error (_("Attempt to assign to an unmodifiable value.")); + /* This is a raw register, we can find directly where it is saved + currently and update it. */ + frame_register (frame, regnum, &optim, &unavail, + &lval, &addr, &realnum, NULL); + if (optim) + error (_("Attempt to assign to a register that was not saved.")); + switch (lval) + { + case lval_memory: + { + write_memory (addr, buf, register_size (gdbarch, regnum)); + break; + } + case lval_register: + regcache_cooked_write (get_current_regcache (), realnum, buf); + break; + default: + error (_("Attempt to assign to an unmodifiable value.")); + } + } + else + { + /* This is a pseudo-register, the arch will find out which raw registers + to modify and update them. */ + gdbarch_pseudo_register_write (gdbarch, frame, regnum, buf); } } diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index c430ebe52a4f..a284a4bfc298 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -1979,13 +1979,13 @@ gdbarch_pseudo_register_read_value_p (struct gdbarch *gdbarch) } struct value * -gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum) +gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum) { gdb_assert (gdbarch != NULL); gdb_assert (gdbarch->pseudo_register_read_value != NULL); if (gdbarch_debug >= 2) fprintf_unfiltered (gdb_stdlog, "gdbarch_pseudo_register_read_value called\n"); - return gdbarch->pseudo_register_read_value (gdbarch, regcache, cookednum); + return gdbarch->pseudo_register_read_value (gdbarch, this_frame, cookednum); } void @@ -2003,13 +2003,13 @@ gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch) } void -gdbarch_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const gdb_byte *buf) +gdbarch_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum, const gdb_byte *buf) { gdb_assert (gdbarch != NULL); gdb_assert (gdbarch->pseudo_register_write != NULL); if (gdbarch_debug >= 2) fprintf_unfiltered (gdb_stdlog, "gdbarch_pseudo_register_write called\n"); - gdbarch->pseudo_register_write (gdbarch, regcache, cookednum, buf); + gdbarch->pseudo_register_write (gdbarch, this_frame, cookednum, buf); } void diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 09edcd5eb282..4a315bb8eb24 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -271,14 +271,14 @@ extern void set_gdbarch_pseudo_register_read (struct gdbarch *gdbarch, gdbarch_p extern int gdbarch_pseudo_register_read_value_p (struct gdbarch *gdbarch); -typedef struct value * (gdbarch_pseudo_register_read_value_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum); -extern struct value * gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum); +typedef struct value * (gdbarch_pseudo_register_read_value_ftype) (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum); +extern struct value * gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum); extern void set_gdbarch_pseudo_register_read_value (struct gdbarch *gdbarch, gdbarch_pseudo_register_read_value_ftype *pseudo_register_read_value); extern int gdbarch_pseudo_register_write_p (struct gdbarch *gdbarch); -typedef void (gdbarch_pseudo_register_write_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const gdb_byte *buf); -extern void gdbarch_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int cookednum, const gdb_byte *buf); +typedef void (gdbarch_pseudo_register_write_ftype) (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum, const gdb_byte *buf); +extern void gdbarch_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame, int cookednum, const gdb_byte *buf); extern void set_gdbarch_pseudo_register_write (struct gdbarch *gdbarch, gdbarch_pseudo_register_write_ftype *pseudo_register_write); extern int gdbarch_num_regs (struct gdbarch *gdbarch); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 733043093742..5a1b53ee9d1b 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -431,8 +431,8 @@ M;enum register_status;pseudo_register_read;readable_regcache *regcache, int coo # or partly unavailable, this should call mark_value_bytes_unavailable # as appropriate. If this is defined, then pseudo_register_read will # never be called. -M;struct value *;pseudo_register_read_value;readable_regcache *regcache, int cookednum;regcache, cookednum -M;void;pseudo_register_write;struct regcache *regcache, int cookednum, const gdb_byte *buf;regcache, cookednum, buf +M;struct value *;pseudo_register_read_value;frame_info *next_frame, int cookednum;next_frame, cookednum +M;void;pseudo_register_write;frame_info *this_frame, int cookednum, const gdb_byte *buf;this_frame, cookednum, buf # v;int;num_regs;;;0;-1 # This macro gives the number of pseudo-registers that live in the diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 646f305edc51..73a87a613f7d 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -3249,17 +3249,14 @@ i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum) the MMX registers need to be mapped onto floating point registers. */ static int -i386_mmx_regnum_to_fp_regnum (readable_regcache *regcache, int regnum) +i386_mmx_regnum_to_fp_regnum (frame_info *next_frame, int regnum) { - struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); - int mmxreg, fpreg; - ULONGEST fstat; - int tos; - - mmxreg = regnum - tdep->mm0_regnum; - regcache->raw_read (I387_FSTAT_REGNUM (tdep), &fstat); - tos = (fstat >> 11) & 0x7; - fpreg = (mmxreg + tos) % 8; + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame)); + int mmxreg = regnum - tdep->mm0_regnum; + ULONGEST fstat + = frame_unwind_register_unsigned (next_frame, I387_FSTAT_REGNUM (tdep)); + int tos = (fstat >> 11) & 0x7; + int fpreg = (mmxreg + tos) % 8; return (I387_ST0_REGNUM (tdep) + fpreg); } @@ -3270,25 +3267,20 @@ i386_mmx_regnum_to_fp_regnum (readable_regcache *regcache, int regnum) void i386_pseudo_register_read_into_value (struct gdbarch *gdbarch, - readable_regcache *regcache, + frame_info *next_frame, int regnum, struct value *result_value) { gdb_byte raw_buf[I386_MAX_REGISTER_SIZE]; - enum register_status status; gdb_byte *buf = value_contents_raw (result_value); if (i386_mmx_regnum_p (gdbarch, regnum)) { - int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum); + int fpnum = i386_mmx_regnum_to_fp_regnum (next_frame, regnum); /* Extract (always little endian). */ - status = regcache->raw_read (fpnum, raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, - TYPE_LENGTH (value_type (result_value))); - else - memcpy (buf, raw_buf, register_size (gdbarch, regnum)); + frame_unwind_register (next_frame, fpnum, raw_buf); + memcpy (buf, raw_buf, register_size (gdbarch, regnum)); } else { @@ -3298,34 +3290,26 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch, regnum -= tdep->bnd0_regnum; /* Extract (always little endian). Read lower 128bits. */ - status = regcache->raw_read (I387_BND0R_REGNUM (tdep) + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, 16); - else - { - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); - LONGEST upper, lower; - int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr); + frame_unwind_register (next_frame, I387_BND0R_REGNUM (tdep) + regnum, raw_buf); - lower = extract_unsigned_integer (raw_buf, 8, byte_order); - upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order); - upper = ~upper; + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); + LONGEST upper, lower; + int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr); - memcpy (buf, &lower, size); - memcpy (buf + size, &upper, size); - } + lower = extract_unsigned_integer (raw_buf, 8, byte_order); + upper = extract_unsigned_integer (raw_buf + 8, 8, byte_order); + upper = ~upper; + + memcpy (buf, &lower, size); + memcpy (buf + size, &upper, size); } else if (i386_k_regnum_p (gdbarch, regnum)) { regnum -= tdep->k0_regnum; /* Extract (always little endian). */ - status = regcache->raw_read (tdep->k0_regnum + regnum, raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, 8); - else - memcpy (buf, raw_buf, 8); + frame_unwind_register (next_frame, tdep->k0_regnum + regnum, raw_buf); + memcpy (buf, raw_buf, 8); } else if (i386_zmm_regnum_p (gdbarch, regnum)) { @@ -3334,98 +3318,57 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch, if (regnum < num_lower_zmm_regs) { /* Extract (always little endian). Read lower 128bits. */ - status = regcache->raw_read (I387_XMM0_REGNUM (tdep) + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, 16); - else - memcpy (buf, raw_buf, 16); + frame_unwind_register (next_frame, I387_XMM0_REGNUM (tdep) + regnum, raw_buf); + memcpy (buf, raw_buf, 16); /* Extract (always little endian). Read upper 128bits. */ - status = regcache->raw_read (tdep->ymm0h_regnum + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 16, 16); - else - memcpy (buf + 16, raw_buf, 16); + frame_unwind_register (next_frame, tdep->ymm0h_regnum + regnum, raw_buf); + memcpy (buf + 16, raw_buf, 16); } else { /* Extract (always little endian). Read lower 128bits. */ - status = regcache->raw_read (I387_XMM16_REGNUM (tdep) + regnum - - num_lower_zmm_regs, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, 16); - else - memcpy (buf, raw_buf, 16); + frame_unwind_register (next_frame, I387_XMM16_REGNUM (tdep) + regnum, raw_buf); + memcpy (buf, raw_buf, 16); /* Extract (always little endian). Read upper 128bits. */ - status = regcache->raw_read (I387_YMM16H_REGNUM (tdep) + regnum - - num_lower_zmm_regs, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 16, 16); - else - memcpy (buf + 16, raw_buf, 16); + frame_unwind_register (next_frame, I387_YMM16H_REGNUM (tdep) + regnum, raw_buf); + memcpy (buf + 16, raw_buf, 16); } /* Read upper 256bits. */ - status = regcache->raw_read (tdep->zmm0h_regnum + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 32, 32); - else - memcpy (buf + 32, raw_buf, 32); + frame_unwind_register (next_frame, tdep->zmm0h_regnum + regnum, raw_buf); + memcpy (buf + 32, raw_buf, 32); } else if (i386_ymm_regnum_p (gdbarch, regnum)) { regnum -= tdep->ymm0_regnum; /* Extract (always little endian). Read lower 128bits. */ - status = regcache->raw_read (I387_XMM0_REGNUM (tdep) + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, 16); - else - memcpy (buf, raw_buf, 16); + frame_unwind_register (next_frame, I387_XMM0_REGNUM (tdep) + regnum, raw_buf); + memcpy (buf, raw_buf, 16); + /* Read upper 128bits. */ - status = regcache->raw_read (tdep->ymm0h_regnum + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 16, 32); - else - memcpy (buf + 16, raw_buf, 16); + frame_unwind_register (next_frame, tdep->ymm0h_regnum + regnum, raw_buf); + memcpy (buf + 16, raw_buf, 16); } else if (i386_ymm_avx512_regnum_p (gdbarch, regnum)) { regnum -= tdep->ymm16_regnum; /* Extract (always little endian). Read lower 128bits. */ - status = regcache->raw_read (I387_XMM16_REGNUM (tdep) + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, 16); - else - memcpy (buf, raw_buf, 16); + frame_unwind_register (next_frame, I387_XMM16_REGNUM (tdep) + regnum, raw_buf); + memcpy (buf, raw_buf, 16); /* Read upper 128bits. */ - status = regcache->raw_read (tdep->ymm16h_regnum + regnum, - raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 16, 16); - else - memcpy (buf + 16, raw_buf, 16); + frame_unwind_register (next_frame, tdep->ymm16h_regnum + regnum, raw_buf); + memcpy (buf + 16, raw_buf, 16); } else if (i386_word_regnum_p (gdbarch, regnum)) { int gpnum = regnum - tdep->ax_regnum; /* Extract (always little endian). */ - status = regcache->raw_read (gpnum, raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, - TYPE_LENGTH (value_type (result_value))); - else - memcpy (buf, raw_buf, 2); + frame_unwind_register (next_frame, gpnum, raw_buf); + memcpy (buf, raw_buf, 2); } else if (i386_byte_regnum_p (gdbarch, regnum)) { @@ -3433,11 +3376,8 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch, /* Extract (always little endian). We read both lower and upper registers. */ - status = regcache->raw_read (gpnum % 4, raw_buf); - if (status != REG_VALID) - mark_value_bytes_unavailable (result_value, 0, - TYPE_LENGTH (value_type (result_value))); - else if (gpnum >= 4) + frame_unwind_register (next_frame, gpnum % 4, raw_buf); + if (gpnum >= 4) memcpy (buf, raw_buf + 1, 1); else memcpy (buf, raw_buf, 1); @@ -3449,36 +3389,34 @@ i386_pseudo_register_read_into_value (struct gdbarch *gdbarch, static struct value * i386_pseudo_register_read_value (struct gdbarch *gdbarch, - readable_regcache *regcache, + frame_info *next_frame, int regnum) { - struct value *result; - - result = allocate_value (register_type (gdbarch, regnum)); - VALUE_LVAL (result) = lval_register; - VALUE_REGNUM (result) = regnum; + struct value *result = allocate_register_value (gdbarch, regnum, next_frame); + set_value_lazy (result, 0); - i386_pseudo_register_read_into_value (gdbarch, regcache, regnum, result); + i386_pseudo_register_read_into_value (gdbarch, next_frame, regnum, result); return result; } void -i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, +i386_pseudo_register_write (struct gdbarch *gdbarch, frame_info *this_frame, int regnum, const gdb_byte *buf) { gdb_byte raw_buf[I386_MAX_REGISTER_SIZE]; if (i386_mmx_regnum_p (gdbarch, regnum)) { - int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum); + frame_info *next_frame = get_next_frame_sentinel_okay (this_frame); + int fpnum = i386_mmx_regnum_to_fp_regnum (next_frame, regnum); /* Read ... */ - regcache_raw_read (regcache, fpnum, raw_buf); + get_frame_register (this_frame, fpnum, raw_buf); /* ... Modify ... (always little endian). */ memcpy (raw_buf, buf, register_size (gdbarch, regnum)); /* ... Write. */ - regcache_raw_write (regcache, fpnum, raw_buf); + put_frame_register (this_frame, fpnum, raw_buf); } else { @@ -3496,9 +3434,9 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, upper = extract_unsigned_integer (buf + size, size, byte_order); /* Fetching register buffer. */ - regcache_raw_read (regcache, - I387_BND0R_REGNUM (tdep) + regnum, - raw_buf); + get_frame_register (this_frame, + I387_BND0R_REGNUM (tdep) + regnum, + raw_buf); upper = ~upper; @@ -3506,8 +3444,7 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, memcpy (raw_buf, &lower, 8); memcpy (raw_buf + 8, &upper, 8); - - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_BND0R_REGNUM (tdep) + regnum, raw_buf); } @@ -3515,7 +3452,7 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, { regnum -= tdep->k0_regnum; - regcache_raw_write (regcache, + put_frame_register (this_frame, tdep->k0_regnum + regnum, buf); } @@ -3526,29 +3463,29 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, if (regnum < num_lower_zmm_regs) { /* Write lower 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_XMM0_REGNUM (tdep) + regnum, buf); /* Write upper 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_YMM0_REGNUM (tdep) + regnum, buf + 16); } else { /* Write lower 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_XMM16_REGNUM (tdep) + regnum - num_lower_zmm_regs, buf); /* Write upper 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_YMM16H_REGNUM (tdep) + regnum - num_lower_zmm_regs, buf + 16); } /* Write upper 256bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, tdep->zmm0h_regnum + regnum, buf + 32); } @@ -3557,11 +3494,11 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, regnum -= tdep->ymm0_regnum; /* ... Write lower 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_XMM0_REGNUM (tdep) + regnum, buf); /* ... Write upper 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, tdep->ymm0h_regnum + regnum, buf + 16); } @@ -3570,11 +3507,11 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, regnum -= tdep->ymm16_regnum; /* ... Write lower 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, I387_XMM16_REGNUM (tdep) + regnum, buf); /* ... Write upper 128bits. */ - regcache_raw_write (regcache, + put_frame_register (this_frame, tdep->ymm16h_regnum + regnum, buf + 16); } @@ -3583,25 +3520,25 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int gpnum = regnum - tdep->ax_regnum; /* Read ... */ - regcache_raw_read (regcache, gpnum, raw_buf); + get_frame_register (this_frame, gpnum, raw_buf); /* ... Modify ... (always little endian). */ memcpy (raw_buf, buf, 2); /* ... Write. */ - regcache_raw_write (regcache, gpnum, raw_buf); + put_frame_register (this_frame, gpnum, raw_buf); } else if (i386_byte_regnum_p (gdbarch, regnum)) { int gpnum = regnum - tdep->al_regnum; /* Read ... We read both lower and upper registers. */ - regcache_raw_read (regcache, gpnum % 4, raw_buf); + get_frame_register (this_frame, gpnum % 4, raw_buf); /* ... Modify ... (always little endian). */ if (gpnum >= 4) memcpy (raw_buf + 1, buf, 1); else memcpy (raw_buf, buf, 1); /* ... Write. */ - regcache_raw_write (regcache, gpnum % 4, raw_buf); + put_frame_register (this_frame, gpnum % 4, raw_buf); } else internal_error (__FILE__, __LINE__, _("invalid regnum")); diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h index 81a93f11af5a..238bb1f533cd 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -364,12 +364,12 @@ extern struct type *i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum); extern void i386_pseudo_register_read_into_value (struct gdbarch *gdbarch, - readable_regcache *regcache, + frame_info *next_frame, int regnum, struct value *result); extern void i386_pseudo_register_write (struct gdbarch *gdbarch, - struct regcache *regcache, + frame_info *this_frame, int regnum, const gdb_byte *buf); extern int i386_ax_pseudo_register_collect (struct gdbarch *gdbarch, diff --git a/gdb/regcache.c b/gdb/regcache.c index 83bcbd22a374..c6c6330bcec6 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -663,7 +663,7 @@ readable_regcache::cooked_read (int regnum, gdb_byte *buf) mark = value_mark (); computed = gdbarch_pseudo_register_read_value (m_descr->gdbarch, - this, regnum); + frame_find_by_id (sentinel_frame_id), regnum); if (value_entirely_available (computed)) memcpy (buf, value_contents_raw (computed), m_descr->sizeof_register[regnum]); @@ -716,7 +716,7 @@ readable_regcache::cooked_read_value (int regnum) } else return gdbarch_pseudo_register_read_value (m_descr->gdbarch, - this, regnum); + frame_find_by_id (sentinel_frame_id), regnum); } enum register_status @@ -838,7 +838,7 @@ regcache::cooked_write (int regnum, const gdb_byte *buf) if (regnum < num_raw_registers ()) raw_write (regnum, buf); else - gdbarch_pseudo_register_write (m_descr->gdbarch, this, + gdbarch_pseudo_register_write (m_descr->gdbarch, get_current_frame (), regnum, buf); } @@ -1598,6 +1598,8 @@ cooked_read_test (struct gdbarch *gdbarch) scoped_restore restore_inferior_ptid = make_scoped_restore (&inferior_ptid, mock_ptid); + frame_info *f = get_current_frame (); + /* Test that read one raw register from regcache_no_target will go to the target layer. */ int regnum; @@ -1609,7 +1611,9 @@ cooked_read_test (struct gdbarch *gdbarch) break; } - readwrite_regcache readwrite (gdbarch); + //readwrite_regcache readwrite (gdbarch); + regcache *r = get_thread_regcache (mock_ptid); + regcache &readwrite = *r; gdb::def_vector buf (register_size (gdbarch, regnum)); readwrite.raw_read (regnum, buf.data ()); @@ -1731,12 +1735,29 @@ cooked_write_test (struct gdbarch *gdbarch) if (target_stack->to_stratum >= process_stratum) error (_("target already pushed")); - /* Create a mock environment. A process_stratum target pushed. */ - target_ops_no_register mock_target; + ptid_t mock_ptid (1, 1); + inferior mock_inferior (mock_ptid.pid ()); + address_space mock_aspace + { }; + mock_inferior.gdbarch = gdbarch; + mock_inferior.aspace = &mock_aspace; + thread_info mock_thread (&mock_inferior, mock_ptid); + + scoped_restore restore_thread_list = make_scoped_restore (&thread_list, + &mock_thread); + + /* Add the mock inferior to the inferior list so that look ups by + target+ptid can find it. */ + scoped_restore restore_inferior_list = make_scoped_restore (&inferior_list); + inferior_list = &mock_inferior; + + /* Switch to the mock inferior. */ + scoped_restore_current_inferior restore_current_inferior; + set_current_inferior (&mock_inferior); /* Push the process_stratum target so we can mock accessing - registers. */ + registers. */ push_target (&mock_target); /* Pop it again on exit (return/exception). */ @@ -1748,7 +1769,15 @@ cooked_write_test (struct gdbarch *gdbarch) } } pop_targets; - readwrite_regcache readwrite (gdbarch); + /* Switch to the mock thread. */ + scoped_restore restore_inferior_ptid = make_scoped_restore (&inferior_ptid, + mock_ptid); + + frame_info *f = get_current_frame (); + + + regcache *r = get_thread_regcache (mock_ptid); + regcache &readwrite = *r; const int num_regs = (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch)); diff --git a/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S new file mode 100644 index 000000000000..390de7c32692 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S @@ -0,0 +1,43 @@ +.global callee +callee: +.cfi_startproc + push %rbp +.cfi_def_cfa rbp, 16 + mov %rsp, %rbp + + # Save caller's rbx value on the stack. +.cfi_offset rbx, -24 + push %rbx + + # Put our own rbx value. + mov $0x2021222324252627, %rbx +break_here_asm: + + pop %rbx + pop %rbp + ret +.cfi_endproc + + +.global caller +caller: +.cfi_startproc + push %rbp +.cfi_def_cfa_offset 16 + mov %rsp, %rbp + + # Save caller's rbx value on the stack. +.cfi_offset rbx, -24 + push %rbx + + # Put our own rbx value. + mov $0x1011121314151617, %rbx + call callee + + # Return the value we put in rbx. + mov %rbx, %rax + + pop %rbx + pop %rbp + ret +.cfi_endproc diff --git a/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c new file mode 100644 index 000000000000..c4553f844e9f --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.c @@ -0,0 +1,33 @@ +/* Copyright 2018 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +uint64_t caller (void); + +static void +break_here_c (uint64_t value) +{ +} + +int +main (void) +{ + uint64_t value = caller (); + break_here_c (value); + return 0; +} diff --git a/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp new file mode 100644 index 000000000000..619f44405e82 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-pseudo-unwind.exp @@ -0,0 +1,81 @@ +# Copyright 2018 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64 pseudo register unwind." + return +} + +standard_testfile amd64-pseudo-unwind.c amd64-pseudo-unwind-asm.S + +if { [prepare_for_testing "failed to prepare" ${testfile} "${srcfile} ${srcfile2}" {debug}] } { + return -1 +} + +clean_restart ${binfile} + +if ![runto_main] then { + fail "could not run to main" +} + +gdb_breakpoint break_here_asm temporary +gdb_continue_to_breakpoint "continue to callee" + +# Verify the value of rbx/ebx in the inner frame (callee) +with_test_prefix "callee, before change" { + gdb_test "p/x \$rbx" " = 0x2021222324252627" + gdb_test "p/x \$ebx" " = 0x24252627" +} + +# Verify that we can change the value of the pseudo register (ebx) in the inner frame (callee) +gdb_test_no_output "set \$ebx = 0x34353637" + +with_test_prefix "callee, after change" { + # Verify the value of rbx/ebx in the inner frame (callee) after the change + gdb_test "p/x \$rbx" " = 0x2021222334353637" + gdb_test "p/x \$ebx" " = 0x34353637" +} + +# Go up one frame, and do the same +gdb_test "up" + +# Verify the value of rbx/ebx in the outer frame (caller) +with_test_prefix "caller, before change" { + gdb_test "p/x \$rbx" " = 0x1011121314151617" + gdb_test "p/x \$ebx" " = 0x14151617" +} + +# Verify that we can change the value of the pseudo register (ebx) in the outer frame (caller) +gdb_test_no_output "set \$ebx = 0x44454647" + +# Verify the value of rbx/ebx in the outer frame (caller) after the change +with_test_prefix "caller, after change" { + gdb_test "p/x \$rbx" " = 0x1011121344454647" + gdb_test "p/x \$ebx" " = 0x44454647" +} + +# Go back to frame 0, check that the change to the outer frame didn't mess up anything there. +gdb_test "down" + +with_test_prefix "callee, after change in caller" { + gdb_test "p/x \$rbx" " = 0x2021222334353637" + gdb_test "p/x \$ebx" " = 0x34353637" +} + +# Verify that the value of the saved rbx we changed is correctly seen by the inferior. +gdb_breakpoint break_here_c temporary +gdb_continue_to_breakpoint "continue to break_here_c" + +gdb_test "p/x value" " = 0x1011121344454647" diff --git a/gdb/value.c b/gdb/value.c index 89ccac7cfc6e..6ea7c200af41 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1049,6 +1049,19 @@ allocate_repeat_value (struct type *type, int count) return allocate_value (array_type); } +struct value * +allocate_register_value (struct gdbarch *gdbarch, int regnum, frame_info *next_frame) +{ + struct type *type = register_type (gdbarch, regnum); + value *v = allocate_value_lazy (type); + + VALUE_LVAL (v) = lval_register; + v->location.reg.regnum = regnum; + v->location.reg.next_frame_id = get_frame_id (next_frame); + + return v; +} + struct value * allocate_computed_value (struct type *type, const struct lval_funcs *funcs, @@ -3758,7 +3771,6 @@ value_fetch_lazy_memory (struct value *val) static void value_fetch_lazy_register (struct value *val) { - struct frame_info *next_frame; int regnum; struct type *type = check_typedef (value_type (val)); struct value *new_val = val, *mark = value_mark (); @@ -3771,7 +3783,7 @@ value_fetch_lazy_register (struct value *val) { struct frame_id next_frame_id = VALUE_NEXT_FRAME_ID (new_val); - next_frame = frame_find_by_id (next_frame_id); + frame_info *next_frame = frame_find_by_id (next_frame_id); regnum = VALUE_REGNUM (new_val); gdb_assert (next_frame != NULL); diff --git a/gdb/value.h b/gdb/value.h index 4d75c966edd6..2335edb0f5eb 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -238,6 +238,9 @@ extern void set_value_pointed_to_offset (struct value *value, LONGEST val); extern LONGEST value_embedded_offset (const struct value *value); extern void set_value_embedded_offset (struct value *value, LONGEST val); +extern struct value *allocate_register_value (struct gdbarch *gdbarch, + int regnum, frame_info *frame); + /* For lval_computed values, this structure holds functions used to retrieve and set the value (or portions of the value). -- 2.17.0