VirtualBox

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

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

Disassembler/ARMv8: Implement decoding of the ldr/str (pre-/post-indexed) variant instructions and add testcases, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.7 KB
Line 
1/* $Id: tstDisasmArmv8-1.cpp 105858 2024-08-25 13:39:38Z 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 <iprt/test.h>
35#include <iprt/ctype.h>
36#include <iprt/string.h>
37#include <iprt/err.h>
38#include <iprt/script.h>
39#include <iprt/stream.h>
40
41#include "tstDisasmArmv8-1-tests.h"
42
43typedef struct TESTRDR
44{
45 const char *pb;
46 unsigned cb;
47} TESTRDR;
48typedef TESTRDR *PTESTRDR;
49
50DECLASM(int) TestProcA64(void);
51DECLASM(int) TestProcA64_EndProc(void);
52
53
54static DECLCALLBACK(int) rtScriptLexParseNumber(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser)
55{
56 RT_NOREF(ch, pvUser);
57 return RTScriptLexScanNumber(hScriptLex, 0 /*uBase*/, false /*fAllowReal*/, pToken);
58}
59
60
61static const char *s_aszSingleStart[] =
62{
63 ";",
64 NULL
65};
66
67
68static const char *s_aszMultiStart[] =
69{
70 "/*",
71 NULL
72};
73
74
75static const char *s_aszMultiEnd[] =
76{
77 "*/",
78 NULL
79};
80
81
82static const RTSCRIPTLEXTOKMATCH s_aMatches[] =
83{
84 /* Begin of stuff which will get ignored in the semantic matching. */
85 { RT_STR_TUPLE(".private_extern"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
86 { RT_STR_TUPLE("_testproca64"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
87 { RT_STR_TUPLE("_testproca64_endproc"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
88 { RT_STR_TUPLE(":"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, 0 },
89 /* End of stuff which will get ignored in the semantic matching. */
90
91 { RT_STR_TUPLE(","), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
92 { RT_STR_TUPLE("."), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
93 { RT_STR_TUPLE("["), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
94 { RT_STR_TUPLE("]"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
95 { RT_STR_TUPLE("!"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, 0 },
96 { NULL, 0, RTSCRIPTLEXTOKTYPE_INVALID, false, 0 }
97};
98
99
100static const RTSCRIPTLEXRULE s_aRules[] =
101{
102 { '#', '#', RTSCRIPT_LEX_RULE_CONSUME, rtScriptLexParseNumber, NULL},
103 { '0', '9', RTSCRIPT_LEX_RULE_CONSUME, rtScriptLexParseNumber, NULL},
104 { 'a', 'z', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
105 { 'A', 'Z', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
106 { '_', '_', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanIdentifier, NULL},
107 { '\0', '\0', RTSCRIPT_LEX_RULE_DEFAULT, NULL, NULL}
108};
109
110
111static const RTSCRIPTLEXCFG s_LexCfg =
112{
113 /** pszName */
114 "ARMv8Dis",
115 /** pszDesc */
116 "ARMv8 disassembler lexer",
117 /** fFlags */
118 RTSCRIPT_LEX_CFG_F_CASE_INSENSITIVE,
119 /** pszWhitespace */
120 NULL,
121 /** pszNewline */
122 NULL,
123 /** papszCommentMultiStart */
124 s_aszMultiStart,
125 /** papszCommentMultiEnd */
126 s_aszMultiEnd,
127 /** papszCommentSingleStart */
128 s_aszSingleStart,
129 /** paTokMatches */
130 s_aMatches,
131 /** paRules */
132 s_aRules,
133 /** pfnProdDef */
134 NULL,
135 /** pfnProdDefUser */
136 NULL
137};
138
139
140static DECLCALLBACK(int) testDisasmLexerRead(RTSCRIPTLEX hScriptLex, size_t offBuf, char *pchCur,
141 size_t cchBuf, size_t *pcchRead, void *pvUser)
142{
143 RT_NOREF(hScriptLex);
144
145 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;
157}
158
159
160static void testDisas(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode,
161 const unsigned char *pbSrc, unsigned cbSrc)
162{
163 RTTestISub(pszSub);
164
165 RTSCRIPTLEX hLexSource = NULL;
166 TESTRDR Rdr;
167
168 Rdr.pb = (const char *)pbSrc;
169 Rdr.cb = cbSrc;
170 int rc = RTScriptLexCreateFromReader(&hLexSource, testDisasmLexerRead,
171 NULL /*pfnDtor*/, &Rdr /*pvUser*/, cbSrc,
172 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
173 &s_LexCfg);
174 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
175 if (RT_FAILURE(rc))
176 return; /* Can't do our work if this fails. */
177
178 PCRTSCRIPTLEXTOKEN pTokSource;
179 rc = RTScriptLexQueryToken(hLexSource, &pTokSource);
180 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
181
182 size_t const cbInstrs = uEndPtr - (uintptr_t)pabInstrs;
183 for (size_t off = 0; off < cbInstrs;)
184 {
185 DISSTATE Dis;
186 uint32_t cb = 1;
187#ifndef DIS_CORE_ONLY
188 uint32_t const cErrBefore = RTTestIErrorCount();
189 char szOutput[256] = {0};
190
191 /*
192 * Can't use DISInstrToStr() here as it would add addresses and opcode bytes
193 * which would trip the semantic matching later on.
194 */
195 rc = DISInstrEx((uintptr_t)&pabInstrs[off], enmDisCpuMode, DISOPTYPE_ALL,
196 NULL /*pfnReadBytes*/, NULL /*pvUser*/, &Dis, &cb);
197 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
198 RTTESTI_CHECK(cb == Dis.cbInstr);
199 RTTESTI_CHECK(cb == sizeof(uint32_t));
200
201 if (RT_SUCCESS(rc))
202 {
203 size_t cch = 0;
204
205 switch (enmDisCpuMode)
206 {
207 case DISCPUMODE_ARMV8_A64:
208 case DISCPUMODE_ARMV8_A32:
209 case DISCPUMODE_ARMV8_T32:
210 cch = DISFormatArmV8Ex(&Dis, &szOutput[0], sizeof(szOutput),
211 DIS_FMT_FLAGS_RELATIVE_BRANCH,
212 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
213 break;
214 default:
215 AssertReleaseFailed(); /* Testcase error. */
216 break;
217 }
218
219 szOutput[cch] = '\0';
220 RTStrStripR(szOutput);
221 RTTESTI_CHECK(szOutput[0]);
222 if (szOutput[0])
223 {
224 /* Build the lexer and compare that it semantically is equal to the source input. */
225 RTSCRIPTLEX hLexDis = NULL;
226 rc = RTScriptLexCreateFromString(&hLexDis, szOutput, NULL /*phStrCacheId*/,
227 NULL /*phStrCacheStringLit*/, &s_LexCfg);
228 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
229 if (RT_SUCCESS(rc))
230 {
231 PCRTSCRIPTLEXTOKEN pTokDis;
232 rc = RTScriptLexQueryToken(hLexDis, &pTokDis);
233 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
234
235 /*
236 * Skip over any keyword tokens in the source lexer because these
237 * are not part of the disassembly.
238 */
239 while (pTokSource->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD)
240 pTokSource = RTScriptLexConsumeToken(hLexSource);
241
242 /* Now compare the token streams until we hit EOS in the disassembly lexer. */
243 do
244 {
245 RTTESTI_CHECK(pTokSource->enmType == pTokDis->enmType);
246 if (pTokSource->enmType == pTokDis->enmType)
247 {
248 switch (pTokSource->enmType)
249 {
250 case RTSCRIPTLEXTOKTYPE_IDENTIFIER:
251 {
252 int iCmp = strcmp(pTokSource->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
253 RTTESTI_CHECK(!iCmp);
254 if (iCmp)
255 RTTestIFailureDetails("<IDE{%u.%u, %u.%u}, %s != %s>\n",
256 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
257 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
258 pTokSource->Type.Id.pszIde, pTokDis->Type.Id.pszIde);
259 break;
260 }
261 case RTSCRIPTLEXTOKTYPE_NUMBER:
262 RTTESTI_CHECK(pTokSource->Type.Number.enmType == pTokDis->Type.Number.enmType);
263 if (pTokSource->Type.Number.enmType == pTokDis->Type.Number.enmType)
264 {
265 switch (pTokSource->Type.Number.enmType)
266 {
267 case RTSCRIPTLEXTOKNUMTYPE_NATURAL:
268 {
269 RTTESTI_CHECK(pTokSource->Type.Number.Type.u64 == pTokDis->Type.Number.Type.u64);
270 if (pTokSource->Type.Number.Type.u64 != pTokDis->Type.Number.Type.u64)
271 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %RU64 != %RU64>\n",
272 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
273 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
274 pTokSource->Type.Number.Type.u64, pTokDis->Type.Number.Type.u64);
275 break;
276 }
277 case RTSCRIPTLEXTOKNUMTYPE_INTEGER:
278 {
279 RTTESTI_CHECK(pTokSource->Type.Number.Type.i64 == pTokDis->Type.Number.Type.i64);
280 if (pTokSource->Type.Number.Type.i64 != pTokDis->Type.Number.Type.i64)
281 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %RI64 != %RI64>\n",
282 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
283 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
284 pTokSource->Type.Number.Type.i64, pTokDis->Type.Number.Type.i64);
285 break;
286 }
287 case RTSCRIPTLEXTOKNUMTYPE_REAL:
288 default:
289 AssertReleaseFailed();
290 }
291 }
292 else
293 RTTestIFailureDetails("<NUM{%u.%u, %u.%u} %u != %u>\n",
294 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
295 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
296 pTokSource->Type.Number.enmType, pTokDis->Type.Number.enmType);
297 break;
298 case RTSCRIPTLEXTOKTYPE_PUNCTUATOR:
299 {
300 int iCmp = strcmp(pTokSource->Type.Punctuator.pPunctuator->pszMatch,
301 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
302 RTTESTI_CHECK(!iCmp);
303 if (iCmp)
304 RTTestIFailureDetails("<PUNCTUATOR{%u.%u, %u.%u}, %s != %s>\n",
305 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
306 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
307 pTokSource->Type.Punctuator.pPunctuator->pszMatch,
308 pTokDis->Type.Punctuator.pPunctuator->pszMatch);
309 break;
310 }
311
312 /* These should never occur and indicate an issue in the lexer. */
313 case RTSCRIPTLEXTOKTYPE_KEYWORD:
314 RTTestIFailureDetails("<KEYWORD{%u.%u, %u.%u}, %s>\n",
315 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
316 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
317 pTokSource->Type.Keyword.pKeyword->pszMatch);
318 break;
319 case RTSCRIPTLEXTOKTYPE_STRINGLIT:
320 RTTestIFailureDetails("<STRINGLIT{%u.%u, %u.%u}, %s>\n",
321 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
322 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
323 pTokSource->Type.StringLit.pszString);
324 break;
325 case RTSCRIPTLEXTOKTYPE_OPERATOR:
326 RTTestIFailureDetails("<OPERATOR{%u.%u, %u.%u}, %s>\n",
327 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
328 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
329 pTokSource->Type.Operator.pOp->pszMatch);
330 break;
331 case RTSCRIPTLEXTOKTYPE_INVALID:
332 RTTestIFailureDetails("<INVALID>\n");
333 break;
334 case RTSCRIPTLEXTOKTYPE_ERROR:
335 RTTestIFailureDetails("<ERROR{%u.%u, %u.%u}> %s\n",
336 pTokSource->PosStart.iLine, pTokSource->PosStart.iCh,
337 pTokSource->PosEnd.iLine, pTokSource->PosEnd.iCh,
338 pTokSource->Type.Error.pErr->pszMsg);
339 break;
340 case RTSCRIPTLEXTOKTYPE_EOS:
341 RTTestIFailureDetails("<EOS>\n");
342 break;
343 default:
344 AssertFailed();
345 }
346 }
347 else
348 RTTestIFailureDetails("pTokSource->enmType=%u pTokDis->enmType=%u\n",
349 pTokSource->enmType, pTokDis->enmType);
350
351 /*
352 * Abort on error as the streams are now out of sync and matching will not work
353 * anymore producing lots of noise.
354 */
355 if (cErrBefore != RTTestIErrorCount())
356 break;
357
358 /* Advance to the next token. */
359 pTokDis = RTScriptLexConsumeToken(hLexDis);
360 Assert(pTokDis);
361
362 pTokSource = RTScriptLexConsumeToken(hLexSource);
363 Assert(pTokSource);
364 } while (pTokDis->enmType != RTSCRIPTLEXTOKTYPE_EOS);
365
366 RTScriptLexDestroy(hLexDis);
367 }
368 }
369 if (cErrBefore != RTTestIErrorCount())
370 {
371 RTTestIFailureDetails("rc=%Rrc, off=%#x (%u) cbInstr=%u enmDisCpuMode=%d\n",
372 rc, off, off, Dis.cbInstr, enmDisCpuMode);
373 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput);
374 break;
375 }
376
377 /* Do the output formatting again, now with all the addresses and opcode bytes. */
378 DISFormatArmV8Ex(&Dis, szOutput, sizeof(szOutput),
379 DIS_FMT_FLAGS_BYTES_LEFT | DIS_FMT_FLAGS_BYTES_BRACKETS | DIS_FMT_FLAGS_BYTES_SPACED
380 | DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_ADDR_LEFT,
381 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
382 RTStrStripR(szOutput);
383 RTTESTI_CHECK(szOutput[0]);
384 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput);
385 }
386 else
387 break;
388
389 /* Check with size-only. */
390 uint32_t cbOnly = 1;
391 DISSTATE DisOnly;
392 rc = DISInstrWithPrefetchedBytes((uintptr_t)&pabInstrs[off], enmDisCpuMode, 0 /*fFilter - none */,
393 Dis.Instr.ab, Dis.cbCachedInstr, NULL, NULL, &DisOnly, &cbOnly);
394
395 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
396 RTTESTI_CHECK(cbOnly == DisOnly.cbInstr);
397 RTTESTI_CHECK_MSG(cbOnly == cb, ("%#x vs %#x\n", cbOnly, cb));
398
399#else /* DIS_CORE_ONLY */
400 rc = DISInstr(&pabInstrs[off], enmDisCpuMode, &Dis, &cb);
401 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
402 RTTESTI_CHECK(cb == Dis.cbInstr);
403#endif /* DIS_CORE_ONLY */
404
405 off += cb;
406 }
407
408 RTScriptLexDestroy(hLexSource);
409}
410
411
412int main(int argc, char **argv)
413{
414 RT_NOREF2(argc, argv);
415 RTTEST hTest;
416 RTEXITCODE rcExit = RTTestInitAndCreate("tstDisasm", &hTest);
417 if (rcExit)
418 return rcExit;
419 RTTestBanner(hTest);
420
421 static const struct
422 {
423 const char *pszDesc;
424 uint8_t const *pbStart;
425 uintptr_t uEndPtr;
426 DISCPUMODE enmCpuMode;
427 const unsigned char *pbSrc;
428 unsigned cbSrc;
429 } aSnippets[] =
430 {
431#ifndef RT_OS_OS2
432 { "64-bit", (uint8_t const *)(uintptr_t)TestProcA64, (uintptr_t)&TestProcA64_EndProc, DISCPUMODE_ARMV8_A64,
433 g_abtstDisasmArmv8_1, g_cbtstDisasmArmv8_1 },
434#endif
435 };
436
437 for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++)
438 testDisas(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode,
439 aSnippets[i].pbSrc, aSnippets[i].cbSrc);
440
441 return RTTestSummaryAndDestroy(hTest);
442}
443
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