VirtualBox

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

Last change on this file since 106791 was 106791, checked in by vboxsync, 4 months ago

Disassembler: Decode Advanced SIMD load/store multiple structures instructions, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
Line 
1/* $Id: tstDisasmArmv8-1.cpp 106791 2024-10-30 13:59:23Z 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(".cpu"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
93 { RT_STR_TUPLE("generic+mte"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
94 { RT_STR_TUPLE("_testproca64"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
95 { RT_STR_TUPLE("_testproca64_endproc"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
96 { RT_STR_TUPLE(":"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
97 /* End of stuff which will get ignored in the semantic matching. */
98
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 { RT_STR_TUPLE("]"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
103 { RT_STR_TUPLE("!"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
104 { RT_STR_TUPLE("{"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
105 { RT_STR_TUPLE("}"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
106 { NULL, 0, RTSCRIPTLEXTOKTYPE_INVALID, false, 0 }
107};
108
109
110static const RTSCRIPTLEXRULE s_aRules[] =
111{
112 { '#', '#', RTSCRIPT_LEX_RULE_CONSUME, rtScriptLexParseNumber, NULL},
113 { '0', '9', RTSCRIPT_LEX_RULE_CONSUME, rtScriptLexParseNumber, NULL},
114 { 'a', 'z', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
115 { 'A', 'Z', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
116 { '_', '_', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
117 { '\0', '\0', RTSCRIPT_LEX_RULE_DEFAULT, NULL, NULL}
118};
119
120
121static const RTSCRIPTLEXCFG s_LexCfg =
122{
123 /** pszName */
124 "ARMv8Dis",
125 /** pszDesc */
126 "ARMv8 disassembler lexer",
127 /** fFlags */
128 RTSCRIPT_LEX_CFG_F_CASE_INSENSITIVE,
129 /** pszWhitespace */
130 NULL,
131 /** pszNewline */
132 NULL,
133 /** papszCommentMultiStart */
134 s_aszMultiStart,
135 /** papszCommentMultiEnd */
136 s_aszMultiEnd,
137 /** papszCommentSingleStart */
138 s_aszSingleStart,
139 /** paTokMatches */
140 s_aMatches,
141 /** paRules */
142 s_aRules,
143 /** pfnProdDef */
144 NULL,
145 /** pfnProdDefUser */
146 NULL
147};
148
149
150static DECLCALLBACK(int) testDisasmLexerRead(RTSCRIPTLEX hScriptLex, size_t offBuf, char *pchCur,
151 size_t cchBuf, size_t *pcchRead, void *pvUser)
152{
153 RT_NOREF(hScriptLex, offBuf);
154
155 PTESTRDR pRdr = (PTESTRDR)pvUser;
156 size_t cbCopied = RTSgBufCopyToBuf(&pRdr->SgBuf, pchCur, cchBuf * sizeof(char));
157
158 *pcchRead = cbCopied * sizeof(char);
159 if (!cbCopied)
160 return VINF_EOF;
161
162 return VINF_SUCCESS;
163}
164
165
166static void testDisas(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode,
167 const unsigned char *pbSrc, unsigned cbSrc)
168{
169 RTTestISub(pszSub);
170
171 RTSCRIPTLEX hLexSource = NULL;
172 TESTRDR Rdr;
173
174 Rdr.aSegs[0].pvSeg = (void *)pbSrc;
175 Rdr.aSegs[0].cbSeg = cbSrc;
176 RTSgBufInit(&Rdr.SgBuf, &Rdr.aSegs[0], 1);
177 int rc = RTScriptLexCreateFromReader(&hLexSource, testDisasmLexerRead,
178 NULL /*pfnDtor*/, &Rdr /*pvUser*/, cbSrc,
179 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
180 &s_LexCfg);
181 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
182 if (RT_FAILURE(rc))
183 return; /* Can't do our work if this fails. */
184
185 PCRTSCRIPTLEXTOKEN pTokSource;
186 rc = RTScriptLexQueryToken(hLexSource, &pTokSource);
187 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
188
189 size_t const cbInstrs = uEndPtr - (uintptr_t)pabInstrs;
190 for (size_t off = 0; off < cbInstrs;)
191 {
192 DISSTATE Dis;
193 uint32_t cb = 1;
194#ifndef DIS_CORE_ONLY
195 uint32_t const cErrBefore = RTTestIErrorCount();
196 char szOutput[256] = {0};
197
198 /*
199 * Can't use DISInstrToStr() here as it would add addresses and opcode bytes
200 * which would trip the semantic matching later on.
201 */
202 rc = DISInstrEx((uintptr_t)&pabInstrs[off], enmDisCpuMode, DISOPTYPE_ALL,
203 NULL /*pfnReadBytes*/, NULL /*pvUser*/, &Dis, &cb);
204 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
205 RTTESTI_CHECK(cb == Dis.cbInstr);
206 RTTESTI_CHECK(cb == sizeof(uint32_t));
207
208 if (RT_SUCCESS(rc))
209 {
210 size_t cch = 0;
211
212 switch (enmDisCpuMode)
213 {
214 case DISCPUMODE_ARMV8_A64:
215 case DISCPUMODE_ARMV8_A32:
216 case DISCPUMODE_ARMV8_T32:
217 cch = DISFormatArmV8Ex(&Dis, &szOutput[0], sizeof(szOutput),
218 DIS_FMT_FLAGS_RELATIVE_BRANCH,
219 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
220 break;
221 default:
222 AssertReleaseFailed(); /* Testcase error. */
223 break;
224 }
225
226 szOutput[cch] = '\0';
227 RTStrStripR(szOutput);
228 RTTESTI_CHECK(szOutput[0]);
229 if (szOutput[0])
230 {
231 /* Build the lexer and compare that it semantically is equal to the source input. */
232 RTSCRIPTLEX hLexDis = NULL;
233 rc = RTScriptLexCreateFromString(&hLexDis, szOutput, NULL /*phStrCacheId*/,
234 NULL /*phStrCacheStringLit*/, &s_LexCfg);
235 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
236 if (RT_SUCCESS(rc))
237 {
238 PCRTSCRIPTLEXTOKEN pTokDis;
239 rc = RTScriptLexQueryToken(hLexDis, &pTokDis);
240 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
241
242 /*
243 * Skip over any keyword tokens in the source lexer because these
244 * are not part of the disassembly.
245 */
246 while (pTokSource->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD)
247 pTokSource = RTScriptLexConsumeToken(hLexSource);
248
249 /* Now compare the token streams until we hit EOS in the disassembly lexer. */
250 do
251 {
252 RTTESTI_CHECK(pTokSource->enmType == pTokDis->enmType);
253 if (pTokSource->enmType == pTokDis->enmType)
254 {
255 switch (pTokSource->enmType)
256 {
257 case RTSCRIPTLEXTOKTYPE_IDENTIFIER:
258 {
259 int iCmp = strcmp(pTokSource->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
260 RTTESTI_CHECK(!iCmp);
261 if (iCmp)
262 RTTestIFailureDetails("<IDE{%u.%u, %u.%u}, %s != %s>\n",
263 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
264 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
265 pTokSource->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
266 break;
267 }
268 case RTSCRIPTLEXTOKTYPE_NUMBER:
269 RTTESTI_CHECK(pTokSource->Type.Number.enmType == pTokDis->Type.Number.enmType);
270 if (pTokSource->Type.Number.enmType == pTokDis->Type.Number.enmType)
271 {
272 switch (pTokSource->Type.Number.enmType)
273 {
274 case RTSCRIPTLEXTOKNUMTYPE_NATURAL:
275 {
276 RTTESTI_CHECK(pTokSource->Type.Number.Type.u64 == pTokDis->Type.Number.Type.u64);
277 if (pTokSource->Type.Number.Type.u64 != pTokDis->Type.Number.Type.u64)
278 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %RU64 != %RU64>\n",
279 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
280 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
281 pTokSource->Type.Number.Type.u64, pTokDis->Type.Number.Type.u64);
282 break;
283 }
284 case RTSCRIPTLEXTOKNUMTYPE_INTEGER:
285 {
286 RTTESTI_CHECK(pTokSource->Type.Number.Type.i64 == pTokDis->Type.Number.Type.i64);
287 if (pTokSource->Type.Number.Type.i64 != pTokDis->Type.Number.Type.i64)
288 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %RI64 != %RI64>\n",
289 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
290 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
291 pTokSource->Type.Number.Type.i64, pTokDis->Type.Number.Type.i64);
292 break;
293 }
294 case RTSCRIPTLEXTOKNUMTYPE_REAL:
295 default:
296 AssertReleaseFailed();
297 }
298 }
299 else
300 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %u != %u>\n",
301 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
302 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
303 pTokSource->Type.Number.enmType, pTokDis->Type.Number.enmType);
304 break;
305 case RTSCRIPTLEXTOKTYPE_PUNCTUATOR:
306 {
307 int iCmp = strcmp(pTokSource->Type.Punctuator.pPunctuator->pszMatch,
308 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
309 RTTESTI_CHECK(!iCmp);
310 if (iCmp)
311 RTTestIFailureDetails("<PUNCTUATOR{%u.%u, %u.%u}, %s != %s>\n",
312 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
313 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
314 pTokSource->Type.Punctuator.pPunctuator->pszMatch,
315 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
316 break;
317 }
318
319 /* These should never occur and indicate an issue in the lexer. */
320 case RTSCRIPTLEXTOKTYPE_KEYWORD:
321 RTTestIFailureDetails("<KEYWORD{%u.%u, %u.%u}, %s>\n",
322 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
323 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
324 pTokSource->Type.Keyword.pKeyword->pszMatch);
325 break;
326 case RTSCRIPTLEXTOKTYPE_STRINGLIT:
327 RTTestIFailureDetails("<STRINGLIT{%u.%u, %u.%u}, %s>\n",
328 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
329 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
330 pTokSource->Type.StringLit.pszString);
331 break;
332 case RTSCRIPTLEXTOKTYPE_OPERATOR:
333 RTTestIFailureDetails("<OPERATOR{%u.%u, %u.%u}, %s>\n",
334 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
335 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
336 pTokSource->Type.Operator.pOp->pszMatch);
337 break;
338 case RTSCRIPTLEXTOKTYPE_INVALID:
339 RTTestIFailureDetails("<INVALID>\n");
340 break;
341 case RTSCRIPTLEXTOKTYPE_ERROR:
342 RTTestIFailureDetails("<ERROR{%u.%u, %u.%u}> %s\n",
343 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
344 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
345 pTokSource->Type.Error.pErr->pszMsg);
346 break;
347 case RTSCRIPTLEXTOKTYPE_EOS:
348 RTTestIFailureDetails("<EOS>\n");
349 break;
350 default:
351 AssertFailed();
352 }
353 }
354 else
355 RTTestIFailureDetails("pTokSource->enmType=%u pTokDis->enmType=%u\n",
356 pTokSource->enmType, pTokDis->enmType);
357
358 /*
359 * Abort on error as the streams are now out of sync and matching will not work
360 * anymore producing lots of noise.
361 */
362 if (cErrBefore != RTTestIErrorCount())
363 break;
364
365 /* Advance to the next token. */
366 pTokDis = RTScriptLexConsumeToken(hLexDis);
367 Assert(pTokDis);
368
369 pTokSource = RTScriptLexConsumeToken(hLexSource);
370 Assert(pTokSource);
371 } while (pTokDis->enmType != RTSCRIPTLEXTOKTYPE_EOS);
372
373 RTScriptLexDestroy(hLexDis);
374 }
375 }
376 if (cErrBefore != RTTestIErrorCount())
377 {
378 RTTestIFailureDetails("rc=%Rrc, off=%#x (%u) cbInstr=%u enmDisCpuMode=%d\n",
379 rc, off, off, Dis.cbInstr, enmDisCpuMode);
380 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput);
381 break;
382 }
383
384 /* Do the output formatting again, now with all the addresses and opcode bytes. */
385 DISFormatArmV8Ex(&Dis, szOutput, sizeof(szOutput),
386 DIS_FMT_FLAGS_BYTES_LEFT | DIS_FMT_FLAGS_BYTES_BRACKETS | DIS_FMT_FLAGS_BYTES_SPACED
387 | DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_ADDR_LEFT,
388 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
389 RTStrStripR(szOutput);
390 RTTESTI_CHECK(szOutput[0]);
391 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput);
392 }
393 else
394 break;
395
396 /* Check with size-only. */
397 uint32_t cbOnly = 1;
398 DISSTATE DisOnly;
399 rc = DISInstrWithPrefetchedBytes((uintptr_t)&pabInstrs[off], enmDisCpuMode, 0 /*fFilter - none */,
400 Dis.Instr.ab, Dis.cbCachedInstr, NULL, NULL, &DisOnly, &cbOnly);
401
402 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
403 RTTESTI_CHECK(cbOnly == DisOnly.cbInstr);
404 RTTESTI_CHECK_MSG(cbOnly == cb, ("%#x vs %#x\n", cbOnly, cb));
405
406#else /* DIS_CORE_ONLY */
407 rc = DISInstr(&pabInstrs[off], enmDisCpuMode, &Dis, &cb);
408 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
409 RTTESTI_CHECK(cb == Dis.cbInstr);
410#endif /* DIS_CORE_ONLY */
411
412 off += cb;
413 }
414
415 RTScriptLexDestroy(hLexSource);
416}
417
418
419#if defined(TST_DISASM_WITH_CAPSTONE_DISASSEMBLER) && !defined(DIS_CORE_ONLY)
420/**
421 * Testcase generating all possible 32-bit instruction values and checking our disassembler
422 * for compliance against the capstone disassembler (based on LLVM).
423 */
424static void testDisasComplianceAgaistCapstone(void)
425{
426 /** @todo SMP */
427
428 csh hDisasm = ~(size_t)0;
429 cs_err rcCs = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &hDisasm);
430 AssertMsgReturnVoid(rcCs == CS_ERR_OK, ("%d (%#x)\n", rcCs, rcCs));
431
432 char szOutput[256] = {0};
433
434 for (uint32_t u32Insn = 0; u32Insn < UINT32_MAX; u32Insn++)
435 {
436 cs_insn *pInstr;
437 size_t cInstrs = cs_disasm(hDisasm, (const uint8_t *)&u32Insn, sizeof(u32Insn),
438 (uintptr_t)&u32Insn, 1, &pInstr);
439
440 DISSTATE Dis;
441 uint32_t cb = 1;
442
443 /*
444 * Can't use DISInstrToStr() here as it would add addresses and opcode bytes
445 * which would trip the semantic matching later on.
446 */
447 int rc = DISInstrEx((uintptr_t)&u32Insn, DISCPUMODE_ARMV8_A64, DISOPTYPE_ALL,
448 NULL /*pfnReadBytes*/, NULL /*pvUser*/, &Dis, &cb);
449 if (rc == VERR_DIS_INVALID_OPCODE)
450 {
451 /* Check whether capstone could successfully disassembler the instruction. */
452 if (cInstrs)
453 {
454 RTTestIFailureDetails("%#08RX32: rcDis==VERR_DIS_INVALID_OPCODE, capstone=%s %s\n",
455 u32Insn, pInstr->mnemonic, pInstr->op_str);
456 }
457 /* else: Invalid encoding from both disassemblers, continue. */
458 }
459 else
460 {
461 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
462 RTTESTI_CHECK(cb == Dis.cbInstr);
463 RTTESTI_CHECK(cb == sizeof(uint32_t));
464
465 size_t cch = DISFormatArmV8Ex(&Dis, &szOutput[0], sizeof(szOutput),
466 DIS_FMT_FLAGS_RELATIVE_BRANCH,
467 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
468 Assert(cch);
469
470 szOutput[cch] = '\0';
471 RTStrStripR(szOutput);
472 RTTESTI_CHECK(szOutput[0]);
473
474 if (cInstrs > 0)
475 {
476 /* Compare semantically. */
477
478 RTSCRIPTLEX hLexCapstone = NULL;
479 TESTRDR Rdr;
480
481 Rdr.aSegs[0].pvSeg = pInstr->mnemonic;
482 Rdr.aSegs[0].cbSeg = strlen(pInstr->mnemonic);
483 Rdr.aSegs[1].pvSeg = (void *)" ";
484 Rdr.aSegs[1].cbSeg = 1;
485 Rdr.aSegs[2].pvSeg = pInstr->op_str;
486 Rdr.aSegs[2].cbSeg = strlen(pInstr->op_str);
487 RTSgBufInit(&Rdr.SgBuf, &Rdr.aSegs[0], 3);
488 rc = RTScriptLexCreateFromReader(&hLexCapstone, testDisasmLexerRead,
489 NULL /*pfnDtor*/, &Rdr /*pvUser*/, 0 /*cchBuf*/,
490 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
491 &s_LexCfg);
492 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
493
494 /* Build the lexer and compare that it semantically is equal to the source input. */
495 RTSCRIPTLEX hLexDis = NULL;
496 rc = RTScriptLexCreateFromString(&hLexDis, szOutput, NULL /*phStrCacheId*/,
497 NULL /*phStrCacheStringLit*/, &s_LexCfg);
498 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
499 if (RT_SUCCESS(rc))
500 {
501 PCRTSCRIPTLEXTOKEN pTokDis;
502 rc = RTScriptLexQueryToken(hLexDis, &pTokDis);
503 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
504
505 PCRTSCRIPTLEXTOKEN pTokCapstone;
506 rc = RTScriptLexQueryToken(hLexCapstone, &pTokCapstone);
507 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
508
509 /* Now compare the token streams until we hit EOS in the disassembly lexer. */
510 bool fFailed = false;
511 do
512 {
513 if (pTokCapstone->enmType == pTokDis->enmType)
514 {
515 switch (pTokCapstone->enmType)
516 {
517 case RTSCRIPTLEXTOKTYPE_IDENTIFIER:
518 {
519 int iCmp = strcmp(pTokCapstone->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
520 if (iCmp)
521 fFailed = true;
522 break;
523 }
524 case RTSCRIPTLEXTOKTYPE_NUMBER:
525 if (pTokCapstone->Type.Number.enmType == pTokDis->Type.Number.enmType)
526 {
527 switch (pTokCapstone->Type.Number.enmType)
528 {
529 case RTSCRIPTLEXTOKNUMTYPE_NATURAL:
530 {
531 if (pTokCapstone->Type.Number.Type.u64 != pTokDis->Type.Number.Type.u64)
532 fFailed = true;
533 break;
534 }
535 case RTSCRIPTLEXTOKNUMTYPE_INTEGER:
536 {
537 if (pTokCapstone->Type.Number.Type.i64 != pTokDis->Type.Number.Type.i64)
538 fFailed = true;
539 break;
540 }
541 case RTSCRIPTLEXTOKNUMTYPE_REAL:
542 default:
543 AssertReleaseFailed();
544 }
545 }
546 else
547 fFailed = true;
548 break;
549 case RTSCRIPTLEXTOKTYPE_PUNCTUATOR:
550 {
551 int iCmp = strcmp(pTokCapstone->Type.Punctuator.pPunctuator->pszMatch,
552 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
553 if (iCmp)
554 fFailed = true;
555 break;
556 }
557
558 /* These should never occur and indicate an issue in the lexer. */
559 case RTSCRIPTLEXTOKTYPE_KEYWORD:
560 case RTSCRIPTLEXTOKTYPE_STRINGLIT:
561 case RTSCRIPTLEXTOKTYPE_OPERATOR:
562 case RTSCRIPTLEXTOKTYPE_INVALID:
563 case RTSCRIPTLEXTOKTYPE_ERROR:
564 case RTSCRIPTLEXTOKTYPE_EOS:
565 fFailed = true;
566 break;
567 default:
568 AssertFailed();
569 }
570 }
571 else
572 fFailed = true;
573
574 /* Abort on error. */
575 if (fFailed)
576 break;
577
578 /* Advance to the next token. */
579 pTokDis = RTScriptLexConsumeToken(hLexDis);
580 Assert(pTokDis);
581
582 pTokCapstone = RTScriptLexConsumeToken(hLexCapstone);
583 Assert(pTokCapstone);
584 } while ( pTokDis->enmType != RTSCRIPTLEXTOKTYPE_EOS
585 || pTokCapstone->enmType != RTSCRIPTLEXTOKTYPE_EOS);
586
587 if (fFailed)
588 RTTestIFailureDetails("%#08RX32: rcDis=%s, capstone=%s %s\n",
589 u32Insn, szOutput, pInstr->mnemonic, pInstr->op_str);
590 }
591
592 RTScriptLexDestroy(hLexCapstone);
593 RTScriptLexDestroy(hLexDis);
594 }
595 else
596 {
597 RTTestIFailureDetails("%#08RX32: Dis=%s, capstone=disassembly failure\n",
598 u32Insn, szOutput);
599 }
600 }
601 }
602
603 /* Cleanup. */
604 cs_close(&hDisasm);
605}
606#endif
607
608int main(int argc, char **argv)
609{
610 RT_NOREF2(argc, argv);
611 RTTEST hTest;
612 RTEXITCODE rcExit = RTTestInitAndCreate("tstDisasm", &hTest);
613 if (rcExit)
614 return rcExit;
615 RTTestBanner(hTest);
616
617 static const struct
618 {
619 const char *pszDesc;
620 uint8_t const *pbStart;
621 uintptr_t uEndPtr;
622 DISCPUMODE enmCpuMode;
623 const unsigned char *pbSrc;
624 unsigned cbSrc;
625 } aSnippets[] =
626 {
627#ifndef RT_OS_OS2
628 { "64-bit", (uint8_t const *)(uintptr_t)TestProcA64, (uintptr_t)&TestProcA64_EndProc, DISCPUMODE_ARMV8_A64,
629 g_abtstDisasmArmv8_1, g_cbtstDisasmArmv8_1 },
630#endif
631 };
632
633 for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++)
634 testDisas(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode,
635 aSnippets[i].pbSrc, aSnippets[i].cbSrc);
636
637#if defined(TST_DISASM_WITH_CAPSTONE_DISASSEMBLER) && !defined(DIS_CORE_ONLY)
638 testDisasComplianceAgaistCapstone();
639#endif
640
641 return RTTestSummaryAndDestroy(hTest);
642}
643
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