VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

  • 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 Success indicator.
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(bool) DISBlock(PDISCPUSTATE pCpu, RTUINTPTR pvCodeBlock, int32_t cbMax, uint32_t *pSize)
56{
57 int32_t i = 0;
58 char szOutput[256];
59
60 while (i < cbMax)
61 {
62 uint32_t cbInstr;
63 if (!DISInstr(pCpu, pvCodeBlock + i, 0, &cbInstr, szOutput))
64 return false;
65
66 i += cbInstr;
67 }
68
69 if (pSize)
70 *pSize = i;
71 return true;
72}
73
74/**
75 * Disassembles one instruction
76 *
77 * @returns Success indicator.
78 * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode
79 * set correctly.
80 * @param pu8Instruction Pointer to the strunction to disassemble.
81 * @param u32EipOffset Offset to add to instruction address to get the real virtual address
82 * @param pcbSize Where to store the size of the instruction.
83 * NULL is allowed.
84 * @param pszOutput Storage for disassembled instruction
85 *
86 * @todo Define output callback.
87 */
88DISDECL(bool) DISInstr(PDISCPUSTATE pCpu, RTUINTPTR pu8Instruction, uint32_t u32EipOffset, uint32_t *pcbSize,
89 char *pszOutput)
90{
91 return DISInstrEx(pCpu, pu8Instruction, u32EipOffset, pcbSize, pszOutput, OPTYPE_ALL);
92}
93
94/**
95 * Disassembles one instruction; only fully disassembly an instruction if it matches the filter criteria
96 *
97 * @returns Success indicator.
98 * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode
99 * set correctly.
100 * @param pu8Instruction Pointer to the strunction to disassemble.
101 * @param u32EipOffset Offset to add to instruction address to get the real virtual address
102 * @param pcbSize Where to store the size of the instruction.
103 * NULL is allowed.
104 * @param pszOutput Storage for disassembled instruction
105 * @param uFilter Instruction type filter
106 *
107 * @todo Define output callback.
108 */
109DISDECL(bool) DISInstrEx(PDISCPUSTATE pCpu, RTUINTPTR pu8Instruction, uint32_t u32EipOffset, uint32_t *pcbSize,
110 char *pszOutput, uint32_t uFilter)
111{
112 int i = 0, prefixbytes;
113 int idx, inc;
114#ifdef __L4ENV__
115 jmp_buf jumpbuffer;
116#endif
117
118 //reset instruction settings
119 pCpu->prefix = PREFIX_NONE;
120 pCpu->prefix_seg = 0;
121 pCpu->addrmode = pCpu->mode;
122 pCpu->opmode = pCpu->mode;
123 pCpu->ModRM = 0;
124 pCpu->SIB = 0;
125 pCpu->lastprefix = 0;
126 pCpu->param1.parval = 0;
127 pCpu->param2.parval = 0;
128 pCpu->param3.parval = 0;
129 pCpu->param1.szParam[0] = 0;
130 pCpu->param2.szParam[0] = 0;
131 pCpu->param3.szParam[0] = 0;
132 pCpu->param1.size = 0;
133 pCpu->param2.size = 0;
134 pCpu->param3.size = 0;
135 pCpu->param1.flags = 0;
136 pCpu->param2.flags = 0;
137 pCpu->param3.flags = 0;
138 pCpu->uFilter = uFilter;
139 pCpu->pfnDisasmFnTable = pfnFullDisasm;
140
141 if (pszOutput)
142 *pszOutput = '\0';
143
144 prefixbytes = 0;
145#ifndef __L4ENV__ /* Unfortunately, we have no exception handling in l4env */
146 try
147#else
148 pCpu->pJumpBuffer = &jumpbuffer;
149 if (setjmp(jumpbuffer) == 0)
150#endif
151 {
152 while(1)
153 {
154 uint8_t codebyte = DISReadByte(pCpu, pu8Instruction+i);
155 uint8_t opcode = g_aOneByteMapX86[codebyte].opcode;
156
157 /* Hardcoded assumption about OP_* values!! */
158 if (opcode <= OP_LOCK)
159 {
160 pCpu->lastprefix = opcode;
161 switch(opcode)
162 {
163 case OP_INVALID:
164#if 0 //defined (DEBUG_Sander)
165 AssertMsgFailed(("Invalid opcode!!\n"));
166#endif
167 return false;
168
169 // segment override prefix byte
170 case OP_SEG:
171 pCpu->prefix_seg = g_aOneByteMapX86[codebyte].param1 - OP_PARM_REG_SEG_START;
172 pCpu->prefix |= PREFIX_SEG;
173 i += sizeof(uint8_t);
174 prefixbytes++;
175 continue; //fetch the next byte
176
177 // lock prefix byte
178 case OP_LOCK:
179 pCpu->prefix |= PREFIX_LOCK;
180 i += sizeof(uint8_t);
181 prefixbytes++;
182 continue; //fetch the next byte
183
184 // address size override prefix byte
185 case OP_ADRSIZE:
186 pCpu->prefix |= PREFIX_ADDRSIZE;
187 if(pCpu->mode == CPUMODE_16BIT)
188 pCpu->addrmode = CPUMODE_32BIT;
189 else pCpu->addrmode = CPUMODE_16BIT;
190 i += sizeof(uint8_t);
191 prefixbytes++;
192 continue; //fetch the next byte
193
194 // operand size override prefix byte
195 case OP_OPSIZE:
196 pCpu->prefix |= PREFIX_OPSIZE;
197 if(pCpu->mode == CPUMODE_16BIT)
198 pCpu->opmode = CPUMODE_32BIT;
199 else pCpu->opmode = CPUMODE_16BIT;
200 i += sizeof(uint8_t);
201 prefixbytes++;
202 continue; //fetch the next byte
203
204 // rep and repne are not really prefixes, but we'll treat them as such
205 case OP_REPE:
206 pCpu->prefix |= PREFIX_REP;
207 i += sizeof(uint8_t);
208 prefixbytes += sizeof(uint8_t);
209 continue; //fetch the next byte
210
211 case OP_REPNE:
212 pCpu->prefix |= PREFIX_REPNE;
213 i += sizeof(uint8_t);
214 prefixbytes += sizeof(uint8_t);
215 continue; //fetch the next byte
216 }
217 }
218
219 idx = i;
220 i += sizeof(uint8_t); //first opcode byte
221
222 pCpu->opcode = codebyte;
223 /* Prefix byte(s) is/are part of the instruction. */
224 pCpu->opaddr = pu8Instruction + idx + u32EipOffset - prefixbytes;
225
226 inc = ParseInstruction(pu8Instruction + i, &g_aOneByteMapX86[pCpu->opcode], pCpu);
227
228 pCpu->opsize = prefixbytes + inc + sizeof(uint8_t);
229
230 if(pszOutput) {
231 disasmSprintf(pszOutput, pu8Instruction+i-1-prefixbytes, pCpu, &pCpu->param1, &pCpu->param2, &pCpu->param3);
232 }
233
234 i += inc;
235 prefixbytes = 0;
236 break;
237 }
238 }
239#ifndef __L4ENV__
240 catch(...)
241#else
242 else /* setjmp has returned a non-zero value: an exception occured */
243#endif
244 {
245 if (pcbSize)
246 *pcbSize = 0;
247 return false;
248 }
249
250 if (pcbSize)
251 *pcbSize = i;
252
253 return true;
254}
255//*****************************************************************************
256//*****************************************************************************
257char *DbgBytesToString(PDISCPUSTATE pCpu, RTUINTPTR pBytes, int size, char *pszOutput)
258{
259 char szByte[4];
260 int len = strlen(pszOutput);
261 int i;
262
263 for(i = len; i < 40; i++)
264 {
265 strcat(pszOutput, " ");
266 }
267 strcat(pszOutput, " [");
268 for(i = 0; i < size; i++)
269 {
270 RTStrPrintf(szByte, sizeof(szByte), "%02X ", DISReadByte(pCpu, pBytes+i));
271 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, szByte);
272 }
273 len = strlen(pszOutput);
274 pszOutput[len - 1] = 0; //cut off last space
275
276 strcat(pszOutput, "]");
277 return pszOutput;
278}
279//*****************************************************************************
280//*****************************************************************************
281void disasmSprintf(char *pszOutput, RTUINTPTR pu8Instruction, PDISCPUSTATE pCpu, OP_PARAMETER *pParam1, OP_PARAMETER *pParam2, OP_PARAMETER *pParam3)
282{
283 const char *lpszFormat = pCpu->pszOpcode;
284 int param = 1;
285
286 RTStrPrintf(pszOutput, 64, "%08X: ", (unsigned)pCpu->opaddr);
287 if(pCpu->prefix & PREFIX_LOCK)
288 {
289 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "lock ");
290 }
291 if(pCpu->prefix & PREFIX_REP)
292 {
293 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "rep(e) ");
294 }
295 else
296 if(pCpu->prefix & PREFIX_REPNE)
297 {
298 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "repne ");
299 }
300
301 if(!strcmp("Invalid Opcode", lpszFormat))
302 {
303 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "Invalid Opcode [%02X][%02X]", DISReadByte(pCpu, pu8Instruction), DISReadByte(pCpu, pu8Instruction+1) );
304 }
305 else
306 while(*lpszFormat)
307 {
308 switch(*lpszFormat)
309 {
310 case '%':
311 switch(*(lpszFormat+1))
312 {
313 case 'J': //Relative jump offset
314 {
315 int32_t disp;
316
317 AssertMsg(param == 1, ("Invalid branch parameter nr"));
318 if(pParam1->flags & USE_IMMEDIATE8_REL)
319 {
320 disp = (int32_t)(char)pParam1->parval;
321 }
322 else
323 if(pParam1->flags & USE_IMMEDIATE16_REL)
324 {
325 disp = (int32_t)(uint16_t)pParam1->parval;
326 }
327 else
328 if(pParam1->flags & USE_IMMEDIATE32_REL)
329 {
330 disp = (int32_t)pParam1->parval;
331 }
332 else
333 {
334 AssertMsgFailed(("Oops!\n"));
335 return;
336 }
337 uint32_t addr = (uint32_t)(pCpu->opaddr + pCpu->opsize) + disp;
338 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "[%08X]", addr);
339 }
340
341 //no break;
342
343 case 'A': //direct address
344 case 'C': //control register
345 case 'D': //debug register
346 case 'E': //ModRM specifies parameter
347 case 'F': //Eflags register
348 case 'G': //ModRM selects general register
349 case 'I': //Immediate data
350 case 'M': //ModRM may only refer to memory
351 case 'O': //No ModRM byte
352 case 'P': //ModRM byte selects MMX register
353 case 'Q': //ModRM byte selects MMX register or memory address
354 case 'R': //ModRM byte may only refer to a general register
355 case 'S': //ModRM byte selects a segment register
356 case 'T': //ModRM byte selects a test register
357 case 'V': //ModRM byte selects an XMM/SSE register
358 case 'W': //ModRM byte selects an XMM/SSE register or a memory address
359 case 'X': //DS:SI
360 case 'Y': //ES:DI
361 switch(param)
362 {
363 case 1:
364 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, pParam1->szParam);
365 break;
366 case 2:
367 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, pParam2->szParam);
368 break;
369 case 3:
370 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, pParam3->szParam);
371 break;
372 }
373 break;
374
375 case 'e': //register based on operand size (e.g. %eAX)
376 if(pCpu->opmode == CPUMODE_32BIT)
377 {
378 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "E");
379 }
380 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "%c%c", lpszFormat[2], lpszFormat[3]);
381 break;
382
383 default:
384 AssertMsgFailed(("Oops!\n"));
385 break;
386 }
387
388 //Go to the next parameter in the format string
389 while(*lpszFormat && *lpszFormat != ',') lpszFormat++;
390 if(*lpszFormat == ',') lpszFormat--;
391
392 break;
393
394 case ',':
395 param++;
396 //no break
397
398 default:
399 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "%c", *lpszFormat);
400 break;
401 }
402
403 if(*lpszFormat) lpszFormat++;
404 }
405 DbgBytesToString(pCpu, pu8Instruction, pCpu->opsize, pszOutput);
406 RTStrPrintf(&pszOutput[strlen(pszOutput)], 64, "\n");
407}
408//*****************************************************************************
409//*****************************************************************************
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