From 30031e06005a839e5b923d046f6b56fe6d07f361 Mon Sep 17 00:00:00 2001 From: Abhinav Anil Sharma Date: Thu, 30 Nov 2023 11:44:48 -0500 Subject: [PATCH] i#5505 kernel tracing: Support clac and stac in DR decoder (#6484) Adds encoding-decoding support for clac and stac which are observed in kernel traces. decode_fast does not need any change and already should get the 3-byte size correctly. Adds EFLAGS_READ_AC and EFLAGS_WRITE_AC to track reads/writes to the Alignment Check flag. Currently we try to avoid a major binary compatibility break by adding them to the end. This makes some code more complicated. Added a TODO with #6485 to re-number when we're about to do the next major release. Issue: #5505 Fixes: #2103 --- clients/drcachesim/drpt2trace/pt2ir.cpp | 3 --- core/ir/instr_api.h | 22 +++++++++++++++---- core/ir/x86/decode_fast.c | 2 +- core/ir/x86/decode_table.c | 10 +++++++-- core/ir/x86/instr_create_api.h | 4 +++- core/ir/x86/opcode_api.h | 5 ++++- suite/tests/api/ir_x86_0args.h | 5 ++++- .../test_decenc/drdecode_decenc_x86.expect | 2 ++ .../test_decenc/drdecode_decenc_x86_64.expect | 2 ++ .../binutils/test_decenc/test_decenc_x86.asm | 14 ++++++++---- .../test_decenc/test_decenc_x86_64.asm | 13 +++++++---- 11 files changed, 61 insertions(+), 21 deletions(-) diff --git a/clients/drcachesim/drpt2trace/pt2ir.cpp b/clients/drcachesim/drpt2trace/pt2ir.cpp index 45397d96350..4a5ad88f293 100644 --- a/clients/drcachesim/drpt2trace/pt2ir.cpp +++ b/clients/drcachesim/drpt2trace/pt2ir.cpp @@ -388,9 +388,6 @@ pt2ir_t::convert(DR_PARAM_IN const uint8_t *pt_data, DR_PARAM_IN size_t pt_data_ instr_valid = true; instr_set_translation(instr, (app_pc)insn.ip); instr_allocate_raw_bits(drir.get_drcontext(), instr, insn.size); - /* TODO i#2103: Currently, the PT raw data may contain 'STAC' and 'CLAC' - * instructions that are not supported by Dynamorio. - */ if (!instr_valid) { /* The decode() function will not correctly identify the raw bits for * invalid instruction. So we need to set the raw bits of instr manually. diff --git a/core/ir/instr_api.h b/core/ir/instr_api.h index 148190886e9..9fc140d7a36 100644 --- a/core/ir/instr_api.h +++ b/core/ir/instr_api.h @@ -2550,6 +2550,7 @@ instr_is_reg_spill_or_restore(void *drcontext, instr_t *instr, bool *tls DR_PARA # define EFLAGS_READ_OF 0x00000100 /**< Reads OF (Overflow Flag). */ # define EFLAGS_READ_NT 0x00000200 /**< Reads NT (Nested Task). */ # define EFLAGS_READ_RF 0x00000400 /**< Reads RF (Resume Flag). */ + # define EFLAGS_WRITE_CF 0x00000800 /**< Writes CF (Carry Flag). */ # define EFLAGS_WRITE_PF 0x00001000 /**< Writes PF (Parity Flag). */ # define EFLAGS_WRITE_AF 0x00002000 /**< Writes AF (Auxiliary Carry Flag). */ @@ -2562,9 +2563,18 @@ instr_is_reg_spill_or_restore(void *drcontext, instr_t *instr, bool *tls DR_PARA # define EFLAGS_WRITE_NT 0x00100000 /**< Writes NT (Nested Task). */ # define EFLAGS_WRITE_RF 0x00200000 /**< Writes RF (Resume Flag). */ -# define EFLAGS_READ_ALL 0x000007ff /**< Reads all flags. */ +/* TODO i#6485: Re-number the following when a major binary compatibility break + * is more convenient. + */ +/* OP_clac and OP_stac both write the AC flag. Even though we do not have an + * opcode that reads it, we still add EFLAGS_READ_AC for parity. + */ +# define EFLAGS_READ_AC 0x00400000 /**< Reads AC (Alignment Check Flag). */ +# define EFLAGS_WRITE_AC 0x00800000 /**< Writes AC (Alignment Check Flag). */ + +# define EFLAGS_READ_ALL 0x004007ff /**< Reads all flags. */ # define EFLAGS_READ_NON_PRED EFLAGS_READ_ALL /**< Flags not read by predicates. */ -# define EFLAGS_WRITE_ALL 0x003ff800 /**< Writes all flags. */ +# define EFLAGS_WRITE_ALL 0x00bff800 /**< Writes all flags. */ /* 6 most common flags ("arithmetic flags"): CF, PF, AF, ZF, SF, OF */ /** Reads all 6 arithmetic flags (CF, PF, AF, ZF, SF, OF). */ # define EFLAGS_READ_6 0x0000011f @@ -2577,9 +2587,13 @@ instr_is_reg_spill_or_restore(void *drcontext, instr_t *instr, bool *tls DR_PARA # define EFLAGS_WRITE_ARITH EFLAGS_WRITE_6 /** Converts an EFLAGS_WRITE_* value to the corresponding EFLAGS_READ_* value. */ -# define EFLAGS_WRITE_TO_READ(x) ((x) >> 11) +# define EFLAGS_WRITE_TO_READ(x) \ + ((((x) & ((EFLAGS_WRITE_ALL) & ~(EFLAGS_WRITE_AC))) >> 11) | \ + (((x) & (EFLAGS_WRITE_AC)) >> 1)) /** Converts an EFLAGS_READ_* value to the corresponding EFLAGS_WRITE_* value. */ -# define EFLAGS_READ_TO_WRITE(x) ((x) << 11) +# define EFLAGS_READ_TO_WRITE(x) \ + ((((x) & ((EFLAGS_READ_ALL) & ~(EFLAGS_READ_AC))) << 11) | \ + (((x) & (EFLAGS_READ_AC)) << 1)) /** * The actual bits in the eflags register that we care about:\n
diff --git a/core/ir/x86/decode_fast.c b/core/ir/x86/decode_fast.c
index 7662bb15df4..0a2686e3d00 100644
--- a/core/ir/x86/decode_fast.c
+++ b/core/ir/x86/decode_fast.c
@@ -1,5 +1,5 @@
 /* **********************************************************
- * Copyright (c) 2011-2022 Google, Inc.  All rights reserved.
+ * Copyright (c) 2011-2023 Google, Inc.  All rights reserved.
  * Copyright (c) 2001-2010 VMware, Inc.  All rights reserved.
  * **********************************************************/
 
diff --git a/core/ir/x86/decode_table.c b/core/ir/x86/decode_table.c
index 408d529e9f3..0c505cb13ec 100644
--- a/core/ir/x86/decode_table.c
+++ b/core/ir/x86/decode_table.c
@@ -1623,6 +1623,10 @@ const instr_info_t * const op_instr[] =
     /* AVX512 VPOPCNTDQ */
     /* OP_vpopcntd, */ &evex_Wb_extensions[274][0],
     /* OP_vpopcntq, */ &evex_Wb_extensions[274][2],
+
+    /* Supervisor Mode Access Prevention (SMAP) */
+    /* OP_clac */ &rm_extensions[1][2],
+    /* OP_stac */ &rm_extensions[1][3]
 };
 
 
@@ -2079,6 +2083,7 @@ const instr_info_t * const op_instr[] =
 #define fRO   EFLAGS_READ_OF
 #define fRN   EFLAGS_READ_NT
 #define fRR   EFLAGS_READ_RF
+#define fRAC   EFLAGS_READ_AC
 #define fRX   EFLAGS_READ_ALL
 #define fR6   EFLAGS_READ_6
 #define fWC   EFLAGS_WRITE_CF
@@ -2092,6 +2097,7 @@ const instr_info_t * const op_instr[] =
 #define fWO   EFLAGS_WRITE_OF
 #define fWN   EFLAGS_WRITE_NT
 #define fWR   EFLAGS_WRITE_RF
+#define fWAC   EFLAGS_WRITE_AC
 #define fWX   EFLAGS_WRITE_ALL
 #define fW6   EFLAGS_WRITE_6
 /* flags affected by OP_int*
@@ -7019,8 +7025,8 @@ const instr_info_t rm_extensions[][8] = {
     /* XXX i#4013: Treat address in xax as IR memref? */
     {OP_monitor, 0xc80f0171, catUncategorized, "monitor",  xx, xx, axAX, ecx, edx, mrm, x, END_LIST},
     {OP_mwait,   0xc90f0171, catUncategorized, "mwait",  xx, xx, eax, ecx, xx, mrm, x, END_LIST},
-    {INVALID,   0x0f0131, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
-    {INVALID,   0x0f0131, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
+    {OP_clac,   0xca0f0171, catUncategorized, "clac", xx, xx, xx, xx, xx, no, fWAC, NA},
+    {OP_stac,   0xcb0f0171, catUncategorized, "stac", xx, xx, xx, xx, xx, no, fWAC, NA},
     {INVALID,   0x0f0131, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
     {INVALID,   0x0f0131, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
     {INVALID,   0x0f0131, catUncategorized, "(bad)", xx, xx, xx, xx, xx, no, x, NA},
diff --git a/core/ir/x86/instr_create_api.h b/core/ir/x86/instr_create_api.h
index 7afdbee971f..8444dd6b8c8 100644
--- a/core/ir/x86/instr_create_api.h
+++ b/core/ir/x86/instr_create_api.h
@@ -1,5 +1,5 @@
 /* **********************************************************
- * Copyright (c) 2011-2022 Google, Inc.  All rights reserved.
+ * Copyright (c) 2011-2023 Google, Inc.  All rights reserved.
  * Copyright (c) 2002-2010 VMware, Inc.  All rights reserved.
  * **********************************************************/
 
@@ -527,6 +527,8 @@
 #define INSTR_CREATE_vzeroupper(dc) instr_create_0dst_0src((dc), OP_vzeroupper)
 #define INSTR_CREATE_vzeroall(dc) instr_create_0dst_0src((dc), OP_vzeroall)
 #define INSTR_CREATE_xtest(dc) instr_create_0dst_0src((dc), OP_xtest)
+#define INSTR_CREATE_clac(dc) instr_create_0dst_0src((dc), OP_clac)
+#define INSTR_CREATE_stac(dc) instr_create_0dst_0src((dc), OP_stac)
 /** @} */ /* end doxygen group */
 
 /* no destination, 1 source */
diff --git a/core/ir/x86/opcode_api.h b/core/ir/x86/opcode_api.h
index 58bf150d868..4272edd1976 100644
--- a/core/ir/x86/opcode_api.h
+++ b/core/ir/x86/opcode_api.h
@@ -1,5 +1,5 @@
 /* **********************************************************
- * Copyright (c) 2011-2021 Google, Inc.  All rights reserved.
+ * Copyright (c) 2011-2023 Google, Inc.  All rights reserved.
  * Copyright (c) 2000-2010 VMware, Inc.  All rights reserved.
  * **********************************************************/
 
@@ -1614,6 +1614,9 @@ enum {
     /* 1433 */ OP_vpopcntd, /**< IA-32/AMD64 vpopcntd opcode. */
     /* 1434 */ OP_vpopcntq, /**< IA-32/AMD64 vpopcntd opcode. */
 
+    /* Supervisor Mode Access Prevention (SMAP) */
+    /* 1435 */ OP_clac,
+    /* 1436 */ OP_stac,
     OP_AFTER_LAST,
     OP_FIRST = OP_add,           /**< First real opcode. */
     OP_LAST = OP_AFTER_LAST - 1, /**< Last real opcode. */
diff --git a/suite/tests/api/ir_x86_0args.h b/suite/tests/api/ir_x86_0args.h
index 6c98022acc2..34a544ab536 100644
--- a/suite/tests/api/ir_x86_0args.h
+++ b/suite/tests/api/ir_x86_0args.h
@@ -1,5 +1,5 @@
 /* **********************************************************
- * Copyright (c) 2011-2016 Google, Inc.  All rights reserved.
+ * Copyright (c) 2011-2023 Google, Inc.  All rights reserved.
  * Copyright (c) 2008-2010 VMware, Inc.  All rights reserved.
  * **********************************************************/
 
@@ -197,3 +197,6 @@ OPCODE(xtest, xtest, xtest, 0)
 
 OPCODE(rdpkru, rdpkru, rdpkru, 0)
 OPCODE(wrpkru, wrpkru, wrpkru, 0)
+
+OPCODE(clac, clac, clac, 0)
+OPCODE(stac, stac, stac, 0)
diff --git a/third_party/binutils/test_decenc/drdecode_decenc_x86.expect b/third_party/binutils/test_decenc/drdecode_decenc_x86.expect
index c9059243d82..1801e89ca5f 100644
--- a/third_party/binutils/test_decenc/drdecode_decenc_x86.expect
+++ b/third_party/binutils/test_decenc/drdecode_decenc_x86.expect
@@ -138762,6 +138762,8 @@ test_s:
  7b 00 00 00
  62 f2 7d 29 91 b4 f5 vpgatherqd 0x0000007b(%ebp,%ymm6,8), %ymm6 {%k1} {%k1}
  7b 00 00 00
+ 0f 01 ca             clac
+ 0f 01 cb             stac
  90                   nop
  90                   nop
  90                   nop
diff --git a/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect b/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect
index 2b19bc9c36e..04fa5247dd0 100644
--- a/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect
+++ b/third_party/binutils/test_decenc/drdecode_decenc_x86_64.expect
@@ -102826,6 +102826,8 @@ test_x86_64_s:
  c4 e2 59 53 11       vpdpwssds %xmm4, (%rcx), %xmm2
  62 b2 5d 08 53 d6    vpdpwssds %xmm4, %xmm22, %xmm2 {%k0}
  62 d2 5d 08 50 d4    vpdpbusd %xmm4, %xmm12, %xmm2 {%k0}
+ 0f 01 ca             clac
+ 0f 01 cb             stac
  90                   nop
  90                   nop
  90                   nop
diff --git a/third_party/binutils/test_decenc/test_decenc_x86.asm b/third_party/binutils/test_decenc/test_decenc_x86.asm
index 1aa50c20c99..1a0ee210522 100644
--- a/third_party/binutils/test_decenc/test_decenc_x86.asm
+++ b/third_party/binutils/test_decenc/test_decenc_x86.asm
@@ -298,10 +298,6 @@ GLOBAL_LABEL(FUNCNAME:)
 
         /* arch_13.s */
 
-        /* clac, CPL 0 instruction. */
-        /* RAW(0f) RAW(01) RAW(ca) */
-        /* stac, CPL 0 instruction. */
-        /* RAW(0f) RAW(01) RAW(cb) */
         RAW(66) RAW(0f) RAW(38) RAW(f6) RAW(ca)
         RAW(f3) RAW(0f) RAW(38) RAW(f6) RAW(ca)
         RAW(0f) RAW(c7) RAW(f8)
@@ -139592,6 +139588,16 @@ GLOBAL_LABEL(FUNCNAME:)
         RAW(7b) RAW(00) RAW(00) RAW(00)
         RAW(62) RAW(f2) RAW(7d) RAW(29) RAW(91) RAW(b4) RAW(f5)
         RAW(7b) RAW(00) RAW(00) RAW(00)
+
+        /* TODO i#5505: Move the following back under
+         * arch_13.s in a separate PR to keep the huge
+         * diff isolated from PR #6484.
+         */
+        /* clac, CPL 0 instruction. */
+        RAW(0f) RAW(01) RAW(ca)
+        /* stac, CPL 0 instruction. */
+        RAW(0f) RAW(01) RAW(cb)
+
         END_OF_SUBTEST_MARKER
 
 #ifdef DISABLED_UNTIL_BUG_3577_IS_FIXED
diff --git a/third_party/binutils/test_decenc/test_decenc_x86_64.asm b/third_party/binutils/test_decenc/test_decenc_x86_64.asm
index d2be83ac5e0..3527f297855 100644
--- a/third_party/binutils/test_decenc/test_decenc_x86_64.asm
+++ b/third_party/binutils/test_decenc/test_decenc_x86_64.asm
@@ -220,10 +220,6 @@ GLOBAL_LABEL(FUNCNAME:)
 
         /* x86_64_arch_3.s */
 
-        /* clac, CPL 0 instruction. */
-        /* RAW(0f) RAW(01) RAW(ca) */
-        /* stac, CPL 0 instruction. */
-        /* RAW(0f) RAW(01) RAW(cb) */
         RAW(66) RAW(0f) RAW(38) RAW(f6) RAW(ca)
         RAW(f3) RAW(0f) RAW(38) RAW(f6) RAW(ca)
         RAW(0f) RAW(c7) RAW(f8)
@@ -106655,5 +106651,14 @@ GLOBAL_LABEL(FUNCNAME:)
         RAW(62) RAW(b2) RAW(5d) RAW(08) RAW(53) RAW(d6)
         RAW(62) RAW(d2) RAW(5d) RAW(08) RAW(50) RAW(d4)
 
+        /* TODO i#5505: Move the following back under
+         * x86_64_arch_3.s in a separate PR to keep the huge
+         * diff isolated from PR #6484.
+         */
+        /* clac, CPL 0 instruction. */
+        RAW(0f) RAW(01) RAW(ca)
+        /* stac, CPL 0 instruction. */
+        RAW(0f) RAW(01) RAW(cb)
+
         END_OF_FUNCTION_MARKER
 END_FUNC(FUNCNAME)