You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
698 lines
21 KiB
698 lines
21 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*
|
|
* This tool instruments all memory accesses in order to verify that the IARG_MEMORY(READ/WRITE)_EA
|
|
* is correct.
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
#include <cstdlib>
|
|
|
|
#ifdef TARGET_LINUX
|
|
# include <unistd.h>
|
|
# include <sys/syscall.h>
|
|
# include <errno.h>
|
|
# if defined(TARGET_IA32E)
|
|
# include <asm/prctl.h>
|
|
# include <sys/prctl.h>
|
|
# endif // TARGET_IA32E
|
|
#endif // TARGET_LINUX
|
|
|
|
#include "pin.H"
|
|
#include "instlib.H"
|
|
using std::iostream;
|
|
using std::ostringstream;
|
|
|
|
#ifdef TARGET_WINDOWS
|
|
namespace WIND
|
|
{
|
|
#include <windows.h>
|
|
}
|
|
using namespace INSTLIB;
|
|
inline ADDRINT InitializeThreadData()
|
|
{
|
|
return reinterpret_cast<ADDRINT>(WIND::NtCurrentTeb());
|
|
}
|
|
#endif // TARGET_WINDOWS
|
|
|
|
#ifdef TARGET_LINUX
|
|
|
|
# ifndef __NR_set_thread_area
|
|
# define __NR_set_thread_area 243
|
|
# endif
|
|
# ifndef __NR_get_thread_area
|
|
# define __NR_get_thread_area 244
|
|
# endif
|
|
# ifndef SYS_set_thread_area
|
|
# define SYS_set_thread_area __NR_set_thread_area
|
|
# endif
|
|
# ifndef SYS_get_thread_area
|
|
# define SYS_get_thread_area __NR_get_thread_area
|
|
# endif
|
|
|
|
typedef struct {
|
|
unsigned int entry_number;
|
|
unsigned int base_addr;
|
|
unsigned int limit;
|
|
unsigned int seg_32bit:1;
|
|
unsigned int contents:2;
|
|
unsigned int read_exec_only:1;
|
|
unsigned int limit_in_pages:1;
|
|
unsigned int seg_not_present:1;
|
|
unsigned int useable:1;
|
|
}UserDesc;
|
|
|
|
|
|
#define TLS_GET_GS_REG() \
|
|
({ int __seg; __asm ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; })
|
|
|
|
#define TLS_SET_GS_REG(val) \
|
|
__asm ("movw %w0, %%gs" :: "q" (val))
|
|
|
|
#define TLS_GET_FS_REG() \
|
|
({ int __seg; __asm ("movw %%fs, %w0" : "=q" (__seg)); __seg & 0xffff; })
|
|
|
|
#define TLS_SET_FS_REG(val) \
|
|
__asm ("movw %w0, %%fs" :: "q" (val))
|
|
|
|
ADDRINT GetTlsBaseAddress()
|
|
{
|
|
#ifdef TARGET_IA32
|
|
unsigned int gsVal = TLS_GET_GS_REG();
|
|
//printf("Current gs val is 0x%x\n", gsVal);
|
|
UserDesc td;
|
|
td.entry_number = gsVal >> 3;
|
|
if (gsVal == 0)
|
|
return 0;
|
|
int res = syscall(SYS_get_thread_area, &td);
|
|
if (res != 0)
|
|
{
|
|
printf("SYS_get_thread_area failed with error: %s\n", strerror(errno));
|
|
return 0;
|
|
}
|
|
//printf("Current td.base_addr 0x%x\n", td.base_addr);
|
|
return td.base_addr;
|
|
#else
|
|
ADDRINT baseAddr;
|
|
int res = syscall(SYS_arch_prctl, ARCH_GET_FS, &baseAddr);
|
|
if (res != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
return baseAddr;
|
|
#endif // TARGET_IA32
|
|
}
|
|
|
|
inline ADDRINT InitializeThreadData()
|
|
{
|
|
return GetTlsBaseAddress();
|
|
}
|
|
|
|
#endif // TARGET_LINUX
|
|
|
|
|
|
#define MAX_THREADS 1024
|
|
#define DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE 0
|
|
#define DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE 1
|
|
#define BASE_DISPLACEMENT_ADDRESSING_READ_TYPE 2
|
|
#define BASE_DISPLACEMENT_ADDRESSING_WRITE_TYPE 3
|
|
#define BASE_INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE 4
|
|
#define BASE_INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE 5
|
|
#define INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE 6
|
|
#define INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE 7
|
|
|
|
struct tdata
|
|
{
|
|
ADDRINT threadTeb;
|
|
|
|
} THREAD_DATA;
|
|
|
|
//struct tdata
|
|
ADDRINT threadData[MAX_THREADS]={0};
|
|
|
|
int numThreads = 0;
|
|
BOOL hadError = FALSE;
|
|
|
|
const char * GetMemoryAccessTypeString (int j)
|
|
{
|
|
switch (j)
|
|
{
|
|
case DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE:
|
|
return ("DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE");
|
|
case BASE_DISPLACEMENT_ADDRESSING_READ_TYPE:
|
|
return ("BASE_DISPLACEMENT_ADDRESSING_READ_TYPE");
|
|
case BASE_INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE:
|
|
return ("BASE_INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE");
|
|
case DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE:
|
|
return ("DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE");
|
|
case BASE_DISPLACEMENT_ADDRESSING_WRITE_TYPE:
|
|
return ("BASE_DISPLACEMENT_ADDRESSING_WRITE_TYPE");
|
|
case BASE_INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE:
|
|
return ("BASE_INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE");
|
|
case INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE:
|
|
return ("INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE");
|
|
case INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE:
|
|
return ("INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE");
|
|
default:
|
|
return ("UNKNOWN_ADDRESSING_TYPE");
|
|
}
|
|
}
|
|
|
|
static char nibble_to_ascii_hex(UINT8 i) {
|
|
if (i<10) return i+'0';
|
|
if (i<16) return i-10+'A';
|
|
return '?';
|
|
}
|
|
|
|
static void print_hex_line(char* buf, const UINT8* array, const int length) {
|
|
int n = length;
|
|
int i=0;
|
|
if (length == 0)
|
|
n = XED_MAX_INSTRUCTION_BYTES;
|
|
for( i=0 ; i< n; i++) {
|
|
buf[2*i+0] = nibble_to_ascii_hex(array[i]>>4);
|
|
buf[2*i+1] = nibble_to_ascii_hex(array[i]&0xF);
|
|
}
|
|
buf[2*i]=0;
|
|
}
|
|
|
|
static string
|
|
disassemble(UINT64 start, UINT64 stop) {
|
|
UINT64 pc = start;
|
|
xed_state_t dstate;
|
|
xed_syntax_enum_t syntax = XED_SYNTAX_INTEL;
|
|
xed_error_enum_t xed_error;
|
|
xed_decoded_inst_t xedd;
|
|
ostringstream os;
|
|
if (sizeof(ADDRINT) == 4)
|
|
xed_state_init(&dstate,
|
|
XED_MACHINE_MODE_LEGACY_32,
|
|
XED_ADDRESS_WIDTH_32b,
|
|
XED_ADDRESS_WIDTH_32b);
|
|
else
|
|
xed_state_init(&dstate,
|
|
XED_MACHINE_MODE_LONG_64,
|
|
XED_ADDRESS_WIDTH_64b,
|
|
XED_ADDRESS_WIDTH_64b);
|
|
|
|
/*while( pc < stop )*/ {
|
|
xed_decoded_inst_zero_set_mode(&xedd, &dstate);
|
|
UINT32 len = 15;
|
|
if (stop - pc < 15)
|
|
len = stop-pc;
|
|
|
|
xed_error = xed_decode(&xedd, reinterpret_cast<const UINT8*>(pc), len);
|
|
bool okay = (xed_error == XED_ERROR_NONE);
|
|
iostream::fmtflags fmt = os.flags();
|
|
os << std::setfill('0')
|
|
<< "XDIS "
|
|
<< std::hex
|
|
<< std::setw(sizeof(ADDRINT)*2)
|
|
<< pc
|
|
<< std::dec
|
|
<< ": "
|
|
<< std::setfill(' ')
|
|
<< std::setw(4);
|
|
|
|
if (okay) {
|
|
char buffer[200];
|
|
unsigned int dec_len, sp;
|
|
|
|
os << xed_extension_enum_t2str(xed_decoded_inst_get_extension(&xedd));
|
|
dec_len = xed_decoded_inst_get_length(&xedd);
|
|
print_hex_line(buffer, reinterpret_cast<UINT8*>(pc), dec_len);
|
|
os << " " << buffer;
|
|
for ( sp=dec_len; sp < 12; sp++) // pad out the instruction bytes
|
|
os << " ";
|
|
os << " ";
|
|
memset(buffer,0,200);
|
|
int dis_okay = xed_format_context(syntax, &xedd, buffer, 200, pc, 0, 0);
|
|
if (dis_okay)
|
|
os << buffer << endl;
|
|
else
|
|
os << "Error disasassembling pc 0x" << std::hex << pc << std::dec << endl;
|
|
pc += dec_len;
|
|
}
|
|
else { // print the byte and keep going.
|
|
UINT8 memval = *reinterpret_cast<UINT8*>(pc);
|
|
os << "???? " // no extension
|
|
<< std::hex
|
|
<< std::setw(2)
|
|
<< std::setfill('0')
|
|
<< static_cast<UINT32>(memval)
|
|
<< std::endl;
|
|
pc += 1;
|
|
}
|
|
os.flags(fmt);
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
|
|
VOID AnalyzeMemAddr(UINT32 effectiveAddressWidth,
|
|
UINT32 hasSegmentedMemAccess,
|
|
INT32 subFromAddrComputation,
|
|
VOID * ip,
|
|
VOID * addr,
|
|
UINT32 accessType,
|
|
ADDRINT gaxRegVal,
|
|
ADDRINT baseRegVal,
|
|
ADDRINT indexRegVal,
|
|
INT32 scale,
|
|
ADDRINT displacement,
|
|
UINT32 insSizeToAdd,
|
|
THREADID tid)
|
|
{
|
|
if (tid < MAX_THREADS)
|
|
{
|
|
if (threadData[tid]==0)
|
|
{
|
|
threadData[tid] = InitializeThreadData();
|
|
}
|
|
|
|
ADDRINT threadTeb = threadData[tid];
|
|
ADDRINT memoryEA = reinterpret_cast<ADDRINT>(addr);
|
|
ADDRINT baseRegValForAddressComputation=0, indexRegValForAddressComputation=0;
|
|
|
|
switch (accessType)
|
|
{
|
|
case BASE_DISPLACEMENT_ADDRESSING_READ_TYPE:
|
|
case BASE_DISPLACEMENT_ADDRESSING_WRITE_TYPE:
|
|
baseRegValForAddressComputation = baseRegVal;
|
|
indexRegValForAddressComputation = 0;
|
|
break;
|
|
|
|
case DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE:
|
|
case DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE:
|
|
baseRegValForAddressComputation = 0;
|
|
indexRegValForAddressComputation = 0;
|
|
break;
|
|
|
|
case BASE_INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE:
|
|
case BASE_INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE:
|
|
baseRegValForAddressComputation = baseRegVal;
|
|
indexRegValForAddressComputation = indexRegVal;
|
|
break;
|
|
|
|
case INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE:
|
|
case INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE:
|
|
baseRegValForAddressComputation = 0;
|
|
indexRegValForAddressComputation = indexRegVal;
|
|
break;
|
|
|
|
default:
|
|
ASSERTX(0);
|
|
break;
|
|
}
|
|
ADDRINT computedAddr
|
|
= static_cast<ADDRINT>(displacement)
|
|
+ static_cast<ADDRINT>(baseRegValForAddressComputation) +
|
|
(static_cast<ADDRINT>(indexRegValForAddressComputation)*scale) -
|
|
static_cast<ADDRINT>(subFromAddrComputation) +
|
|
+ static_cast<ADDRINT>(insSizeToAdd);
|
|
if (hasSegmentedMemAccess)
|
|
{
|
|
computedAddr += static_cast<ADDRINT>(threadTeb);
|
|
}
|
|
if (computedAddr != memoryEA)
|
|
{
|
|
printf ( "**ERROR conflicting memoryEA %s ip: %p (tid %x)\n (computedAddr %p expectedEA %p teb %p isSegmented %x displacement %p baseRegVal %p indexRegVal %p scale %d\n gaxRegVal %p)\n",
|
|
GetMemoryAccessTypeString(accessType),
|
|
ip,
|
|
tid,
|
|
reinterpret_cast<VOID *>(computedAddr),
|
|
reinterpret_cast<VOID *>(memoryEA),
|
|
reinterpret_cast<VOID *>(threadTeb),
|
|
hasSegmentedMemAccess,
|
|
reinterpret_cast<VOID *>(displacement),
|
|
reinterpret_cast<VOID *>(baseRegValForAddressComputation),
|
|
reinterpret_cast<VOID *>(indexRegValForAddressComputation),
|
|
scale,
|
|
reinterpret_cast<VOID *>(gaxRegVal));
|
|
string s = disassemble (reinterpret_cast<ADDRINT>(ip),reinterpret_cast<ADDRINT>(ip)+15);
|
|
printf (" %s\n", s.c_str());
|
|
hadError = TRUE;
|
|
exit (-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle BTx instructions, where some of the bit index is added to the EA
|
|
VOID AnalyzeBTMemAddr(UINT32 effectiveAddressWidth,
|
|
UINT32 hasSegmentedMemAccess,
|
|
ADDRINT bitIndex,
|
|
VOID * ip,
|
|
VOID * addr,
|
|
UINT32 accessType,
|
|
ADDRINT gaxRegVal,
|
|
ADDRINT baseRegVal,
|
|
ADDRINT indexRegVal,
|
|
INT32 scale,
|
|
ADDRINT displacement,
|
|
UINT32 readSize,
|
|
THREADID tid)
|
|
{
|
|
// Compute the additional offset from the bitIndex and pass it down to AnalyzeMemAddr
|
|
UINT32 shift = (readSize == 2) ? 4 : (readSize == 4) ? 5 : 6;
|
|
|
|
// fprintf (stderr, "0x%08x: BTx bitIndex 0x%08x, addr 0x%08x, readsize %d\n", ip, bitIndex, addr, readSize);
|
|
|
|
AnalyzeMemAddr(effectiveAddressWidth,
|
|
hasSegmentedMemAccess,
|
|
0, // subFromAddrComputation
|
|
ip,
|
|
addr,
|
|
accessType,
|
|
gaxRegVal,
|
|
baseRegVal,
|
|
indexRegVal,
|
|
scale,
|
|
displacement,
|
|
(bitIndex >> shift)*readSize, // insSizeToAdd (cheating, really, but it gets added in which is what we need).
|
|
tid);
|
|
}
|
|
|
|
#ifndef TARGET_LINUX
|
|
#ifdef TARGET_IA32
|
|
#define TESTED_SEG_REG REG_SEG_FS
|
|
#else
|
|
#define TESTED_SEG_REG REG_SEG_GS
|
|
#endif
|
|
#else
|
|
#ifdef TARGET_IA32
|
|
#define TESTED_SEG_REG REG_SEG_GS
|
|
#else
|
|
#define TESTED_SEG_REG REG_SEG_FS
|
|
#endif
|
|
#endif
|
|
|
|
BOOL doNotInstrumentSegmentedAccess = FALSE;
|
|
|
|
BOOL InstrumentMemAccess (INS ins, BOOL isRead)
|
|
{
|
|
UINT32 i, scale=0;
|
|
ADDRINT displacement=0;
|
|
REG baseReg = REG_INVALID(), indexReg = REG_INVALID();
|
|
UINT32 hasSegmentedMemAccess = 0;
|
|
INT32 subFromAddrComputation = 0;
|
|
OPCODE opcode = INS_Opcode(ins);
|
|
|
|
if (opcode==XED_ICLASS_PUSH
|
|
|| opcode==XED_ICLASS_PUSHA
|
|
|| opcode==XED_ICLASS_PUSHAD
|
|
|| opcode==XED_ICLASS_PUSHF
|
|
|| opcode==XED_ICLASS_PUSHFD
|
|
|| opcode==XED_ICLASS_PUSHFQ
|
|
|| opcode==XED_ICLASS_CALL_NEAR
|
|
|| opcode==XED_ICLASS_CALL_FAR
|
|
|| opcode==XED_ICLASS_ENTER)
|
|
{ // These all decrement the stack pointer before the write
|
|
subFromAddrComputation = INS_MemoryWriteSize(ins);
|
|
}
|
|
|
|
|
|
BOOL foundMemOp = FALSE;
|
|
UINT32 operandCount = INS_OperandCount (ins);
|
|
for (i=0; i<operandCount; i++)
|
|
{
|
|
if (INS_OperandIsMemory (ins, i) &&
|
|
((isRead && INS_OperandRead (ins, i)) || (!isRead && INS_OperandWritten (ins, i)))
|
|
)
|
|
{
|
|
displacement = INS_OperandMemoryDisplacement (ins, i);
|
|
baseReg = INS_OperandMemoryBaseReg (ins, i);
|
|
indexReg = INS_OperandMemoryIndexReg (ins, i);
|
|
scale = INS_OperandMemoryScale (ins, i);
|
|
hasSegmentedMemAccess = (INS_OperandMemorySegmentReg (ins, i) == TESTED_SEG_REG );
|
|
foundMemOp = TRUE;
|
|
// printf ("op %d memop isRead %d baseReg %s indexReg %s scale %x\n",
|
|
// i, isRead, REG_StringShort(baseReg).c_str(), REG_StringShort(indexReg).c_str(),
|
|
// scale);
|
|
break;
|
|
}
|
|
}
|
|
ASSERTX (foundMemOp);
|
|
#ifdef TARGET_LINUX
|
|
/* do not support segmented addresses on linux - due to virtual segments
|
|
*/
|
|
if (hasSegmentedMemAccess)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
#endif
|
|
UINT32 addressingType;
|
|
IARG_TYPE iargMemoryEffectiveAddrType;
|
|
UINT32 foundAddressingType = 0;
|
|
if (!(baseReg != REG_INVALID() && indexReg == REG_INVALID()))
|
|
{
|
|
ASSERTX (!INS_HasMemoryRead2(ins));
|
|
}
|
|
if (isRead)
|
|
{
|
|
iargMemoryEffectiveAddrType = IARG_MEMORYREAD_EA;
|
|
subFromAddrComputation = 0;
|
|
}
|
|
else
|
|
{
|
|
iargMemoryEffectiveAddrType = IARG_MEMORYWRITE_EA;
|
|
}
|
|
if (baseReg != REG_INVALID())
|
|
{
|
|
if (indexReg != REG_INVALID())
|
|
{
|
|
if (isRead)
|
|
{
|
|
addressingType = BASE_INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE;
|
|
}
|
|
else
|
|
{
|
|
addressingType = BASE_INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE;
|
|
}
|
|
foundAddressingType++;
|
|
}
|
|
else // indexReg == REG_INVALID()
|
|
{
|
|
indexReg = REG_GDX;
|
|
if (isRead)
|
|
{
|
|
addressingType = BASE_DISPLACEMENT_ADDRESSING_READ_TYPE;
|
|
}
|
|
else
|
|
{
|
|
addressingType = BASE_DISPLACEMENT_ADDRESSING_WRITE_TYPE;
|
|
}
|
|
foundAddressingType++;
|
|
}
|
|
}
|
|
else // baseReg == REG_INVALID()
|
|
{
|
|
baseReg = REG_GDX;
|
|
if (indexReg != REG_INVALID())
|
|
{
|
|
if (isRead)
|
|
{
|
|
addressingType = INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE;
|
|
}
|
|
else
|
|
{
|
|
addressingType = INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE;
|
|
}
|
|
|
|
foundAddressingType++;
|
|
}
|
|
else // indexReg == REG_INVALID()
|
|
{
|
|
indexReg = REG_GDX;
|
|
if (isRead)
|
|
{
|
|
addressingType = DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE;
|
|
}
|
|
else
|
|
{
|
|
addressingType = DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE;
|
|
}
|
|
|
|
foundAddressingType++;
|
|
}
|
|
}
|
|
ASSERTX (foundAddressingType==1);
|
|
UINT32 insSizeToAdd= 0;
|
|
if (baseReg == REG_INST_PTR)
|
|
{
|
|
insSizeToAdd = INS_Size (ins);
|
|
}
|
|
|
|
// Need also to worry about instructions where some of the operand spills over into the
|
|
// EA calculation. This applies to BTx with a register operand to hold the bit index.
|
|
if ((opcode == XED_ICLASS_BT ||
|
|
opcode == XED_ICLASS_BTC ||
|
|
opcode == XED_ICLASS_BTR ||
|
|
opcode == XED_ICLASS_BTS) && !INS_OperandIsImmediate(ins,1))
|
|
{
|
|
INS_InsertCall(
|
|
ins, IPOINT_BEFORE, (AFUNPTR)AnalyzeBTMemAddr,
|
|
IARG_UINT32, INS_EffectiveAddressWidth(ins),
|
|
IARG_UINT32, hasSegmentedMemAccess,
|
|
IARG_REG_VALUE, INS_OperandReg(ins, 1), // The bit index
|
|
IARG_INST_PTR,
|
|
iargMemoryEffectiveAddrType,
|
|
IARG_UINT32, addressingType,
|
|
IARG_REG_VALUE, REG_GAX,
|
|
IARG_REG_VALUE, baseReg,
|
|
IARG_REG_VALUE, indexReg,
|
|
IARG_UINT32, scale,
|
|
IARG_ADDRINT, displacement,
|
|
IARG_UINT32, INS_MemoryReadSize(ins),
|
|
IARG_THREAD_ID,
|
|
IARG_END);
|
|
}
|
|
else
|
|
{
|
|
INS_InsertPredicatedCall(
|
|
ins, IPOINT_BEFORE, (AFUNPTR)AnalyzeMemAddr,
|
|
IARG_UINT32, INS_EffectiveAddressWidth(ins),
|
|
IARG_UINT32, hasSegmentedMemAccess,
|
|
IARG_UINT32, subFromAddrComputation,
|
|
IARG_INST_PTR,
|
|
iargMemoryEffectiveAddrType,
|
|
IARG_UINT32, addressingType,
|
|
IARG_REG_VALUE, REG_GAX,
|
|
IARG_REG_VALUE, baseReg,
|
|
IARG_REG_VALUE, indexReg,
|
|
IARG_UINT32, scale,
|
|
IARG_ADDRINT, displacement,
|
|
IARG_UINT32, insSizeToAdd,
|
|
IARG_THREAD_ID,
|
|
IARG_END);
|
|
}
|
|
if (isRead && INS_HasMemoryRead2(ins))
|
|
{
|
|
addressingType = BASE_DISPLACEMENT_ADDRESSING_READ_TYPE;
|
|
iargMemoryEffectiveAddrType = IARG_MEMORYREAD2_EA;
|
|
subFromAddrComputation = 0;
|
|
|
|
INS_InsertPredicatedCall(
|
|
ins, IPOINT_BEFORE, (AFUNPTR)AnalyzeMemAddr,
|
|
IARG_UINT32, INS_EffectiveAddressWidth(ins),
|
|
IARG_UINT32, hasSegmentedMemAccess,
|
|
IARG_UINT32, subFromAddrComputation,
|
|
IARG_INST_PTR,
|
|
iargMemoryEffectiveAddrType,
|
|
IARG_UINT32, addressingType,
|
|
IARG_REG_VALUE, REG_GAX,
|
|
IARG_REG_VALUE, REG_GDI, /* Read2 is always GDI */
|
|
IARG_REG_VALUE, indexReg,
|
|
IARG_UINT32, scale,
|
|
IARG_ADDRINT, displacement,
|
|
IARG_UINT32, insSizeToAdd,
|
|
IARG_THREAD_ID,
|
|
IARG_END);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
|
|
// Is called for every instruction and instruments reads and writes
|
|
VOID Instruction(INS ins, VOID *v)
|
|
{
|
|
#ifdef TARGET_LINUX
|
|
{
|
|
UINT32 operandCount = INS_OperandCount (ins);
|
|
UINT32 i;
|
|
|
|
for (i=0; i<operandCount; i++)
|
|
{
|
|
if (INS_OperandIsReg (ins, i) && REG_is_seg(INS_OperandReg (ins, i)) && INS_OperandWritten(ins, i))
|
|
{
|
|
printf("**WARNING SegOperand-WRITE not supported, no longer instrumenting segmented mem-accesses\n %p: %s\n", reinterpret_cast<VOID *>(INS_Address(ins)), INS_Disassemble(ins).c_str());
|
|
doNotInstrumentSegmentedAccess = TRUE;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
BOOL instrumentedRead = FALSE;
|
|
BOOL instrumentedWrite = FALSE;
|
|
if (INS_IsMemoryRead(ins))
|
|
{
|
|
instrumentedRead = InstrumentMemAccess (ins, TRUE);
|
|
}
|
|
if (INS_IsMemoryWrite(ins))
|
|
{
|
|
instrumentedWrite = InstrumentMemAccess (ins, FALSE);
|
|
}
|
|
|
|
if (instrumentedRead || instrumentedWrite)
|
|
{
|
|
fprintf (stdout, "Instrumented ins forRead %d forWrite %d: %x %s\n",
|
|
instrumentedRead, instrumentedWrite, INS_Address(ins), INS_Disassemble(ins).c_str());
|
|
}
|
|
*/
|
|
|
|
/*fprintf(trace, "%p %s\n", INS_Address(ins), INS_Disassemble(ins).c_str());
|
|
*/
|
|
}
|
|
|
|
VOID Fini(INT32 code, VOID *v)
|
|
{
|
|
|
|
/*if (!hadError)
|
|
{
|
|
printf ("SUCCESS\n");
|
|
}
|
|
else
|
|
{
|
|
printf ("Had ERRORS - search above for string ERROR\n");
|
|
}*/
|
|
}
|
|
|
|
PIN_LOCK pinLock;
|
|
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
|
|
{
|
|
PIN_GetLock(&pinLock, threadid+1);
|
|
//fprintf(trace, "thread begin %x %x\n",threadid, numThreads);
|
|
numThreads++;
|
|
if (threadid < MAX_THREADS)
|
|
{
|
|
#ifndef TARGET_LINUX
|
|
threadData[threadid] = InitializeThreadData();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
printf ( "ERROR - maximum #threads exceeded\n");
|
|
}
|
|
fflush (stdout);
|
|
PIN_ReleaseLock(&pinLock);
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
PIN_Init(argc, argv);
|
|
|
|
PIN_InitLock(&pinLock);
|
|
PIN_AddThreadStartFunction(ThreadStart, 0);
|
|
INS_AddInstrumentFunction(Instruction, 0);
|
|
PIN_AddFiniFunction(Fini, 0);
|
|
|
|
// Never returns
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|