VirtualBox

source: vbox/trunk/src/VBox/Disassembler/testcase/tstDisasmArmv8-1.cpp@ 106512

Last change on this file since 106512 was 106003, checked in by vboxsync, 5 months ago

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.5 KB
Line 
1/* $Id: tstDisasmArmv8-1.cpp 106003 2024-09-10 11:46:42Z vboxsync $ */
2/** @file
3 * VBox disassembler - Testcase for ARMv8 A64
4 */
5
6/*
7 * Copyright (C) 2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define VBOX_DIS_WITH_ARMV8
33#include <VBox/dis.h>
34#include <VBox/err.h>
35#include <iprt/test.h>
36#include <iprt/ctype.h>
37#include <iprt/string.h>
38#include <iprt/err.h>
39#include <iprt/script.h>
40#include <iprt/sg.h>
41#include <iprt/stream.h>
42
43#ifdef TST_DISASM_WITH_CAPSTONE_DISASSEMBLER
44# include "/opt/homebrew/include/capstone/capstone.h"
45#endif
46
47#include "tstDisasmArmv8-1-tests.h"
48
49typedef struct TESTRDR
50{
51 RTSGSEG aSegs[3];
52 RTSGBUF SgBuf;
53} TESTRDR;
54typedef TESTRDR *PTESTRDR;
55
56DECLASM(int) TestProcA64(void);
57DECLASM(int) TestProcA64_EndProc(void);
58
59
60static DECLCALLBACK(int) rtScriptLexParseNumber(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser)
61{
62 RT_NOREF(ch, pvUser);
63 return RTScriptLexScanNumber(hScriptLex, 0 /*uBase*/, false /*fAllowReal*/, pToken);
64}
65
66
67static const char *s_aszSingleStart[] =
68{
69 ";",
70 NULL
71};
72
73
74static const char *s_aszMultiStart[] =
75{
76 "/*",
77 NULL
78};
79
80
81static const char *s_aszMultiEnd[] =
82{
83 "*/",
84 NULL
85};
86
87
88static const RTSCRIPTLEXTOKMATCH s_aMatches[] =
89{
90 /* Begin of stuff which will get ignored in the semantic matching. */
91 { RT_STR_TUPLE(".private_extern"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
92 { RT_STR_TUPLE("_testproca64"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
93 { RT_STR_TUPLE("_testproca64_endproc"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
94 { RT_STR_TUPLE(":"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
95 /* End of stuff which will get ignored in the semantic matching. */
96
97 { RT_STR_TUPLE(","), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
98 { RT_STR_TUPLE("."), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
99 { RT_STR_TUPLE("["), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
100 { RT_STR_TUPLE("]"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
101 { RT_STR_TUPLE("!"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
102 { NULL, 0, RTSCRIPTLEXTOKTYPE_INVALID, false, 0 }
103};
104
105
106static const RTSCRIPTLEXRULE s_aRules[] =
107{
108 { '#', '#', RTSCRIPT_LEX_RULE_CONSUME, rtScriptLexParseNumber, NULL},
109 { '0', '9', RTSCRIPT_LEX_RULE_CONSUME, rtScriptLexParseNumber, NULL},
110 { 'a', 'z', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
111 { 'A', 'Z', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
112 { '_', '_', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
113 { '\0', '\0', RTSCRIPT_LEX_RULE_DEFAULT, NULL, NULL}
114};
115
116
117static const RTSCRIPTLEXCFG s_LexCfg =
118{
119 /** pszName */
120 "ARMv8Dis",
121 /** pszDesc */
122 "ARMv8 disassembler lexer",
123 /** fFlags */
124 RTSCRIPT_LEX_CFG_F_CASE_INSENSITIVE,
125 /** pszWhitespace */
126 NULL,
127 /** pszNewline */
128 NULL,
129 /** papszCommentMultiStart */
130 s_aszMultiStart,
131 /** papszCommentMultiEnd */
132 s_aszMultiEnd,
133 /** papszCommentSingleStart */
134 s_aszSingleStart,
135 /** paTokMatches */
136 s_aMatches,
137 /** paRules */
138 s_aRules,
139 /** pfnProdDef */
140 NULL,
141 /** pfnProdDefUser */
142 NULL
143};
144
145
146static DECLCALLBACK(int) testDisasmLexerRead(RTSCRIPTLEX hScriptLex, size_t offBuf, char *pchCur,
147 size_t cchBuf, size_t *pcchRead, void *pvUser)
148{
149 RT_NOREF(hScriptLex, offBuf);
150
151 PTESTRDR pRdr = (PTESTRDR)pvUser;
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;
159}
160
161
162static void testDisas(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode,
163 const unsigned char *pbSrc, unsigned cbSrc)
164{
165 RTTestISub(pszSub);
166
167 RTSCRIPTLEX hLexSource = NULL;
168 TESTRDR Rdr;
169
170 Rdr.aSegs[0].pvSeg = (void *)pbSrc;
171 Rdr.aSegs[0].cbSeg = cbSrc;
172 RTSgBufInit(&Rdr.SgBuf, &Rdr.aSegs[0], 1);
173 int rc = RTScriptLexCreateFromReader(&hLexSource, testDisasmLexerRead,
174 NULL /*pfnDtor*/, &Rdr /*pvUser*/, cbSrc,
175 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
176 &s_LexCfg);
177 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
178 if (RT_FAILURE(rc))
179 return; /* Can't do our work if this fails. */
180
181 PCRTSCRIPTLEXTOKEN pTokSource;
182 rc = RTScriptLexQueryToken(hLexSource, &pTokSource);
183 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
184
185 size_t const cbInstrs = uEndPtr - (uintptr_t)pabInstrs;
186 for (size_t off = 0; off < cbInstrs;)
187 {
188 DISSTATE Dis;
189 uint32_t cb = 1;
190#ifndef DIS_CORE_ONLY
191 uint32_t const cErrBefore = RTTestIErrorCount();
192 char szOutput[256] = {0};
193
194 /*
195 * Can't use DISInstrToStr() here as it would add addresses and opcode bytes
196 * which would trip the semantic matching later on.
197 */
198 rc = DISInstrEx((uintptr_t)&pabInstrs[off], enmDisCpuMode, DISOPTYPE_ALL,
199 NULL /*pfnReadBytes*/, NULL /*pvUser*/, &Dis, &cb);
200 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
201 RTTESTI_CHECK(cb == Dis.cbInstr);
202 RTTESTI_CHECK(cb == sizeof(uint32_t));
203
204 if (RT_SUCCESS(rc))
205 {
206 size_t cch = 0;
207
208 switch (enmDisCpuMode)
209 {
210 case DISCPUMODE_ARMV8_A64:
211 case DISCPUMODE_ARMV8_A32:
212 case DISCPUMODE_ARMV8_T32:
213 cch = DISFormatArmV8Ex(&Dis, &szOutput[0], sizeof(szOutput),
214 DIS_FMT_FLAGS_RELATIVE_BRANCH,
215 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
216 break;
217 default:
218 AssertReleaseFailed(); /* Testcase error. */
219 break;
220 }
221
222 szOutput[cch] = '\0';
223 RTStrStripR(szOutput);
224 RTTESTI_CHECK(szOutput[0]);
225 if (szOutput[0])
226 {
227 /* Build the lexer and compare that it semantically is equal to the source input. */
228 RTSCRIPTLEX hLexDis = NULL;
229 rc = RTScriptLexCreateFromString(&hLexDis, szOutput, NULL /*phStrCacheId*/,
230 NULL /*phStrCacheStringLit*/, &s_LexCfg);
231 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
232 if (RT_SUCCESS(rc))
233 {
234 PCRTSCRIPTLEXTOKEN pTokDis;
235 rc = RTScriptLexQueryToken(hLexDis, &pTokDis);
236 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
237
238 /*
239 * Skip over any keyword tokens in the source lexer because these
240 * are not part of the disassembly.
241 */
242 while (pTokSource->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD)
243 pTokSource = RTScriptLexConsumeToken(hLexSource);
244
245 /* Now compare the token streams until we hit EOS in the disassembly lexer. */
246 do
247 {
248 RTTESTI_CHECK(pTokSource->enmType == pTokDis->enmType);
249 if (pTokSource->enmType == pTokDis->enmType)
250 {
251 switch (pTokSource->enmType)
252 {
253 case RTSCRIPTLEXTOKTYPE_IDENTIFIER:
254 {
255 int iCmp = strcmp(pTokSource->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
256 RTTESTI_CHECK(!iCmp);
257 if (iCmp)
258 RTTestIFailureDetails("<IDE{%u.%u, %u.%u}, %s != %s>\n",
259 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
260 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
261 pTokSource->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
262 break;
263 }
264 case RTSCRIPTLEXTOKTYPE_NUMBER:
265 RTTESTI_CHECK(pTokSource->Type.Number.enmType == pTokDis->Type.Number.enmType);
266 if (pTokSource->Type.Number.enmType == pTokDis->Type.Number.enmType)
267 {
268 switch (pTokSource->Type.Number.enmType)
269 {
270 case RTSCRIPTLEXTOKNUMTYPE_NATURAL:
271 {
272 RTTESTI_CHECK(pTokSource->Type.Number.Type.u64 == pTokDis->Type.Number.Type.u64);
273 if (pTokSource->Type.Number.Type.u64 != pTokDis->Type.Number.Type.u64)
274 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %RU64 != %RU64>\n",
275 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
276 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
277 pTokSource->Type.Number.Type.u64, pTokDis->Type.Number.Type.u64);
278 break;
279 }
280 case RTSCRIPTLEXTOKNUMTYPE_INTEGER:
281 {
282 RTTESTI_CHECK(pTokSource->Type.Number.Type.i64 == pTokDis->Type.Number.Type.i64);
283 if (pTokSource->Type.Number.Type.i64 != pTokDis->Type.Number.Type.i64)
284 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %RI64 != %RI64>\n",
285 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
286 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
287 pTokSource->Type.Number.Type.i64, pTokDis->Type.Number.Type.i64);
288 break;
289 }
290 case RTSCRIPTLEXTOKNUMTYPE_REAL:
291 default:
292 AssertReleaseFailed();
293 }
294 }
295 else
296 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %u != %u>\n",
297 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
298 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
299 pTokSource->Type.Number.enmType, pTokDis->Type.Number.enmType);
300 break;
301 case RTSCRIPTLEXTOKTYPE_PUNCTUATOR:
302 {
303 int iCmp = strcmp(pTokSource->Type.Punctuator.pPunctuator->pszMatch,
304 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
305 RTTESTI_CHECK(!iCmp);
306 if (iCmp)
307 RTTestIFailureDetails("<PUNCTUATOR{%u.%u, %u.%u}, %s != %s>\n",
308 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
309 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
310 pTokSource->Type.Punctuator.pPunctuator->pszMatch,
311 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
312 break;
313 }
314
315 /* These should never occur and indicate an issue in the lexer. */
316 case RTSCRIPTLEXTOKTYPE_KEYWORD:
317 RTTestIFailureDetails("<KEYWORD{%u.%u, %u.%u}, %s>\n",
318 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
319 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
320 pTokSource->Type.Keyword.pKeyword->pszMatch);
321 break;
322 case RTSCRIPTLEXTOKTYPE_STRINGLIT:
323 RTTestIFailureDetails("<STRINGLIT{%u.%u, %u.%u}, %s>\n",
324 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
325 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
326 pTokSource->Type.StringLit.pszString);
327 break;
328 case RTSCRIPTLEXTOKTYPE_OPERATOR:
329 RTTestIFailureDetails("<OPERATOR{%u.%u, %u.%u}, %s>\n",
330 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
331 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
332 pTokSource->Type.Operator.pOp->pszMatch);
333 break;
334 case RTSCRIPTLEXTOKTYPE_INVALID:
335 RTTestIFailureDetails("<INVALID>\n");
336 break;
337 case RTSCRIPTLEXTOKTYPE_ERROR:
338 RTTestIFailureDetails("<ERROR{%u.%u, %u.%u}> %s\n",
339 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
340 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
341 pTokSource->Type.Error.pErr->pszMsg);
342 break;
343 case RTSCRIPTLEXTOKTYPE_EOS:
344 RTTestIFailureDetails("<EOS>\n");
345 break;
346 default:
347 AssertFailed();
348 }
349 }
350 else
351 RTTestIFailureDetails("pTokSource->enmType=%u pTokDis->enmType=%u\n",
352 pTokSource->enmType, pTokDis->enmType);
353
354 /*
355 * Abort on error as the streams are now out of sync and matching will not work
356 * anymore producing lots of noise.
357 */
358 if (cErrBefore != RTTestIErrorCount())
359 break;
360
361 /* Advance to the next token. */
362 pTokDis = RTScriptLexConsumeToken(hLexDis);
363 Assert(pTokDis);
364
365 pTokSource = RTScriptLexConsumeToken(hLexSource);
366 Assert(pTokSource);
367 } while (pTokDis->enmType != RTSCRIPTLEXTOKTYPE_EOS);
368
369 RTScriptLexDestroy(hLexDis);
370 }
371 }
372 if (cErrBefore != RTTestIErrorCount())
373 {
374 RTTestIFailureDetails("rc=%Rrc, off=%#x (%u) cbInstr=%u enmDisCpuMode=%d\n",
375 rc, off, off, Dis.cbInstr, enmDisCpuMode);
376 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput);
377 break;
378 }
379
380 /* Do the output formatting again, now with all the addresses and opcode bytes. */
381 DISFormatArmV8Ex(&Dis, szOutput, sizeof(szOutput),
382 DIS_FMT_FLAGS_BYTES_LEFT | DIS_FMT_FLAGS_BYTES_BRACKETS | DIS_FMT_FLAGS_BYTES_SPACED
383 | DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_ADDR_LEFT,
384 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
385 RTStrStripR(szOutput);
386 RTTESTI_CHECK(szOutput[0]);
387 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput);
388 }
389 else
390 break;
391
392 /* Check with size-only. */
393 uint32_t cbOnly = 1;
394 DISSTATE DisOnly;
395 rc = DISInstrWithPrefetchedBytes((uintptr_t)&pabInstrs[off], enmDisCpuMode, 0 /*fFilter - none */,
396 Dis.Instr.ab, Dis.cbCachedInstr, NULL, NULL, &DisOnly, &cbOnly);
397
398 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
399 RTTESTI_CHECK(cbOnly == DisOnly.cbInstr);
400 RTTESTI_CHECK_MSG(cbOnly == cb, ("%#x vs %#x\n", cbOnly, cb));
401
402#else /* DIS_CORE_ONLY */
403 rc = DISInstr(&pabInstrs[off], enmDisCpuMode, &Dis, &cb);
404 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
405 RTTESTI_CHECK(cb == Dis.cbInstr);
406#endif /* DIS_CORE_ONLY */
407
408 off += cb;
409 }
410
411 RTScriptLexDestroy(hLexSource);
412}
413
414
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
604int main(int argc, char **argv)
605{
606 RT_NOREF2(argc, argv);
607 RTTEST hTest;
608 RTEXITCODE rcExit = RTTestInitAndCreate("tstDisasm", &hTest);
609 if (rcExit)
610 return rcExit;
611 RTTestBanner(hTest);
612
613 static const struct
614 {
615 const char *pszDesc;
616 uint8_t const *pbStart;
617 uintptr_t uEndPtr;
618 DISCPUMODE enmCpuMode;
619 const unsigned char *pbSrc;
620 unsigned cbSrc;
621 } aSnippets[] =
622 {
623#ifndef RT_OS_OS2
624 { "64-bit", (uint8_t const *)(uintptr_t)TestProcA64, (uintptr_t)&TestProcA64_EndProc, DISCPUMODE_ARMV8_A64,
625 g_abtstDisasmArmv8_1, g_cbtstDisasmArmv8_1 },
626#endif
627 };
628
629 for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++)
630 testDisas(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode,
631 aSnippets[i].pbSrc, aSnippets[i].cbSrc);
632
633#if defined(TST_DISASM_WITH_CAPSTONE_DISASSEMBLER) && !defined(DIS_CORE_ONLY)
634 testDisasComplianceAgaistCapstone();
635#endif
636
637 return RTTestSummaryAndDestroy(hTest);
638}
639
Note: See TracBrowser for help on using the repository browser.

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