1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-24 14:30:43 -08:00
emacs/mps/code/prmctest.c
Helmut Eller 698a403d32 Recognize some Amd64 instruction patterns
* mps/code/prmci6.c (IsSimpleMov): Actually do something.
(IsRexPrefix, DecodeSimpleMov, RexR, RexB, RexX, DecodeDisp32)
(SignedInsElt, RegValue, DecodeModRM, DecodeSIB, DecodeCB): New helpers.
* mps/code/prmctest.c: New file.
* mps/code/comm.gmk: Add prmctest.
* mps/tool/testcases.txt: Here too.
2025-10-11 20:33:40 +02:00

276 lines
8.2 KiB
C

/* prmctest.c: TEST INSTRUCTION EMULATION
*
* $Id$
* Copyright (c) 2001-2020 Ravenbrook Limited. See end of file for license.
*/
#include "prmc.h"
#include "prmcix.h"
#include "testlib.h"
#include <stdio.h>
#if defined MPS_PF_LII6GC && !defined CONFIG_PF_ANSI
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define VERBOSE 0
#pragma GCC diagnostic ignored "-Wpedantic"
static void **asmcode(int) __attribute__((optimize(0)));
static void **asmcode(int f)
{
static void *labels[] = {&&start, &&end};
if (f)
return labels;
start:
__asm__(
"mov (%rax),%rax\n"
"mov (%rcx),%r15\n"
"mov (%r12),%rdx\n"
"mov (%r13),%r8\n"
"mov mem(%rip),%r8\n"
"mov 0x8(%r14),%rsi\n"
"mov 0xabcdef(%rax),%rax\n"
"mov 0x1(%r12),%r8\n"
"mov (%rax,%rdx,8),%rsi\n"
"mov (%r8,%r9,1),%r8\n"
"mov (%r8,%r12,2),%r8\n"
"mov 0x10(%rax,%rdx,8),%rsi\n"
/* TODO: "movq (%rax),%xmm1\n */
);
end:
goto start;
}
static mps_word_t mem[8];
static void testMovRm64ToR64(MutatorContext ctx, size_t srcreg,
size_t disp, size_t scale, size_t idxreg,
size_t dstreg, size_t len)
{
mps_word_t *gregs = (void *)ctx->ucontext->uc_mcontext.gregs;
siginfo_t *siginfo = ctx->info;
size_t ip0 = gregs[REG_RIP];
const size_t some_value = (size_t)rnd_addr();
memset(gregs, 0, sizeof(ctx->ucontext->uc_mcontext.gregs));
memset(mem, 0, sizeof(mem));
gregs[REG_RIP] = ip0;
if (scale) {
assert(idxreg != srcreg);
gregs[idxreg] = rnd();
}
if (srcreg != REG_RIP) {
gregs[srcreg]
= (size_t)((Byte *)mem - disp - gregs[idxreg] * scale);
}
siginfo->si_addr = mem;
mem[0] = some_value;
if (!(dstreg == srcreg || (scale && dstreg == idxreg)))
assert(gregs[dstreg] == 0);
assert(gregs[dstreg] != some_value);
assert(MutatorContextCanStepInstruction(ctx));
assert(MutatorContextStepInstruction(ctx) == MPS_RES_OK);
assert(gregs[dstreg] == some_value);
assert(mem[0] == some_value);
assert(gregs[REG_RIP] - ip0 == len);
}
struct regname {
size_t num;
const char *name;
};
static struct regname const gprs[] = {
{REG_R8, "%r8"}, {REG_R9, "%r9"}, {REG_R10, "%r10"},
{REG_R11, "%r11"}, {REG_R12, "%r12"}, {REG_R13, "%r13"},
{REG_R14, "%r14"}, {REG_R15, "%r15"}, {REG_RDI, "%rdi"},
{REG_RSI, "%rsi"}, {REG_RBP, "%rbp"}, {REG_RBX, "%rbx"},
{REG_RDX, "%rdx"}, {REG_RAX, "%rax"}, {REG_RCX, "%rcx"},
{REG_RSP, "%rsp"}, {REG_RIP, "%rip"},
};
static const char *regname(size_t regnum)
{
size_t i;
for (i = 0; i < NELEMS(gprs); i++)
if (gprs[i].num == regnum)
return gprs[i].name;
assert(0);
}
static char *open_tmpfile(const char *mode, FILE **f)
{
static const char *template = "/tmp/prmc-XXXXXX";
char buf[32];
int fd;
strcpy(buf, template);
fd = mkstemp(buf);
assert(fd != -1);
*f = fdopen(fd, mode);
assert(*f != NULL);
return strdup(buf);
}
static Byte *genCode(const char *txt, size_t *len)
{
FILE *a, *o, *s;
char *aname = open_tmpfile("wb", &a);
char *oname = open_tmpfile("rb", &o);
char *sname = open_tmpfile("rb", &s);
char cmd[256];
size_t size, offset;
Byte *code;
if (VERBOSE)
fprintf(stderr, "%s", txt);
fprintf(a, "%s", txt);
fflush(a);
snprintf(cmd, sizeof cmd,
"as %s -o %s"
" && objdump -h %s "
" | awk '/text/ "
" { print $2 \" size: \" $3 \" offset: \" $6 }'"
" >%s",
aname, oname, oname, sname);
assert(system(cmd) == 0);
assert(fscanf(s, ".text size: %lx offset: %lx\n", &size, &offset)
== 2);
assert(fseek(o, offset, SEEK_SET) == 0);
code = malloc(size);
assert(code);
assert(fread(code, 1, size, o) == size);
remove(aname);
remove(oname);
remove(sname);
free(aname);
free(oname);
free(sname);
fclose(a);
fclose(o);
fclose(s);
*len = size;
return code;
}
static void genTest(MutatorContext ctx, size_t base, int32_t disp,
size_t scale, size_t index, size_t dst)
{
char buf[1024];
size_t len;
Byte *code;
if (scale)
snprintf(buf, sizeof buf, "mov %d(%s,%s,%ld),%s\n", disp,
regname(base), regname(index), scale, regname(dst));
else
snprintf(buf, sizeof buf, "mov %d(%s),%s\n", disp, regname(base),
regname(dst));
code = genCode(buf, &len);
ctx->ucontext->uc_mcontext.gregs[REG_RIP] = (size_t)code;
testMovRm64ToR64(ctx, base, disp, scale, index, dst, len);
}
static int32_t displacemts[] = {0, -1, 255, -256, 256, 0xabcdef01};
static Bool filterRandomly(double probability)
{
return probability < rnd_double();
}
static void genTests(MutatorContext ctx)
{
const size_t NSCALEBITS = 3;
const size_t NTESTS = NELEMS(gprs) * (NSCALEBITS + 1) * NELEMS(gprs)
* NELEMS(gprs) * NELEMS(displacemts);
const double probability = (double)500 / NTESTS;
size_t b, sbits, i, d, e;
for (b = 0; b < NELEMS(gprs); b++)
for (sbits = 0; sbits < NSCALEBITS + 1; sbits++)
for (i = 0; i < NELEMS(gprs); i++)
for (d = 0; d < NELEMS(gprs); d++) {
for (e = 0; e < NELEMS(displacemts); e++) {
size_t base = gprs[b].num;
size_t index = gprs[i].num;
size_t dst = gprs[d].num;
int32_t disp = displacemts[e];
size_t scale = sbits ? (1 << sbits) : 0;
if (dst == REG_RIP || (!sbits && i)
|| (sbits && base == index) || index == REG_RSP
|| base == REG_RIP || index == REG_RIP
|| filterRandomly(probability))
continue;
genTest(ctx, base, disp, scale, index, dst);
}
}
}
static void runTests(void)
{
siginfo_t siginfo;
struct ucontext_t ucontext;
struct MutatorContextStruct ctx;
MutatorContextInitFault(&ctx, &siginfo, &ucontext);
ucontext.uc_mcontext.gregs[REG_RIP] = (size_t)(asmcode(1)[0]);
testMovRm64ToR64(&ctx, REG_RAX, 0, 0, 0, REG_RAX, 3);
testMovRm64ToR64(&ctx, REG_RCX, 0, 0, 0, REG_R15, 3);
testMovRm64ToR64(&ctx, REG_R12, 0, 0, 0, REG_RDX, 4);
testMovRm64ToR64(&ctx, REG_R13, 0, 0, 0, REG_R8, 4);
testMovRm64ToR64(&ctx, REG_RIP, 8, 0, 0, REG_R8, 7);
testMovRm64ToR64(&ctx, REG_R14, 8, 0, 0, REG_RSI, 4);
testMovRm64ToR64(&ctx, REG_RAX, 0xabcdef, 0, 0, REG_RAX, 7);
testMovRm64ToR64(&ctx, REG_R12, 0x1, 0, 0, REG_R8, 5);
testMovRm64ToR64(&ctx, REG_RAX, 0, 8, REG_RDX, REG_RSI, 4);
testMovRm64ToR64(&ctx, REG_R8, 0, 1, REG_R9, REG_R8, 4);
testMovRm64ToR64(&ctx, REG_R8, 0, 2, REG_R12, REG_R8, 4);
testMovRm64ToR64(&ctx, REG_RAX, 0x10, 8, REG_RDX, REG_RSI, 5);
genTests(&ctx);
}
#endif
int main(int argc, char *argv[])
{
testlib_init(argc, argv);
#if defined MPS_PF_LII6GC && !defined CONFIG_PF_ANSI
runTests();
#endif
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2020 Ravenbrook Limited <https://www.ravenbrook.com/>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/