From patchwork Tue May 21 20:27:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 90635 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D52E0384AB72 for ; Tue, 21 May 2024 20:29:19 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id CAC2A3858D1E for ; Tue, 21 May 2024 20:28:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CAC2A3858D1E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CAC2A3858D1E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716323325; cv=none; b=R/ouXPe/+F+eM+MtNINo1pK9BRtufjG0KtF1cM+hOWwh0FCS6r3Nwy7QvUuZArFqkQjMPDld9vRnXlQmDLmM3yXEGvkmX1mPuRo7zje30om79d7sd+TWpKeXM4rgpwqfwmV5xZlfcSe7JJKfitoy/zE2wu23k4LEHIqL/Bk3Z/Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716323325; c=relaxed/simple; bh=IE+P4Fk9awTtC+Mff78laiOgbaXI/i3WZhaiSdfRjxk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=afl5VXEJk7NU0fZT6BBCZKbOONNjAESU/WUhZLET+Xdk56WHargqMlkT4pqWrtDdRSMk5qz51+qkRzmrf/wu7EKm2Z3uqbM2p3/p1TTXPoMW/eQAWcsB29XvIRJaTdA4A+6slMpsZ3lhGWR5wPgNLw/kiLuXV5pvnb8sZ7wODV8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716323323; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+8NMai+lbtCyhEKI9bOJ4/P9PTm/1m9aPMwvhk4y7Vg=; b=KTtYD01NwhB/AMvEEwtGT8gm+rP7y8xm3IJCncvFTgKPGUC0KKuPbL0/5bhJ6bih95v59V 7j03UBKjKF06MvJ9vvA7p25CFCZ6OSF5n4mRsBE3kfYQSNHXNHfXJhlJZ4g7S3N3ii0wMI BmhrRc7FdEGgvFFivOmKyucsvc6iLDY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-27-Xy-bWJQ4OV-on7adk-o96Q-1; Tue, 21 May 2024 16:28:41 -0400 X-MC-Unique: Xy-bWJQ4OV-on7adk-o96Q-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (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 mimecast-mx02.redhat.com (Postfix) with ESMTPS id E42478008A4 for ; Tue, 21 May 2024 20:28:40 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.84]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 24E1A40004D; Tue, 21 May 2024 20:28:39 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH 1/3] gdb: Start supporting AVX instruction Date: Tue, 21 May 2024 17:27:58 -0300 Message-ID: <20240521202800.2865871-2-blarsen@redhat.com> In-Reply-To: <20240521202800.2865871-1-blarsen@redhat.com> References: <20240521202800.2865871-1-blarsen@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org This patch introduces the information needed to properly identify the VEX prefix, used to signal an AVX and AVX2 instruction, and introduces a helper function to handle all AVX instruction, instead of adding to the 3000 line long recording function. The new helper also handles unsupported instructions so that the largest part of the i386_process_record doesn't have to be shifted by 2 spaces, which made an unreadably big patch file. The only expected difference added by this patch is a small change to the unsupported message. As a note for the future, we don't handle xmm16-31 and ymm16-31 because those require the EVEX prefix, meaning avx512 support. --- gdb/amd64-tdep.c | 3 +- gdb/i386-tdep.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++-- gdb/i386-tdep.h | 2 ++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index df6b882a3fb..27d6e20f90c 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -3134,7 +3134,8 @@ static const int amd64_record_regmap[] = AMD64_R8_REGNUM, AMD64_R9_REGNUM, AMD64_R10_REGNUM, AMD64_R11_REGNUM, AMD64_R12_REGNUM, AMD64_R13_REGNUM, AMD64_R14_REGNUM, AMD64_R15_REGNUM, AMD64_RIP_REGNUM, AMD64_EFLAGS_REGNUM, AMD64_CS_REGNUM, AMD64_SS_REGNUM, - AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM + AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM, + AMD64_XMM0_REGNUM, AMD64_YMM0H_REGNUM }; /* Implement the "in_indirect_branch_thunk" gdbarch function. */ diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index f1f909e1616..93a0926c4bc 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -4637,6 +4637,12 @@ struct i386_record_s int rip_offset; int popl_esp_hack; const int *regmap; + + /* These are used by VEX and XOP prefixes. */ + uint8_t map_select; + uint8_t vvvv; + uint8_t pp; + uint8_t l; }; /* Parse the "modrm" part of the memory address irp->addr points at. @@ -4975,6 +4981,31 @@ static int i386_record_floats (struct gdbarch *gdbarch, return 0; } +/* i386_process_record helper to deal with instructions that start + with VEX prefix. */ + +static bool +i386_record_vex (struct i386_record_s *ir, uint8_t rex_w, uint8_t rex_r, + int opcode, struct gdbarch *gdbarch) +{ + switch (opcode) + { + default: + gdb_printf (gdb_stderr, + _("Process record does not support VEX instruction 0x%02x " + "at address %s.\n"), + (unsigned int) (opcode), + paddress (gdbarch, ir->orig_addr)); + return -1; + } + + record_full_arch_list_add_reg (ir->regcache, ir->regmap[X86_RECORD_REIP_REGNUM]); + if (record_full_arch_list_add_end ()) + return -1; + + return 0; +} + /* Parse the current instruction, and record the values of the registers and memory that will be changed by the current instruction. Returns -1 if something goes wrong, 0 otherwise. */ @@ -4997,6 +5028,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache, i386_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); uint8_t rex_w = -1; uint8_t rex_r = 0; + bool vex_prefix = false; memset (&ir, 0, sizeof (struct i386_record_s)); ir.regcache = regcache; @@ -5082,6 +5114,53 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache, else /* 32 bit target */ goto out_prefixes; break; + case 0xc4: /* 3-byte VEX prefixes (for AVX/AVX2 instructions). */ + { + /* The first byte just identifies the VEX prefix. Data is stored + on the following 2 bytes. */ + uint8_t byte; + if (record_read_memory (gdbarch, ir.addr, &byte, 1)) + return -1; + ir.addr++; + + rex_r = !((byte >> 7) & 0x1); + ir.rex_x = !((byte >> 6) & 0x1); + ir.rex_b = !((byte >> 5) & 0x1); + ir.map_select = byte & 0x1f; + /* Collect the last byte of the prefix. */ + if (record_read_memory (gdbarch, ir.addr, &byte, 1)) + return -1; + ir.addr++; + rex_w = (byte >> 7) & 0x1; + ir.vvvv = (~(byte >> 3) & 0xf); + ir.l = (byte >> 2) & 0x1; + ir.pp = byte & 0x3; + vex_prefix = true; + + break; + } + case 0xc5: /* 2-byte VEX prefix for AVX/AVX2 instructions. */ + { + /* The first byte just identifies the VEX prefix. Data is stored + on the following 2 bytes. */ + uint8_t byte; + if (record_read_memory (gdbarch, ir.addr, &byte, 1)) + return -1; + ir.addr++; + + /* On the 2-byte versions, these are pre-defined. */ + ir.rex_x = 0; + ir.rex_b = 0; + rex_w = 0; + ir.map_select = 1; + + rex_r = !((byte >> 7) & 0x1); + ir.vvvv = (~(byte >> 3) & 0xf); + ir.l = (byte >> 2) & 0x1; + ir.pp = byte & 0x3; + vex_prefix = true; + break; + } default: goto out_prefixes; break; @@ -5104,6 +5183,12 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache, /* Now check op code. */ opcode = (uint32_t) opcode8; + if (vex_prefix) + { + /* If we found the VEX prefix, i386 will either record or warn that + the instruction isn't supported, so we can return the VEX result. */ + return i386_record_vex (&ir, rex_w, rex_r, opcode, gdbarch); + } reswitch: switch (opcode) { @@ -8088,9 +8173,11 @@ static const int i386_record_regmap[] = { I386_EAX_REGNUM, I386_ECX_REGNUM, I386_EDX_REGNUM, I386_EBX_REGNUM, I386_ESP_REGNUM, I386_EBP_REGNUM, I386_ESI_REGNUM, I386_EDI_REGNUM, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, I386_EIP_REGNUM, I386_EFLAGS_REGNUM, I386_CS_REGNUM, I386_SS_REGNUM, - I386_DS_REGNUM, I386_ES_REGNUM, I386_FS_REGNUM, I386_GS_REGNUM + I386_DS_REGNUM, I386_ES_REGNUM, I386_FS_REGNUM, I386_GS_REGNUM, + /* xmm0_regnum */ 0, I386_YMM0H_REGNUM }; /* Check that the given address appears suitable for a fast diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h index a85e0a984a0..1f21f8de06c 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -339,6 +339,8 @@ enum record_i386_regnum X86_RECORD_ES_REGNUM, X86_RECORD_FS_REGNUM, X86_RECORD_GS_REGNUM, + X86_RECORD_XMM0_REGNUM, + X86_RECORD_YMM0H_REGNUM, }; #define I386_NUM_GREGS 16 From patchwork Tue May 21 20:27:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 90637 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B7454384AB5B for ; Tue, 21 May 2024 20:29:28 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 644FB3858C41 for ; Tue, 21 May 2024 20:28:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 644FB3858C41 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 644FB3858C41 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716323327; cv=none; b=vl9YLDRZm/55KahMxK8XFq9Rmd5Q5RzoQrPv3O2826La7jvT4SW4kdiBAyWadM5BgNgcAwTy5g3pj50KAMQYJju1EA9zjFaVbb/A2YzwbkHIHVXlD1BRYDYVZTf9+Y1gpwCx19G4pgEyIQgzNS74h4UPMiyNHEsAlbIOR3NNUSg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716323327; c=relaxed/simple; bh=aBbfusvYxdmKanVc63n4Kqw8DY6n6061Uk7owGulCSo=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=wV3hE86WH6AG1BJfg3PffogVI181CpVuERs346HikBjmr0VrzjyVw8XDa0o+mz3vJfz+sZghFtQelsF6dVJB8VBiN8AIggEnMzijOHkLUAnY26yPSW4Ai9IYX75cp4Q4u6NO6TcjmkqQdwRpY6kcUhLLTmegV2BZpfM+zELhhdc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716323324; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=X6a/PCkN6KJ8jrAhbqaFbj/OD72bduM1VeFWo9hqmsM=; b=WqAORoNMM1kft6/mv92oKwoewLM8Xz4fbzYFWvoPlKYKOgeIRmovQPUibgzPP0SVLGXh8l 1tDGN4Tt9C7lkGHVTyspdaFEZI6y/qUPat77YXRprxCbZQkTNbxnh1qcmcKY688ryXLe01 OrAvER7z+Xur2ebzraDuSI5lbVqXtLg= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-564-d0uZ7lsYPdeq6S7MYBTdkA-1; Tue, 21 May 2024 16:28:42 -0400 X-MC-Unique: d0uZ7lsYPdeq6S7MYBTdkA-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (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 mimecast-mx02.redhat.com (Postfix) with ESMTPS id 181BE3C025B6 for ; Tue, 21 May 2024 20:28:42 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.84]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 370D5491032; Tue, 21 May 2024 20:28:41 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH 2/3] gdb/record: add support to vmovd and vmovq instructions Date: Tue, 21 May 2024 17:27:59 -0300 Message-ID: <20240521202800.2865871-3-blarsen@redhat.com> In-Reply-To: <20240521202800.2865871-1-blarsen@redhat.com> References: <20240521202800.2865871-1-blarsen@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org This commit adds support to the x86_64 AVX instructions vmovd and vmovq. The programmers manuals for Intel and AMD describe these 2 instructions as being almost the same, but my local testing, using gcc 13.2 on Fedora 39, showed several differences and inconsistencies. The instruction is supposed to always use the 3-byte VEX prefix, but I could only find 2-byte versions. The instructions aren't differentiated by the VEX.w bit, but by opcodes and VEX.pp. This patch adds a test with many different uses for both vmovd and vmovq. --- gdb/i386-tdep.c | 69 ++++++- gdb/testsuite/gdb.reverse/i386-avx-reverse.c | 90 +++++++++ .../gdb.reverse/i386-avx-reverse.exp | 171 ++++++++++++++++++ 3 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.reverse/i386-avx-reverse.c create mode 100644 gdb/testsuite/gdb.reverse/i386-avx-reverse.exp diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 93a0926c4bc..d2848970ec4 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -4985,11 +4985,78 @@ static int i386_record_floats (struct gdbarch *gdbarch, with VEX prefix. */ static bool -i386_record_vex (struct i386_record_s *ir, uint8_t rex_w, uint8_t rex_r, +i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r, int opcode, struct gdbarch *gdbarch) { switch (opcode) { + case 0x6e: /* VMOVD XMM, reg/mem */ + /* This is moving from a regular register or memory region into an + XMM register. */ + i386_record_modrm (ir); + /* ModR/M only has the 3 least significant bits of the destination + register, the last one is indicated by VEX.R (stored inverted). */ + record_full_arch_list_add_reg (ir->regcache, + ir->regmap[X86_RECORD_XMM0_REGNUM] + + ir->reg + vex_r * 8); + break; + case 0x7e: /* VMOV(D/Q) */ + i386_record_modrm (ir); + /* Both the intel and AMD manual are wrong about this. According to + it, the only difference between vmovq and vmovd should be the rex_w + bit, but in empirical testing, it seems that they share this opcode, + and the way to differentiate it here is looking at VEX.PP. */ + if (ir->pp == 2) + { + /* This is vmovq moving from a regular register or memory + into an XMM register. As above, VEX.R is the final bit for + destination register. */ + record_full_arch_list_add_reg (ir->regcache, + ir->regmap[X86_RECORD_XMM0_REGNUM] + + ir->reg + vex_r * 8); + } + else if (ir->pp == 1) + { + /* This is the vmovd version that stores into a regular register + or memory region. */ + /* If ModRM.mod is 11 we are saving into a register. */ + if (ir->mod == 3) + record_full_arch_list_add_reg (ir->regcache, ir->regmap[ir->rm]); + else + { + /* Calculate the size of memory that will be modified + and store it in the form of 1 << ir->ot, since that + is how the function uses it. In theory, VEX.W is supposed + to indicate the size of the memory. In practice, I only + ever seen it set to 0, and for 16 bytes, 0xD6 opcode + is used. */ + if (vex_w) + ir->ot = 4; + else + ir->ot = 3; + + i386_record_lea_modrm (ir); + } + } + else + error ("Unrecognized VEX.PP value %d at address %s.", + ir->pp, paddress(gdbarch, ir->orig_addr)); + break; + case 0xd6: /* VMOVQ reg/mem XMM */ + i386_record_modrm (ir); + /* This is the vmovq version that stores into a regular register + or memory region. */ + /* If ModRM.mod is 11 we are saving into a register. */ + if (ir->mod == 3) + record_full_arch_list_add_reg (ir->regcache, ir->regmap[ir->rm]); + else + { + /* We know that this operation is always 64 bits. */ + ir->ot = 4; + i386_record_lea_modrm (ir); + } + break; + default: gdb_printf (gdb_stderr, _("Process record does not support VEX instruction 0x%02x " diff --git a/gdb/testsuite/gdb.reverse/i386-avx-reverse.c b/gdb/testsuite/gdb.reverse/i386-avx-reverse.c new file mode 100644 index 00000000000..216b593736b --- /dev/null +++ b/gdb/testsuite/gdb.reverse/i386-avx-reverse.c @@ -0,0 +1,90 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2023 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 . */ + +/* Architecture tests for intel i386 platform. */ + +#include + +char global_buf0[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; +char global_buf1[] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; +char *dyn_buf0; +char *dyn_buf1; + +void +vmov_test () +{ + char buf0[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; + char buf1[] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + + /* Operations on registers. */ + asm volatile ("mov $0, %rcx"); + asm volatile ("mov $0xbeef, %rax"); + asm volatile ("vmovd %rax, %xmm0"); + asm volatile ("vmovd %xmm0, %rcx"); + + /* Operations based on local buffers. */ + asm volatile ("vmovd %0, %%xmm0": : "m"(buf0)); + asm volatile ("vmovd %%xmm0, %0": "=m"(buf1)); + asm volatile ("vmovq %0, %%xmm0": : "m"(buf0)); + asm volatile ("vmovq %%xmm0, %0": "=m"(buf1)); + + /* Operations based on global buffers. */ + asm volatile ("vmovd %0, %%xmm0": : "m"(global_buf0)); + asm volatile ("vmovd %%xmm0, %0": "=m"(global_buf1)); + asm volatile ("vmovq %0, %%xmm0": : "m"(global_buf0)); + asm volatile ("vmovq %%xmm0, %0": "=m"(global_buf1)); + + /* Operations based on dynamic buffers. */ + asm volatile ("vmovd %0, %%xmm0": : "m"(*dyn_buf0)); + asm volatile ("vmovd %%xmm0, %0": "=m"(*dyn_buf1)); + asm volatile ("vmovq %0, %%xmm0": : "m"(*dyn_buf0)); + asm volatile ("vmovq %%xmm0, %0": "=m"(*dyn_buf1)); + + /* Reset all relevant buffers. */ + asm volatile ("vmovq %%xmm15, %0": "=m" (buf1)); + asm volatile ("vmovq %%xmm15, %0": "=m" (global_buf1)); + asm volatile ("vmovq %%xmm15, %0": "=m" (*dyn_buf1)); + + /* Quick test for a different xmm register. */ + asm volatile ("vmovd %0, %%xmm15": "=m" (buf0)); + asm volatile ("vmovd %0, %%xmm15": "=m" (buf1)); + asm volatile ("vmovq %0, %%xmm15": "=m" (buf0)); + asm volatile ("vmovq %0, %%xmm15": "=m" (buf1)); +} /* end vmov_test */ + +int +main () +{ + dyn_buf0 = (char *) malloc(sizeof(char) * 16); + dyn_buf1 = (char *) malloc(sizeof(char) * 16); + for (int i =0; i < 16; i++) + { + dyn_buf0[i] = 0x20 + i; + dyn_buf1[i] = 0; + } + /* Zero relevant xmm registers, se we know what to look for. */ + asm volatile ("vmovq %0, %%xmm0": : "m" (global_buf1)); + asm volatile ("vmovq %0, %%xmm15": : "m" (global_buf1)); + + /* Start recording. */ + vmov_test (); + return 0; /* end of main */ +} diff --git a/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp b/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp new file mode 100644 index 00000000000..42ddc3a6526 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp @@ -0,0 +1,171 @@ +# Copyright 2009-2023 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 . + +# This file is part of the gdb testsuite. + +# +# This test tests some i386 general instructions for reverse execution. +# + +require supports_reverse + +if {![istarget "*86*-*linux*"]} { + verbose "Skipping i386 reverse tests." + return +} + +standard_testfile + +# some targets have leading underscores on assembly symbols. +set additional_flags [gdb_target_symbol_prefix_flags] + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ + [list debug $additional_flags]]} { + return -1 +} + +# Shorthand to test reversing through one instruction and +# testing if a register has the expected value. +# Prefix, if included, should end with a colon and space. + +proc test_one_register {insn register value {prefix ""}} { + gdb_test "reverse-step" "$insn.*" \ + "${prefix}reverse-step from $insn to test register $register" + + gdb_test "info register $register" \ + "$register.*uint128 = $value.*" \ + "${prefix}verify $register before $insn" +} + +# Shorthand to test reversing through one instruction and +# testing if a variable has the expected value. +# Prefix, if used, should end with a colon and space. + +proc test_one_memory {insn mem value {dynamic false} {prefix ""}} { + gdb_test "reverse-step" "$insn.*" \ + "${prefix}reverse-step from $insn to test memory $mem" + + # For the dynamic buffer, we have to cast and dereference the pointer + set cast "" + if {$dynamic == true} { + set cast {(char [16]) *} + } + + gdb_test "p/x $cast$mem" \ + ".*$value.*" \ + "${prefix}verify $mem before $insn" + +} + +# Record the execution for the whole function, and stop at its end +# to check if we can correctly reconstruct the state. +# In the source code, the function must be FUNCTION_test, and +# at the end, it must have a comment in the form: +# /* end FUNCTION_test */ +# Returns true if the full function could be recorded, false otherwise. +proc record_full_function {function} { + set end [gdb_get_line_number "end ${function}_test "] + gdb_breakpoint $end temporary + + if [supports_process_record] { + # Activate process record/replay. + gdb_test_no_output "record" "${function}: turn on process record" + } + + gdb_test_multiple "continue" "continue to end of ${function}_test" { + -re " end ${function}_test .*\r\n$::gdb_prompt $" { + pass $gdb_test_name + } + -re " Illegal instruction.*\r\n$::gdb_prompt $" { + fail $gdb_test_name + return false + } + -re "Process record does not support VEX instruction.*" { + fail $gdb_test_name + return false + } + } + return true +} + +set end_of_main [gdb_get_line_number " end of main "] +set rec_start [gdb_get_line_number " Start recording"] + +runto_main + +gdb_breakpoint $rec_start +gdb_continue_to_breakpoint "vmov_test" ".*vmov_test.*" + +global hex +global decimal + +# Record all the execution for vmov tests first. + +if {[record_full_function "vmov"] == true} { + # Now execute backwards, checking all instructions. + # First we test all instructions handling global buffers. + + test_one_register "vmovq" "xmm15" "0x3736353433323130" "reg_reset: " + test_one_register "vmovq" "xmm15" "0x0" + test_one_register "vmovd" "xmm15" "0x33323130" "reg_reset: " + test_one_register "vmovd" "xmm15" "0x0" + + with_test_prefix buffer_reset { + test_one_memory "vmovq" "dyn_buf1" \ + "0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x0" true + test_one_memory "vmovq" "global_buf1" \ + "0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x0" + test_one_memory "vmovq" "buf1" \ + "0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x0" + } + + with_test_prefix dynamic_buffers { + test_one_memory "vmovq" "dyn_buf1" "0x20, 0x21, 0x22, 0x23, 0x0" true + test_one_register "vmovq" "xmm0" "0x23222120" + test_one_memory "vmovd" "dyn_buf1" "0x0 .repeats 16 times" true + test_one_register "vmovd" "xmm0" "0x1716151413121110" + } + + with_test_prefix global_buffers { + test_one_memory "vmovq" "global_buf1" "0x10, 0x11, 0x12, 0x13, 0x0" + test_one_register "vmovq" "xmm0" "0x13121110" + test_one_memory "vmovd" "global_buf1" "0x0 .repeats 16 times" + test_one_register "vmovd" "xmm0" "0x3736353433323130" + } + + with_test_prefix local_buffers { + test_one_memory "vmovq" "buf1" "0x30, 0x31, 0x32, 0x33, 0x0" + test_one_register "vmovq" "xmm0" "0x33323130" + test_one_memory "vmovd" "buf1" "0x0 .repeats 16 times" + test_one_register "vmovd" "xmm0" "0xbeef" + } + + # regular registers don't have uint128 members, so do it manually + with_test_prefix registers { + gdb_test "reverse-step" "vmovd %xmm0, %rcx.*" \ + "reverse step to check rcx recording" + gdb_test "print/x \$rcx" "= 0x0" "rcx was recorded" + + test_one_register "vmovd" "xmm0" "0x0" + } +} else { + untested "could not record vmov_test" +} + +# Move to the end of vmov_test to set up next. +# Stop recording in case of recording errors. +gdb_test "record stop" "Process record is stopped.*" \ + "delete history for vmov_test" +gdb_test "finish" "Run till exit from.*vmov_test.*" "leaving vmov_test" From patchwork Tue May 21 20:28:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 90636 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E7547384AB73 for ; Tue, 21 May 2024 20:29:19 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id EBF113858C60 for ; Tue, 21 May 2024 20:28:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EBF113858C60 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org EBF113858C60 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716323327; cv=none; b=TNUEnGx0FLoNrnWzj+v5oXvUnKlDNENxXlzWmfv8QXDjwZyqoGlghOC4M4kMYXFKFXiHOOCkn/3FG37TVkuC9OKYeAixVtT8JzXlEkPCZgeFnypvRm27CMLnvbnSVxqdZxhXy3NVVyBVb2DY8HBKANk+C/ZPYrbnO2gbPDNeDok= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716323327; c=relaxed/simple; bh=3l6KGDr7yuEvb4sJzqaSghBqDweh/CZZynk7Vpw1xwI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=n8kxD3Oya2vEVF85RQkbcb3pq4o6quTuIABIvNzu5aMZoBvkP+k+QfwuKtQK4481gDNWmIP8Ov5bxYw3Nk9UfCSZ8Sye28oXkxmqZCe2R+uVMriuj5IigroEiNhQkrsxWobYEfa8fF0MypEWqPvPduPBMaDJFvHpPxfNy1O7aW4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716323324; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7L2owhDu62zwJOXoO8xJcFqCUdRgwE1FhTKx7Iauprc=; b=IO3u4LfehnLv8gsC2ID1jOBd/Kk3e3IhTo/DIQdro5uEqOo2/bV05wTSy8UYGHXYTV3bf8 HiNwky7med7TTneUfe0yFLslsYF8IudUcWUnUE97mj9Xq4rZ/hvB+iLOOj4IcbyWsPWZK9 JFEo2cEMiHXx2ibV3bEBxTMZEtWQPVU= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-133-oVyarQTaOzec6T1c4vUAng-1; Tue, 21 May 2024 16:28:43 -0400 X-MC-Unique: oVyarQTaOzec6T1c4vUAng-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (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 mimecast-mx02.redhat.com (Postfix) with ESMTPS id 134E11C05133 for ; Tue, 21 May 2024 20:28:43 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.84]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5F4DE40004D; Tue, 21 May 2024 20:28:42 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH 3/3] gdb/record: add support to AVX unpack instructions Date: Tue, 21 May 2024 17:28:00 -0300 Message-ID: <20240521202800.2865871-4-blarsen@redhat.com> In-Reply-To: <20240521202800.2865871-1-blarsen@redhat.com> References: <20240521202800.2865871-1-blarsen@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org This commit adds support to recording instructions to unpack high or low data from XMM registers, identified by the mnemonics in the form: VPUNPCK [L|H] [BW|WD|DQ|QDQ]. All these instructions are encoded the exact same way, and only affect the destination register, making them trivial to implement together. It also updates the test gdb.reverse/i386-avx-reverse.exp to test these new instructions. --- gdb/i386-tdep.c | 12 ++++++ gdb/testsuite/gdb.reverse/i386-avx-reverse.c | 37 +++++++++++++++++++ .../gdb.reverse/i386-avx-reverse.exp | 26 +++++++++++++ 3 files changed, 75 insertions(+) diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index d2848970ec4..250aff73389 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -5057,6 +5057,18 @@ i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r, } break; + case 0x60: /* VPUNPCKLBW */ + case 0x61: /* VPUNPCKLWD */ + case 0x62: /* VPUNPCKLDQ */ + case 0x6c: /* VPUNPCKLQDQ */ + case 0x68: /* VPUNPCKHBW */ + case 0x69: /* VPUNPCKHWD */ + case 0x6a: /* VPUNPCKHDQ */ + case 0x6d: /* VPUNPCKHQDQ */ + i386_record_modrm (ir); + record_full_arch_list_add_reg (ir->regcache, ir->regmap[X86_RECORD_XMM0_REGNUM] + ir->reg + vex_r * 8); + break; + default: gdb_printf (gdb_stderr, _("Process record does not support VEX instruction 0x%02x " diff --git a/gdb/testsuite/gdb.reverse/i386-avx-reverse.c b/gdb/testsuite/gdb.reverse/i386-avx-reverse.c index 216b593736b..4a4785ee99e 100644 --- a/gdb/testsuite/gdb.reverse/i386-avx-reverse.c +++ b/gdb/testsuite/gdb.reverse/i386-avx-reverse.c @@ -70,6 +70,40 @@ vmov_test () asm volatile ("vmovq %0, %%xmm15": "=m" (buf1)); } /* end vmov_test */ +/* Test if we can properly record (and undo) vpunpck style instructions. + Most tests will use xmm0 and xmm1 as sources. The registers xmm15 and xmm2 + are used as destination to ensure we're reading the VEX.R bit correctly. */ +void +vpunpck_test () +{ + /* Using GDB, load these values onto registers, for ease of testing. + xmm0.uint128 = 0x1f1e1d1c1b1a19181716151413121110 + xmm1.uint128 = 0x2f2e2d2c2b2a29282726252423222120 + so that's easy to confirm that the unpacking went as expected. */ + + /* 17 27 16 26 15 25 14 24 ...*/ + asm volatile ("vpunpcklbw %xmm0, %xmm1, %xmm15"); + /* 17 16 27 26 15 14 25 24 ...*/ + asm volatile ("vpunpcklwd %0, %%xmm1, %%xmm15" + : : "m" (global_buf0)); + /* 17 16 15 14 27 26 25 24 ...*/ + asm volatile ("vpunpckldq %0, %%xmm1, %%xmm2" + : : "m" (global_buf0)); + /* 17 16 15 14 13 12 11 10 ...*/ + asm volatile ("vpunpcklqdq %xmm0, %xmm1, %xmm2"); + + /* 17 27 16 26 15 25 14 24 ...*/ + asm volatile ("vpunpckhbw %xmm0, %xmm1, %xmm15"); + /* 17 16 27 26 15 14 25 24 ...*/ + asm volatile ("vpunpckhwd %0, %%xmm1, %%xmm15" + : : "m" (global_buf0)); + /* 17 16 15 14 27 26 25 24 ...*/ + asm volatile ("vpunpckhdq %0, %%xmm1, %%xmm2" + : : "m" (global_buf0)); + /* 17 16 15 14 13 12 11 10 ...*/ + asm volatile ("vpunpckhqdq %xmm0, %xmm1, %xmm2"); +} /* end vpunpck_test */ + int main () { @@ -82,9 +116,12 @@ main () } /* Zero relevant xmm registers, se we know what to look for. */ asm volatile ("vmovq %0, %%xmm0": : "m" (global_buf1)); + asm volatile ("vmovq %0, %%xmm1": : "m" (global_buf1)); + asm volatile ("vmovq %0, %%xmm2": : "m" (global_buf1)); asm volatile ("vmovq %0, %%xmm15": : "m" (global_buf1)); /* Start recording. */ vmov_test (); + vpunpck_test (); return 0; /* end of main */ } diff --git a/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp b/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp index 42ddc3a6526..c5e82eaeca6 100644 --- a/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp +++ b/gdb/testsuite/gdb.reverse/i386-avx-reverse.exp @@ -169,3 +169,29 @@ if {[record_full_function "vmov"] == true} { gdb_test "record stop" "Process record is stopped.*" \ "delete history for vmov_test" gdb_test "finish" "Run till exit from.*vmov_test.*" "leaving vmov_test" + +# Starting vpunpck tests. +gdb_test "step" "vpunpck_test \\\(\\\) at .*" "entering vpunpck_test function" +gdb_test_no_output "set \$xmm0.v2_int64 = {0x1716151413121110, 0x1f1e1d1c1b1a1918}" +gdb_test_no_output "set \$xmm1.v2_int64 = {0x2726252423222120, 0x2f2e2d2c2b2a2928}" +gdb_test_no_output "set \$xmm2.uint128 = 0x0" +gdb_test_no_output "set \$xmm15.uint128 = 0x0" +if {[record_full_function "vpunpck"] == true} { + test_one_register "vpunpckhqdq" "xmm2" "0x" + test_one_register "vpunpckhdq" "xmm2" "0x" + test_one_register "vpunpckhwd" "xmm15" "0x" + test_one_register "vpunpckhbw" "xmm15" "0x" + + test_one_register "vpunpcklqdq" "xmm2" "0x17161514272625241312111023222120" + test_one_register "vpunpckldq" "xmm2" "0x0" + test_one_register "vpunpcklwd" "xmm15" "0x17271626152514241323122211211020" + test_one_register "vpunpcklbw" "xmm15" "0x0" +} else { + untested "couldn't test vpunpck tests" +} + +# Move to the end of vmov_test to set up next. +# Stop recording in case of recording errors. +gdb_test "record stop" "Process record is stopped.*" \ + "delete history for vpunpck_test" +gdb_test "finish" "Run till exit from.*vpunpck_test.*" "leaving vpunpck_test"