VirtualBox

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

Last change on this file since 8936 was 8935, checked in by vboxsync, 17 years ago

props, export, and fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.8 KB
Line 
1/* $Id: tstDisasm-2.cpp 8935 2008-05-19 20:39:21Z 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.215389.xyz. 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 RTPrintf("yasm not implemented: %s", pState->szLine);
75}
76
77
78/**
79 * Masm style.
80 *
81 * @param pState The disassembler state.
82 */
83static void MyDisasMasmFormatter(PMYDISSTATE pState)
84{
85 RTPrintf("masm not implemented: %s", pState->szLine);
86}
87
88
89
90/**
91 * Callback for reading bytes.
92 */
93static DECLCALLBACK(int) MyDisasInstrRead(RTUINTPTR uSrcAddr, uint8_t *pbDst, uint32_t cbRead, void *pvDisCpu)
94{
95 PMYDISSTATE pState = (PMYDISSTATE)pvDisCpu;
96 if (RT_LIKELY( pState->uNextAddr == uSrcAddr
97 && pState->cbLeft >= cbRead))
98 {
99 /*
100 * Straight forward reading.
101 */
102 if (cbRead == 1)
103 {
104 pState->cbLeft--;
105 *pbDst = *pState->pbNext++;
106 pState->uNextAddr++;
107 }
108 else
109 {
110 memcpy(pbDst, pState->pbNext, cbRead);
111 pState->pbNext += cbRead;
112 pState->cbLeft -= cbRead;
113 pState->uNextAddr += cbRead;
114 }
115 }
116 else
117 {
118 /*
119 * Jumping up the stream.
120 */
121 uint64_t offReq64 = uSrcAddr - pState->uAddress;
122 if (offReq64 < 32)
123 {
124 uint32_t offReq = offReq64;
125 uintptr_t off = pState->pbNext - pState->pbInstr;
126 if (off + pState->cbLeft <= offReq)
127 {
128 pState->pbNext += pState->cbLeft;
129 pState->uNextAddr += pState->cbLeft;
130 pState->cbLeft = 0;
131
132 memset(pbDst, 0xcc, cbRead);
133 pState->rc = VERR_EOF;
134 return VERR_EOF;
135 }
136
137 /* reset the stream. */
138 pState->cbLeft += off;
139 pState->pbNext = pState->pbInstr;
140 pState->uNextAddr = pState->uAddress;
141
142 /* skip ahead. */
143 pState->cbLeft -= offReq;
144 pState->pbNext += offReq;
145 pState->uNextAddr += offReq;
146
147 /* do the reading. */
148 if (pState->cbLeft >= cbRead)
149 {
150 memcpy(pbDst, pState->pbNext, cbRead);
151 pState->cbLeft -= cbRead;
152 pState->pbNext += cbRead;
153 pState->uNextAddr += cbRead;
154 }
155 else
156 {
157 if (pState->cbLeft > 0)
158 {
159 memcpy(pbDst, pState->pbNext, pState->cbLeft);
160 pbDst += pState->cbLeft;
161 cbRead -= pState->cbLeft;
162 pState->pbNext += pState->cbLeft;
163 pState->uNextAddr += pState->cbLeft;
164 pState->cbLeft = 0;
165 }
166 memset(pbDst, 0xcc, cbRead);
167 pState->rc = VERR_EOF;
168 return VERR_EOF;
169 }
170 }
171 else
172 {
173 RTStrmPrintf(g_pStdErr, "Reading before current instruction!\n");
174 memset(pbDst, 0x90, cbRead);
175 pState->rc = VERR_INTERNAL_ERROR;
176 return VERR_INTERNAL_ERROR;
177 }
178 }
179
180 return VINF_SUCCESS;
181}
182
183
184/**
185 * Disassembles a block of memory.
186 *
187 * @returns VBox status code.
188 * @param argv0 Program name (for errors and warnings).
189 * @param enmCpuMode The cpu mode to disassemble in.
190 * @param uAddress The address we're starting to disassemble at.
191 * @param pbFile Where to start disassemble.
192 * @param cbFile How much to disassemble.
193 * @param enmStyle The assembly output style.
194 * @param fListing Whether to print in a listing like mode.
195 * @param fRaw Whether to output byte definitions for invalid sequences.
196 * @param fAllInvalid Whether all instructions are expected to be invalid.
197 */
198static int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress, uint8_t *pbFile, size_t cbFile,
199 ASMSTYLE enmStyle, bool fListing, bool fRaw, bool fAllInvalid)
200{
201 /*
202 * Initialize the CPU context.
203 */
204 MYDISSTATE State;
205 State.Cpu.mode = enmCpuMode;
206 State.Cpu.pfnReadBytes = MyDisasInstrRead;
207 State.uAddress = uAddress;
208 State.pbInstr = pbFile;
209 State.cbInstr = 0;
210 State.fInvalid = false;
211 State.fRaw = fRaw;
212 State.rc = VINF_SUCCESS;
213 State.cbLeft = cbFile;
214 State.pbNext = pbFile;
215 State.uNextAddr = uAddress;
216
217 void (*pfnFormatter)(PMYDISSTATE pState);
218 switch (enmStyle)
219 {
220 case kAsmStyle_Default:
221 pfnFormatter = MyDisasDefaultFormatter;
222 break;
223
224 case kAsmStyle_yasm:
225 pfnFormatter = MyDisasYasmFormatter;
226 break;
227
228 case kAsmStyle_masm:
229 pfnFormatter = MyDisasMasmFormatter;
230 break;
231
232 default:
233 AssertFailedReturn(VERR_INTERNAL_ERROR);
234 }
235
236 /*
237 * The loop.
238 */
239 int rcRet = VINF_SUCCESS;
240 while (State.cbLeft > 0)
241 {
242 /*
243 * Disassemble it.
244 */
245 State.cbInstr = 0;
246 State.cbLeft += State.pbNext - State.pbInstr;
247 State.uNextAddr = State.uAddress;
248 State.pbNext = State.pbInstr;
249
250 int rc = DISInstr(&State.Cpu, State.uAddress, 0, &State.cbInstr, State.szLine);
251 if (RT_SUCCESS(rc))
252 {
253 State.fInvalid = State.Cpu.pCurInstr->opcode == OP_INVALID
254 || State.Cpu.pCurInstr->opcode == OP_ILLUD2;
255 if (!fAllInvalid || State.fInvalid)
256 pfnFormatter(&State);
257 else
258 {
259 RTPrintf("%s: error at %#RX64: unexpected valid instruction\n", argv0, State.uAddress);
260 pfnFormatter(&State);
261 rcRet = VERR_GENERAL_FAILURE;
262 }
263 }
264 else
265 {
266 State.cbInstr = State.pbNext - State.pbInstr;
267 if (!State.cbLeft)
268 RTPrintf("%s: error at %#RX64: read beyond the end (%Rrc)\n", argv0, State.uAddress, rc);
269 else if (State.cbInstr)
270 RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d\n", argv0, State.uAddress, rc, State.cbInstr);
271 else
272 {
273 RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d!\n", argv0, State.uAddress, rc, State.cbInstr);
274 if (rcRet == VINF_SUCCESS)
275 rcRet = rc;
276 break;
277 }
278 }
279
280
281 /* next */
282 State.uAddress += State.cbInstr;
283 State.pbInstr += State.cbInstr;
284 }
285
286 return rcRet;
287}
288
289
290/**
291 * Prints usage info.
292 *
293 * @returns 1.
294 * @param argv0 The program name.
295 */
296static int Usage(const char *argv0)
297{
298 RTStrmPrintf(g_pStdErr,
299"usage: %s [options] <file1> [file2..fileN]\n"
300" or: %s <--help|-h>\n"
301"\n"
302"Options:\n"
303" --address|-a <address>\n"
304" The base address. Default: 0\n"
305" --max-bytes|-b <bytes>\n"
306" The maximum number of bytes to disassemble. Default: 1GB\n"
307" --cpumode|-c <16|32|64>\n"
308" The cpu mode. Default: 32\n"
309" --all-invalid|-i\n"
310" When specified all instructions are expected to be invalid.\n"
311" --listing|-l, --no-listing|-L\n"
312" Enables or disables listing mode. Default: --no-listing\n"
313" --offset|-o <offset>\n"
314" The file offset at which to start disassembling. Default: 0\n"
315" --raw|-r, --no-raw|-R\n"
316" Whether to employ byte defines for unknown bits. Default: --no-raw\n"
317" --style|-s <default|yasm|masm>\n"
318" The assembly output style. Default: default\n"
319 , argv0, argv0);
320 return 1;
321}
322
323
324int main(int argc, char **argv)
325{
326 RTR3Init();
327
328 /* options */
329 uint64_t uAddress = 0;
330 ASMSTYLE enmStyle = kAsmStyle_Default;
331 bool fListing = true;
332 bool fRaw = false;
333 bool fAllInvalid = false;
334 DISCPUMODE enmCpuMode = CPUMODE_32BIT;
335 RTFOFF off = 0;
336 RTFOFF cbMax = _1G;
337
338 /*
339 * Parse arguments.
340 */
341 static const RTOPTIONDEF g_aOptions[] =
342 {
343 { "--address", 'a', RTGETOPT_REQ_UINT64 },
344 { "--cpumode", 'c', RTGETOPT_REQ_UINT32 },
345 { "--help", 'h', 0 },
346 { "--bytes", 'b', RTGETOPT_REQ_INT64 },
347 { "--all-invalid", 'i', 0, },
348 { "--listing", 'l', 0 },
349 { "--no-listing", 'L', 0 },
350 { "--offset", 'o', RTGETOPT_REQ_INT64 },
351 { "--raw", 'r', 0 },
352 { "--no-raw", 'R', 0 },
353 { "--style", 's', RTGETOPT_REQ_STRING },
354 };
355
356 int ch;
357 int iArg = 1;
358 RTOPTIONUNION ValueUnion;
359 while ((ch = RTGetOpt(argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), &iArg, &ValueUnion)))
360 {
361 switch (ch)
362 {
363 case 'a':
364 uAddress = ValueUnion.u64;
365 break;
366
367 case 'b':
368 cbMax = ValueUnion.i;
369 break;
370
371 case 'c':
372 if (ValueUnion.u32 == 16)
373 enmCpuMode = CPUMODE_16BIT;
374 else if (ValueUnion.u32 == 32)
375 enmCpuMode = CPUMODE_32BIT;
376 else if (ValueUnion.u32 == 64)
377 enmCpuMode = CPUMODE_64BIT;
378 else
379 {
380 RTStrmPrintf(g_pStdErr, "%s: Invalid CPU mode value %RU32\n", argv[0], ValueUnion.u32);
381 return 1;
382 }
383 break;
384
385 case 'h':
386 return Usage(argv[0]);
387
388 case 'i':
389 fAllInvalid = true;
390 break;
391
392 case 'l':
393 fListing = true;
394 break;
395
396 case 'L':
397 fListing = false;
398 break;
399
400 case 'o':
401 off = ValueUnion.i;
402 break;
403
404 case 'r':
405 fRaw = true;
406 break;
407
408 case 'R':
409 fRaw = false;
410 break;
411
412 case 's':
413 if (!strcmp(ValueUnion.psz, "default"))
414 enmStyle = kAsmStyle_Default;
415 else if (!strcmp(ValueUnion.psz, "yasm"))
416 enmStyle = kAsmStyle_yasm;
417 else if (!strcmp(ValueUnion.psz, "masm"))
418 {
419 enmStyle = kAsmStyle_masm;
420 RTStrmPrintf(g_pStdErr, "%s: masm style isn't implemented yet\n", argv[0]);
421 return 1;
422 }
423 else
424 {
425 RTStrmPrintf(g_pStdErr, "%s: unknown assembly style: %s\n", argv[0], ValueUnion.psz);
426 return 1;
427 }
428 break;
429
430 default:
431 RTStrmPrintf(g_pStdErr, "%s: syntax error: %Rrc\n", argv[0], ch);
432 return 1;
433 }
434 }
435 if (iArg >= argc)
436 return Usage(argv[0]);
437
438 /*
439 * Process the files.
440 */
441 int rc = VINF_SUCCESS;
442 for ( ; iArg < argc; iArg++)
443 {
444 /*
445 * Read the file into memory.
446 */
447 void *pvFile;
448 size_t cbFile;
449 rc = RTFileReadAllEx(argv[iArg], off, cbMax, 0, &pvFile, &cbFile);
450 if (RT_FAILURE(rc))
451 {
452 RTStrmPrintf(g_pStdErr, "%s: %s: %Rrc\n", argv[0], argv[iArg], rc);
453 break;
454 }
455
456 /*
457 * Disassemble it.
458 */
459 rc = MyDisasmBlock(argv[0], enmCpuMode, uAddress, (uint8_t *)pvFile, cbFile, enmStyle, fListing, fRaw, fAllInvalid);
460 if (RT_FAILURE(rc))
461 break;
462 }
463
464 return RT_SUCCESS(rc) ? 0 : 1;
465}
466
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