From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id TK6cJguCz18zbQAAWB0awg (envelope-from ) for ; Tue, 08 Dec 2020 08:39:23 -0500 Received: by simark.ca (Postfix, from userid 112) id 912ED1F096; Tue, 8 Dec 2020 08:39:23 -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 2FFDC1E590 for ; Tue, 8 Dec 2020 08:39:21 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 65EAE385041B; Tue, 8 Dec 2020 13:39:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 65EAE385041B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1607434760; bh=bVeD3NMSoVcQE5ieiwHr9Nu7T4R8LrooNukZOTi8A6E=; 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=jQy7n3h8y4YIv93RHIeO0rkFYzbK+1/87g0PpMVe0l68czOc03lr88ORnsDawx19B eniusivUeFW9ejq2BMvkMulnd+ML32o9oAndfcxpRCiEBmglSRzDRl3wuaXS7ZTwwE h0cItCP8DA86nZYh7fRm3gjU545o7EjMDPdlJa8s= Received: from mail-qt1-x832.google.com (mail-qt1-x832.google.com [IPv6:2607:f8b0:4864:20::832]) by sourceware.org (Postfix) with ESMTPS id F36DF3850414 for ; Tue, 8 Dec 2020 13:39:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org F36DF3850414 Received: by mail-qt1-x832.google.com with SMTP id 7so11913989qtp.1 for ; Tue, 08 Dec 2020 05:39:15 -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=bVeD3NMSoVcQE5ieiwHr9Nu7T4R8LrooNukZOTi8A6E=; b=JwOANgQn8nJwhbPATi4vjQNfQwkt1HsL0sWfpvJhNxnPG95E+pdcKAyKNJ1o5U4y1n +7WhmWOxp5grDg7e3JgzZnIylOXqa558o1QDvw1VnR6LFAm1ScF2VU52ZPIzu29VoezB ldRlWCeFiwhhKlDdkEvVd2KPr7c2ODM4lwwZjWg6Ng3T2FlVKQ8nVmb29/JKaPCyQq62 hK40nFJKlmn83Vde6zZ5FZ91e1LtozyhugGf5tfSCnfyY8sFkY/EdX1SWvfOkMZvudh2 fa3QwChYSM/auJThPSNlYoLdDSoVYaPDDX87o06vvnCE3UMSXDCUBOqiYB1n/Qjyj4B+ BiIA== X-Gm-Message-State: AOAM531Zxza51Fax7xsbkChcqCR2qKQWrPLQqvcGj0GnN+q3MCL8pf23 DcU9HP99O4p6ep6xLL/ecyElQw== X-Google-Smtp-Source: ABdhPJwWJshpMo/YxvIvWtbN6lghcs+77PYfmZDBYNX2qiw4Kkmmq31tVbEVgxwsTzTGXIBecU9wpw== X-Received: by 2002:aed:3144:: with SMTP id 62mr29900293qtg.342.1607434755306; Tue, 08 Dec 2020 05:39:15 -0800 (PST) Received: from ?IPv6:2804:7f0:8284:370e:cba:9844:31b8:6c2a? ([2804:7f0:8284:370e:cba:9844:31b8:6c2a]) by smtp.gmail.com with ESMTPSA id c138sm14619019qke.95.2020.12.08.05.39.13 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 08 Dec 2020 05:39:14 -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> <33b1cca4-0f45-3999-36d3-d68e169e7acc@linaro.org> Message-ID: <2b56ab6f-02ef-9c74-64cc-64485857ef32@linaro.org> Date: Tue, 8 Dec 2020 10:39:11 -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: <33b1cca4-0f45-3999-36d3-d68e169e7acc@linaro.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit 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" Ping? On 12/4/20 11:22 AM, Luis Machado wrote: > 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); >>