- Timestamp:
- Jun 15, 2012 12:30:46 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Disassembler/DisasmCore.cpp
r41748 r41753 29 29 #include <iprt/stdarg.h> 30 30 #include "DisasmInternal.h" 31 32 33 /******************************************************************************* 34 * Defined Constants And Macros * 35 *******************************************************************************/ 36 /** This must be less or equal to DISCPUSTATE::abInstr. */ 37 #define DIS_MAX_INSTR_LENGTH 16 38 39 /** Whether we can do unaligned access. */ 40 #if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) 41 # define DIS_HOST_UNALIGNED_ACCESS_OK 42 #endif 31 43 32 44 … … 433 445 } 434 446 435 AssertMsg(pCpu->cbInstr == iByte || RT_FAILURE_NP(pCpu->rc), ("%u %u\n", pCpu->cbInstr, iByte));436 447 pCpu->cbInstr = iByte; 437 448 if (pcbInstr) … … 2374 2385 2375 2386 2376 /** 2377 * Slow path for storing instruction bytes. 2378 * 2379 * @param pCpu The disassembler state. 2380 * @param uAddress The address. 2381 * @param pbSrc The bytes. 2382 * @param cbSrc The number of bytes. 2383 */ 2384 DECL_NO_INLINE(static, void) 2385 disStoreInstrBytesSlow(PDISCPUSTATE pCpu, RTUINTPTR uAddress, const uint8_t *pbSrc, size_t cbSrc) 2386 { 2387 /* 2388 * Figure out which case it is. 2389 */ 2390 uint32_t cbInstr = pCpu->cbInstr; 2391 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2392 if (off < cbInstr) 2393 { 2394 if (off + cbSrc <= cbInstr) 2395 { 2396 AssertMsg(memcmp(&pCpu->abInstr[off], pbSrc, cbSrc) == 0, 2397 ("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr)); 2398 return; /* fully re-reading old stuff. */ 2399 } 2400 2401 /* Only partially re-reading stuff, skip ahead and add the rest. */ 2402 uint32_t cbAlreadyRead = cbInstr - (uint32_t)off; 2403 Assert(memcmp(&pCpu->abInstr[off], pbSrc, cbAlreadyRead) == 0); 2404 uAddress += cbAlreadyRead; 2405 pbSrc += cbAlreadyRead; 2406 cbSrc -= cbAlreadyRead; 2407 } 2408 2409 if (off >= sizeof(pCpu->abInstr)) 2410 { 2411 /* The instruction is too long! This shouldn't happen. */ 2412 AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr)); 2413 return; 2414 } 2415 else if (off > cbInstr) 2416 { 2417 /* Mind the gap - this shouldn't happen, but read the gap bytes if it does. */ 2418 AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.16Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr)); 2419 uint32_t cbGap = off - cbInstr; 2420 int rc = pCpu->pfnReadBytes(pCpu, &pCpu->abInstr[cbInstr], uAddress - cbGap, cbGap); 2421 if (RT_FAILURE(rc)) 2422 { 2423 pCpu->rc = VERR_DIS_MEM_READ; 2424 RT_BZERO(&pCpu->abInstr[cbInstr], cbGap); 2425 } 2426 pCpu->cbInstr = cbInstr = off; 2427 } 2428 2429 /* 2430 * Copy the bytes. 2431 */ 2432 if (off + cbSrc <= sizeof(pCpu->abInstr)) 2433 { 2434 memcpy(&pCpu->abInstr[cbInstr], pbSrc, cbSrc); 2435 pCpu->cbInstr = cbInstr + (uint32_t)cbSrc; 2436 } 2437 else 2438 { 2439 size_t cbToCopy = sizeof(pCpu->abInstr) - off; 2440 memcpy(&pCpu->abInstr[cbInstr], pbSrc, cbToCopy); 2441 pCpu->cbInstr = sizeof(pCpu->abInstr); 2442 AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, sizeof(pCpu->abInstr), pCpu->abInstr)); 2443 } 2444 } 2387 //***************************************************************************** 2388 /* Read functions for getting the opcode bytes */ 2389 //***************************************************************************** 2390 2445 2391 2446 2392 static DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pCpu, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead) … … 2456 2402 } 2457 2403 2458 //***************************************************************************** 2459 /* Read functions for getting the opcode bytes */ 2460 //***************************************************************************** 2404 2405 /** 2406 * Read more bytes into the DISCPUSTATE::abInstr buffer, advance 2407 * DISCPUSTATE::cbCachedInstr. 2408 * 2409 * Will set DISCPUSTATE::rc on failure, but still advance cbCachedInstr. 2410 * 2411 * The caller shall fend off reads beyond the DISCPUSTATE::abInstr buffer. 2412 * 2413 * @param pCpu The disassembler state. 2414 * @param off The offset of the read request. 2415 * @param cbMin The size of the read request that needs to be 2416 * satisfied. 2417 */ 2418 DECL_NO_INLINE(static, void) disReadMore(PDISCPUSTATE pCpu, uint8_t off, uint8_t cbMin) 2419 { 2420 Assert(cbMin + off <= sizeof(pCpu->abInstr)); 2421 2422 /* 2423 * Adjust the incoming request to not overlap with bytes that has already 2424 * been read and to make sure we don't leave unread gaps. 2425 */ 2426 if (off < pCpu->cbCachedInstr) 2427 { 2428 Assert(off + cbMin > pCpu->cbCachedInstr); 2429 cbMin -= pCpu->cbCachedInstr - off; 2430 off = pCpu->cbCachedInstr; 2431 } 2432 else if (off > pCpu->cbCachedInstr) 2433 { 2434 cbMin += off - pCpu->cbCachedInstr; 2435 off = pCpu->cbCachedInstr; 2436 } 2437 2438 /* 2439 * Do the read. No need to zero anything, abInstr is already zeroed by the 2440 * DISInstrEx API. 2441 */ 2442 /** @todo Change the callback API so it can read more, thus avoid lots of 2443 * calls or it doing its own caching. */ 2444 int rc = pCpu->pfnReadBytes(pCpu, &pCpu->abInstr[off], pCpu->uInstrAddr + off, cbMin); 2445 if (RT_FAILURE(rc)) 2446 { 2447 Log(("disReadMore failed with rc=%Rrc!!\n", rc)); 2448 pCpu->rc = VERR_DIS_MEM_READ; 2449 } 2450 pCpu->cbCachedInstr = off + cbMin; 2451 } 2452 2453 2454 /** 2455 * Function for handling a 8-bit read beyond the max instruction length. 2456 * 2457 * @returns 0 2458 * @param pCpu The disassembler state. 2459 * @param uAddress The address. 2460 */ 2461 DECL_NO_INLINE(static, uint8_t) disReadByteBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2462 { 2463 Log(("disReadByte: too long instruction...\n")); 2464 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 2465 return 0; 2466 } 2467 2468 2469 /** 2470 * Read a byte (8-bit) instruction byte. 2471 * 2472 * @returns The requested byte. 2473 * @param pCpu The disassembler state. 2474 * @param uAddress The address. 2475 */ 2461 2476 static uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2462 2477 { 2463 uint8_t bTemp = 0; 2464 int rc = pCpu->pfnReadBytes(pCpu, &bTemp, uAddress, sizeof(bTemp)); 2465 if (RT_FAILURE(rc)) 2466 { 2467 Log(("disReadByte failed!!\n")); 2468 pCpu->rc = VERR_DIS_MEM_READ; 2469 } 2470 2471 /** @todo change this into reading directly into abInstr and use it as a 2472 * cache. */ 2473 if (RT_LIKELY( pCpu->uInstrAddr + pCpu->cbInstr == uAddress 2474 && pCpu->cbInstr + sizeof(bTemp) < sizeof(pCpu->abInstr))) 2475 pCpu->abInstr[pCpu->cbInstr++] = bTemp; 2476 else 2477 disStoreInstrBytesSlow(pCpu, uAddress, &bTemp, sizeof(bTemp)); 2478 2479 return bTemp; 2480 } 2481 //***************************************************************************** 2482 //***************************************************************************** 2478 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2479 if (RT_UNLIKELY(off + 1 > DIS_MAX_INSTR_LENGTH)) 2480 return disReadByteBad(pCpu, uAddress); 2481 2482 if (off + 1 > pCpu->cbCachedInstr) 2483 disReadMore(pCpu, off, 1); 2484 return pCpu->abInstr[off]; 2485 } 2486 2487 2488 /** 2489 * Function for handling a 16-bit read beyond the max instruction length. 2490 * 2491 * @returns 0 2492 * @param pCpu The disassembler state. 2493 * @param uAddress The address. 2494 */ 2495 DECL_NO_INLINE(static, uint16_t) disReadWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2496 { 2497 Log(("disReadWord: too long instruction...\n")); 2498 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 2499 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2500 if (off < DIS_MAX_INSTR_LENGTH) 2501 return pCpu->abInstr[off]; 2502 return 0; 2503 } 2504 2505 2506 /** 2507 * Read a word (16-bit) instruction byte. 2508 * 2509 * @returns The requested byte. 2510 * @param pCpu The disassembler state. 2511 * @param uAddress The address. 2512 */ 2483 2513 static uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2484 2514 { 2485 RTUINT16U uTemp; 2486 uTemp.u = 0; 2487 int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp)); 2488 if (RT_FAILURE(rc)) 2489 { 2490 Log(("disReadWord failed!!\n")); 2491 pCpu->rc = VERR_DIS_MEM_READ; 2492 } 2493 2494 if (RT_LIKELY( pCpu->uInstrAddr + pCpu->cbInstr == uAddress 2495 && pCpu->cbInstr + sizeof(uTemp) < sizeof(pCpu->abInstr))) 2496 { 2497 pCpu->abInstr[pCpu->cbInstr ] = uTemp.au8[0]; 2498 pCpu->abInstr[pCpu->cbInstr + 1] = uTemp.au8[1]; 2499 pCpu->cbInstr += 2; 2500 } 2501 else 2502 disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp)); 2503 2504 return uTemp.u; 2505 } 2506 //***************************************************************************** 2507 //***************************************************************************** 2515 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2516 if (RT_UNLIKELY(off + 2 > DIS_MAX_INSTR_LENGTH)) 2517 return disReadWordBad(pCpu, uAddress); 2518 2519 if (off + 2 > pCpu->cbCachedInstr) 2520 disReadMore(pCpu, off, 2); 2521 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 2522 return *(uint16_t const *)&pCpu->abInstr[off]; 2523 #else 2524 return RT_MAKE_U16(pCpu->abInstr[off], pCpu->abInstr[off + 1]); 2525 #endif 2526 } 2527 2528 2529 /** 2530 * Function for handling a 32-bit read beyond the max instruction length. 2531 * 2532 * @returns 0 2533 * @param pCpu The disassembler state. 2534 * @param uAddress The address. 2535 */ 2536 DECL_NO_INLINE(static, uint32_t) disReadDWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2537 { 2538 Log(("disReadDWord: too long instruction...\n")); 2539 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 2540 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2541 switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off) 2542 { 2543 case 1: 2544 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], 0, 0, 0); 2545 case 2: 2546 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0); 2547 case 3: 2548 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0); 2549 default: 2550 return 0; 2551 } 2552 return 0; 2553 } 2554 2555 2556 /** 2557 * Read a word (32-bit) instruction byte. 2558 * 2559 * @returns The requested byte. 2560 * @param pCpu The disassembler state. 2561 * @param uAddress The address. 2562 */ 2508 2563 static uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2509 2564 { 2510 RTUINT32U uTemp; 2511 uTemp.u = 0; 2512 int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp)); 2513 if (RT_FAILURE(rc)) 2514 { 2515 Log(("disReadDWord failed!!\n")); 2516 pCpu->rc = VERR_DIS_MEM_READ; 2517 } 2518 2519 if (RT_LIKELY( pCpu->uInstrAddr + pCpu->cbInstr == uAddress 2520 && pCpu->cbInstr + sizeof(uTemp) < sizeof(pCpu->abInstr))) 2521 { 2522 pCpu->abInstr[pCpu->cbInstr ] = uTemp.au8[0]; 2523 pCpu->abInstr[pCpu->cbInstr + 1] = uTemp.au8[1]; 2524 pCpu->abInstr[pCpu->cbInstr + 2] = uTemp.au8[2]; 2525 pCpu->abInstr[pCpu->cbInstr + 3] = uTemp.au8[3]; 2526 pCpu->cbInstr += 4; 2527 } 2528 else 2529 disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp)); 2530 2531 return uTemp.u; 2532 } 2533 //***************************************************************************** 2534 //***************************************************************************** 2565 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2566 if (RT_UNLIKELY(off + 4 > DIS_MAX_INSTR_LENGTH)) 2567 return disReadDWordBad(pCpu, uAddress); 2568 2569 if (off + 4 > pCpu->cbCachedInstr) 2570 disReadMore(pCpu, off, 4); 2571 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 2572 return *(uint32_t const *)&pCpu->abInstr[off]; 2573 #else 2574 return RT_MAKE_U32_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3]); 2575 #endif 2576 } 2577 2578 2579 /** 2580 * Function for handling a 64-bit read beyond the max instruction length. 2581 * 2582 * @returns 0 2583 * @param pCpu The disassembler state. 2584 * @param uAddress The address. 2585 */ 2586 DECL_NO_INLINE(static, uint64_t) disReadQWordBad(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2587 { 2588 Log(("disReadQWord: too long instruction...\n")); 2589 pCpu->rc = VERR_DIS_TOO_LONG_INSTR; 2590 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2591 switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - off) 2592 { 2593 case 1: 2594 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], 0, 0, 0, 0, 0, 0, 0); 2595 case 2: 2596 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], 0, 0, 0, 0, 0, 0); 2597 case 3: 2598 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], 0, 0, 0, 0, 0); 2599 case 4: 2600 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 2601 pCpu->abInstr[off + 4], 0, 0, 0); 2602 case 5: 2603 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 2604 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], 0, 0); 2605 case 6: 2606 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 2607 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], 0); 2608 default: 2609 return 0; 2610 } 2611 return 0; 2612 } 2613 2614 2615 /** 2616 * Read a word (64-bit) instruction byte. 2617 * 2618 * @returns The requested byte. 2619 * @param pCpu The disassembler state. 2620 * @param uAddress The address. 2621 */ 2535 2622 static uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress) 2536 2623 { 2537 RTUINT64U uTemp; 2538 uTemp.u = 0; 2539 int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp)); 2540 if (RT_FAILURE(rc)) 2541 { 2542 Log(("disReadQWord %x failed!!\n", uAddress)); 2543 pCpu->rc = VERR_DIS_MEM_READ; 2544 } 2545 2546 if (RT_LIKELY( pCpu->uInstrAddr + pCpu->cbInstr == uAddress 2547 && pCpu->cbInstr + sizeof(uTemp) < sizeof(pCpu->abInstr))) 2548 { 2549 pCpu->abInstr[pCpu->cbInstr ] = uTemp.au8[0]; 2550 pCpu->abInstr[pCpu->cbInstr + 1] = uTemp.au8[1]; 2551 pCpu->abInstr[pCpu->cbInstr + 2] = uTemp.au8[2]; 2552 pCpu->abInstr[pCpu->cbInstr + 3] = uTemp.au8[3]; 2553 pCpu->abInstr[pCpu->cbInstr + 4] = uTemp.au8[4]; 2554 pCpu->abInstr[pCpu->cbInstr + 5] = uTemp.au8[5]; 2555 pCpu->abInstr[pCpu->cbInstr + 6] = uTemp.au8[6]; 2556 pCpu->abInstr[pCpu->cbInstr + 7] = uTemp.au8[7]; 2557 pCpu->cbInstr += 8; 2558 } 2559 else 2560 disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp)); 2561 2562 return uTemp.u; 2563 } 2624 RTUINTPTR off = uAddress - pCpu->uInstrAddr; 2625 if (RT_UNLIKELY(off + 8 > DIS_MAX_INSTR_LENGTH)) 2626 return disReadQWordBad(pCpu, uAddress); 2627 2628 if (off + 8 > pCpu->cbCachedInstr) 2629 disReadMore(pCpu, off, 8); 2630 #ifdef DIS_HOST_UNALIGNED_ACCESS_OK 2631 return *(uint64_t const *)&pCpu->abInstr[off]; 2632 #else 2633 return RT_MAKE_U64_FROM_U8(pCpu->abInstr[off ], pCpu->abInstr[off + 1], pCpu->abInstr[off + 2], pCpu->abInstr[off + 3], 2634 pCpu->abInstr[off + 4], pCpu->abInstr[off + 5], pCpu->abInstr[off + 6], pCpu->abInstr[off + 7]); 2635 #endif 2636 } 2637 2564 2638 2565 2639
Note:
See TracChangeset
for help on using the changeset viewer.