From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Jan Beulich <jbeulich@suse.com>
Cc: "Andrew Cooper" <andrew.cooper3@citrix.com>,
"Roger Pau Monné" <roger@xenproject.org>,
"Teddy Astie" <teddy.astie@vates.tech>,
Xen-devel <xen-devel@lists.xenproject.org>
Subject: Re: [PATCH v3 2/5] tests/x86: Introduce a userspace test harness for x86_decode_lite()
Date: Tue, 4 Aug 2026 20:37:15 +0100 [thread overview]
Message-ID: <21d3fae8-e9b0-4c8a-a7b9-483a0257e44e@citrix.com> (raw)
In-Reply-To: <dd065a33-0105-4527-92f5-f3f127422ee6@suse.com>
On 03/08/2026 5:03 pm, Jan Beulich wrote:
> On 03.08.2026 09:20, Andrew Cooper wrote:
>> --- /dev/null
>> +++ b/tools/tests/x86-decode-lite/insns.S
>> @@ -0,0 +1,703 @@
>> +#include "macro-magic.h"
>> +
>> + .code64
>> +
>> + .allow_index_reg
>> +
>> + .text
>> +
>> +DECL(tests_rel0)
>> +modrm:
>> + /* Mod=0, Reg=0, RM {0..f} */
>> + _ add %al, (%rax)
>> + _ add %al, (%rcx)
>> + _ add %al, (%rdx)
>> + _ add %al, (%rbx)
>> + _ add %al, (%rsp) /* SIB */
>> + /*add %al, (%rbp) RIP --> tests_rel4 */
>> + _ add %al, (%rsi)
>> + _ add %al, (%rdi)
>> + _ add %al, (%r8)
>> + _ add %al, (%r9)
>> + _ add %al, (%r10)
>> + _ add %al, (%r11)
>> + _ add %al, (%r12) /* SIB */
>> + /*add %al, (%r13) RIP --> tests_rel4 */
>> + _ add %al, (%r14)
>> + _ add %al, (%r15)
>> +
>> + /* Mod=1, Reg=0, RM {0..f} */
>> + _ add %al, 0x01(%rax)
>> + _ add %al, 0x01(%rcx)
>> + _ add %al, 0x01(%rdx)
>> + _ add %al, 0x01(%rbx)
>> + _ add %al, 0x01(%rsp) /* SIB */
>> + _ add %al, 0x01(%rbp)
>> + _ add %al, 0x01(%rsi)
>> + _ add %al, 0x01(%rdi)
>> + _ add %al, 0x01(%r8)
>> + _ add %al, 0x01(%r9)
>> + _ add %al, 0x01(%r10)
>> + _ add %al, 0x01(%r11)
>> + _ add %al, 0x01(%r12) /* SIB */
>> + _ add %al, 0x01(%r13)
>> + _ add %al, 0x01(%r14)
>> + _ add %al, 0x01(%r15)
>> +
>> + /* Mod=2, Reg=0, RM {0..f} */
>> + _ add %al, 0x7f000001(%rax)
>> + _ add %al, 0x7f000001(%rcx)
>> + _ add %al, 0x7f000001(%rdx)
>> + _ add %al, 0x7f000001(%rbx)
>> + _ add %al, 0x7f000001(%rsp) /* SIB */
>> + _ add %al, 0x7f000001(%rbp)
>> + _ add %al, 0x7f000001(%rsi)
>> + _ add %al, 0x7f000001(%rdi)
>> + _ add %al, 0x7f000001(%r8)
>> + _ add %al, 0x7f000001(%r9)
>> + _ add %al, 0x7f000001(%r10)
>> + _ add %al, 0x7f000001(%r11)
>> + _ add %al, 0x7f000001(%r12) /* SIB */
>> + _ add %al, 0x7f000001(%r13)
>> + _ add %al, 0x7f000001(%r14)
>> + _ add %al, 0x7f000001(%r15)
>> +
>> + /* Mod=3, Reg=0, RM {0..f} */
>> + _ add %al, %al
>> + _ add %al, %cl
>> + _ add %al, %dl
>> + _ add %al, %bl
>> + _ add %al, %ah
>> + _ add %al, %ch
>> + _ add %al, %dh
>> + _ add %al, %dl
> Perhaps also include %bpl, %sil, and %dil?
They're not relevant to this test, and interfere with the intentional
pattern set up.
>
>> +onebyte_row_9x:
>> + _ nop
>> + _ pause
>> + _ xchg %ax, %ax
>> + _ xchg %eax, %eax
>> + _ xchg %rax, %rax
>> + _ rex.w xchg %rax, %rax
>> + _ cltq
>> + _ cqto
>> + _ wait
>> + _ pushf
>> + _ popf
>> + _ sahf
>> + _ lahf
>> +
>> +onebyte_row_ax:
> May I suggest onebyte_row_Ax?
Ok.
>
>> +DECL(tests_rel1)
>> +disp8:
>> +1:
>> + _ jo 1b
>> + _ jno 1b
>> + _ jb 1b
>> + _ jae 1b
>> + _ je 1b
>> + _ jne 1b
>> + _ jbe 1b
>> + _ ja 1b
>> + _ js 1b
>> + _ jns 1b
>> + _ jp 1b
>> + _ jnp 1b
>> + _ jl 1b
>> + _ jge 1b
>> + _ jle 1b
>> + _ jg 1b
>> + _ jmp 1b
>> +
>> +disp8_rex:
>> + _ rex.w jo 1b
>> + _ rex.w jno 1b
>> + _ rex.w jb 1b
>> + _ rex.w jae 1b
>> + _ rex.w je 1b
>> + _ rex.w jne 1b
>> + _ rex.w jbe 1b
>> + _ rex.w ja 1b
>> + _ rex.w js 1b
>> + _ rex.w jns 1b
>> + _ rex.w jp 1b
>> + _ rex.w jnp 1b
>> + _ rex.w jl 1b
>> + _ rex.w jge 1b
>> + _ rex.w jle 1b
>> + _ rex.w jg 1b
>> + _ rex.w jmp 1b
>> +END(tests_rel1)
> What's the idea behind the separate REX.W testing?
Testing osize handling vs Imm8/Imm.
> It almost suggests that
> tests with an operand size prefix also may want adding. Except that's
> difficult, because of ...
>
>> +DECL(tests_rel4)
>> +disp32:
>> + _ call other_section
>> + _ jmp other_section
>> + _ jo other_section
>> + _ jno other_section
>> + _ jb other_section
>> + _ jae other_section
>> + _ je other_section
>> + _ jne other_section
>> + _ jbe other_section
>> + _ ja other_section
>> + _ js other_section
>> + _ jns other_section
>> + _ jp other_section
>> + _ jnp other_section
>> + _ jl other_section
>> + _ jge other_section
>> + _ jle other_section
>> + _ jg other_section
>> + _ xbegin other_section
>> +
>> +disp32_rex:
>> + _ rex.w call other_section
>> + _ rex.w jmp other_section
>> + _ rex.w jo other_section
>> + _ rex.w jno other_section
>> + _ rex.w jb other_section
>> + _ rex.w jae other_section
>> + _ rex.w je other_section
>> + _ rex.w jne other_section
>> + _ rex.w jbe other_section
>> + _ rex.w ja other_section
>> + _ rex.w js other_section
>> + _ rex.w jns other_section
>> + _ rex.w jp other_section
>> + _ rex.w jnp other_section
>> + _ rex.w jl other_section
>> + _ rex.w jge other_section
>> + _ rex.w jle other_section
>> + _ rex.w jg other_section
>> + _ rex.w xbegin other_section
> ... vendor differences here. Perhaps the decoder itself would better
> reject handling of operand-size-prefixed branches.
Excluding 66-prefix is easy, but excluding rex.w on jumps is hard and
would require extra logic.
>> +opsize_branch: /* 66-prefixed branches are decoded differently by vendors */
>> + _ data16 call other_section
>> + _ data16 jmp other_section
>> + _ data16 jo other_section
>> + _ data16 jno other_section
>> + _ data16 jb other_section
>> + _ data16 jae other_section
>> + _ data16 je other_section
>> + _ data16 jne other_section
>> + _ data16 jbe other_section
>> + _ data16 ja other_section
>> + _ data16 js other_section
>> + _ data16 jns other_section
>> + _ data16 jp other_section
>> + _ data16 jnp other_section
>> + _ data16 jl other_section
>> + _ data16 jge other_section
>> + _ data16 jle other_section
>> + _ data16 jg other_section
>> + _ data16 xbegin other_section
> Oh, you even cover the case here. For XBEGIN, however, this can only be pure
> guesswork as to AMD behavior, I suppose.
Remember that RTM is available on Zen2 if you know which chickenbits to
clobber.
I've not tried. I expect it's more likely that they behave consistently
than differently.
> I also don't see how you force which form you want.
Binutils always produces AMD behaviour. (As far as I can see.)
This is in the negative-tests section, which confirms that
x86_decode_lite() rejects the byte pattern.
If Binutils changes behaviour, the test will start failing.
>
>> --- /dev/null
>> +++ b/tools/tests/x86-decode-lite/main.c
>> @@ -0,0 +1,111 @@
>> +/*
>> + * Userspace test harness for x86_decode_lite().
>> + */
>> +#include <stdio.h>
>> +
>> +#include "x86-emulate.h"
>> +
>> +static unsigned int nr_failures;
>> +#define fail(t, fmt, ...) \
>> +({ \
>> + const unsigned char *insn = (t)->ip; \
>> + \
>> + nr_failures++; \
>> + \
>> + (void)printf(" Fail '%s' [%02x", (t)->name, *insn); \
>> + for ( unsigned int i = 1; i < (t)->len; i++ ) \
>> + printf(" %02x", insn[i]); \
>> + printf("]\n"); \
>> + \
>> + (void)printf(fmt, ##__VA_ARGS__); \
>> +})
>> +
>> +struct test {
>> + const char *name;
>> + void *ip;
>> + unsigned long len;
>> +};
>> +
>> +extern const struct test
>> +/* Defined in insns.S, ends with sentinel */
>> + tests_rel0[], /* No relocatable entry */
>> + tests_rel1[], /* disp8 */
>> + tests_rel4[], /* disp32 or RIP-relative */
>> + tests_unsup[]; /* Unsupported instructions */
>> +
>> +static inline void run_tests(const struct test *tests, unsigned int rel_sz)
>> +{
>> + printf("Test rel%u\n", rel_sz);
>> +
>> + for ( unsigned int i = 0; tests[i].name; ++i )
>> + {
>> + const struct test *t = &tests[i];
>> + x86_decode_lite_t r;
>> +
>> + /*
>> + * Don't end strictly at t->len. This provides better diagnostics if
>> + * too many bytes end up getting consumed.
>> + */
>> + r = x86_decode_lite(t->ip, t->ip + /* t->len */ 20);
> For the excess bytes to at least be legitimate to access (not causing UB),
> shouldn't finish_arr emit enough filler bytes?
finish_arr is the wrong place, but I've folded in:
diff --git a/tools/tests/x86-decode-lite/insns.S b/tools/tests/x86-decode-lite/insns.S
index e52c2934c8d8..dc017016b2d2 100644
--- a/tools/tests/x86-decode-lite/insns.S
+++ b/tools/tests/x86-decode-lite/insns.S
@@ -695,6 +695,13 @@ unsup_insn: /* Instructions that would complicated decode, or shouldn't be used
END(tests_unsup)
+ /*
+ * For improved diagnostics, we allow some overreading of the
+ * instruction under test. Ensure there are good bytes to read.
+ */
+overread_padding:
+ .skip 20
+
/* This is here to cause jmps to use their disp32 form. */
.section .text.other_section, "ax", @progbits
other_section:
>
>> --- /dev/null
>> +++ b/tools/tests/x86-decode-lite/x86-emulate.h
>> @@ -0,0 +1,27 @@
>> +#ifndef X86_EMULATE_H
>> +#define X86_EMULATE_H
>> +
>> +#include <assert.h>
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +
>> +#include <xen/asm/x86-defns.h>
>> +#include <xen/asm/x86-vendors.h>
>> +
>> +#include <xen-tools/common-macros.h>
>> +
>> +#define ASSERT assert
>> +
>> +#define printk(...)
>> +
>> +#define likely
>> +#define unlikely
>> +#define cf_check
>> +#define init_or_livepatch
>> +#define init_or_livepatch_const
>> +
>> +#include "x86_emulate/x86_emulate.h"
> Why does this end up being needed?
Well, this for starters:
main.c: In function ‘run_tests’:
main.c:43:9: error: unknown type name ‘x86_decode_lite_t’
43 | x86_decode_lite_t r;
| ^~~~~~~~~~~~~~~~~
main.c:49:13: error: implicit declaration of function ‘x86_decode_lite’ [-Werror=implicit-function-declaration]
49 | r = x86_decode_lite(t->ip, t->ip + /* t->len */ 20);
| ^~~~~~~~~~~~~~~
~Andrew
next prev parent reply other threads:[~2026-08-04 19:37 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 7:20 [PATCH v3 0/5] x86/alternatives: Adjust all insn-relative fields Andrew Cooper
2026-08-03 7:20 ` [PATCH v3 1/5] x86/emul: Introduce x86_decode_lite() Andrew Cooper
2026-08-03 9:14 ` Andrew Cooper
2026-08-03 15:26 ` Jan Beulich
2026-08-04 15:39 ` Jan Beulich
2026-08-04 18:56 ` Andrew Cooper
2026-08-05 6:24 ` Jan Beulich
2026-08-03 7:20 ` [PATCH v3 2/5] tests/x86: Introduce a userspace test harness for x86_decode_lite() Andrew Cooper
2026-08-03 16:03 ` Jan Beulich
2026-08-04 19:37 ` Andrew Cooper [this message]
2026-08-05 6:45 ` Jan Beulich
2026-08-03 7:20 ` [PATCH v3 3/5] x86/alternative: Walk all replacements during self tests Andrew Cooper
2026-08-03 7:20 ` [PATCH v3 4/5] x86/alternative: Relocate all insn-relative fields Andrew Cooper
2026-08-03 7:20 ` [PATCH v3 5/5] x86/spec-ctrl: Introduce and use DO_COND_BHB_SEQ Andrew Cooper
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=21d3fae8-e9b0-4c8a-a7b9-483a0257e44e@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=jbeulich@suse.com \
--cc=roger@xenproject.org \
--cc=teddy.astie@vates.tech \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.