From patchwork Tue Jun 12 08:03:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Hayward X-Patchwork-Id: 27746 Received: (qmail 64311 invoked by alias); 12 Jun 2018 08:04:34 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 62684 invoked by uid 89); 12 Jun 2018 08:04:31 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_NONE, TIME_LIMIT_EXCEEDED autolearn=unavailable version=3.3.2 spammy= X-HELO: EUR01-HE1-obe.outbound.protection.outlook.com Received: from mail-he1eur01on0058.outbound.protection.outlook.com (HELO EUR01-HE1-obe.outbound.protection.outlook.com) (104.47.0.58) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 12 Jun 2018 08:04:12 +0000 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Alan.Hayward@arm.com; Received: from C02TF0U7HF1T.arm.com (217.140.96.140) by DB6PR0802MB2136.eurprd08.prod.outlook.com (2603:10a6:4:83::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.841.14; Tue, 12 Jun 2018 08:04:08 +0000 From: Alan Hayward To: gdb-patches@sourceware.org Cc: nd@arm.com, Alan Hayward Subject: [PATCH] Support large registers in regcache transfer_regset Date: Tue, 12 Jun 2018 09:03:56 +0100 Message-Id: <20180612080356.33157-1-alan.hayward@arm.com> MIME-Version: 1.0 X-ClientProxiedBy: CWXP265CA0016.GBRP265.PROD.OUTLOOK.COM (2603:10a6:400:2e::28) To DB6PR0802MB2136.eurprd08.prod.outlook.com (2603:10a6:4:83::23) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-MS-TrafficTypeDiagnostic: DB6PR0802MB2136: NoDisclaimer: True X-Exchange-Antispam-Report-Test: UriScan:(180628864354917); X-MS-Exchange-SenderADCheck: 1 X-Forefront-PRVS: 07013D7479 Received-SPF: None (protection.outlook.com: arm.com does not designate permitted sender hosts) SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Office365-Filtering-Correlation-Id: 27898c15-38e7-435a-d168-08d5d03b1380 X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Jun 2018 08:04:08.8677 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 27898c15-38e7-435a-d168-08d5d03b1380 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0802MB2136 X-IsSubscribed: yes Regcache transfer_regset is used to copy registers to/from a regset. If the size of a regcache register is greater than it's slot in the regset then the writes will overflow into the next slot(s), causing general overflow corruption with the latter slots. Add raw_collect_part and raw_supply_part, which are simplified versions of raw_read_part and raw_write_part. Use these in accordingly in transfer_regset. This is required to support the .reg2 core section on Aarch64 SVE, which only has enough space to store the first 128bits of each vector register. This patch replaces [PATCH v2 10/10] Remove reg2 section from Aarch64 SVE cores Tested by generating cores on aarch64 and aarch64 sve, both via gdb and the kernel, then ensuring the cores load back on the both systems. Checked cores on x86 still look ok. Ran make check on x86 and aarch64. 2018-06-12 Alan Hayward * regcache.c (reg_buffer::raw_collect_part): New function. (reg_buffer::raw_supply_part): Likewise. (regcache::transfer_regset): Call new functions. * regcache.h (reg_buffer::raw_collect_part): New declaration. (reg_buffer::raw_supply_part): Likewise. --- gdb/regcache.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ gdb/regcache.h | 8 +++++ 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/gdb/regcache.c b/gdb/regcache.c index 750ea2ad30..babc0e1d43 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -812,6 +812,27 @@ readable_regcache::read_part (int regnum, int offset, int len, void *in, return REG_VALID; } +/* See regcache.h. */ + +void +reg_buffer::raw_collect_part (int regnum, int offset, int len, void *in) const +{ + struct gdbarch *gdbarch = arch (); + gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum)); + + gdb_assert (in != NULL); + gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); + gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]); + /* Something to do? */ + if (offset + len == 0) + return; + /* Read (when needed) ... */ + raw_collect (regnum, reg); + + /* ... modify ... */ + memcpy (in, reg + offset, len); +} + enum register_status regcache::write_part (int regnum, int offset, int len, const void *out, bool is_raw) @@ -849,6 +870,33 @@ regcache::write_part (int regnum, int offset, int len, return REG_VALID; } +/* See regcache.h. */ + +void +reg_buffer::raw_supply_part (int regnum, int offset, int len, + const gdb_byte *out) +{ + struct gdbarch *gdbarch = arch (); + gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum)); + + gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); + gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]); + /* Something to do? */ + if (offset + len == 0) + return; + /* Read (when needed) ... */ + if (offset > 0 + || offset + len < m_descr->sizeof_register[regnum]) + raw_collect (regnum, reg); + + if (out == nullptr) + memset (reg + offset, 0, len); + else + memcpy (reg + offset, out, len); + /* ... write (when needed). */ + raw_supply (regnum, reg); +} + enum register_status readable_regcache::raw_read_part (int regnum, int offset, int len, gdb_byte *buf) { @@ -1016,12 +1064,26 @@ regcache::transfer_regset (const struct regset *regset, if (offs + slot_size > size) break; - if (out_buf) - raw_collect (regno, (gdb_byte *) out_buf + offs); + gdb_byte *out_loc = (gdb_byte *) out_buf + offs; + const gdb_byte *in_loc = in_buf ? (const gdb_byte *) in_buf + offs + : NULL; + + if (slot_size < m_descr->sizeof_register[regno]) + { + /* Register is bigger than the size of the slot. Prevent + possible overflow. */ + if (out_buf) + raw_collect_part (regno, 0, slot_size, out_loc); + else + out_regcache->raw_supply_part (regno, 0, slot_size, in_loc); + } else - out_regcache->raw_supply (regno, in_buf - ? (const gdb_byte *) in_buf + offs - : NULL); + { + if (out_buf) + raw_collect (regno, out_loc); + else + out_regcache->raw_supply (regno, in_loc); + } } else { @@ -1030,12 +1092,26 @@ regcache::transfer_regset (const struct regset *regset, if (offs + slot_size > size) return; - if (out_buf) - raw_collect (regnum, (gdb_byte *) out_buf + offs); + gdb_byte *out_loc = (gdb_byte *) out_buf + offs; + const gdb_byte *in_loc = in_buf ? (const gdb_byte *) in_buf + offs + : NULL; + + if (slot_size < m_descr->sizeof_register[regno]) + { + /* Register is bigger than the size of the slot. Prevent + possible overflow. */ + if (out_buf) + raw_collect_part (regnum, 0, slot_size, out_loc); + else + out_regcache->raw_supply_part (regnum, 0, slot_size, in_loc); + } else - out_regcache->raw_supply (regnum, in_buf - ? (const gdb_byte *) in_buf + offs - : NULL); + { + if (out_buf) + raw_collect (regnum, out_loc); + else + out_regcache->raw_supply (regnum, in_loc); + } return; } } diff --git a/gdb/regcache.h b/gdb/regcache.h index 41465fb20d..3e2c5a9067 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -163,6 +163,10 @@ public: void raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, bool is_signed) const; + /* Collect register REGNUM from REGCACHE, starting at offset in REGCACHE, + reading only LEN. */ + void raw_collect_part (int regnum, int offset, int len, void *in) const; + /* See common/common-regcache.h. */ void raw_supply (int regnum, const void *buf) override; @@ -184,6 +188,10 @@ public: unavailable). */ void raw_supply_zeroed (int regnum); + /* Supply register REGNUM to REGCACHE, starting at offset in REGCACHE, writing + only LEN. */ + void raw_supply_part (int regnum, int offset, int len, const gdb_byte *out); + void invalidate (int regnum); virtual ~reg_buffer () = default;