mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-16 09:14:18 +00:00
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.
This commit is contained in:
parent
51e1001a70
commit
698a403d32
4 changed files with 464 additions and 11 deletions
|
|
@ -297,6 +297,7 @@ TEST_TARGETS=\
|
|||
mv2test$(EXEEXT) \
|
||||
nailboardtest$(EXEEXT) \
|
||||
poolncv$(EXEEXT) \
|
||||
prmctest$(EXEEXT) \
|
||||
qs$(EXEEXT) \
|
||||
sacss$(EXEEXT) \
|
||||
segsmss$(EXEEXT) \
|
||||
|
|
@ -568,6 +569,9 @@ $(PFM)/$(VARIETY)/nailboardtest$(EXEEXT): $(PFM)/$(VARIETY)/nailboardtest.o \
|
|||
$(PFM)/$(VARIETY)/poolncv$(EXEEXT): $(PFM)/$(VARIETY)/poolncv.o \
|
||||
$(POOLNOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/prmctest$(EXEEXT): $(PFM)/$(VARIETY)/prmctest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/qs$(EXEEXT): $(PFM)/$(VARIETY)/qs.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
|
|
|
|||
|
|
@ -34,25 +34,197 @@ SRCID(prmci6, "$Id$");
|
|||
#error "prmci6.c is specific to MPS_ARCH_I6"
|
||||
#endif
|
||||
|
||||
/* DecodeCB -- Decode an Intel x86 control byte into Hi, Medium & Low
|
||||
fields */
|
||||
|
||||
static Bool IsSimpleMov(Size *inslenReturn,
|
||||
MRef *srcReturn,
|
||||
MRef *destReturn,
|
||||
MutatorContext context)
|
||||
static void DecodeCB(size_t *hReturn, size_t *mReturn, size_t *lReturn,
|
||||
Byte op)
|
||||
{
|
||||
*lReturn = op & 7;
|
||||
*mReturn = (op >> 3) & 7;
|
||||
*hReturn = (op >> 6) & 3;
|
||||
}
|
||||
|
||||
|
||||
/* DecodeSIB -- Decode a Scale Index Base byte for an Intel x86
|
||||
instruction */
|
||||
|
||||
static void DecodeSIB(size_t *sReturn, size_t *iReturn, size_t *bReturn,
|
||||
Byte op)
|
||||
{
|
||||
DecodeCB(sReturn, iReturn, bReturn, op);
|
||||
}
|
||||
|
||||
|
||||
/* DecodeModRM -- Decode a ModR/M byte for an Intel x86 instruction */
|
||||
|
||||
static void DecodeModRM(size_t *modReturn, size_t *rReturn,
|
||||
size_t *mReturn, Byte op)
|
||||
{
|
||||
DecodeCB(modReturn, rReturn, mReturn, op);
|
||||
}
|
||||
|
||||
|
||||
/* RegValue -- Return the value of a machine register from a context */
|
||||
|
||||
static Word RegValue(MutatorContext context, size_t regnum)
|
||||
{
|
||||
MRef addr;
|
||||
|
||||
addr = Prmci6AddressHoldingReg(context, regnum);
|
||||
return *addr;
|
||||
}
|
||||
|
||||
|
||||
/* Return a byte element of an instruction vector as a
|
||||
* Word value, with sign extension
|
||||
*/
|
||||
static Word SignedInsElt(Byte insvec[], Count i)
|
||||
{
|
||||
signed char eltb;
|
||||
|
||||
eltb = ((signed char *)insvec)[i];
|
||||
return (Word)eltb;
|
||||
}
|
||||
|
||||
static signed DecodeDisp32(Byte *bytes)
|
||||
{
|
||||
unsigned r = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < 4; i++) r |= bytes[i] << (i * 8);
|
||||
return r;
|
||||
}
|
||||
|
||||
static Word RexR(Byte rex) { return (rex >> 2) & 1; }
|
||||
static Word RexB(Byte rex) { return (rex >> 0) & 1; }
|
||||
static Word RexX(Byte rex) { return (rex >> 1) & 1; }
|
||||
|
||||
static Bool DecodeSimpleMov(size_t *regnumReturn, MRef *memReturn,
|
||||
Size *inslenReturn, MutatorContext context,
|
||||
Byte insvec[])
|
||||
{
|
||||
Byte rex = insvec[0];
|
||||
Byte modRM = insvec[2];
|
||||
Word base, disp = 0, scaled_index = 0;
|
||||
size_t mod, reg, rm;
|
||||
DecodeModRM(&mod, ®, &rm, modRM);
|
||||
switch (mod) {
|
||||
case 0:
|
||||
switch (rm) {
|
||||
default:
|
||||
*inslenReturn = 3;
|
||||
base = RegValue(context, rm | (RexB(rex) << 3));
|
||||
goto done;
|
||||
|
||||
case 4:
|
||||
*inslenReturn = 4;
|
||||
goto decode_sib;
|
||||
|
||||
case 5: {
|
||||
Word rip = (Word)insvec;
|
||||
*inslenReturn = 7;
|
||||
base = rip + *inslenReturn;
|
||||
disp = DecodeDisp32(insvec + 3);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
case 1:
|
||||
switch (rm) {
|
||||
default:
|
||||
*inslenReturn = 4;
|
||||
disp = SignedInsElt(insvec, 3);
|
||||
base = RegValue(context, rm | (RexB(rex) << 3));
|
||||
goto done;
|
||||
|
||||
case 4:
|
||||
*inslenReturn = 5;
|
||||
disp = SignedInsElt(insvec, 4);
|
||||
goto decode_sib;
|
||||
}
|
||||
|
||||
case 2:
|
||||
switch (rm) {
|
||||
default:
|
||||
*inslenReturn = 7;
|
||||
disp = DecodeDisp32(insvec + 3);
|
||||
base = RegValue(context, rm | (RexB(rex) << 3));
|
||||
goto done;
|
||||
|
||||
case 4:
|
||||
*inslenReturn = 8;
|
||||
disp = DecodeDisp32(insvec + 4);
|
||||
goto decode_sib;
|
||||
}
|
||||
|
||||
case 3:
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
NOTREACHED;
|
||||
}
|
||||
NOTREACHED;
|
||||
|
||||
decode_sib: {
|
||||
size_t s, i, b;
|
||||
DecodeSIB(&s, &i, &b, insvec[3]);
|
||||
base = RegValue(context, b | (RexB(rex) << 3));
|
||||
if (i == 4 && !RexX(rex))
|
||||
scaled_index = 0;
|
||||
else
|
||||
scaled_index = (RegValue(context, i | RexX(rex) << 3) << s);
|
||||
}
|
||||
|
||||
done:
|
||||
*memReturn = (MRef)(base + disp + scaled_index);
|
||||
*regnumReturn = reg | (RexR(rex) << 3);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static Bool IsRexPrefix(Byte b) { return (b >> 4) == 0x4; }
|
||||
|
||||
static Bool IsSimpleMov(Size *inslenReturn, MRef *srcReturn,
|
||||
MRef *destReturn, MutatorContext context)
|
||||
{
|
||||
Byte *insvec;
|
||||
size_t regnum;
|
||||
MRef mem;
|
||||
MRef faultmem;
|
||||
|
||||
Prmci6DecodeFaultContext(&faultmem, &insvec, context);
|
||||
/* Unimplemented */
|
||||
UNUSED(inslenReturn);
|
||||
UNUSED(srcReturn);
|
||||
UNUSED(destReturn);
|
||||
|
||||
if (IsRexPrefix(insvec[0])) {
|
||||
switch (insvec[1]) {
|
||||
case 0x8b: /* MOV r64, r/m64 */
|
||||
if (DecodeSimpleMov(®num, &mem, inslenReturn, context,
|
||||
insvec)) {
|
||||
AVER(faultmem == mem); /* Ensure computed address
|
||||
matches exception */
|
||||
*srcReturn = mem;
|
||||
*destReturn = Prmci6AddressHoldingReg(context, regnum);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
|
||||
case 0x89: /* MOV r/m64, r64 */
|
||||
if (DecodeSimpleMov(®num, &mem, inslenReturn, context,
|
||||
insvec)) {
|
||||
AVER(faultmem == mem); /* Ensure computed address
|
||||
matches exception */
|
||||
*destReturn = mem;
|
||||
*srcReturn = Prmci6AddressHoldingReg(context, regnum);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Bool MutatorContextCanStepInstruction(MutatorContext context)
|
||||
{
|
||||
Size inslen;
|
||||
|
|
@ -62,7 +234,7 @@ Bool MutatorContextCanStepInstruction(MutatorContext context)
|
|||
AVERT(MutatorContext, context);
|
||||
|
||||
/* .assume.null */
|
||||
if(IsSimpleMov(&inslen, &src, &dest, context)) {
|
||||
if (IsSimpleMov(&inslen, &src, &dest, context)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +251,7 @@ Res MutatorContextStepInstruction(MutatorContext context)
|
|||
AVERT(MutatorContext, context);
|
||||
|
||||
/* .assume.null */
|
||||
if(IsSimpleMov(&inslen, &src, &dest, context)) {
|
||||
if (IsSimpleMov(&inslen, &src, &dest, context)) {
|
||||
*dest = *src;
|
||||
Prmci6StepOverIns(context, inslen);
|
||||
return ResOK;
|
||||
|
|
|
|||
276
mps/code/prmctest.c
Normal file
276
mps/code/prmctest.c
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
|
@ -35,6 +35,7 @@ mpsicv
|
|||
mv2test
|
||||
nailboardtest
|
||||
poolncv
|
||||
prmctest
|
||||
qs
|
||||
sacss
|
||||
segsmss
|
||||
|
|
|
|||
Loading…
Reference in a new issue