VirtualBox

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

最後變更 在這個檔案從108453是 108280,由 vboxsync 提交於 3 週 前

Runtime/RTScriptLex*: Implement support for optionally returning parsed comments (single and multi line) as tokens when enabled in the lexer config, bugref:10321

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

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