VirtualBox

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

Last change on this file since 108646 was 108646, checked in by vboxsync, 2 weeks ago

Disassembler/Disasm.cpp: Make it work for hosts where we don't know the host page size when building, bugref:10391

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