VirtualBox

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

Last change on this file was 105724, checked in by vboxsync, 4 weeks ago

Disassembler,VMM,HostDrivers,Debugger,MakeAlternativeSource: Convert DISSTATE::Param1,...,DISSTATE::Param4 to DISSTATE::aParams[4] for easier indexing, bugref:10394

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