VirtualBox

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

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

InnoTek -> innotek: all the headers and comments.

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