VirtualBox

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

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

Cleaned up disassembler

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
Line 
1/** @file
2 *
3 * VBox disassembler:
4 * Main
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#ifdef USING_VISUAL_STUDIO
24# include <stdafx.h>
25#endif
26#include <VBox/dis.h>
27#include <VBox/disopcode.h>
28#include <VBox/err.h>
29#include <iprt/assert.h>
30#include <iprt/string.h>
31#include "DisasmInternal.h"
32#include "DisasmTables.h"
33
34
35/**
36 * Disassembles a code block.
37 *
38 * @returns VBox error code
39 * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode
40 * set correctly.
41 * @param pvCodeBlock Pointer to the strunction to disassemble.
42 * @param cbMax Maximum number of bytes to disassemble.
43 * @param pcbSize Where to store the size of the instruction.
44 * NULL is allowed.
45 *
46 *
47 * @todo Define output callback.
48 * @todo Using signed integers as sizes is a bit odd. There are still
49 * some GCC warnings about mixing signed and unsigend integers.
50 * @todo Need to extend this interface to include a code address so we
51 * can dissassemble GC code. Perhaps a new function is better...
52 * @remark cbMax isn't respected as a boundry. DISInstr() will read beyond cbMax.
53 * This means *pcbSize >= cbMax sometimes.
54 */
55DISDECL(int) DISBlock(PDISCPUSTATE pCpu, RTUINTPTR pvCodeBlock, unsigned cbMax, unsigned *pSize)
56{
57 unsigned i = 0;
58 char szOutput[256];
59
60 while (i < cbMax)
61 {
62 unsigned cbInstr;
63 int rc = DISInstr(pCpu, pvCodeBlock + i, 0, &cbInstr, szOutput);
64 if (VBOX_FAILURE(rc))
65 return rc;
66
67 i += cbInstr;
68 }
69
70 if (pSize)
71 *pSize = i;
72 return true;
73}
74
75/**
76 * Disassembles one instruction
77 *
78 * @returns VBox error code
79 * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode
80 * set correctly.
81 * @param pu8Instruction Pointer to the strunction to disassemble.
82 * @param u32EipOffset Offset to add to instruction address to get the real virtual address
83 * @param pcbSize Where to store the size of the instruction.
84 * NULL is allowed.
85 * @param pszOutput Storage for disassembled instruction
86 *
87 * @todo Define output callback.
88 */
89DISDECL(int) DISInstr(PDISCPUSTATE pCpu, RTUINTPTR pu8Instruction, unsigned u32EipOffset, unsigned *pcbSize,
90 char *pszOutput)
91{
92 return DISInstrEx(pCpu, pu8Instruction, u32EipOffset, pcbSize, pszOutput, OPTYPE_ALL);
93}
94
95/**
96 * Disassembles one instruction; only fully disassembly an instruction if it matches the filter criteria
97 *
98 * @returns VBox error code
99 * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode
100 * set correctly.
101 * @param pu8Instruction Pointer to the strunction to disassemble.
102 * @param u32EipOffset Offset to add to instruction address to get the real virtual address
103 * @param pcbSize Where to store the size of the instruction.
104 * NULL is allowed.
105 * @param pszOutput Storage for disassembled instruction
106 * @param uFilter Instruction type filter
107 *
108 * @todo Define output callback.
109 */
110DISDECL(int) DISInstrEx(PDISCPUSTATE pCpu, RTUINTPTR pu8Instruction, unsigned u32EipOffset, unsigned *pcbSize,
111 char *pszOutput, unsigned uFilter)
112{
113 unsigned i = 0, prefixbytes;
114 unsigned idx, inc;
115#ifdef __L4ENV__
116 jmp_buf jumpbuffer;
117#endif
118
119 //reset instruction settings
120 pCpu->prefix = PREFIX_NONE;
121 pCpu->prefix_seg = 0;
122 pCpu->addrmode = pCpu->mode;
123 pCpu->opmode = pCpu->mode;
124 pCpu->ModRM = 0;
125 pCpu->SIB = 0;
126 pCpu->lastprefix = 0;
127 pCpu->param1.parval = 0;
128 pCpu->param2.parval = 0;
129 pCpu->param3.parval = 0;
130 pCpu->param1.szParam[0] = 0;
131 pCpu->param2.szParam[0] = 0;
132 pCpu->param3.szParam[0] = 0;
133 pCpu->param1.size = 0;
134 pCpu->param2.size = 0;
135 pCpu->param3.size = 0;
136 pCpu->param1.flags = 0;
137 pCpu->param2.flags = 0;
138 pCpu->param3.flags = 0;
139 pCpu->uFilter = uFilter;
140 pCpu->pfnDisasmFnTable = pfnFullDisasm;
141
142 if (pszOutput)
143 *pszOutput = '\0';
144
145 prefixbytes = 0;
146#ifndef __L4ENV__ /* Unfortunately, we have no exception handling in l4env */
147 try
148#else
149 pCpu->pJumpBuffer = &jumpbuffer;
150 if (setjmp(jumpbuffer) == 0)
151#endif
152 {
153 while(1)
154 {
155 uint8_t codebyte = DISReadByte(pCpu, pu8Instruction+i);
156 uint8_t opcode = g_aOneByteMapX86[codebyte].opcode;
157
158 /* Hardcoded assumption about OP_* values!! */
159 if (opcode <= OP_LOCK)
160 {
161 pCpu->lastprefix = opcode;
162 switch(opcode)
163 {
164 case OP_INVALID:
165#if 0 //defined (DEBUG_Sander)
166 AssertMsgFailed(("Invalid opcode!!\n"));
167#endif
168 return VERR_DIS_INVALID_OPCODE;
169
170 // segment override prefix byte
171 case OP_SEG:
172 pCpu->prefix_seg = g_aOneByteMapX86[codebyte].param1 - OP_PARM_REG_SEG_START;
173 pCpu->prefix |= PREFIX_SEG;
174 i += sizeof(uint8_t);
175 prefixbytes++;
176 continue; //fetch the next byte
177
178 // lock prefix byte
179 case OP_LOCK:
180 pCpu->prefix |= PREFIX_LOCK;
181 i += sizeof(uint8_t);
182 prefixbytes++;
183 continue; //fetch the next byte
184
185 // address size override prefix byte
186 case OP_ADRSIZE:
187 pCpu->prefix |= PREFIX_ADDRSIZE;
188 if(pCpu->mode == CPUMODE_16BIT)
189 pCpu->addrmode = CPUMODE_32BIT;
190 else pCpu->addrmode = CPUMODE_16BIT;
191 i += sizeof(uint8_t);
192 prefixbytes++;
193 continue; //fetch the next byte
194
195 // operand size override prefix byte
196 case OP_OPSIZE:
197 pCpu->prefix |= PREFIX_OPSIZE;
198 if(pCpu->mode == CPUMODE_16BIT)
199 pCpu->opmode = CPUMODE_32BIT;
200 else pCpu->opmode = CPUMODE_16BIT;
201 i += sizeof(uint8_t);
202 prefixbytes++;
203 continue; //fetch the next byte
204
205 // rep and repne are not really prefixes, but we'll treat them as such
206 case OP_REPE:
207 pCpu->prefix |= PREFIX_REP;
208 i += sizeof(uint8_t);
209 prefixbytes += sizeof(uint8_t);
210 continue; //fetch the next byte
211
212 case OP_REPNE:
213 pCpu->prefix |= PREFIX_REPNE;
214 i += sizeof(uint8_t);
215 prefixbytes += sizeof(uint8_t);
216 continue; //fetch the next byte
217 }
218 }
219
220 idx = i;
221 i += sizeof(uint8_t); //first opcode byte
222
223 pCpu->opcode = codebyte;
224 /* Prefix byte(s) is/are part of the instruction. */
225 pCpu->opaddr = pu8Instruction + idx + u32EipOffset - prefixbytes;
226
227 inc = ParseInstruction(pu8Instruction + i, &g_aOneByteMapX86[pCpu->opcode], pCpu);
228
229 pCpu->opsize = prefixbytes + inc + sizeof(uint8_t);
230
231 if(pszOutput) {
232 disasmSprintf(pszOutput, pu8Instruction+i-1-prefixbytes, pCpu, &pCpu->param1, &pCpu->param2, &pCpu->param3);
233 }
234
235 i += inc;
236 prefixbytes = 0;
237 break;
238 }
239 }
240#ifndef __L4ENV__
241 catch(...)
242#else
243 else /* setjmp has returned a non-zero value: an exception occured */
244#endif
245 {
246 if (pcbSize)
247 *pcbSize = 0;
248 return VERR_DIS_GEN_FAILURE;
249 }
250
251 if (pcbSize)
252 *pcbSize = i;
253
254 return VINF_SUCCESS;
255}
256//*****************************************************************************
257//*****************************************************************************
258char *DbgBytesToString(PDISCPUSTATE pCpu, RTUINTPTR pBytes, int size, char *pszOutput)
259{
260 char szByte[4];
261 int len = strlen(pszOutput);
262 int i;
263
264 for(i = len; i < 40; i++)
265 {
266 strcat(pszOutput, " ");
267 }
268 strcat(pszOutput, " [");
269 for(i = 0; i < size; i++)
270 {
271 RTStrPrintf(szByte, sizeof(szByte), "%02X ", DISReadByte(pCpu, pBytes+i));
272 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, szByte);
273 }
274 len = strlen(pszOutput);
275 pszOutput[len - 1] = 0; //cut off last space
276
277 strcat(pszOutput, "]");
278 return pszOutput;
279}
280//*****************************************************************************
281//*****************************************************************************
282void disasmSprintf(char *pszOutput, RTUINTPTR pu8Instruction, PDISCPUSTATE pCpu, OP_PARAMETER *pParam1, OP_PARAMETER *pParam2, OP_PARAMETER *pParam3)
283{
284 const char *lpszFormat = pCpu->pszOpcode;
285 int param = 1;
286
287 RTStrPrintf(pszOutput, 64, "%08X: ", (unsigned)pCpu->opaddr);
288 if(pCpu->prefix & PREFIX_LOCK)
289 {
290 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "lock ");
291 }
292 if(pCpu->prefix & PREFIX_REP)
293 {
294 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "rep(e) ");
295 }
296 else
297 if(pCpu->prefix & PREFIX_REPNE)
298 {
299 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "repne ");
300 }
301
302 if(!strcmp("Invalid Opcode", lpszFormat))
303 {
304 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "Invalid Opcode [%02X][%02X]", DISReadByte(pCpu, pu8Instruction), DISReadByte(pCpu, pu8Instruction+1) );
305 }
306 else
307 while(*lpszFormat)
308 {
309 switch(*lpszFormat)
310 {
311 case '%':
312 switch(*(lpszFormat+1))
313 {
314 case 'J': //Relative jump offset
315 {
316 int32_t disp;
317
318 AssertMsg(param == 1, ("Invalid branch parameter nr"));
319 if(pParam1->flags & USE_IMMEDIATE8_REL)
320 {
321 disp = (int32_t)(char)pParam1->parval;
322 }
323 else
324 if(pParam1->flags & USE_IMMEDIATE16_REL)
325 {
326 disp = (int32_t)(uint16_t)pParam1->parval;
327 }
328 else
329 if(pParam1->flags & USE_IMMEDIATE32_REL)
330 {
331 disp = (int32_t)pParam1->parval;
332 }
333 else
334 {
335 AssertMsgFailed(("Oops!\n"));
336 return;
337 }
338 uint32_t addr = (uint32_t)(pCpu->opaddr + pCpu->opsize) + disp;
339 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "[%08X]", addr);
340 }
341
342 //no break;
343
344 case 'A': //direct address
345 case 'C': //control register
346 case 'D': //debug register
347 case 'E': //ModRM specifies parameter
348 case 'F': //Eflags register
349 case 'G': //ModRM selects general register
350 case 'I': //Immediate data
351 case 'M': //ModRM may only refer to memory
352 case 'O': //No ModRM byte
353 case 'P': //ModRM byte selects MMX register
354 case 'Q': //ModRM byte selects MMX register or memory address
355 case 'R': //ModRM byte may only refer to a general register
356 case 'S': //ModRM byte selects a segment register
357 case 'T': //ModRM byte selects a test register
358 case 'V': //ModRM byte selects an XMM/SSE register
359 case 'W': //ModRM byte selects an XMM/SSE register or a memory address
360 case 'X': //DS:SI
361 case 'Y': //ES:DI
362 switch(param)
363 {
364 case 1:
365 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, pParam1->szParam);
366 break;
367 case 2:
368 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, pParam2->szParam);
369 break;
370 case 3:
371 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, pParam3->szParam);
372 break;
373 }
374 break;
375
376 case 'e': //register based on operand size (e.g. %eAX)
377 if(pCpu->opmode == CPUMODE_32BIT)
378 {
379 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "E");
380 }
381 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "%c%c", lpszFormat[2], lpszFormat[3]);
382 break;
383
384 default:
385 AssertMsgFailed(("Oops!\n"));
386 break;
387 }
388
389 //Go to the next parameter in the format string
390 while(*lpszFormat && *lpszFormat != ',') lpszFormat++;
391 if(*lpszFormat == ',') lpszFormat--;
392
393 break;
394
395 case ',':
396 param++;
397 //no break
398
399 default:
400 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "%c", *lpszFormat);
401 break;
402 }
403
404 if(*lpszFormat) lpszFormat++;
405 }
406 DbgBytesToString(pCpu, pu8Instruction, pCpu->opsize, pszOutput);
407 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "\n");
408}
409//*****************************************************************************
410//*****************************************************************************
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