VirtualBox

source: vbox/trunk/src/VBox/Disassembler/testcase/tstDisasm-2.cpp@ 8985

Last change on this file since 8985 was 8937, checked in by vboxsync, 17 years ago

Wrote up the makefile bits or the dissassembler test 'framework' and hacked together a yasmification of the DIS output sufficient to make the current tests work.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.4 KB
Line 
1/* $Id: tstDisasm-2.cpp 8937 2008-05-20 00:52:26Z vboxsync $ */
2/** @file
3 * Testcase - Generic Disassembler Tool.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <VBox/dis.h>
26#include <iprt/stream.h>
27#include <iprt/getopt.h>
28#include <iprt/file.h>
29#include <iprt/string.h>
30#include <iprt/runtime.h>
31#include <iprt/err.h>
32
33
34/*******************************************************************************
35* Structures and Typedefs *
36*******************************************************************************/
37typedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_invalid } ASMSTYLE;
38
39typedef struct MYDISSTATE
40{
41 DISCPUSTATE Cpu;
42 uint64_t uAddress; /**< The current instruction address. */
43 uint8_t *pbInstr; /**< The current instruction (pointer). */
44 uint32_t cbInstr; /**< The size of the current instruction. */
45 bool fInvalid; /**< Whether the instruction is invalid/illegal or not. */
46 bool fRaw; /**< Whether invalid instructions are printed as byte defintions or not. */
47 int rc; /**< Set if we hit EOF. */
48 size_t cbLeft; /**< The number of bytes left. (read) */
49 uint8_t *pbNext; /**< The next byte. (read) */
50 uint64_t uNextAddr; /**< The address of the next byte. (read) */
51 char szLine[256]; /**< The disassembler text output. */
52} MYDISSTATE;
53typedef MYDISSTATE *PMYDISSTATE;
54
55
56/**
57 * Default style.
58 *
59 * @param pState The disassembler state.
60 */
61static void MyDisasDefaultFormatter(PMYDISSTATE pState)
62{
63 RTPrintf("%s", pState->szLine);
64}
65
66
67/**
68 * Yasm style.
69 *
70 * @param pState The disassembler state.
71 */
72static void MyDisasYasmFormatter(PMYDISSTATE pState)
73{
74 /* a very quick hack. */
75 char szTmp[256];
76 strcpy(szTmp, RTStrStripL(strchr(pState->szLine, ':') + 1));
77
78 char *psz = strrchr(szTmp, '[');
79 *psz = '\0';
80 RTStrStripR(szTmp);
81
82 psz = strstr(szTmp, " ptr ");
83 if (psz)
84 memset(psz, ' ', 5);
85
86 char *pszEnd = strchr(szTmp, '\0');
87 while (pszEnd - &szTmp[0] < 71)
88 *pszEnd++ = ' ';
89 *pszEnd = '\0';
90
91 RTPrintf(" %s ; %s", szTmp, pState->szLine);
92}
93
94
95/**
96 * Masm style.
97 *
98 * @param pState The disassembler state.
99 */
100static void MyDisasMasmFormatter(PMYDISSTATE pState)
101{
102 RTPrintf("masm not implemented: %s", pState->szLine);
103}
104
105
106
107/**
108 * Callback for reading bytes.
109 */
110static DECLCALLBACK(int) MyDisasInstrRead(RTUINTPTR uSrcAddr, uint8_t *pbDst, uint32_t cbRead, void *pvDisCpu)
111{
112 PMYDISSTATE pState = (PMYDISSTATE)pvDisCpu;
113 if (RT_LIKELY( pState->uNextAddr == uSrcAddr
114 && pState->cbLeft >= cbRead))
115 {
116 /*
117 * Straight forward reading.
118 */
119 if (cbRead == 1)
120 {
121 pState->cbLeft--;
122 *pbDst = *pState->pbNext++;
123 pState->uNextAddr++;
124 }
125 else
126 {
127 memcpy(pbDst, pState->pbNext, cbRead);
128 pState->pbNext += cbRead;
129 pState->cbLeft -= cbRead;
130 pState->uNextAddr += cbRead;
131 }
132 }
133 else
134 {
135 /*
136 * Jumping up the stream.
137 */
138 uint64_t offReq64 = uSrcAddr - pState->uAddress;
139 if (offReq64 < 32)
140 {
141 uint32_t offReq = offReq64;
142 uintptr_t off = pState->pbNext - pState->pbInstr;
143 if (off + pState->cbLeft <= offReq)
144 {
145 pState->pbNext += pState->cbLeft;
146 pState->uNextAddr += pState->cbLeft;
147 pState->cbLeft = 0;
148
149 memset(pbDst, 0xcc, cbRead);
150 pState->rc = VERR_EOF;
151 return VERR_EOF;
152 }
153
154 /* reset the stream. */
155 pState->cbLeft += off;
156 pState->pbNext = pState->pbInstr;
157 pState->uNextAddr = pState->uAddress;
158
159 /* skip ahead. */
160 pState->cbLeft -= offReq;
161 pState->pbNext += offReq;
162 pState->uNextAddr += offReq;
163
164 /* do the reading. */
165 if (pState->cbLeft >= cbRead)
166 {
167 memcpy(pbDst, pState->pbNext, cbRead);
168 pState->cbLeft -= cbRead;
169 pState->pbNext += cbRead;
170 pState->uNextAddr += cbRead;
171 }
172 else
173 {
174 if (pState->cbLeft > 0)
175 {
176 memcpy(pbDst, pState->pbNext, pState->cbLeft);
177 pbDst += pState->cbLeft;
178 cbRead -= pState->cbLeft;
179 pState->pbNext += pState->cbLeft;
180 pState->uNextAddr += pState->cbLeft;
181 pState->cbLeft = 0;
182 }
183 memset(pbDst, 0xcc, cbRead);
184 pState->rc = VERR_EOF;
185 return VERR_EOF;
186 }
187 }
188 else
189 {
190 RTStrmPrintf(g_pStdErr, "Reading before current instruction!\n");
191 memset(pbDst, 0x90, cbRead);
192 pState->rc = VERR_INTERNAL_ERROR;
193 return VERR_INTERNAL_ERROR;
194 }
195 }
196
197 return VINF_SUCCESS;
198}
199
200
201/**
202 * Disassembles a block of memory.
203 *
204 * @returns VBox status code.
205 * @param argv0 Program name (for errors and warnings).
206 * @param enmCpuMode The cpu mode to disassemble in.
207 * @param uAddress The address we're starting to disassemble at.
208 * @param pbFile Where to start disassemble.
209 * @param cbFile How much to disassemble.
210 * @param enmStyle The assembly output style.
211 * @param fListing Whether to print in a listing like mode.
212 * @param fRaw Whether to output byte definitions for invalid sequences.
213 * @param fAllInvalid Whether all instructions are expected to be invalid.
214 */
215static int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress, uint8_t *pbFile, size_t cbFile,
216 ASMSTYLE enmStyle, bool fListing, bool fRaw, bool fAllInvalid)
217{
218 /*
219 * Initialize the CPU context.
220 */
221 MYDISSTATE State;
222 State.Cpu.mode = enmCpuMode;
223 State.Cpu.pfnReadBytes = MyDisasInstrRead;
224 State.uAddress = uAddress;
225 State.pbInstr = pbFile;
226 State.cbInstr = 0;
227 State.fInvalid = false;
228 State.fRaw = fRaw;
229 State.rc = VINF_SUCCESS;
230 State.cbLeft = cbFile;
231 State.pbNext = pbFile;
232 State.uNextAddr = uAddress;
233
234 void (*pfnFormatter)(PMYDISSTATE pState);
235 switch (enmStyle)
236 {
237 case kAsmStyle_Default:
238 pfnFormatter = MyDisasDefaultFormatter;
239 break;
240
241 case kAsmStyle_yasm:
242 RTPrintf(" BITS %d\n", enmCpuMode == CPUMODE_16BIT ? 16 : enmCpuMode == CPUMODE_32BIT ? 32 : 64);
243 pfnFormatter = MyDisasYasmFormatter;
244 break;
245
246 case kAsmStyle_masm:
247 pfnFormatter = MyDisasMasmFormatter;
248 break;
249
250 default:
251 AssertFailedReturn(VERR_INTERNAL_ERROR);
252 }
253
254 /*
255 * The loop.
256 */
257 int rcRet = VINF_SUCCESS;
258 while (State.cbLeft > 0)
259 {
260 /*
261 * Disassemble it.
262 */
263 State.cbInstr = 0;
264 State.cbLeft += State.pbNext - State.pbInstr;
265 State.uNextAddr = State.uAddress;
266 State.pbNext = State.pbInstr;
267
268 int rc = DISInstr(&State.Cpu, State.uAddress, 0, &State.cbInstr, State.szLine);
269 if (RT_SUCCESS(rc))
270 {
271 State.fInvalid = State.Cpu.pCurInstr->opcode == OP_INVALID
272 || State.Cpu.pCurInstr->opcode == OP_ILLUD2;
273 if (!fAllInvalid || State.fInvalid)
274 pfnFormatter(&State);
275 else
276 {
277 RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode);
278 pfnFormatter(&State);
279 rcRet = VERR_GENERAL_FAILURE;
280 }
281 }
282 else
283 {
284 State.cbInstr = State.pbNext - State.pbInstr;
285 if (!State.cbLeft)
286 RTPrintf("%s: error at %#RX64: read beyond the end (%Rrc)\n", argv0, State.uAddress, rc);
287 else if (State.cbInstr)
288 RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d\n", argv0, State.uAddress, rc, State.cbInstr);
289 else
290 {
291 RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d!\n", argv0, State.uAddress, rc, State.cbInstr);
292 if (rcRet == VINF_SUCCESS)
293 rcRet = rc;
294 break;
295 }
296 }
297
298
299 /* next */
300 State.uAddress += State.cbInstr;
301 State.pbInstr += State.cbInstr;
302 }
303
304 return rcRet;
305}
306
307
308/**
309 * Prints usage info.
310 *
311 * @returns 1.
312 * @param argv0 The program name.
313 */
314static int Usage(const char *argv0)
315{
316 RTStrmPrintf(g_pStdErr,
317"usage: %s [options] <file1> [file2..fileN]\n"
318" or: %s <--help|-h>\n"
319"\n"
320"Options:\n"
321" --address|-a <address>\n"
322" The base address. Default: 0\n"
323" --max-bytes|-b <bytes>\n"
324" The maximum number of bytes to disassemble. Default: 1GB\n"
325" --cpumode|-c <16|32|64>\n"
326" The cpu mode. Default: 32\n"
327" --all-invalid|-i\n"
328" When specified all instructions are expected to be invalid.\n"
329" --listing|-l, --no-listing|-L\n"
330" Enables or disables listing mode. Default: --no-listing\n"
331" --offset|-o <offset>\n"
332" The file offset at which to start disassembling. Default: 0\n"
333" --raw|-r, --no-raw|-R\n"
334" Whether to employ byte defines for unknown bits. Default: --no-raw\n"
335" --style|-s <default|yasm|masm>\n"
336" The assembly output style. Default: default\n"
337 , argv0, argv0);
338 return 1;
339}
340
341
342int main(int argc, char **argv)
343{
344 RTR3Init();
345 const char * const argv0 = RTPathFilename(argv[0]);
346
347 /* options */
348 uint64_t uAddress = 0;
349 ASMSTYLE enmStyle = kAsmStyle_Default;
350 bool fListing = true;
351 bool fRaw = false;
352 bool fAllInvalid = false;
353 DISCPUMODE enmCpuMode = CPUMODE_32BIT;
354 RTFOFF off = 0;
355 RTFOFF cbMax = _1G;
356
357 /*
358 * Parse arguments.
359 */
360 static const RTOPTIONDEF g_aOptions[] =
361 {
362 { "--address", 'a', RTGETOPT_REQ_UINT64 },
363 { "--cpumode", 'c', RTGETOPT_REQ_UINT32 },
364 { "--help", 'h', 0 },
365 { "--bytes", 'b', RTGETOPT_REQ_INT64 },
366 { "--all-invalid", 'i', 0, },
367 { "--listing", 'l', 0 },
368 { "--no-listing", 'L', 0 },
369 { "--offset", 'o', RTGETOPT_REQ_INT64 },
370 { "--raw", 'r', 0 },
371 { "--no-raw", 'R', 0 },
372 { "--style", 's', RTGETOPT_REQ_STRING },
373 };
374
375 int ch;
376 int iArg = 1;
377 RTOPTIONUNION ValueUnion;
378 while ((ch = RTGetOpt(argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), &iArg, &ValueUnion)))
379 {
380 switch (ch)
381 {
382 case 'a':
383 uAddress = ValueUnion.u64;
384 break;
385
386 case 'b':
387 cbMax = ValueUnion.i;
388 break;
389
390 case 'c':
391 if (ValueUnion.u32 == 16)
392 enmCpuMode = CPUMODE_16BIT;
393 else if (ValueUnion.u32 == 32)
394 enmCpuMode = CPUMODE_32BIT;
395 else if (ValueUnion.u32 == 64)
396 enmCpuMode = CPUMODE_64BIT;
397 else
398 {
399 RTStrmPrintf(g_pStdErr, "%s: Invalid CPU mode value %RU32\n", argv0, ValueUnion.u32);
400 return 1;
401 }
402 break;
403
404 case 'h':
405 return Usage(argv0);
406
407 case 'i':
408 fAllInvalid = true;
409 break;
410
411 case 'l':
412 fListing = true;
413 break;
414
415 case 'L':
416 fListing = false;
417 break;
418
419 case 'o':
420 off = ValueUnion.i;
421 break;
422
423 case 'r':
424 fRaw = true;
425 break;
426
427 case 'R':
428 fRaw = false;
429 break;
430
431 case 's':
432 if (!strcmp(ValueUnion.psz, "default"))
433 enmStyle = kAsmStyle_Default;
434 else if (!strcmp(ValueUnion.psz, "yasm"))
435 enmStyle = kAsmStyle_yasm;
436 else if (!strcmp(ValueUnion.psz, "masm"))
437 {
438 enmStyle = kAsmStyle_masm;
439 RTStrmPrintf(g_pStdErr, "%s: masm style isn't implemented yet\n", argv0);
440 return 1;
441 }
442 else
443 {
444 RTStrmPrintf(g_pStdErr, "%s: unknown assembly style: %s\n", argv0, ValueUnion.psz);
445 return 1;
446 }
447 break;
448
449 default:
450 RTStrmPrintf(g_pStdErr, "%s: syntax error: %Rrc\n", argv0, ch);
451 return 1;
452 }
453 }
454 if (iArg >= argc)
455 return Usage(argv0);
456
457 /*
458 * Process the files.
459 */
460 int rc = VINF_SUCCESS;
461 for ( ; iArg < argc; iArg++)
462 {
463 /*
464 * Read the file into memory.
465 */
466 void *pvFile;
467 size_t cbFile;
468 rc = RTFileReadAllEx(argv[iArg], off, cbMax, 0, &pvFile, &cbFile);
469 if (RT_FAILURE(rc))
470 {
471 RTStrmPrintf(g_pStdErr, "%s: %s: %Rrc\n", argv0, argv[iArg], rc);
472 break;
473 }
474
475 /*
476 * Disassemble it.
477 */
478 rc = MyDisasmBlock(argv0, enmCpuMode, uAddress, (uint8_t *)pvFile, cbFile, enmStyle, fListing, fRaw, fAllInvalid);
479 if (RT_FAILURE(rc))
480 break;
481 }
482
483 return RT_SUCCESS(rc) ? 0 : 1;
484}
485
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