Changeset 41781 in vbox for trunk/src/VBox
- Timestamp:
- Jun 16, 2012 7:02:30 PM (13 years ago)
- Location:
- trunk/src/VBox/Disassembler
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Disassembler/DisasmCore.cpp
r41760 r41781 26 26 #include <VBox/log.h> 27 27 #include <iprt/assert.h> 28 #include <iprt/param.h> 28 29 #include <iprt/string.h> 29 30 #include <iprt/stdarg.h> … … 46 47 * Internal Functions * 47 48 *******************************************************************************/ 48 static int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr);49 static unsigned disParseInstruction(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISCPUSTATE pCpu);50 51 static unsigned QueryModRM(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);52 static unsigned QueryModRM_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);53 static void UseSIB(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);54 static unsigned ParseSIB_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);55 56 49 static void disasmModRMReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr); 57 50 static void disasmModRMReg16(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam); 58 51 static void disasmModRMSReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam); 59 60 static void disValidateLockSequence(PDISCPUSTATE pCpu);61 62 /* Read functions */63 static uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress);64 static uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);65 static uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);66 static uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);67 static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead);68 52 69 53 … … 227 211 228 212 213 214 215 216 //***************************************************************************** 217 /* Read functions for getting the opcode bytes */ 218 //***************************************************************************** 219 220 229 221 /** 230 * Parses one guest instruction. 222 * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.} 223 */ 224 static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead) 225 { 226 #ifdef IN_RING0 227 AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n")); 228 RT_BZERO(&pDis->abInstr[offInstr], cbMaxRead); 229 pDis->cbCachedInstr = offInstr + cbMaxRead; 230 return VERR_DIS_NO_READ_CALLBACK; 231 #else 232 uint8_t const *pbSrc = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr; 233 size_t cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK; 234 uint8_t cbToRead = cbLeftOnPage >= cbMaxRead 235 ? cbMaxRead 236 : cbLeftOnPage <= cbMinRead 237 ? cbMinRead 238 : (uint8_t)cbLeftOnPage; 239 memcpy(&pDis->abInstr[offInstr], pbSrc, cbToRead); 240 pDis->cbCachedInstr = offInstr + cbToRead; 241 return VINF_SUCCESS; 242 #endif 243 } 244 245 246 /** 247 * Read more bytes into the DISCPUSTATE::abInstr buffer, advance 248 * DISCPUSTATE::cbCachedInstr. 231 249 * 232 * The result is found in pCpu and pcbInstr.250 * Will set DISCPUSTATE::rc on failure, but still advance cbCachedInstr. 233 251 * 234 * @returns VBox status code. 235 * @param pvInstr Address of the instruction to decode. This is a 236 * real address in the current context that can be 237 * accessed without faulting. (Consider 238 * DISInstrWithReader if this isn't the case.) 239 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT. 240 * @param pfnReadBytes Callback for reading instruction bytes. 241 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.) 242 * @param pCpu Pointer to cpu structure. Will be initialized. 243 * @param pcbInstr Where to store the size of the instruction. 244 * NULL is allowed. This is also stored in 245 * PDISCPUSTATE::cbInstr. 252 * The caller shall fend off reads beyond the DISCPUSTATE::abInstr buffer. 253 * 254 * @param pCpu The disassembler state. 255 * @param off The offset of the read request. 256 * @param cbMin The size of the read request that needs to be 257 * satisfied. 246 258 */ 247 DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISCPUSTATE pCpu, uint32_t *pcbInstr) 248 { 249 return DISInstEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pCpu, pcbInstr); 259 DECL_NO_INLINE(static, void) disReadMore(PDISCPUSTATE pCpu, uint8_t off, uint8_t cbMin) 260 { 261 Assert(cbMin + off <= sizeof(pCpu->abInstr)); 262 263 /* 264 * Adjust the incoming request to not overlap with bytes that has already 265 * been read and to make sure we don't leave unread gaps. 266 */ 267 if (off < pCpu->cbCachedInstr) 268 { 269 Assert(off + cbMin > pCpu->cbCachedInstr); 270 cbMin -= pCpu->cbCachedInstr - off; 271 off = pCpu->cbCachedInstr; 272 } 273 else if (off > pCpu->cbCachedInstr) 274 { 275 cbMin += off - pCpu->cbCachedInstr; 276 off = pCpu->cbCachedInstr; 277 } 278 279 /* 280 * Do the read. 281 * (No need to zero anything on failure as abInstr is already zeroed by the 282 * DISInstrEx API.) 283 */ 284 int rc = pCpu->pfnReadBytes(pCpu, off, cbMin, sizeof(pCpu->abInstr) - off); 285 if (RT_SUCCESS(rc)) 286 { 287 Assert(pCpu->cbCachedInstr >= off + cbMin); 288 Assert(pCpu->cbCachedInstr <= sizeof(pCpu->abInstr)); 289 } 290 else 291 { 292 Log(("disReadMore failed with rc=%Rrc!!\n", rc)); 293 pCpu->rc = VERR_DIS_MEM_READ; 294 } 250 295 } 251 296 252 297 253 298 /** 254 * Parses one guest instruction.299 * Function for handling a 8-bit cache miss. 255 300 * 256 * The result is found in pCpu and pcbInstr. 301 * @returns The requested byte. 302 * @param pCpu The disassembler state. 303 * @param off The offset of the byte relative to the 304 * instruction. 305 */ 306 DECL_NO_INLINE(static, uint8_t) disReadByteSlow(PDISCPUSTATE pCpu, RTUINTPTR off) 307 { 308 if (RT_UNLIKELY(off >= DIS_MAX_INSTR_LENGTH)) 309 { 310 Log(("disReadByte: too long instruction...\n")); 311 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 312 return 0; 313 } 314 315 if (off <= pCpu->cbCachedInstr) 316 disReadMore(pCpu, off, 1); 317 318 return pCpu->abInstr[off]; 319 } 320 321 322 /** 323 * Read a byte (8-bit) instruction byte by offset. 257 324 * 258 * @returns VBox status code. 259 * @param uInstrAddr Address of the instruction to decode. What this means 260 * is left to the pfnReadBytes function. 261 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT. 262 * @param pfnReadBytes Callback for reading instruction bytes. 263 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.) 264 * @param pCpu Pointer to cpu structure. Will be initialized. 265 * @param pcbInstr Where to store the size of the instruction. 266 * NULL is allowed. This is also stored in 267 * PDISCPUSTATE::cbInstr. 325 * @returns The requested byte. 326 * @param pCpu The disassembler state. 327 * @param uAddress The address. 268 328 */ 269 DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, 270 PDISCPUSTATE pCpu, uint32_t *pcbInstr) 271 { 272 return DISInstEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pCpu, pcbInstr); 329 DECLINLINE(uint8_t) disReadByteByOff(PDISCPUSTATE pCpu, RTUINTPTR off) 330 { 331 if (RT_UNLIKELY(off >= pCpu->cbCachedInstr)) 332 return disReadByteSlow(pCpu, off); 333 334 return pCpu->abInstr[off]; 273 335 } 274 336 275 337 276 338 /** 277 * Disassembles on instruction, details in @a pCpu and length in @a pcbInstr.339 * Read a byte (8-bit) instruction byte. 278 340 * 279 * @returns VBox status code. 280 * @param uInstrAddr Address of the instruction to decode. What this means 281 * is left to the pfnReadBytes function. 282 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT. 283 * @param pfnReadBytes Callback for reading instruction bytes. 284 * @param fFilter Instruction type filter. 285 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.) 286 * @param pCpu Pointer to CPU structure. With the exception of 287 * DISCPUSTATE::pvUser2, the structure will be 288 * completely initialized by this API, i.e. no input is 289 * taken from it. 290 * @param pcbInstr Where to store the size of the instruction. (This 291 * is also stored in PDISCPUSTATE::cbInstr.) Optional. 341 * @returns The requested byte. 342 * @param pCpu The disassembler state. 343 * @param uAddress The address. 292 344 */ 293 DISDECL(int) DISInstEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter, 294 PFNDISREADBYTES pfnReadBytes, void *pvUser, 295 PDISCPUSTATE pCpu, uint32_t *pcbInstr) 296 { 297 PCDISOPCODE paOneByteMap; 298 299 /* 300 * Initialize the CPU state. 301 * Note! The RT_BZERO make ASSUMPTIONS about the placement of pvUser2. 302 */ 303 RT_BZERO(pCpu, RT_OFFSETOF(DISCPUSTATE, pvUser2)); 304 305 pCpu->uCpuMode = enmCpuMode; 306 if (enmCpuMode == DISCPUMODE_64BIT) 307 { 308 paOneByteMap = g_aOneByteMapX64; 309 pCpu->uAddrMode = DISCPUMODE_64BIT; 310 pCpu->uOpMode = DISCPUMODE_32BIT; 311 } 312 else 313 { 314 paOneByteMap = g_aOneByteMapX86; 315 pCpu->uAddrMode = enmCpuMode; 316 pCpu->uOpMode = enmCpuMode; 317 } 318 pCpu->fPrefix = DISPREFIX_NONE; 319 pCpu->idxSegPrefix = DISSELREG_DS; 320 pCpu->uInstrAddr = uInstrAddr; 321 pCpu->pfnDisasmFnTable = g_apfnFullDisasm; 322 pCpu->fFilter = fFilter; 323 pCpu->rc = VINF_SUCCESS; 324 pCpu->pfnReadBytes = pfnReadBytes ? pfnReadBytes : disReadBytesDefault; 325 pCpu->pvUser = pvUser; 326 327 return disInstrWorker(pCpu, uInstrAddr, paOneByteMap, pcbInstr); 345 DECL_FORCE_INLINE(uint8_t) disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 346 { 347 return disReadByteByOff(pCpu, uAddress - pCpu->uInstrAddr); 328 348 } 329 349 330 350 331 351 /** 332 * Internal worker for DISInstEx.352 * Function for handling a 16-bit cache miss. 333 353 * 334 * @returns VBox status code. 335 * @param pCpu Initialized cpu state. 336 * @param paOneByteMap The one byte opcode map to use. 337 * @param uInstrAddr Instruction address. 338 * @param pcbInstr Where to store the instruction size. Can be NULL. 354 * @returns The requested word. 355 * @param pCpu The disassembler state. 356 * @param off The offset of the word relative to the 357 * instruction. 339 358 */ 340 static int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr) 341 { 342 /* 343 * Parse byte by byte. 344 */ 345 unsigned iByte = 0; 346 unsigned cbInc; 347 for (;;) 348 { 349 uint8_t codebyte = disReadByte(pCpu, uInstrAddr+iByte); 350 uint8_t opcode = paOneByteMap[codebyte].uOpcode; 351 352 /* Hardcoded assumption about OP_* values!! */ 353 if (opcode <= OP_LAST_PREFIX) 359 DECL_NO_INLINE(static, uint16_t) disReadWordSlow(PDISCPUSTATE pCpu, RTUINTPTR off) 360 { 361 if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH)) 362 { 363 Log(("disReadWord: too long instruction...\n")); 364 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 365 if (off < DIS_MAX_INSTR_LENGTH) 366 return pCpu->abInstr[off]; 367 return 0; 368 } 369 370 if (off + 2 < pCpu->cbCachedInstr) 371 disReadMore(pCpu, off, 2); 372 373 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 374 return *(uint16_t const *)&pCpu->abInstr[off]; 375 #else 376 return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]); 377 #endif 378 } 379 380 381 /** 382 * Read a word (16-bit) instruction byte by offset. 383 * 384 * @returns The requested word. 385 * @param pCpu The disassembler state. 386 * @param uAddress The address. 387 */ 388 DECLINLINE(uint16_t) disReadWordByOff(PDISCPUSTATE pCpu, RTUINTPTR off) 389 { 390 if (RT_UNLIKELY(off + 2 > pCpu->cbCachedInstr)) 391 return disReadWordSlow(pCpu, off); 392 393 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 394 return *(uint16_t const *)&pCpu->abInstr[off]; 395 #else 396 return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]); 397 #endif 398 } 399 400 401 /** 402 * Read a word (16-bit) instruction byte. 403 * 404 * @returns The requested word. 405 * @param pCpu The disassembler state. 406 * @param uAddress The address. 407 */ 408 DECL_FORCE_INLINE(uint16_t) disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 409 { 410 return disReadWordByOff(pCpu, uAddress - pCpu->uInstrAddr); 411 } 412 413 414 /** 415 * Function for handling a 32-bit cache miss. 416 * 417 * @returns The requested dword. 418 * @param pCpu The disassembler state. 419 * @param off The offset of the dword relative to the 420 * instruction. 421 */ 422 DECL_NO_INLINE(static, uint32_t) disReadDWordSlow(PDISCPUSTATE pCpu, RTUINTPTR off) 423 { 424 if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH)) 425 { 426 Log(("disReadDWord: too long instruction...\n")); 427 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 428 switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off) 354 429 { 355 /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */ 356 if (opcode != OP_REX) 357 { 358 /** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */ 359 pCpu->bLastPrefix = opcode; 360 pCpu->fPrefix &= ~DISPREFIX_REX; 361 } 362 363 switch (opcode) 364 { 365 case OP_INVALID: 366 if (pcbInstr) 367 *pcbInstr = iByte + 1; 368 return pCpu->rc = VERR_DIS_INVALID_OPCODE; 369 370 // segment override prefix byte 371 case OP_SEG: 372 pCpu->idxSegPrefix = (DISSELREG)(paOneByteMap[codebyte].fParam1 - OP_PARM_REG_SEG_START); 373 /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */ 374 if ( pCpu->uCpuMode != DISCPUMODE_64BIT 375 || pCpu->idxSegPrefix >= DISSELREG_FS) 376 { 377 pCpu->fPrefix |= DISPREFIX_SEG; 378 } 379 iByte += sizeof(uint8_t); 380 continue; //fetch the next byte 381 382 // lock prefix byte 383 case OP_LOCK: 384 pCpu->fPrefix |= DISPREFIX_LOCK; 385 iByte += sizeof(uint8_t); 386 continue; //fetch the next byte 387 388 // address size override prefix byte 389 case OP_ADDRSIZE: 390 pCpu->fPrefix |= DISPREFIX_ADDRSIZE; 391 if (pCpu->uCpuMode == DISCPUMODE_16BIT) 392 pCpu->uAddrMode = DISCPUMODE_32BIT; 393 else 394 if (pCpu->uCpuMode == DISCPUMODE_32BIT) 395 pCpu->uAddrMode = DISCPUMODE_16BIT; 396 else 397 pCpu->uAddrMode = DISCPUMODE_32BIT; /* 64 bits */ 398 399 iByte += sizeof(uint8_t); 400 continue; //fetch the next byte 401 402 // operand size override prefix byte 403 case OP_OPSIZE: 404 pCpu->fPrefix |= DISPREFIX_OPSIZE; 405 if (pCpu->uCpuMode == DISCPUMODE_16BIT) 406 pCpu->uOpMode = DISCPUMODE_32BIT; 407 else 408 pCpu->uOpMode = DISCPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */ 409 410 iByte += sizeof(uint8_t); 411 continue; //fetch the next byte 412 413 // rep and repne are not really prefixes, but we'll treat them as such 414 case OP_REPE: 415 pCpu->fPrefix |= DISPREFIX_REP; 416 iByte += sizeof(uint8_t); 417 continue; //fetch the next byte 418 419 case OP_REPNE: 420 pCpu->fPrefix |= DISPREFIX_REPNE; 421 iByte += sizeof(uint8_t); 422 continue; //fetch the next byte 423 424 case OP_REX: 425 Assert(pCpu->uCpuMode == DISCPUMODE_64BIT); 426 /* REX prefix byte */ 427 pCpu->fPrefix |= DISPREFIX_REX; 428 pCpu->fRexPrefix = DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].fParam1); 429 iByte += sizeof(uint8_t); 430 431 if (pCpu->fRexPrefix & DISPREFIX_REX_FLAGS_W) 432 pCpu->uOpMode = DISCPUMODE_64BIT; /* overrides size prefix byte */ 433 continue; //fetch the next byte 434 } 435 } 436 437 unsigned uIdx = iByte; 438 iByte += sizeof(uint8_t); //first opcode byte 439 440 pCpu->bOpCode = codebyte; 441 442 cbInc = disParseInstruction(uInstrAddr + iByte, &paOneByteMap[pCpu->bOpCode], pCpu); 443 iByte += cbInc; 444 break; 445 } 446 447 pCpu->cbInstr = iByte; 448 if (pcbInstr) 449 *pcbInstr = iByte; 450 451 if (pCpu->fPrefix & DISPREFIX_LOCK) 452 disValidateLockSequence(pCpu); 453 454 return pCpu->rc; 455 } 430 case 1: 431 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], 0, 0, 0); 432 case 2: 433 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0); 434 case 3: 435 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0); 436 } 437 return 0; 438 } 439 440 if (off + 2 < pCpu->cbCachedInstr) 441 disReadMore(pCpu, off, 2); 442 443 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 444 return *(uint32_t const *)&pCpu->abInstr[off]; 445 #else 446 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]); 447 #endif 448 } 449 450 451 /** 452 * Read a dword (32-bit) instruction byte by offset. 453 * 454 * @returns The requested dword. 455 * @param pCpu The disassembler state. 456 * @param uAddress The address. 457 */ 458 DECLINLINE(uint32_t) disReadDWordByOff(PDISCPUSTATE pCpu, RTUINTPTR off) 459 { 460 if (RT_UNLIKELY(off + 2 > pCpu->cbCachedInstr)) 461 return disReadDWordSlow(pCpu, off); 462 463 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 464 return *(uint32_t const *)&pCpu->abInstr[off]; 465 #else 466 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]); 467 #endif 468 } 469 470 471 /** 472 * Read a dword (32-bit) instruction byte. 473 * 474 * @returns The requested dword. 475 * @param pCpu The disassembler state. 476 * @param uAddress The address. 477 */ 478 DECL_FORCE_INLINE(uint32_t) disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 479 { 480 return disReadDWordByOff(pCpu, uAddress - pCpu->uInstrAddr); 481 } 482 483 484 /** 485 * Function for handling a 64-bit cache miss. 486 * 487 * @returns The requested qword. 488 * @param pCpu The disassembler state. 489 * @param off The offset of the qword relative to the 490 * instruction. 491 */ 492 DECL_NO_INLINE(static, uint64_t) disReadQWordSlow(PDISCPUSTATE pCpu, RTUINTPTR off) 493 { 494 if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH)) 495 { 496 Log(("disReadQWord: too long instruction...\n")); 497 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 498 switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off) 499 { 500 case 1: 501 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], 0, 0, 0, 0, 0, 0, 0); 502 case 2: 503 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0, 0, 0, 0, 0); 504 case 3: 505 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0, 0, 0, 0, 0); 506 case 4: 507 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 508 pCpu->abInstr[off + 4], 0, 0, 0); 509 case 5: 510 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 511 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], 0, 0); 512 case 6: 513 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 514 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], 0); 515 } 516 return 0; 517 } 518 519 if (off + 2 < pCpu->cbCachedInstr) 520 disReadMore(pCpu, off, 2); 521 522 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 523 return *(uint64_t const *)&pCpu->abInstr[off]; 524 #else 525 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 526 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]); 527 #endif 528 } 529 530 531 /** 532 * Read a qword (64-bit) instruction byte by offset. 533 * 534 * @returns The requested qword. 535 * @param pCpu The disassembler state. 536 * @param uAddress The address. 537 */ 538 DECLINLINE(uint64_t) disReadQWordByOff(PDISCPUSTATE pCpu, RTUINTPTR off) 539 { 540 if (RT_UNLIKELY(off + 2 > pCpu->cbCachedInstr)) 541 return disReadQWordSlow(pCpu, off); 542 543 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 544 return *(uint64_t const *)&pCpu->abInstr[off]; 545 #else 546 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 547 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]); 548 #endif 549 } 550 551 552 /** 553 * Read a qword (64-bit) instruction byte. 554 * 555 * @returns The requested qword. 556 * @param pCpu The disassembler state. 557 * @param uAddress The address. 558 */ 559 DECL_FORCE_INLINE(uint64_t) disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 560 { 561 return disReadQWordByOff(pCpu, uAddress - pCpu->uInstrAddr); 562 } 563 564 565 456 566 //***************************************************************************** 457 567 //***************************************************************************** … … 2040 2150 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM); 2041 2151 2042 modrmsize = QueryModRM(uCodePtr+sizeof(uint8_t), pOp, pParam, pCpu );2152 modrmsize = QueryModRM(uCodePtr+sizeof(uint8_t), pOp, pParam, pCpu, NULL); 2043 2153 2044 2154 uint8_t opcode = disReadByte(pCpu, uCodePtr+sizeof(uint8_t)+modrmsize); … … 2382 2492 pParam->fUse |= DISUSE_REG_SEG; 2383 2493 pParam->Base.idxSegReg = (DISSELREG)idx; 2384 }2385 2386 2387 //*****************************************************************************2388 /* Read functions for getting the opcode bytes */2389 //*****************************************************************************2390 2391 2392 static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)2393 {2394 #ifdef IN_RING02395 AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));2396 RT_BZERO(&pDis->abInstr[offInstr], cbMaxRead);2397 pDis->cbCachedInstr = offInstr + cbMaxRead;2398 return VERR_DIS_NO_READ_CALLBACK;2399 #else2400 memcpy(&pDis->abInstr[offInstr], (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr, cbMaxRead);2401 pDis->cbCachedInstr = offInstr + cbMaxRead;2402 return VINF_SUCCESS;2403 #endif2404 }2405 2406 2407 /**2408 * Read more bytes into the DISCPUSTATE::abInstr buffer, advance2409 * DISCPUSTATE::cbCachedInstr.2410 *2411 * Will set DISCPUSTATE::rc on failure, but still advance cbCachedInstr.2412 *2413 * The caller shall fend off reads beyond the DISCPUSTATE::abInstr buffer.2414 *2415 * @param pCpu The disassembler state.2416 * @param off The offset of the read request.2417 * @param cbMin The size of the read request that needs to be2418 * satisfied.2419 */2420 DECL_NO_INLINE(static, void) disReadMore(PDISCPUSTATE pCpu, uint8_t off, uint8_t cbMin)2421 {2422 Assert(cbMin + off <= sizeof(pCpu->abInstr));2423 2424 /*2425 * Adjust the incoming request to not overlap with bytes that has already2426 * been read and to make sure we don't leave unread gaps.2427 */2428 if (off < pCpu->cbCachedInstr)2429 {2430 Assert(off + cbMin > pCpu->cbCachedInstr);2431 cbMin -= pCpu->cbCachedInstr - off;2432 off = pCpu->cbCachedInstr;2433 }2434 else if (off > pCpu->cbCachedInstr)2435 {2436 cbMin += off - pCpu->cbCachedInstr;2437 off = pCpu->cbCachedInstr;2438 }2439 2440 /*2441 * Do the read.2442 * (No need to zero anything on failure as abInstr is already zeroed by the2443 * DISInstrEx API.)2444 */2445 int rc = pCpu->pfnReadBytes(pCpu, off, cbMin, sizeof(pCpu->abInstr) - off);2446 if (RT_SUCCESS(rc))2447 {2448 Assert(pCpu->cbCachedInstr >= off + cbMin);2449 Assert(pCpu->cbCachedInstr <= sizeof(pCpu->abInstr));2450 }2451 else2452 {2453 Log(("disReadMore failed with rc=%Rrc!!\n", rc));2454 pCpu->rc = VERR_DIS_MEM_READ;2455 }2456 }2457 2458 2459 /**2460 * Function for handling a 8-bit read beyond the max instruction length.2461 *2462 * @returns 02463 * @param pCpu The disassembler state.2464 * @param uAddress The address.2465 */2466 DECL_NO_INLINE(static, uint8_t) disReadByteBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2467 {2468 Log(("disReadByte: too long instruction...\n"));2469 pCpu->rc = VERR_DIS_TOO_LONG_INSTR;2470 return 0;2471 }2472 2473 2474 /**2475 * Read a byte (8-bit) instruction byte.2476 *2477 * @returns The requested byte.2478 * @param pCpu The disassembler state.2479 * @param uAddress The address.2480 */2481 static uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2482 {2483 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2484 if (RT_UNLIKELY(off + 1 > DIS_MAX_INSTR_LENGTH))2485 return disReadByteBad(pCpu, uAddress);2486 2487 if (off + 1 > pCpu->cbCachedInstr)2488 disReadMore(pCpu, off, 1);2489 return pCpu->abInstr[off];2490 }2491 2492 2493 /**2494 * Function for handling a 16-bit read beyond the max instruction length.2495 *2496 * @returns 02497 * @param pCpu The disassembler state.2498 * @param uAddress The address.2499 */2500 DECL_NO_INLINE(static, uint16_t) disReadWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2501 {2502 Log(("disReadWord: too long instruction...\n"));2503 pCpu->rc = VERR_DIS_TOO_LONG_INSTR;2504 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2505 if (off < DIS_MAX_INSTR_LENGTH)2506 return pCpu->abInstr[off];2507 return 0;2508 }2509 2510 2511 /**2512 * Read a word (16-bit) instruction byte.2513 *2514 * @returns The requested byte.2515 * @param pCpu The disassembler state.2516 * @param uAddress The address.2517 */2518 static uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2519 {2520 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2521 if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH))2522 return disReadWordBad(pCpu, uAddress);2523 2524 if (off + 2 > pCpu->cbCachedInstr)2525 disReadMore(pCpu, off, 2);2526 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK2527 return *(uint16_t const *)&pCpu->abInstr[off];2528 #else2529 return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]);2530 #endif2531 }2532 2533 2534 /**2535 * Function for handling a 32-bit read beyond the max instruction length.2536 *2537 * @returns 02538 * @param pCpu The disassembler state.2539 * @param uAddress The address.2540 */2541 DECL_NO_INLINE(static, uint32_t) disReadDWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2542 {2543 Log(("disReadDWord: too long instruction...\n"));2544 pCpu->rc = VERR_DIS_TOO_LONG_INSTR;2545 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2546 switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)2547 {2548 case 1:2549 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], 0, 0, 0);2550 case 2:2551 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0);2552 case 3:2553 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0);2554 default:2555 return 0;2556 }2557 return 0;2558 }2559 2560 2561 /**2562 * Read a word (32-bit) instruction byte.2563 *2564 * @returns The requested byte.2565 * @param pCpu The disassembler state.2566 * @param uAddress The address.2567 */2568 static uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2569 {2570 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2571 if (RT_UNLIKELY(off + 4 > DIS_MAX_INSTR_LENGTH))2572 return disReadDWordBad(pCpu, uAddress);2573 2574 if (off + 4 > pCpu->cbCachedInstr)2575 disReadMore(pCpu, off, 4);2576 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK2577 return *(uint32_t const *)&pCpu->abInstr[off];2578 #else2579 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]);2580 #endif2581 }2582 2583 2584 /**2585 * Function for handling a 64-bit read beyond the max instruction length.2586 *2587 * @returns 02588 * @param pCpu The disassembler state.2589 * @param uAddress The address.2590 */2591 DECL_NO_INLINE(static, uint64_t) disReadQWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2592 {2593 Log(("disReadQWord: too long instruction...\n"));2594 pCpu->rc = VERR_DIS_TOO_LONG_INSTR;2595 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2596 switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off)2597 {2598 case 1:2599 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], 0, 0, 0, 0, 0, 0, 0);2600 case 2:2601 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0, 0, 0, 0, 0);2602 case 3:2603 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0, 0, 0, 0, 0);2604 case 4:2605 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],2606 pCpu->abInstr[off + 4], 0, 0, 0);2607 case 5:2608 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],2609 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], 0, 0);2610 case 6:2611 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],2612 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], 0);2613 default:2614 return 0;2615 }2616 return 0;2617 }2618 2619 2620 /**2621 * Read a word (64-bit) instruction byte.2622 *2623 * @returns The requested byte.2624 * @param pCpu The disassembler state.2625 * @param uAddress The address.2626 */2627 static uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)2628 {2629 RTUINTPTR off = uAddress - pCpu->uInstrAddr;2630 if (RT_UNLIKELY(off + 8 > DIS_MAX_INSTR_LENGTH))2631 return disReadQWordBad(pCpu, uAddress);2632 2633 if (off + 8 > pCpu->cbCachedInstr)2634 disReadMore(pCpu, off, 8);2635 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK2636 return *(uint64_t const *)&pCpu->abInstr[off];2637 #else2638 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3],2639 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]);2640 #endif2641 2494 } 2642 2495 … … 2724 2577 } 2725 2578 2579 2580 /** 2581 * Internal worker for DISInstEx. 2582 * 2583 * @returns VBox status code. 2584 * @param pCpu Initialized cpu state. 2585 * @param paOneByteMap The one byte opcode map to use. 2586 * @param uInstrAddr Instruction address. 2587 * @param pcbInstr Where to store the instruction size. Can be NULL. 2588 */ 2589 static int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr) 2590 { 2591 /* 2592 * Parse byte by byte. 2593 */ 2594 size_t offByte = 0; 2595 for (;;) 2596 { 2597 uint8_t codebyte = disReadByteByOff(pCpu, offByte++); 2598 uint8_t opcode = paOneByteMap[codebyte].uOpcode; 2599 2600 /* Hardcoded assumption about OP_* values!! */ 2601 if (opcode <= OP_LAST_PREFIX) 2602 { 2603 /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */ 2604 if (opcode != OP_REX) 2605 { 2606 /** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */ 2607 pCpu->bLastPrefix = opcode; 2608 pCpu->fPrefix &= ~DISPREFIX_REX; 2609 } 2610 2611 switch (opcode) 2612 { 2613 case OP_INVALID: 2614 if (pcbInstr) 2615 *pcbInstr = (uint32_t)offByte; 2616 return pCpu->rc = VERR_DIS_INVALID_OPCODE; 2617 2618 // segment override prefix byte 2619 case OP_SEG: 2620 pCpu->idxSegPrefix = (DISSELREG)(paOneByteMap[codebyte].fParam1 - OP_PARM_REG_SEG_START); 2621 /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */ 2622 if ( pCpu->uCpuMode != DISCPUMODE_64BIT 2623 || pCpu->idxSegPrefix >= DISSELREG_FS) 2624 { 2625 pCpu->fPrefix |= DISPREFIX_SEG; 2626 } 2627 continue; //fetch the next byte 2628 2629 // lock prefix byte 2630 case OP_LOCK: 2631 pCpu->fPrefix |= DISPREFIX_LOCK; 2632 continue; //fetch the next byte 2633 2634 // address size override prefix byte 2635 case OP_ADDRSIZE: 2636 pCpu->fPrefix |= DISPREFIX_ADDRSIZE; 2637 if (pCpu->uCpuMode == DISCPUMODE_16BIT) 2638 pCpu->uAddrMode = DISCPUMODE_32BIT; 2639 else 2640 if (pCpu->uCpuMode == DISCPUMODE_32BIT) 2641 pCpu->uAddrMode = DISCPUMODE_16BIT; 2642 else 2643 pCpu->uAddrMode = DISCPUMODE_32BIT; /* 64 bits */ 2644 continue; //fetch the next byte 2645 2646 // operand size override prefix byte 2647 case OP_OPSIZE: 2648 pCpu->fPrefix |= DISPREFIX_OPSIZE; 2649 if (pCpu->uCpuMode == DISCPUMODE_16BIT) 2650 pCpu->uOpMode = DISCPUMODE_32BIT; 2651 else 2652 pCpu->uOpMode = DISCPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */ 2653 continue; //fetch the next byte 2654 2655 // rep and repne are not really prefixes, but we'll treat them as such 2656 case OP_REPE: 2657 pCpu->fPrefix |= DISPREFIX_REP; 2658 continue; //fetch the next byte 2659 2660 case OP_REPNE: 2661 pCpu->fPrefix |= DISPREFIX_REPNE; 2662 continue; //fetch the next byte 2663 2664 case OP_REX: 2665 Assert(pCpu->uCpuMode == DISCPUMODE_64BIT); 2666 /* REX prefix byte */ 2667 pCpu->fPrefix |= DISPREFIX_REX; 2668 pCpu->fRexPrefix = DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].fParam1); 2669 if (pCpu->fRexPrefix & DISPREFIX_REX_FLAGS_W) 2670 pCpu->uOpMode = DISCPUMODE_64BIT; /* overrides size prefix byte */ 2671 continue; //fetch the next byte 2672 } 2673 } 2674 2675 /* first opcode byte. */ 2676 pCpu->bOpCode = codebyte; 2677 offByte += disParseInstruction(uInstrAddr + offByte, &paOneByteMap[pCpu->bOpCode], pCpu); 2678 break; 2679 } 2680 2681 pCpu->cbInstr = offByte; 2682 if (pcbInstr) 2683 *pcbInstr = offByte; 2684 2685 if (pCpu->fPrefix & DISPREFIX_LOCK) 2686 disValidateLockSequence(pCpu); 2687 2688 return pCpu->rc; 2689 } 2690 2691 2692 /** 2693 * Disassembles on instruction, details in @a pCpu and length in @a pcbInstr. 2694 * 2695 * @returns VBox status code. 2696 * @param uInstrAddr Address of the instruction to decode. What this means 2697 * is left to the pfnReadBytes function. 2698 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT. 2699 * @param pfnReadBytes Callback for reading instruction bytes. 2700 * @param fFilter Instruction type filter. 2701 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.) 2702 * @param pCpu Pointer to CPU structure. With the exception of 2703 * DISCPUSTATE::pvUser2, the structure will be 2704 * completely initialized by this API, i.e. no input is 2705 * taken from it. 2706 * @param pcbInstr Where to store the size of the instruction. (This 2707 * is also stored in PDISCPUSTATE::cbInstr.) Optional. 2708 */ 2709 DISDECL(int) DISInstEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter, 2710 PFNDISREADBYTES pfnReadBytes, void *pvUser, 2711 PDISCPUSTATE pCpu, uint32_t *pcbInstr) 2712 { 2713 PCDISOPCODE paOneByteMap; 2714 2715 /* 2716 * Initialize the CPU state. 2717 * Note! The RT_BZERO make ASSUMPTIONS about the placement of pvUser2. 2718 */ 2719 RT_BZERO(pCpu, RT_OFFSETOF(DISCPUSTATE, pvUser2)); 2720 2721 #ifdef VBOX_STRICT /* poison */ 2722 pCpu->Param1.Base.idxGenReg = 0xc1; 2723 pCpu->Param2.Base.idxGenReg = 0xc2; 2724 pCpu->Param3.Base.idxGenReg = 0xc3; 2725 pCpu->Param1.Index.idxGenReg = 0xc4; 2726 pCpu->Param2.Index.idxGenReg = 0xc5; 2727 pCpu->Param3.Index.idxGenReg = 0xc6; 2728 pCpu->Param1.uDisp.u64 = UINT64_C(0xd1d1d1d1d1d1d1d1); 2729 pCpu->Param2.uDisp.u64 = UINT64_C(0xd2d2d2d2d2d2d2d2); 2730 pCpu->Param3.uDisp.u64 = UINT64_C(0xd3d3d3d3d3d3d3d3); 2731 pCpu->Param1.uValue = UINT64_C(0xb1b1b1b1b1b1b1b1); 2732 pCpu->Param2.uValue = UINT64_C(0xb2b2b2b2b2b2b2b2); 2733 pCpu->Param3.uValue = UINT64_C(0xb3b3b3b3b3b3b3b3); 2734 pCpu->Param1.uScale = 28; 2735 pCpu->Param2.uScale = 29; 2736 pCpu->Param3.uScale = 30; 2737 #endif 2738 2739 pCpu->uCpuMode = enmCpuMode; 2740 if (enmCpuMode == DISCPUMODE_64BIT) 2741 { 2742 paOneByteMap = g_aOneByteMapX64; 2743 pCpu->uAddrMode = DISCPUMODE_64BIT; 2744 pCpu->uOpMode = DISCPUMODE_32BIT; 2745 } 2746 else 2747 { 2748 paOneByteMap = g_aOneByteMapX86; 2749 pCpu->uAddrMode = enmCpuMode; 2750 pCpu->uOpMode = enmCpuMode; 2751 } 2752 pCpu->fPrefix = DISPREFIX_NONE; 2753 pCpu->idxSegPrefix = DISSELREG_DS; 2754 pCpu->uInstrAddr = uInstrAddr; 2755 pCpu->pfnDisasmFnTable = g_apfnFullDisasm; 2756 pCpu->fFilter = fFilter; 2757 pCpu->rc = VINF_SUCCESS; 2758 pCpu->pfnReadBytes = pfnReadBytes ? pfnReadBytes : disReadBytesDefault; 2759 pCpu->pvUser = pvUser; 2760 2761 /* 2762 * Read some bytes into the cache. (If this fail we continue as nothing 2763 * has gone wrong since this is what would happen if we didn't precharge 2764 * the cache here.) 2765 */ 2766 int rc = pCpu->pfnReadBytes(pCpu, 0, 1, sizeof(pCpu->abInstr)); 2767 if (RT_SUCCESS(rc)) 2768 { 2769 Assert(pCpu->cbCachedInstr >= 1); 2770 Assert(pCpu->cbCachedInstr <= sizeof(pCpu->abInstr)); 2771 } 2772 else 2773 { 2774 Log(("Initial read failed with rc=%Rrc!!\n", rc)); 2775 pCpu->rc = VERR_DIS_MEM_READ; 2776 } 2777 2778 return disInstrWorker(pCpu, uInstrAddr, paOneByteMap, pcbInstr); 2779 } 2780 2781 2782 /** 2783 * Parses one guest instruction. 2784 * 2785 * The result is found in pCpu and pcbInstr. 2786 * 2787 * @returns VBox status code. 2788 * @param uInstrAddr Address of the instruction to decode. What this means 2789 * is left to the pfnReadBytes function. 2790 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT. 2791 * @param pfnReadBytes Callback for reading instruction bytes. 2792 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.) 2793 * @param pCpu Pointer to cpu structure. Will be initialized. 2794 * @param pcbInstr Where to store the size of the instruction. 2795 * NULL is allowed. This is also stored in 2796 * PDISCPUSTATE::cbInstr. 2797 */ 2798 DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, 2799 PDISCPUSTATE pCpu, uint32_t *pcbInstr) 2800 { 2801 return DISInstEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pCpu, pcbInstr); 2802 } 2803 2804 2805 /** 2806 * Parses one guest instruction. 2807 * 2808 * The result is found in pCpu and pcbInstr. 2809 * 2810 * @returns VBox status code. 2811 * @param pvInstr Address of the instruction to decode. This is a 2812 * real address in the current context that can be 2813 * accessed without faulting. (Consider 2814 * DISInstrWithReader if this isn't the case.) 2815 * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT. 2816 * @param pfnReadBytes Callback for reading instruction bytes. 2817 * @param pvUser User argument for the instruction reader. (Ends up in pvUser.) 2818 * @param pCpu Pointer to cpu structure. Will be initialized. 2819 * @param pcbInstr Where to store the size of the instruction. 2820 * NULL is allowed. This is also stored in 2821 * PDISCPUSTATE::cbInstr. 2822 */ 2823 DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISCPUSTATE pCpu, uint32_t *pcbInstr) 2824 { 2825 return DISInstEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pCpu, pcbInstr); 2826 } 2827 -
trunk/src/VBox/Disassembler/testcase/tstDisasm-1.cpp
r41751 r41781 24 24 #include <iprt/string.h> 25 25 #include <iprt/err.h> 26 #include <iprt/time.h> 26 27 27 28 … … 73 74 off += cb; 74 75 } 76 } 75 77 78 static void testPerformance(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode) 79 { 80 RTTestISubF("Performance - %s", pszSub); 81 82 size_t const cbInstrs = uEndPtr - (uintptr_t)pabInstrs; 83 uint64_t cInstrs = 0; 84 uint64_t nsStart = RTTimeNanoTS(); 85 for (uint32_t i = 0; i < _512K; i++) /* the samples are way to small. :-) */ 86 { 87 for (size_t off = 0; off < cbInstrs; cInstrs++) 88 { 89 uint32_t cb = 1; 90 DISCPUSTATE Cpu; 91 DISInstr(&pabInstrs[off], enmDisCpuMode, &Cpu, &cb); 92 off += cb; 93 } 94 } 95 uint64_t cNsElapsed = RTTimeNanoTS() - nsStart; 96 97 RTTestIValueF(cNsElapsed, RTTESTUNIT_NS, "%s-Total", pszSub); 98 RTTestIValueF(cNsElapsed / cInstrs, RTTESTUNIT_NS_PER_CALL, "%s-per-instruction", pszSub); 76 99 } 77 100 … … 85 108 RTTestBanner(hTest); 86 109 87 testDisas("32-bit", (uint8_t const *)(uintptr_t)TestProc32, (uintptr_t)&TestProc32_EndProc, DISCPUMODE_32BIT); 88 #ifndef RT_OS_OS2 89 testDisas("64-bit", (uint8_t const *)(uintptr_t)TestProc64, (uintptr_t)&TestProc64_EndProc, DISCPUMODE_64BIT); 90 #endif 110 static const struct 111 { 112 const char *pszDesc; 113 uint8_t const *pbStart; 114 uintptr_t uEndPtr; 115 DISCPUMODE enmCpuMode; 116 } aSnippets[] = 117 { 118 { "32-bit", (uint8_t const *)(uintptr_t)TestProc32, (uintptr_t)&TestProc32_EndProc, DISCPUMODE_32BIT }, 119 { "64-bit", (uint8_t const *)(uintptr_t)TestProc64, (uintptr_t)&TestProc64_EndProc, DISCPUMODE_64BIT }, 120 }; 121 122 for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++) 123 testDisas(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode); 124 125 if (RTTestIErrorCount() == 0) 126 { 127 for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++) 128 testPerformance(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode); 129 } 91 130 92 131 return RTTestSummaryAndDestroy(hTest); -
trunk/src/VBox/Disassembler/testcase/tstDisasm-2.cpp
r41760 r41781 166 166 167 167 /** 168 * Callback for reading bytes.168 * @interface_method_impl{FNDISREADBYTES} 169 169 */ 170 170 static DECLCALLBACK(int) MyDisasInstrRead(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
Note:
See TracChangeset
for help on using the changeset viewer.