VirtualBox

Changeset 106003 in vbox


Ignore:
Timestamp:
Sep 10, 2024 11:46:42 AM (8 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
164749
Message:

Disassembler/testcase/tstDisasmArmv8-1: Implement testcase which utilizes capstone to compare the output of both diassemblers against each other to spot differences across the whole 32-bit instruction encoding space, bugref:10394

Location:
trunk/src/VBox/Disassembler/testcase
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Disassembler/testcase/Makefile.kmk

    r105756 r106003  
    100100        $(PATH_STAGE_LIB)/DisasmR3$(VBOX_SUFF_LIB) \
    101101        $(LIB_RUNTIME)
     102
     103  if defined(TST_DISASM_WITH_CAPSTONE_DISASSEMBLER)
     104   tstDisasmArmv8-1_DEFS        += TST_DISASM_WITH_CAPSTONE_DISASSEMBLER
     105   tstDisasmArmv8-1_LIBS.darwin += /opt/homebrew/lib/libcapstone.dylib
     106   tstDisasmArmv8-1_LIBS.linux  += capstone
     107  endif
     108
    102109 endif
    103110
  • trunk/src/VBox/Disassembler/testcase/tstDisasmArmv8-1.cpp

    r105858 r106003  
    3232#define VBOX_DIS_WITH_ARMV8
    3333#include <VBox/dis.h>
     34#include <VBox/err.h>
    3435#include <iprt/test.h>
    3536#include <iprt/ctype.h>
     
    3738#include <iprt/err.h>
    3839#include <iprt/script.h>
     40#include <iprt/sg.h>
    3941#include <iprt/stream.h>
    4042
     43#ifdef TST_DISASM_WITH_CAPSTONE_DISASSEMBLER
     44# include "/opt/homebrew/include/capstone/capstone.h"
     45#endif
     46
    4147#include "tstDisasmArmv8-1-tests.h"
    4248
    4349typedef struct TESTRDR
    4450{
    45     const char *pb;
    46     unsigned   cb;
     51    RTSGSEG aSegs[3];
     52    RTSGBUF SgBuf;
    4753} TESTRDR;
    4854typedef TESTRDR *PTESTRDR;
     
    141147                                             size_t cchBuf, size_t *pcchRead, void *pvUser)
    142148{
    143     RT_NOREF(hScriptLex);
     149    RT_NOREF(hScriptLex, offBuf);
    144150
    145151    PTESTRDR pRdr = (PTESTRDR)pvUser;
    146     size_t cbCopy = RT_MIN(cchBuf / sizeof(char), pRdr->cb - offBuf);
    147     int rc = VINF_SUCCESS;
    148 
    149     *pcchRead = cbCopy * sizeof(char);
    150 
    151     if (cbCopy)
    152         memcpy(pchCur, &pRdr->pb[offBuf], cbCopy);
    153     else
    154         rc = VINF_EOF;
    155 
    156     return rc;
     152    size_t cbCopied = RTSgBufCopyToBuf(&pRdr->SgBuf, pchCur, cchBuf * sizeof(char));
     153
     154    *pcchRead = cbCopied * sizeof(char);
     155    if (!cbCopied)
     156        return VINF_EOF;
     157
     158    return VINF_SUCCESS;
    157159}
    158160
     
    166168    TESTRDR Rdr;
    167169
    168     Rdr.pb = (const char *)pbSrc;
    169     Rdr.cb = cbSrc;
     170    Rdr.aSegs[0].pvSeg = (void *)pbSrc;
     171    Rdr.aSegs[0].cbSeg = cbSrc;
     172    RTSgBufInit(&Rdr.SgBuf, &Rdr.aSegs[0], 1);
    170173    int rc = RTScriptLexCreateFromReader(&hLexSource, testDisasmLexerRead,
    171174                                         NULL /*pfnDtor*/, &Rdr /*pvUser*/, cbSrc,
     
    410413
    411414
     415#if defined(TST_DISASM_WITH_CAPSTONE_DISASSEMBLER) && !defined(DIS_CORE_ONLY)
     416/**
     417 * Testcase generating all possible 32-bit instruction values and checking our disassembler
     418 * for compliance against the capstone disassembler (based on LLVM).
     419 */
     420static void testDisasComplianceAgaistCapstone(void)
     421{
     422    /** @todo SMP */
     423
     424    csh    hDisasm = ~(size_t)0;
     425    cs_err rcCs    = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &hDisasm);
     426    AssertMsgReturnVoid(rcCs == CS_ERR_OK, ("%d (%#x)\n", rcCs, rcCs));
     427
     428    char szOutput[256] = {0};
     429
     430    for (uint32_t u32Insn = 0; u32Insn < UINT32_MAX; u32Insn++)
     431    {
     432        cs_insn *pInstr;
     433        size_t   cInstrs = cs_disasm(hDisasm, (const uint8_t *)&u32Insn, sizeof(u32Insn),
     434                                     (uintptr_t)&u32Insn, 1, &pInstr);
     435
     436        DISSTATE        Dis;
     437        uint32_t        cb = 1;
     438
     439        /*
     440         * Can't use DISInstrToStr() here as it would add addresses and opcode bytes
     441         * which would trip the semantic matching later on.
     442         */
     443        int rc = DISInstrEx((uintptr_t)&u32Insn, DISCPUMODE_ARMV8_A64, DISOPTYPE_ALL,
     444                            NULL /*pfnReadBytes*/, NULL /*pvUser*/, &Dis, &cb);
     445        if (rc == VERR_DIS_INVALID_OPCODE)
     446        {
     447            /* Check whether capstone could successfully disassembler the instruction. */
     448            if (cInstrs)
     449            {
     450                RTTestIFailureDetails("%#08RX32: rcDis==VERR_DIS_INVALID_OPCODE, capstone=%s %s\n",
     451                                      u32Insn, pInstr->mnemonic, pInstr->op_str);
     452            }
     453            /* else: Invalid encoding from both disassemblers, continue. */
     454        }
     455        else
     456        {
     457            RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
     458            RTTESTI_CHECK(cb == Dis.cbInstr);
     459            RTTESTI_CHECK(cb == sizeof(uint32_t));
     460
     461            size_t cch = DISFormatArmV8Ex(&Dis, &szOutput[0], sizeof(szOutput),
     462                                          DIS_FMT_FLAGS_RELATIVE_BRANCH,
     463                                          NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
     464            Assert(cch);
     465
     466            szOutput[cch] = '\0';
     467            RTStrStripR(szOutput);
     468            RTTESTI_CHECK(szOutput[0]);
     469
     470            if (cInstrs > 0)
     471            {
     472                /* Compare semantically. */
     473
     474                RTSCRIPTLEX hLexCapstone = NULL;
     475                TESTRDR Rdr;
     476
     477                Rdr.aSegs[0].pvSeg = pInstr->mnemonic;
     478                Rdr.aSegs[0].cbSeg = strlen(pInstr->mnemonic);
     479                Rdr.aSegs[1].pvSeg = (void *)" ";
     480                Rdr.aSegs[1].cbSeg = 1;
     481                Rdr.aSegs[2].pvSeg = pInstr->op_str;
     482                Rdr.aSegs[2].cbSeg = strlen(pInstr->op_str);
     483                RTSgBufInit(&Rdr.SgBuf, &Rdr.aSegs[0], 3);
     484                rc = RTScriptLexCreateFromReader(&hLexCapstone, testDisasmLexerRead,
     485                                                 NULL /*pfnDtor*/, &Rdr /*pvUser*/, 0 /*cchBuf*/,
     486                                                 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
     487                                                 &s_LexCfg);
     488                RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
     489
     490                /* Build the lexer and compare that it semantically is equal to the source input. */
     491                RTSCRIPTLEX hLexDis = NULL;
     492                rc = RTScriptLexCreateFromString(&hLexDis, szOutput, NULL /*phStrCacheId*/,
     493                                                 NULL /*phStrCacheStringLit*/, &s_LexCfg);
     494                RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
     495                if (RT_SUCCESS(rc))
     496                {
     497                    PCRTSCRIPTLEXTOKEN pTokDis;
     498                    rc = RTScriptLexQueryToken(hLexDis, &pTokDis);
     499                    RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
     500
     501                    PCRTSCRIPTLEXTOKEN pTokCapstone;
     502                    rc = RTScriptLexQueryToken(hLexCapstone, &pTokCapstone);
     503                    RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
     504
     505                    /* Now compare the token streams until we hit EOS in the disassembly lexer. */
     506                    bool fFailed = false;
     507                    do
     508                    {
     509                        if (pTokCapstone->enmType == pTokDis->enmType)
     510                        {
     511                            switch (pTokCapstone->enmType)
     512                            {
     513                                case RTSCRIPTLEXTOKTYPE_IDENTIFIER:
     514                                {
     515                                    int iCmp = strcmp(pTokCapstone->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
     516                                    if (iCmp)
     517                                        fFailed = true;
     518                                    break;
     519                                }
     520                                case RTSCRIPTLEXTOKTYPE_NUMBER:
     521                                    if (pTokCapstone->Type.Number.enmType == pTokDis->Type.Number.enmType)
     522                                    {
     523                                        switch (pTokCapstone->Type.Number.enmType)
     524                                        {
     525                                            case RTSCRIPTLEXTOKNUMTYPE_NATURAL:
     526                                            {
     527                                                if (pTokCapstone->Type.Number.Type.u64 != pTokDis->Type.Number.Type.u64)
     528                                                    fFailed = true;
     529                                                break;
     530                                            }
     531                                            case RTSCRIPTLEXTOKNUMTYPE_INTEGER:
     532                                            {
     533                                                if (pTokCapstone->Type.Number.Type.i64 != pTokDis->Type.Number.Type.i64)
     534                                                    fFailed = true;
     535                                                break;
     536                                            }
     537                                        case RTSCRIPTLEXTOKNUMTYPE_REAL:
     538                                            default:
     539                                                AssertReleaseFailed();
     540                                        }
     541                                    }
     542                                    else
     543                                        fFailed = true;
     544                                    break;
     545                                case RTSCRIPTLEXTOKTYPE_PUNCTUATOR:
     546                                {
     547                                    int iCmp = strcmp(pTokCapstone->Type.Punctuator.pPunctuator->pszMatch,
     548                                                      pTokDis->Type.Punctuator.pPunctuator->pszMatch);
     549                                    if (iCmp)
     550                                        fFailed = true;
     551                                    break;
     552                                }
     553
     554                                /* These should never occur and indicate an issue in the lexer. */
     555                                case RTSCRIPTLEXTOKTYPE_KEYWORD:
     556                                case RTSCRIPTLEXTOKTYPE_STRINGLIT:
     557                                case RTSCRIPTLEXTOKTYPE_OPERATOR:
     558                                case RTSCRIPTLEXTOKTYPE_INVALID:
     559                                case RTSCRIPTLEXTOKTYPE_ERROR:
     560                                case RTSCRIPTLEXTOKTYPE_EOS:
     561                                    fFailed = true;
     562                                    break;
     563                                default:
     564                                    AssertFailed();
     565                            }
     566                        }
     567                        else
     568                            fFailed = true;
     569
     570                        /* Abort on error. */
     571                        if (fFailed)
     572                            break;
     573
     574                        /* Advance to the next token. */
     575                        pTokDis = RTScriptLexConsumeToken(hLexDis);
     576                        Assert(pTokDis);
     577
     578                        pTokCapstone = RTScriptLexConsumeToken(hLexCapstone);
     579                        Assert(pTokCapstone);
     580                    } while (   pTokDis->enmType != RTSCRIPTLEXTOKTYPE_EOS
     581                             || pTokCapstone->enmType != RTSCRIPTLEXTOKTYPE_EOS);
     582
     583                    if (fFailed)
     584                        RTTestIFailureDetails("%#08RX32: rcDis=%s, capstone=%s %s\n",
     585                                              u32Insn, szOutput, pInstr->mnemonic, pInstr->op_str);
     586                }
     587
     588                RTScriptLexDestroy(hLexCapstone);
     589                RTScriptLexDestroy(hLexDis);
     590            }
     591            else
     592            {
     593                RTTestIFailureDetails("%#08RX32: Dis=%s, capstone=disassembly failure\n",
     594                                      u32Insn, szOutput);
     595            }
     596        }
     597    }
     598
     599    /* Cleanup. */
     600    cs_close(&hDisasm);
     601}
     602#endif
     603
    412604int main(int argc, char **argv)
    413605{
     
    439631                  aSnippets[i].pbSrc, aSnippets[i].cbSrc);
    440632
     633#if defined(TST_DISASM_WITH_CAPSTONE_DISASSEMBLER) && !defined(DIS_CORE_ONLY)
     634    testDisasComplianceAgaistCapstone();
     635#endif
     636
    441637    return RTTestSummaryAndDestroy(hTest);
    442638}
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette