VirtualBox

source: vbox/trunk/src/VBox/Disassembler/Disasm.cpp@ 108825

Last change on this file since 108825 was 108700, checked in by vboxsync, 6 weeks ago

Disassembler: Get rid of PAGE_SIZE dependency in userspace for hosts where the page size can't be determined during build time. Use the smallest possible page size available across all supported architectures, bugref:10391 [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.3 KB
Line 
1/* $Id: Disasm.cpp 108700 2025-03-21 16:56:27Z vboxsync $ */
2/** @file
3 * VBox disassembler - Disassemble and optionally format.
4 */
5
6/*
7 * Copyright (C) 2006-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 LOG_GROUP LOG_GROUP_DIS
33#include <VBox/dis.h>
34#include <iprt/errcore.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37#include "DisasmInternal.h"
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43
44
45/*********************************************************************************************************************************
46* Internal Functions *
47*********************************************************************************************************************************/
48
49/**
50 * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.}
51 */
52static DECLCALLBACK(int) disReadBytesDefault(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
53{
54 uint8_t const *pbSrc = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr;
55#ifdef IN_RING0
56 size_t const cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK;
57#else
58 size_t const cbLeftOnPage = (uintptr_t)pbSrc & (uintptr_t)(_4K - 1); /* Minimum page size for safety. */
59#endif
60 uint8_t cbToRead = cbLeftOnPage >= cbMaxRead
61 ? cbMaxRead
62 : cbLeftOnPage <= cbMinRead
63 ? cbMinRead
64 : (uint8_t)cbLeftOnPage;
65 memcpy(&pDis->Instr.ab[offInstr], pbSrc, cbToRead);
66 pDis->cbCachedInstr = offInstr + cbToRead;
67 return VINF_SUCCESS;
68}
69
70
71/**
72 * Read more bytes into the DISSTATE::Instr.ab buffer, advance
73 * DISSTATE::cbCachedInstr.
74 *
75 * Will set DISSTATE::rc on failure, but still advance cbCachedInstr.
76 *
77 * The caller shall fend off reads beyond the DISSTATE::Instr.ab buffer.
78 *
79 * @param pDis The disassembler state.
80 * @param offInstr The offset of the read request.
81 * @param cbMin The size of the read request that needs to be
82 * satisfied.
83 */
84DECLHIDDEN(void) disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin)
85{
86 Assert(cbMin + offInstr <= sizeof(pDis->Instr.ab));
87
88 /*
89 * Adjust the incoming request to not overlap with bytes that has already
90 * been read and to make sure we don't leave unread gaps.
91 */
92 if (offInstr < pDis->cbCachedInstr)
93 {
94 Assert(offInstr + cbMin > pDis->cbCachedInstr);
95 cbMin -= pDis->cbCachedInstr - offInstr;
96 offInstr = pDis->cbCachedInstr;
97 }
98 else if (offInstr > pDis->cbCachedInstr)
99 {
100 cbMin += offInstr - pDis->cbCachedInstr;
101 offInstr = pDis->cbCachedInstr;
102 }
103
104 /*
105 * Do the read.
106 * (No need to zero anything on failure as Instr.ab is already zeroed by the
107 * DISInstrEx API.)
108 */
109 int rc = pDis->pfnReadBytes(pDis, offInstr, cbMin, sizeof(pDis->Instr.ab) - offInstr);
110 if (RT_SUCCESS(rc))
111 {
112 Assert(pDis->cbCachedInstr >= offInstr + cbMin);
113 Assert(pDis->cbCachedInstr <= sizeof(pDis->Instr.ab));
114 }
115 else
116 {
117 Log(("disReadMore failed with rc=%Rrc!!\n", rc));
118 pDis->rc = rc;
119 }
120}
121
122
123/**
124 * Function for handling a 8-bit cache miss.
125 *
126 * @returns The requested byte.
127 * @param pDis The disassembler state.
128 * @param offInstr The offset of the byte relative to the
129 * instruction.
130 */
131DECLHIDDEN(uint8_t) disReadByteSlow(PDISSTATE pDis, size_t offInstr)
132{
133 if (RT_LIKELY(offInstr < DIS_MAX_INSTR_LENGTH))
134 {
135 disReadMore(pDis, (uint8_t)offInstr, 1);
136 return pDis->Instr.ab[offInstr];
137 }
138
139 Log(("disReadByte: too long instruction...\n"));
140 pDis->rc = VERR_DIS_TOO_LONG_INSTR;
141 ssize_t cbLeft = (ssize_t)(sizeof(pDis->Instr.ab) - offInstr);
142 if (cbLeft > 0)
143 return pDis->Instr.ab[offInstr];
144 return 0;
145}
146
147
148/**
149 * Function for handling a 16-bit cache miss.
150 *
151 * @returns The requested word.
152 * @param pDis The disassembler state.
153 * @param offInstr The offset of the word relative to the
154 * instruction.
155 */
156DECLHIDDEN(uint16_t) disReadWordSlow(PDISSTATE pDis, size_t offInstr)
157{
158 if (RT_LIKELY(offInstr + 2 <= DIS_MAX_INSTR_LENGTH))
159 {
160 disReadMore(pDis, (uint8_t)offInstr, 2);
161#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
162 return *(uint16_t const *)&pDis->Instr.ab[offInstr];
163#else
164 return RT_MAKE_U16(pDis->Instr.ab[offInstr], pDis->Instr.ab[offInstr + 1]);
165#endif
166 }
167
168 Log(("disReadWord: too long instruction...\n"));
169 pDis->rc = VERR_DIS_TOO_LONG_INSTR;
170 ssize_t cbLeft = (ssize_t)(sizeof(pDis->Instr.ab) - offInstr);
171 switch (cbLeft)
172 {
173 case 1:
174 return pDis->Instr.ab[offInstr];
175 default:
176 if (cbLeft >= 2)
177 return RT_MAKE_U16(pDis->Instr.ab[offInstr], pDis->Instr.ab[offInstr + 1]);
178 return 0;
179 }
180}
181
182
183/**
184 * Function for handling a 32-bit cache miss.
185 *
186 * @returns The requested dword.
187 * @param pDis The disassembler state.
188 * @param offInstr The offset of the dword relative to the
189 * instruction.
190 */
191DECLHIDDEN(uint32_t) disReadDWordSlow(PDISSTATE pDis, size_t offInstr)
192{
193 if (RT_LIKELY(offInstr + 4 <= DIS_MAX_INSTR_LENGTH))
194 {
195 disReadMore(pDis, (uint8_t)offInstr, 4);
196#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
197 return *(uint32_t const *)&pDis->Instr.ab[offInstr];
198#else
199 return RT_MAKE_U32_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
200 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3]);
201#endif
202 }
203
204 Log(("disReadDWord: too long instruction...\n"));
205 pDis->rc = VERR_DIS_TOO_LONG_INSTR;
206 ssize_t cbLeft = (ssize_t)(sizeof(pDis->Instr.ab) - offInstr);
207 switch (cbLeft)
208 {
209 case 1:
210 return RT_MAKE_U32_FROM_U8(pDis->Instr.ab[offInstr], 0, 0, 0);
211 case 2:
212 return RT_MAKE_U32_FROM_U8(pDis->Instr.ab[offInstr], pDis->Instr.ab[offInstr + 1], 0, 0);
213 case 3:
214 return RT_MAKE_U32_FROM_U8(pDis->Instr.ab[offInstr], pDis->Instr.ab[offInstr + 1], pDis->Instr.ab[offInstr + 2], 0);
215 default:
216 if (cbLeft >= 4)
217 return RT_MAKE_U32_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
218 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3]);
219 return 0;
220 }
221}
222
223
224/**
225 * Function for handling a 64-bit cache miss.
226 *
227 * @returns The requested qword.
228 * @param pDis The disassembler state.
229 * @param offInstr The offset of the qword relative to the
230 * instruction.
231 */
232DECLHIDDEN(uint64_t) disReadQWordSlow(PDISSTATE pDis, size_t offInstr)
233{
234 if (RT_LIKELY(offInstr + 8 <= DIS_MAX_INSTR_LENGTH))
235 {
236 disReadMore(pDis, (uint8_t)offInstr, 8);
237#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
238 return *(uint64_t const *)&pDis->Instr.ab[offInstr];
239#else
240 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
241 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3],
242 pDis->Instr.ab[offInstr + 4], pDis->Instr.ab[offInstr + 5],
243 pDis->Instr.ab[offInstr + 6], pDis->Instr.ab[offInstr + 7]);
244#endif
245 }
246
247 Log(("disReadQWord: too long instruction...\n"));
248 pDis->rc = VERR_DIS_TOO_LONG_INSTR;
249 ssize_t cbLeft = (ssize_t)(sizeof(pDis->Instr.ab) - offInstr);
250 switch (cbLeft)
251 {
252 case 1:
253 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr], 0, 0, 0, 0, 0, 0, 0);
254 case 2:
255 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr], pDis->Instr.ab[offInstr + 1], 0, 0, 0, 0, 0, 0);
256 case 3:
257 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
258 pDis->Instr.ab[offInstr + 2], 0, 0, 0, 0, 0);
259 case 4:
260 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
261 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3],
262 0, 0, 0, 0);
263 case 5:
264 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
265 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3],
266 pDis->Instr.ab[offInstr + 4], 0, 0, 0);
267 case 6:
268 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
269 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3],
270 pDis->Instr.ab[offInstr + 4], pDis->Instr.ab[offInstr + 5],
271 0, 0);
272 case 7:
273 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
274 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3],
275 pDis->Instr.ab[offInstr + 4], pDis->Instr.ab[offInstr + 5],
276 pDis->Instr.ab[offInstr + 6], 0);
277 default:
278 if (cbLeft >= 8)
279 return RT_MAKE_U64_FROM_U8(pDis->Instr.ab[offInstr ], pDis->Instr.ab[offInstr + 1],
280 pDis->Instr.ab[offInstr + 2], pDis->Instr.ab[offInstr + 3],
281 pDis->Instr.ab[offInstr + 4], pDis->Instr.ab[offInstr + 5],
282 pDis->Instr.ab[offInstr + 6], pDis->Instr.ab[offInstr + 7]);
283 return 0;
284 }
285}
286
287
288/**
289 * Inlined worker that initializes the disassembler state.
290 *
291 * @returns The primary opcode map to use.
292 * @param pDis The disassembler state.
293 * @param uInstrAddr The instruction address.
294 * @param enmCpuMode The CPU mode.
295 * @param fFilter The instruction filter settings.
296 * @param pfnReadBytes The byte reader, can be NULL.
297 * @param pvUser The user data for the reader.
298 */
299DECL_FORCE_INLINE(PCDISOPCODE)
300disInitializeState(PDISSTATE pDis, RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
301 PFNDISREADBYTES pfnReadBytes, void *pvUser)
302{
303 RT_ZERO(*pDis);
304
305#ifdef VBOX_STRICT
306 pDis->aParams[0].uValue = UINT64_C(0xb1b1b1b1b1b1b1b1);
307 pDis->aParams[1].uValue = UINT64_C(0xb2b2b2b2b2b2b2b2);
308 pDis->aParams[2].uValue = UINT64_C(0xb3b3b3b3b3b3b3b3);
309 pDis->aParams[3].uValue = UINT64_C(0xb4b4b4b4b4b4b4b4);
310#endif
311
312 pDis->rc = VINF_SUCCESS;
313 pDis->uInstrAddr = uInstrAddr;
314 pDis->pfnReadBytes = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
315 pDis->pvUser = pvUser;
316 pDis->uCpuMode = (uint8_t)enmCpuMode;
317
318 switch (enmCpuMode)
319 {
320 case DISCPUMODE_16BIT:
321 case DISCPUMODE_32BIT:
322 case DISCPUMODE_64BIT:
323#if defined(VBOX_DIS_WITH_X86_AMD64)
324 return disInitializeStateX86(pDis, enmCpuMode, fFilter);
325#else
326 return NULL;
327#endif
328 case DISCPUMODE_ARMV8_A64:
329 case DISCPUMODE_ARMV8_A32:
330 case DISCPUMODE_ARMV8_T32:
331#if defined(VBOX_DIS_WITH_ARMV8)
332 return disInitializeStateArmV8(pDis, enmCpuMode, fFilter);
333#else
334 return NULL;
335#endif
336 default:
337 break;
338 }
339
340 AssertReleaseFailed(); /* Should never get here. */
341 return NULL;
342}
343
344
345/**
346 * Disassembles on instruction, details in @a pDis and length in @a pcbInstr.
347 *
348 * @returns VBox status code.
349 * @param uInstrAddr Address of the instruction to decode. What this means
350 * is left to the pfnReadBytes function.
351 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
352 * @param pfnReadBytes Callback for reading instruction bytes.
353 * @param fFilter Instruction type filter.
354 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
355 * @param pDis Pointer to disassembler state (output).
356 * @param pcbInstr Where to store the size of the instruction. (This
357 * is also stored in PDISSTATE::cbInstr.) Optional.
358 */
359DISDECL(int) DISInstrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
360 PFNDISREADBYTES pfnReadBytes, void *pvUser,
361 PDISSTATE pDis, uint32_t *pcbInstr)
362{
363
364 PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
365 disPrefetchBytes(pDis);
366
367 switch (enmCpuMode)
368 {
369 case DISCPUMODE_16BIT:
370 case DISCPUMODE_32BIT:
371 case DISCPUMODE_64BIT:
372#if defined(VBOX_DIS_WITH_X86_AMD64)
373 return disInstrWorkerX86(pDis, paOneByteMap, pcbInstr);
374#else
375 return VERR_NOT_SUPPORTED;
376#endif
377 case DISCPUMODE_ARMV8_A64:
378 case DISCPUMODE_ARMV8_A32:
379 case DISCPUMODE_ARMV8_T32:
380#if defined(VBOX_DIS_WITH_ARMV8)
381 return disInstrWorkerArmV8(pDis, paOneByteMap, pcbInstr);
382#else
383 return VERR_NOT_SUPPORTED;
384#endif
385 default:
386 break;
387 }
388
389 AssertReleaseFailed(); /* Should never get here. */
390 return VERR_INTERNAL_ERROR;
391}
392
393
394/**
395 * Disassembles on instruction partially or fully from prefetched bytes, details
396 * in @a pDis and length in @a pcbInstr.
397 *
398 * @returns VBox status code.
399 * @param uInstrAddr Address of the instruction to decode. What this means
400 * is left to the pfnReadBytes function.
401 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
402 * @param pvPrefetched Pointer to the prefetched bytes.
403 * @param cbPrefetched The number of valid bytes pointed to by @a
404 * pbPrefetched.
405 * @param pfnReadBytes Callback for reading instruction bytes.
406 * @param fFilter Instruction type filter.
407 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
408 * @param pDis Pointer to disassembler state (output).
409 * @param pcbInstr Where to store the size of the instruction. (This
410 * is also stored in PDISSTATE::cbInstr.) Optional.
411 */
412DISDECL(int) DISInstrWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
413 void const *pvPrefetched, size_t cbPretched,
414 PFNDISREADBYTES pfnReadBytes, void *pvUser,
415 PDISSTATE pDis, uint32_t *pcbInstr)
416{
417 PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
418
419 if (!cbPretched)
420 disPrefetchBytes(pDis);
421 else
422 {
423 if (cbPretched >= sizeof(pDis->Instr.ab))
424 {
425 memcpy(pDis->Instr.ab, pvPrefetched, sizeof(pDis->Instr.ab));
426 pDis->cbCachedInstr = (uint8_t)sizeof(pDis->Instr.ab);
427 }
428 else
429 {
430 memcpy(pDis->Instr.ab, pvPrefetched, cbPretched);
431 pDis->cbCachedInstr = (uint8_t)cbPretched;
432 }
433 }
434
435 switch (enmCpuMode)
436 {
437 case DISCPUMODE_16BIT:
438 case DISCPUMODE_32BIT:
439 case DISCPUMODE_64BIT:
440#if defined(VBOX_DIS_WITH_X86_AMD64)
441 return disInstrWorkerX86(pDis, paOneByteMap, pcbInstr);
442#else
443 return VERR_NOT_SUPPORTED;
444#endif
445 case DISCPUMODE_ARMV8_A64:
446 case DISCPUMODE_ARMV8_A32:
447 case DISCPUMODE_ARMV8_T32:
448#if defined(VBOX_DIS_WITH_ARMV8)
449 return disInstrWorkerArmV8(pDis, paOneByteMap, pcbInstr);
450#else
451 return VERR_NOT_SUPPORTED;
452#endif
453 default:
454 break;
455 }
456
457 AssertReleaseFailed(); /* Should never get here. */
458 return VERR_INTERNAL_ERROR;
459}
460
461
462/**
463 * Parses one guest instruction.
464 *
465 * The result is found in pDis and pcbInstr.
466 *
467 * @returns VBox status code.
468 * @param uInstrAddr Address of the instruction to decode. What this means
469 * is left to the pfnReadBytes function.
470 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
471 * @param pfnReadBytes Callback for reading instruction bytes.
472 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
473 * @param pDis Pointer to disassembler state (output).
474 * @param pcbInstr Where to store the size of the instruction.
475 * NULL is allowed. This is also stored in
476 * PDISSTATE::cbInstr.
477 */
478DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
479 PDISSTATE pDis, uint32_t *pcbInstr)
480{
481 return DISInstrEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pDis, pcbInstr);
482}
483
484
485/**
486 * Parses one guest instruction.
487 *
488 * The result is found in pDis and pcbInstr.
489 *
490 * @returns VBox status code.
491 * @param pvInstr Address of the instruction to decode. This is a
492 * real address in the current context that can be
493 * accessed without faulting. (Consider
494 * DISInstrWithReader if this isn't the case.)
495 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
496 * @param pfnReadBytes Callback for reading instruction bytes.
497 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
498 * @param pDis Pointer to disassembler state (output).
499 * @param pcbInstr Where to store the size of the instruction.
500 * NULL is allowed. This is also stored in
501 * PDISSTATE::cbInstr.
502 */
503DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr)
504{
505 return DISInstrEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pDis, pcbInstr);
506}
507
508
509#ifndef DIS_CORE_ONLY
510/**
511 * Disassembles one instruction
512 *
513 * @returns VBox error code
514 * @param pvInstr Pointer to the instruction to disassemble.
515 * @param enmCpuMode The CPU state.
516 * @param pDis The disassembler state (output).
517 * @param pcbInstr Where to store the size of the instruction. NULL is
518 * allowed.
519 * @param pszOutput Storage for disassembled instruction
520 * @param cbOutput Size of the output buffer.
521 *
522 * @todo Define output callback.
523 */
524DISDECL(int) DISInstrToStr(void const *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr,
525 char *pszOutput, size_t cbOutput)
526{
527 return DISInstrToStrEx((uintptr_t)pvInstr, enmCpuMode, NULL, NULL, DISOPTYPE_ALL,
528 pDis, pcbInstr, pszOutput, cbOutput);
529}
530
531
532/**
533 * Disassembles one instruction with a byte fetcher caller.
534 *
535 * @returns VBox error code
536 * @param uInstrAddr Pointer to the structure to disassemble.
537 * @param enmCpuMode The CPU mode.
538 * @param pfnCallback The byte fetcher callback.
539 * @param pvUser The user argument (found in
540 * DISSTATE::pvUser).
541 * @param pDis The disassembler state (output).
542 * @param pcbInstr Where to store the size of the instruction. NULL is
543 * allowed.
544 * @param pszOutput Storage for disassembled instruction.
545 * @param cbOutput Size of the output buffer.
546 *
547 * @todo Define output callback.
548 */
549DISDECL(int) DISInstrToStrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
550 PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput)
551
552{
553 return DISInstrToStrEx(uInstrAddr, enmCpuMode, pfnReadBytes, pvUser, DISOPTYPE_ALL,
554 pDis, pcbInstr, pszOutput, cbOutput);
555}
556
557
558/**
559 * Disassembles one instruction; only fully disassembly an instruction if it matches the filter criteria
560 *
561 * @returns VBox error code
562 * @param uInstrAddr Pointer to the structure to disassemble.
563 * @param enmCpuMode The CPU mode.
564 * @param pfnCallback The byte fetcher callback.
565 * @param uFilter Instruction filter.
566 * @param pDis Where to return the disassembled instruction info.
567 * @param pcbInstr Where to store the size of the instruction. NULL is
568 * allowed.
569 * @param pszOutput Storage for disassembled instruction.
570 * @param cbOutput Size of the output buffer.
571 *
572 * @todo Define output callback.
573 */
574DISDECL(int) DISInstrToStrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode,
575 PFNDISREADBYTES pfnReadBytes, void *pvUser, uint32_t uFilter,
576 PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput)
577{
578 /* Don't filter if formatting is desired. */
579 if (uFilter != DISOPTYPE_ALL && pszOutput && cbOutput)
580 uFilter = DISOPTYPE_ALL;
581
582 int rc = DISInstrEx(uInstrAddr, enmCpuMode, uFilter, pfnReadBytes, pvUser, pDis, pcbInstr);
583 if (RT_SUCCESS(rc) && pszOutput && cbOutput)
584 {
585 size_t cch = 0;
586
587 switch (enmCpuMode)
588 {
589 case DISCPUMODE_16BIT:
590 case DISCPUMODE_32BIT:
591 case DISCPUMODE_64BIT:
592#if defined(VBOX_DIS_WITH_X86_AMD64)
593 cch = DISFormatYasmEx(pDis, pszOutput, cbOutput,
594 DIS_FMT_FLAGS_BYTES_LEFT | DIS_FMT_FLAGS_BYTES_BRACKETS | DIS_FMT_FLAGS_BYTES_SPACED
595 | DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_ADDR_LEFT,
596 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
597#else
598 AssertReleaseFailed(); /* Shouldn't ever get here (DISInstrEx() returning VERR_NOT_SUPPORTED). */
599#endif
600 break;
601 case DISCPUMODE_ARMV8_A64:
602 case DISCPUMODE_ARMV8_A32:
603 case DISCPUMODE_ARMV8_T32:
604#if defined(VBOX_DIS_WITH_ARMV8)
605 cch = DISFormatArmV8Ex(pDis, pszOutput, cbOutput,
606 DIS_FMT_FLAGS_BYTES_LEFT | DIS_FMT_FLAGS_BYTES_BRACKETS | DIS_FMT_FLAGS_BYTES_SPACED
607 | DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_ADDR_LEFT,
608 NULL /*pfnGetSymbol*/, NULL /*pvUser*/);
609#else
610 AssertReleaseFailed(); /* Shouldn't ever get here (DISInstrEx() returning VERR_NOT_SUPPORTED). */
611#endif
612 break;
613 default:
614 break;
615 }
616
617 if (cch + 2 <= cbOutput)
618 {
619 pszOutput[cch++] = '\n';
620 pszOutput[cch] = '\0';
621 }
622 }
623 return rc;
624}
625#endif /* DIS_CORE_ONLY */
626
Note: See TracBrowser for help on using the repository browser.

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