/* * 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 file contains a tool for testing 16bit addressing including IARG_MEMORY(READ/WRITE)_EA of those addresses on PIN Windows */ #include #include #include "pin.H" #include #ifdef TARGET_WINDOWS namespace WIND { #include } inline ADDRINT InitializeThreadData() { return reinterpret_cast(WIND::NtCurrentTeb()); } #endif #ifdef TARGET_LINUX #include #include #include #ifdef TARGET_IA32E #include #include #endif #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 using std::cerr; using std::endl; 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; } 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 } inline ADDRINT InitializeThreadData() { return GetTlsBaseAddress(); } #endif FILE * trace=stdout; #define MAX_THREADS 1024 #define DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE 0 #define BASE_DISPLACEMENT_ADDRESSING_READ_TYPE 1 #define BASE_INDEX_DISPLACEMENT_ADDRESSING_READ_TYPE 2 #define DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE 3 #define BASE_DISPLACEMENT_ADDRESSING_WRITE_TYPE 4 #define BASE_INDEX_DISPLACEMENT_ADDRESSING_WRITE_TYPE 5 #define MAX_ADDRESSING_TYPES 6 struct tdata { ADDRINT threadTeb; int numEffectiveAddressesAnalyzed[MAX_ADDRESSING_TYPES]; int numNonSegEffectiveAddressesAnalyzed[MAX_ADDRESSING_TYPES]; } THREAD_DATA; int numThreads = 0; BOOL hadError = FALSE; static TLS_KEY tls_key = INVALID_TLS_KEY; tdata* get_tls(THREADID threadid) { return static_cast(PIN_GetThreadData(tls_key, threadid)); } 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"); default: return ("UNKNOWN_ADDRESSING_TYPE"); } } VOID AnalyzeSegmentedMemAccessDispl(VOID * ip, VOID * addr, UINT32 accessType, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { if (!data->threadTeb) data->threadTeb = InitializeThreadData(); ADDRINT threadTeb = data->threadTeb; ADDRINT memoryEA = reinterpret_cast(addr); data->numEffectiveAddressesAnalyzed[accessType]++; if ((threadTeb + displacement) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (teb %p displacement %x expectedEA %p)\n", ip, addr, tid, reinterpret_cast(threadTeb), displacement, reinterpret_cast(threadTeb+displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeSegmentedMemAccessBaseIndexDispl(VOID * ip, VOID * addr, UINT32 accessType, ADDRINT baseRegVal, ADDRINT indexRegVal, UINT32 scale, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { if (!data->threadTeb) data->threadTeb = InitializeThreadData(); ADDRINT threadTeb = data->threadTeb; ADDRINT memoryEA = reinterpret_cast(addr); data->numEffectiveAddressesAnalyzed[accessType]++; if ((threadTeb + displacement + baseRegVal + (indexRegVal*scale)) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (teb %p displacement %x baseRegVal %x indexRegVal %x scale %d expectedEA %p)\n", ip, addr, tid, reinterpret_cast(threadTeb), displacement, baseRegVal, indexRegVal, scale, reinterpret_cast(threadTeb+displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeSegmentedMemAccessBaseDispl(VOID * ip, VOID * addr, UINT32 accessType, ADDRINT baseRegVal, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { if (!data->threadTeb) data->threadTeb = InitializeThreadData(); ADDRINT threadTeb = data->threadTeb; ADDRINT memoryEA = reinterpret_cast(addr); data->numEffectiveAddressesAnalyzed[accessType]++; if ((threadTeb + displacement + baseRegVal) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (teb %p displacement %x baseRegVal %x expectedEA %p)\n", ip, addr, tid, reinterpret_cast(threadTeb), displacement, baseRegVal, reinterpret_cast(threadTeb+displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeSegmentedMemAccessIndexDispl(VOID * ip, VOID * addr, UINT32 accessType, ADDRINT indexRegVal, UINT32 scale, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { if (!data->threadTeb) data->threadTeb = InitializeThreadData(); ADDRINT threadTeb = data->threadTeb; ADDRINT memoryEA = reinterpret_cast(addr); data->numEffectiveAddressesAnalyzed[accessType]++; if ((threadTeb + displacement + (indexRegVal*scale)) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (teb %p displacement %x indexRegVal %x scale %d expectedEA %p)\n", ip, addr, tid, reinterpret_cast(threadTeb), displacement, indexRegVal, scale, reinterpret_cast(threadTeb+displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeMemAccessDispl(VOID * ip, VOID * addr, UINT32 accessType, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { if (!data->threadTeb) data->threadTeb = InitializeThreadData(); ADDRINT memoryEA = reinterpret_cast(addr); data->numNonSegEffectiveAddressesAnalyzed[accessType]++; if ((displacement) != memoryEA) { fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) ( displacement %x expectedEA %p)\n", ip, addr, tid, displacement, reinterpret_cast(displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeMemAccessBaseIndexDispl(VOID * ip, VOID * addr, UINT32 accessType, ADDRINT baseRegVal, ADDRINT indexRegVal, UINT32 scale, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { if (!data->threadTeb) data->threadTeb = InitializeThreadData(); ADDRINT memoryEA = reinterpret_cast(addr); data->numNonSegEffectiveAddressesAnalyzed[accessType]++; if ((displacement + baseRegVal + (indexRegVal*scale)) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (displacement %x baseRegVal %x indexRegVal %x scale %d expectedEA %p)\n", ip, addr, tid, displacement, baseRegVal, indexRegVal, scale, reinterpret_cast(displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeMemAccessBaseDispl(VOID * ip, VOID * addr, UINT32 accessType, ADDRINT baseRegVal, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { ADDRINT memoryEA = reinterpret_cast(addr); data->numNonSegEffectiveAddressesAnalyzed[accessType]++; if ((displacement + baseRegVal) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (displacement %x baseRegVal %x expectedEA %p)\n", ip, addr, tid, displacement, baseRegVal, reinterpret_cast(displacement)); fflush(trace); hadError = TRUE; } } } VOID AnalyzeMemAccessIndexDispl(VOID * ip, VOID * addr, UINT32 accessType, ADDRINT indexRegVal, UINT32 scale, UINT32 displacement, THREADID tid) { tdata* data = get_tls(tid); if (data != NULL) { ADDRINT memoryEA = reinterpret_cast(addr); data->numNonSegEffectiveAddressesAnalyzed[accessType]++; if ((displacement + (indexRegVal*scale)) != memoryEA) {// memoryEA is the TEB of the thread + displacement that is in the segmented operand fprintf (trace, "TRACED_INST_ERROR %p: R %p (tid %x) (displacement %x indexRegVal %x scale %d expectedEA %p)\n", ip, addr, tid, displacement, indexRegVal, scale, reinterpret_cast(displacement)); fflush(trace); hadError = TRUE; } } } #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 VOID HandleSegmentedAccess (INS ins, BOOL isRead, BOOL *hasSegmentedMemAccess) { UINT32 operandCount = INS_OperandCount (ins); UINT32 i, displacement, scale; REG baseReg = REG_INVALID(), indexReg = REG_INVALID(); *hasSegmentedMemAccess = FALSE; for (i=0; inumEffectiveAddressesAnalyzed[j] == 0) { fprintf(trace, "ERROR - Thread %x: no segment[%s] based accesses\n", threadid, GetMemoryAccessTypeString(j)); hadError = TRUE; } else { fprintf(trace, "Thread %x: verified %d segmented[%s] accesses\n", threadid, data->numEffectiveAddressesAnalyzed[j], GetMemoryAccessTypeString(j)); } if (DISPLACEMENT_ONLY_ADDRESSING_READ_TYPE!=j && DISPLACEMENT_ONLY_ADDRESSING_WRITE_TYPE!=j) { if (data->numNonSegEffectiveAddressesAnalyzed[j]==0) { fprintf(trace, "ERROR - Thread %x: no non-segment[%s] based accesses\n", threadid, GetMemoryAccessTypeString(j)); hadError = TRUE; } else { fprintf(trace, "Thread %x: verified %d non-segmented[%s] accesses\n", threadid, data->numNonSegEffectiveAddressesAnalyzed[j], GetMemoryAccessTypeString(j)); } } } fprintf(trace, "\n"); } } PIN_LOCK pinLock; THREADID myThread = INVALID_THREADID; VOID ThreadStartUtil(THREADID threadid, CONTEXT *ctxt) { fprintf(trace, "thread begin %x %x\n",threadid, numThreads); numThreads++; if (threadid < MAX_THREADS) { #ifndef TARGET_LINUX tdata* data = new tdata; data->threadTeb = InitializeThreadData(); if (PIN_SetThreadData(tls_key, data, threadid) == FALSE) { std::cerr << "PIN_SetThreadData failed" << std::endl; PIN_ExitProcess(1); } #endif } else { fprintf (trace, "ERROR - maximum #threads exceeded\n"); } fflush(trace); } VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v) { if (INVALID_THREADID == myThread) { myThread = PIN_ThreadId(); ThreadStartUtil(threadid, ctxt); } } VOID AppThreadStart(THREADID threadid, CONTEXT *ctxt) { PIN_GetLock(&pinLock, PIN_GetTid()); ThreadStartUtil(threadid, ctxt); PIN_ReleaseLock(&pinLock); } //Instrument the app thread rtn VOID InstrumentRtn(RTN rtn, VOID *) { if (PIN_UndecorateSymbolName(RTN_Name(rtn), UNDECORATION_NAME_ONLY) == "longfun" || PIN_UndecorateSymbolName(RTN_Name(rtn), UNDECORATION_NAME_ONLY) == "shortfun") { RTN_Open(rtn); RTN_InsertCall(rtn, IPOINT_BEFORE, AFUNPTR(AppThreadStart), IARG_THREAD_ID, IARG_CONTEXT, IARG_END); RTN_Close(rtn); } } int main(int argc, char *argv[]) { PIN_Init(argc, argv); PIN_InitSymbols(); PIN_InitLock(&pinLock); tls_key = PIN_CreateThreadDataKey(NULL); if (tls_key == INVALID_TLS_KEY) { std::cerr << "number of already allocated keys reached the MAX_CLIENT_TLS_KEYS limit" << std::endl; PIN_ExitProcess(1); } RTN_AddInstrumentFunction(InstrumentRtn, NULL); PIN_AddThreadStartFunction(ThreadStart, NULL); INS_AddInstrumentFunction(Instruction, NULL); PIN_AddThreadFiniFunction(ThreadFini, NULL); PIN_AddFiniFunction(Fini, NULL); // Never returns PIN_StartProgram(); return 1; }