From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id MqEnOxdGyl9NNAAAWB0awg (envelope-from ) for ; Fri, 04 Dec 2020 09:22:15 -0500 Received: by simark.ca (Postfix, from userid 112) id E39DA1F0AB; Fri, 4 Dec 2020 09:22:15 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id DE8891E58D for ; Fri, 4 Dec 2020 09:22:13 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 61CE6386EC25; Fri, 4 Dec 2020 14:22:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 61CE6386EC25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1607091733; bh=ejDC9MP7K0Ayfv64ezU5awFe+HSjqaCv1BAG/sEevt4=; h=Subject:To:References:Date:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=q0vdcCCUyn7SFg9mvan/TWFBOBx/yVWsWBgV47sJ4uR+P1w8pJ9sRqtfIb0eSb3r+ +/WOnO0bgi7efX7q6ibSNEJhISVz7UxGqXpFG2GFEfdScAH9iIphysoOOEqWlVK4xf E6OUL2+BOdRvb2CMIvKvuyT7WwTSdwFrQxezz2Do= Received: from mail-qt1-x834.google.com (mail-qt1-x834.google.com [IPv6:2607:f8b0:4864:20::834]) by sourceware.org (Postfix) with ESMTPS id BFE943850418 for ; Fri, 4 Dec 2020 14:22:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org BFE943850418 Received: by mail-qt1-x834.google.com with SMTP id o1so3979649qtp.5 for ; Fri, 04 Dec 2020 06:22:09 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:references:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=ejDC9MP7K0Ayfv64ezU5awFe+HSjqaCv1BAG/sEevt4=; b=RViWBWnL+4ah9n/oKUqLu1UhQQbu/y7J2gtGZ7O9ujA90Ki4OSq/JJ6cuq5/hxV3hA +QUD8wrqdabibJcicUghFFWQ1oFV9nQ5RFwPt7h7WlmAosbrcLGuZBwh1iiCzwwXGkqU 6EPQcPDNvw4vbTpl/qpYPQBdwy0G8LpiWgiTk4CulJ7v/myEWkdFnPxSXm8vs/bO6Jl1 OXiXktlj2NzrIKWgnJY01lphxXlMtmK3AdCkiwKXW0ashZowCCzESnPS/kHbrrGQIj3e eXct8uhWxV2TX7z7cTxULCFcxOB4ERjB592z2GBbBviLkgqafTtGnMYMxOSaCUNGqlj5 wx9w== X-Gm-Message-State: AOAM533U5GjgfiXyF6LEHHNNtvVPiUh5FiyDdXrJ6nM/CidxXYHV7WI9 j07PQyW0N9lKXoN+H4y31ZRH/xH/f3WwHg== X-Google-Smtp-Source: ABdhPJw2lVDgbxPe6PhthojQz2Oev16cK4WoWw+fskpeHwmkd1Apyf+q07cQ8vBb63HG81kPiXjMcg== X-Received: by 2002:ac8:c02:: with SMTP id k2mr2684153qti.210.1607091729032; Fri, 04 Dec 2020 06:22:09 -0800 (PST) Received: from ?IPv6:2804:7f0:8284:370e:e82c:e47f:d499:edff? ([2804:7f0:8284:370e:e82c:e47f:d499:edff]) by smtp.gmail.com with ESMTPSA id i7sm4720109qkl.94.2020.12.04.06.22.07 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 04 Dec 2020 06:22:08 -0800 (PST) Subject: Re: [PATCH,v2] SVE/FPSIMD fixup for big endian To: gdb-patches@sourceware.org References: <20201130185545.940242-1-luis.machado@linaro.org> <20201202175718.1034781-1-luis.machado@linaro.org> Message-ID: <33b1cca4-0f45-3999-36d3-d68e169e7acc@linaro.org> Date: Fri, 4 Dec 2020 11:22:05 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <20201202175718.1034781-1-luis.machado@linaro.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Luis Machado via Gdb-patches Reply-To: Luis Machado Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" With the AArch64-specific parts approved, do the global maintainers have any comments on the trad-frame changes, or does it look good? On 12/2/20 2:57 PM, Luis Machado wrote: > Updates on v2: > > - Reworked ptrace functions and made byteswap function more like a memcpy. > - Adjusted memset calls to zero register buffers. > - Adjusted comments. > - Moved V_REGISTER_SIZE constant definition. > > The FPSIMD dump in signal frames and ptrace FPSIMD dump in the SVE context > structure follows the target endianness, whereas the SVE dumps are > endianness-independent (LE). > > Therefore, when the system is in BE mode, we need to reverse the bytes > for the FPSIMD data. > > Given the V registers are larger than 64-bit, I've added a way for value > bytes to be set, as opposed to passing a 64-bit fixed quantity. This fits > nicely with the unwinding *_got_bytes function and makes the trad-frame > more flexible and capable of saving larger registers. > > The memory for the bytes is allocated via the frame obstack, so it gets freed > after we're done inspecting the frame. > > gdb/ChangeLog: > > YYYY-MM-DD Luis Machado > > * aarch64-linux-tdep.c (aarch64_linux_restore_vreg) New function. > (aarch64_linux_sigframe_init): Call aarch64_linux_restore_vreg. > * aarch64-tdep.h (V_REGISTER_SIZE): Move to ... > * arch/aarch64.h: ... here. > * nat/aarch64-sve-linux-ptrace.c: Include endian.h. > (aarch64_maybe_swab128): New function. > (aarch64_sve_regs_copy_to_reg_buf) > (aarch64_sve_regs_copy_from_reg_buf): Adjust FPSIMD entries. > * trad-frame.c (trad_frame_reset_saved_regs): Initialize > the data field. > (TF_REG_VALUE_BYTES): New enum value. > (trad_frame_value_bytes_p): New function. > (trad_frame_set_value_bytes): New function. > (trad_frame_set_reg_value_bytes): New function. > (trad_frame_get_prev_register): Handle register values saved as bytes. > * trad-frame.h (trad_frame_set_reg_value_bytes): New prototype. > (struct trad_frame_saved_reg) : New field. > (trad_frame_set_value_bytes): New prototype. > (trad_frame_value_bytes_p): New prototype. > --- > gdb/aarch64-linux-tdep.c | 114 ++++++++++++++++++++++++----- > gdb/aarch64-tdep.h | 1 - > gdb/arch/aarch64.h | 2 + > gdb/nat/aarch64-sve-linux-ptrace.c | 77 +++++++++++++++---- > gdb/trad-frame.c | 46 +++++++++++- > gdb/trad-frame.h | 19 +++++ > 6 files changed, 224 insertions(+), 35 deletions(-) > > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c > index c9898bdafd..9429af0fe1 100644 > --- a/gdb/aarch64-linux-tdep.c > +++ b/gdb/aarch64-linux-tdep.c > @@ -180,6 +180,93 @@ read_aarch64_ctx (CORE_ADDR ctx_addr, enum bfd_endian byte_order, > return magic; > } > > +/* Given CACHE, use the trad_frame* functions to restore the FPSIMD > + registers from a signal frame. > + > + VREG_NUM is the number of the V register being restored, OFFSET is the > + address containing the register value, BYTE_ORDER is the endianness and > + HAS_SVE tells us if we have a valid SVE context or not. */ > + > +static void > +aarch64_linux_restore_vreg (struct trad_frame_cache *cache, int num_regs, > + int vreg_num, CORE_ADDR offset, > + enum bfd_endian byte_order, bool has_sve) > +{ > + /* WARNING: SIMD state is laid out in memory in target-endian format. > + > + So we have a couple cases to consider: > + > + 1 - If the target is big endian, then SIMD state is big endian, > + requiring a byteswap. > + > + 2 - If the target is little endian, then SIMD state is little endian, so > + no byteswap is needed. */ > + > + if (byte_order == BFD_ENDIAN_BIG) > + { > + gdb_byte buf[V_REGISTER_SIZE]; > + > + if (target_read_memory (offset, buf, V_REGISTER_SIZE) != 0) > + { > + size_t size = V_REGISTER_SIZE/2; > + > + /* Read the two halves of the V register in reverse byte order. */ > + CORE_ADDR u64 = extract_unsigned_integer (buf, size, > + byte_order); > + CORE_ADDR l64 = extract_unsigned_integer (buf + size, size, > + byte_order); > + > + /* Copy the reversed bytes to the buffer. */ > + store_unsigned_integer (buf, size, BFD_ENDIAN_LITTLE, l64); > + store_unsigned_integer (buf + size , size, BFD_ENDIAN_LITTLE, u64); > + > + /* Now we can store the correct bytes for the V register. */ > + trad_frame_set_reg_value_bytes (cache, AARCH64_V0_REGNUM + vreg_num, > + buf, V_REGISTER_SIZE); > + trad_frame_set_reg_value_bytes (cache, > + num_regs + AARCH64_Q0_REGNUM > + + vreg_num, buf, Q_REGISTER_SIZE); > + trad_frame_set_reg_value_bytes (cache, > + num_regs + AARCH64_D0_REGNUM > + + vreg_num, buf, D_REGISTER_SIZE); > + trad_frame_set_reg_value_bytes (cache, > + num_regs + AARCH64_S0_REGNUM > + + vreg_num, buf, S_REGISTER_SIZE); > + trad_frame_set_reg_value_bytes (cache, > + num_regs + AARCH64_H0_REGNUM > + + vreg_num, buf, H_REGISTER_SIZE); > + trad_frame_set_reg_value_bytes (cache, > + num_regs + AARCH64_B0_REGNUM > + + vreg_num, buf, B_REGISTER_SIZE); > + > + if (has_sve) > + trad_frame_set_reg_value_bytes (cache, > + num_regs + AARCH64_SVE_V0_REGNUM > + + vreg_num, buf, V_REGISTER_SIZE); > + } > + return; > + } > + > + /* Little endian, just point at the address containing the register > + value. */ > + trad_frame_set_reg_addr (cache, AARCH64_V0_REGNUM + vreg_num, offset); > + trad_frame_set_reg_addr (cache, num_regs + AARCH64_Q0_REGNUM + vreg_num, > + offset); > + trad_frame_set_reg_addr (cache, num_regs + AARCH64_D0_REGNUM + vreg_num, > + offset); > + trad_frame_set_reg_addr (cache, num_regs + AARCH64_S0_REGNUM + vreg_num, > + offset); > + trad_frame_set_reg_addr (cache, num_regs + AARCH64_H0_REGNUM + vreg_num, > + offset); > + trad_frame_set_reg_addr (cache, num_regs + AARCH64_B0_REGNUM + vreg_num, > + offset); > + > + if (has_sve) > + trad_frame_set_reg_addr (cache, num_regs + AARCH64_SVE_V0_REGNUM > + + vreg_num, offset); > + > +} > + > /* Implement the "init" method of struct tramp_frame. */ > > static void > @@ -332,27 +419,16 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, > > /* If there was no SVE section then set up the V registers. */ > if (sve_regs == 0) > - for (int i = 0; i < 32; i++) > - { > - CORE_ADDR offset = (fpsimd + AARCH64_FPSIMD_V0_OFFSET > + { > + for (int i = 0; i < 32; i++) > + { > + CORE_ADDR offset = (fpsimd + AARCH64_FPSIMD_V0_OFFSET > + (i * AARCH64_FPSIMD_VREG_SIZE)); > > - trad_frame_set_reg_addr (this_cache, AARCH64_V0_REGNUM + i, offset); > - trad_frame_set_reg_addr (this_cache, > - num_regs + AARCH64_Q0_REGNUM + i, offset); > - trad_frame_set_reg_addr (this_cache, > - num_regs + AARCH64_D0_REGNUM + i, offset); > - trad_frame_set_reg_addr (this_cache, > - num_regs + AARCH64_S0_REGNUM + i, offset); > - trad_frame_set_reg_addr (this_cache, > - num_regs + AARCH64_H0_REGNUM + i, offset); > - trad_frame_set_reg_addr (this_cache, > - num_regs + AARCH64_B0_REGNUM + i, offset); > - if (tdep->has_sve ()) > - trad_frame_set_reg_addr (this_cache, > - num_regs + AARCH64_SVE_V0_REGNUM + i, > - offset); > - } > + aarch64_linux_restore_vreg (this_cache, num_regs, i, offset, > + byte_order, tdep->has_sve ()); > + } > + } > } > > trad_frame_set_id (this_cache, frame_id_build (sp, func)); > diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h > index 81ce4d84b4..ba72a771cd 100644 > --- a/gdb/aarch64-tdep.h > +++ b/gdb/aarch64-tdep.h > @@ -47,7 +47,6 @@ struct regset; > #define H_REGISTER_SIZE 2 > #define S_REGISTER_SIZE 4 > #define D_REGISTER_SIZE 8 > -#define V_REGISTER_SIZE 16 > #define Q_REGISTER_SIZE 16 > > /* Total number of general (X) registers. */ > diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h > index 857bb22b03..b75352461a 100644 > --- a/gdb/arch/aarch64.h > +++ b/gdb/arch/aarch64.h > @@ -58,6 +58,8 @@ enum aarch64_regnum > AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7 > }; > > +#define V_REGISTER_SIZE 16 > + > /* Pseudo register base numbers. */ > #define AARCH64_Q0_REGNUM 0 > #define AARCH64_D0_REGNUM (AARCH64_Q0_REGNUM + AARCH64_D_REGISTER_COUNT) > diff --git a/gdb/nat/aarch64-sve-linux-ptrace.c b/gdb/nat/aarch64-sve-linux-ptrace.c > index 2ce90ccfd7..5f08995f87 100644 > --- a/gdb/nat/aarch64-sve-linux-ptrace.c > +++ b/gdb/nat/aarch64-sve-linux-ptrace.c > @@ -26,6 +26,7 @@ > #include "arch/aarch64.h" > #include "gdbsupport/common-regcache.h" > #include "gdbsupport/byte-vector.h" > +#include > > /* See nat/aarch64-sve-linux-ptrace.h. */ > > @@ -142,6 +143,24 @@ aarch64_sve_get_sveregs (int tid) > return buf; > } > > +/* If we are running in BE mode, byteswap the contents > + of SRC to DST for SIZE bytes. Other, just copy the contents > + from SRC to DST. */ > + > +static void > +aarch64_maybe_swab128 (gdb_byte *dst, const gdb_byte *src, size_t size) > +{ > + gdb_assert (src != nullptr && dst != nullptr); > + gdb_assert (size > 1); > + > +#if (__BYTE_ORDER == __BIG_ENDIAN) > + for (int i = 0; i < size - 1; i++) > + dst[i] = src[size - i]; > +#else > + memcpy (dst, src, size); > +#endif > +} > + > /* See nat/aarch64-sve-linux-ptrace.h. */ > > void > @@ -184,34 +203,50 @@ aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf, > } > else > { > + /* WARNING: SIMD state is laid out in memory in target-endian format, > + while SVE state is laid out in an endianness-independent format (LE). > + > + So we have a couple cases to consider: > + > + 1 - If the target is big endian, then SIMD state is big endian, > + requiring a byteswap. > + > + 2 - If the target is little endian, then SIMD state is little endian, > + which matches the SVE format, so no byteswap is needed. */ > + > /* There is no SVE state yet - the register dump contains a fpsimd > structure instead. These registers still exist in the hardware, but > the kernel has not yet initialised them, and so they will be null. */ > > - char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); > + gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); > struct user_fpsimd_state *fpsimd > = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET); > > + /* Make sure we have a zeroed register buffer. We will need the zero > + padding below. */ > + memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); > + > /* Copy across the V registers from fpsimd structure to the Z registers, > ensuring the non overlapping state is set to null. */ > > - memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); > - > for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) > { > - memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t)); > - reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg); > + /* Handle big endian/little endian SIMD/SVE conversion. */ > + aarch64_maybe_swab128 (reg, (const gdb_byte *) &fpsimd->vregs[i], > + V_REGISTER_SIZE); > + reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg); > } > > reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr); > reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr); > > /* Clear the SVE only registers. */ > + memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); > > for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) > - reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, zero_reg); > + reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg); > > - reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg); > + reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg); > } > } > > @@ -240,11 +275,11 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf, > kernel, which is why we try to avoid it. */ > > bool has_sve_state = false; > - char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); > + gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); > struct user_fpsimd_state *fpsimd > = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET); > > - memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); > + memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); > > /* Check in the reg_buf if any of the Z registers are set after the > first 128 bits, or if any of the other SVE registers are set. */ > @@ -252,7 +287,7 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf, > for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) > { > has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i, > - zero_reg, sizeof (__int128_t)); > + reg, sizeof (__int128_t)); > if (has_sve_state) > break; > } > @@ -261,19 +296,31 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf, > for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) > { > has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i, > - zero_reg, 0); > + reg, 0); > if (has_sve_state) > break; > } > > if (!has_sve_state) > has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM, > - zero_reg, 0); > + reg, 0); > > /* If no SVE state exists, then use the existing fpsimd structure to > write out state and return. */ > if (!has_sve_state) > { > + /* WARNING: SIMD state is laid out in memory in target-endian format, > + while SVE state is laid out in an endianness-independent format > + (LE). > + > + So we have a couple cases to consider: > + > + 1 - If the target is big endian, then SIMD state is big endian, > + requiring a byteswap. > + > + 2 - If the target is little endian, then SIMD state is little > + endian, which matches the SVE format, so no byteswap is needed. */ > + > /* The collects of the Z registers will overflow the size of a vreg. > There is enough space in the structure to allow for this, but we > cannot overflow into the next register as we might not be > @@ -284,8 +331,10 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf, > if (REG_VALID > == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i)) > { > - reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg); > - memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t)); > + reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, reg); > + /* Handle big endian/little endian SIMD/SVE conversion. */ > + aarch64_maybe_swab128 ((gdb_byte *) &fpsimd->vregs[i], reg, > + V_REGISTER_SIZE); > } > } > > diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c > index a6a84790a9..8a1aa818ad 100644 > --- a/gdb/trad-frame.c > +++ b/gdb/trad-frame.c > @@ -56,6 +56,7 @@ trad_frame_reset_saved_regs (struct gdbarch *gdbarch, > { > regs[regnum].realreg = regnum; > regs[regnum].addr = -1; > + regs[regnum].data = nullptr; > } > } > > @@ -83,7 +84,7 @@ trad_frame_alloc_saved_regs (struct frame_info *this_frame) > return trad_frame_alloc_saved_regs (gdbarch); > } > > -enum { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2 }; > +enum { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2, TF_REG_VALUE_BYTES = -3 }; > > int > trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[], int regnum) > @@ -106,6 +107,16 @@ trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[], > && this_saved_regs[regnum].addr == -1); > } > > +/* See trad-frame.h. */ > + > +bool > +trad_frame_value_bytes_p (struct trad_frame_saved_reg this_saved_regs[], > + int regnum) > +{ > + return (this_saved_regs[regnum].realreg == TF_REG_VALUE_BYTES > + && this_saved_regs[regnum].data != nullptr); > +} > + > void > trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[], > int regnum, LONGEST val) > @@ -224,6 +235,35 @@ trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[], > this_saved_regs[regnum].addr = -1; > } > > +/* See trad-frame.h. */ > + > +void > +trad_frame_set_value_bytes (struct trad_frame_saved_reg this_saved_regs[], > + int regnum, const gdb_byte *bytes, > + size_t size) > +{ > + this_saved_regs[regnum].realreg = TF_REG_VALUE_BYTES; > + > + /* Allocate the space and copy the data bytes. */ > + this_saved_regs[regnum].data = FRAME_OBSTACK_CALLOC (size, gdb_byte); > + memcpy (this_saved_regs[regnum].data, bytes, size); > +} > + > +/* See trad-frame.h. */ > + > +void > +trad_frame_set_reg_value_bytes (struct trad_frame_cache *this_trad_cache, > + int regnum, const gdb_byte *bytes, > + size_t size) > +{ > + /* External interface for users of trad_frame_cache > + (who cannot access the prev_regs object directly). */ > + trad_frame_set_value_bytes (this_trad_cache->prev_regs, regnum, bytes, > + size); > +} > + > + > + > struct value * > trad_frame_get_prev_register (struct frame_info *this_frame, > struct trad_frame_saved_reg this_saved_regs[], > @@ -240,6 +280,10 @@ trad_frame_get_prev_register (struct frame_info *this_frame, > /* The register's value is available. */ > return frame_unwind_got_constant (this_frame, regnum, > this_saved_regs[regnum].addr); > + else if (trad_frame_value_bytes_p (this_saved_regs, regnum)) > + /* The register's value is available as a sequence of bytes. */ > + return frame_unwind_got_bytes (this_frame, regnum, > + this_saved_regs[regnum].data); > else > return frame_unwind_got_optimized (this_frame, regnum); > } > diff --git a/gdb/trad-frame.h b/gdb/trad-frame.h > index 7b5785616e..38db439579 100644 > --- a/gdb/trad-frame.h > +++ b/gdb/trad-frame.h > @@ -52,6 +52,12 @@ void trad_frame_set_reg_regmap (struct trad_frame_cache *this_trad_cache, > void trad_frame_set_reg_value (struct trad_frame_cache *this_cache, > int regnum, LONGEST val); > > +/* Given the cache in THIS_TRAD_CACHE, set the value of REGNUM to the bytes > + contained in BYTES with size SIZE. */ > +void trad_frame_set_reg_value_bytes (struct trad_frame_cache *this_trad_cache, > + int regnum, const gdb_byte *bytes, > + size_t size); > + > struct value *trad_frame_get_register (struct trad_frame_cache *this_trad_cache, > struct frame_info *this_frame, > int regnum); > @@ -86,6 +92,8 @@ struct trad_frame_saved_reg > { > LONGEST addr; /* A CORE_ADDR fits in a longest. */ > int realreg; > + /* Register data (for values that don't fit in ADDR). */ > + gdb_byte *data; > }; > > /* Encode REGNUM value in the trad-frame. */ > @@ -104,6 +112,12 @@ void trad_frame_set_addr (struct trad_frame_saved_reg this_trad_cache[], > void trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[], > int regnum); > > +/* Encode REGNUM value in the trad-frame as a sequence of bytes. This is > + useful when the value is larger than what primitive types can hold. */ > +void trad_frame_set_value_bytes (struct trad_frame_saved_reg this_saved_regs[], > + int regnum, const gdb_byte *bytes, > + size_t size); > + > /* Convenience functions, return non-zero if the register has been > encoded as specified. */ > int trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[], > @@ -113,6 +127,11 @@ int trad_frame_addr_p (struct trad_frame_saved_reg this_saved_regs[], > int trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[], > int regnum); > > +/* Return TRUE if REGNUM is stored as a sequence of bytes, and FALSE > + otherwise. */ > +bool trad_frame_value_bytes_p (struct trad_frame_saved_reg this_saved_regs[], > + int regnum); > + > /* Reset the save regs cache, setting register values to -1. */ > void trad_frame_reset_saved_regs (struct gdbarch *gdbarch, > struct trad_frame_saved_reg *regs); >