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.
227 lines
9.1 KiB
227 lines
9.1 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.
|
|
*/
|
|
|
|
#include "pin.H"
|
|
#include <iostream>
|
|
#include <cstdlib>
|
|
#include <signal.h>
|
|
#include <list>
|
|
#include <string>
|
|
using std::hex;
|
|
|
|
using std::cerr;
|
|
using std::endl;
|
|
using std::list;
|
|
using std::string;
|
|
|
|
extern "C" void ToolRaiseAccessInvalidAddressException(ADDRINT **addr, ADDRINT val);
|
|
extern "C" ADDRINT ToolCatchAccessInvalidAddressException;
|
|
extern "C" ADDRINT ToolIpAccessInvalidAddressException;
|
|
|
|
extern "C" ADDRINT ToolRaiseIntDivideByZeroException(ADDRINT catchAddr, ADDRINT code);
|
|
extern "C" ADDRINT ToolCatchIntDivideByZeroException;
|
|
extern "C" ADDRINT ToolIpIntDivideByZeroException;
|
|
|
|
enum ToolExceptionEnumeration { TEE_ACCESS_INVALID_ADDRESS, TEE_INT_DIV_ZERO };
|
|
|
|
struct ToolException {
|
|
ADDRINT ip;
|
|
ADDRINT fixIp;
|
|
string name;
|
|
bool* handled;
|
|
};
|
|
|
|
bool handledPinException = false;
|
|
bool handledToolAccessInvalidAddress = false;
|
|
bool handledToolIntDivZero = false;
|
|
bool handledApplicationDivZero = false;
|
|
|
|
ToolException toolExceptions[2];
|
|
list<ADDRINT> inslist;
|
|
|
|
// This is the tool's generic handler. It handles the excpetion defined in toolException.
|
|
static EXCEPT_HANDLING_RESULT toolHandler(ToolException* toolException, EXCEPTION_INFO* exptInfo,
|
|
PHYSICAL_CONTEXT* pctxt)
|
|
{
|
|
ADDRINT exptAddr = PIN_GetExceptionAddress(exptInfo);
|
|
ADDRINT ip = PIN_GetPhysicalContextReg(pctxt, REG_INST_PTR);
|
|
if (ip == toolException->ip) { // Only handle this exception.
|
|
cerr << "TOOL: Identified " << toolException->name << " exception in the tool, fixing the problem..." << endl;
|
|
PIN_SetPhysicalContextReg(pctxt, REG_INST_PTR, toolException->fixIp);
|
|
if (exptAddr != ip) {
|
|
cerr << hex << "TOOL ERROR: Exception address 0x" << exptAddr << " does not match ip 0x" << ip << endl;
|
|
}
|
|
else {
|
|
*(toolException->handled) = true;
|
|
}
|
|
return EHR_HANDLED;
|
|
}
|
|
return EHR_UNHANDLED;
|
|
}
|
|
|
|
// Global handler for SIGFPE exceptions.
|
|
// This handler only deals with a specific int-div-zero exception, the one raised in "generateToolException()".
|
|
// All other exceptions are not handled here and are forwarded to the next level.
|
|
static EXCEPT_HANDLING_RESULT onException(THREADID tid, EXCEPTION_INFO* exptInfo, PHYSICAL_CONTEXT* pctxt, VOID* v) {
|
|
return toolHandler(&toolExceptions[TEE_INT_DIV_ZERO], exptInfo, pctxt);
|
|
}
|
|
|
|
// Thread specific handler for PIN_Try exceptions.
|
|
// This handler only deals with a specific access-invalid-address exception, the one raised in "generateToolException()".
|
|
// All other exceptions are not handled here and are forwarded to the next level.
|
|
static EXCEPT_HANDLING_RESULT onTryException(THREADID tid, EXCEPTION_INFO* exptInfo, PHYSICAL_CONTEXT* pctxt, VOID* v) {
|
|
return toolHandler(&toolExceptions[TEE_ACCESS_INVALID_ADDRESS], exptInfo, pctxt);
|
|
}
|
|
|
|
// Pin generates an access violation in SafeCopy (due to the given arguments).
|
|
// This should return an exception with a null exception address
|
|
static void generatePinException(ADDRINT address) {
|
|
cerr << "TOOL: Generate pin exception" << endl;
|
|
VOID* to = (VOID*)address;
|
|
ADDRINT* from = 0;
|
|
EXCEPTION_INFO exptInfo;
|
|
size_t toCopy = 1024;
|
|
if (PIN_SafeCopyEx(to, from, toCopy, &exptInfo) != toCopy) {
|
|
if (PIN_GetExceptionCode(&exptInfo) != EXCEPTCODE_ACCESS_INVALID_ADDRESS) {
|
|
cerr << "TOOL ERROR: PIN_SafeCopyEx returned with an unexpected exception code" << endl;
|
|
cerr << PIN_ExceptionToString(&exptInfo) << endl;
|
|
return;
|
|
}
|
|
ADDRINT exptAddr = PIN_GetExceptionAddress(&exptInfo);
|
|
if (exptAddr != 0) {
|
|
cerr << "TOOL ERROR: Exception from PIN_SafeCopyEx returned with non NULL address: 0x"
|
|
<< hex << exptAddr << endl;
|
|
return;
|
|
}
|
|
else {
|
|
cerr << "TOOL: PIN_SafeCopyEx failed as expected, continue test..." << endl;
|
|
handledPinException = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tool generates a div zero exception.
|
|
// This should return an exception address which equals the IP value.
|
|
// The address is in the analysis routine placed in the codecache.
|
|
static void generateToolException() {
|
|
ToolRaiseIntDivideByZeroException(ToolCatchIntDivideByZeroException, 0);
|
|
PIN_TryStart(PIN_ThreadId(), onTryException, 0);
|
|
ADDRINT *addressPair[2];
|
|
addressPair[0] = 0;
|
|
addressPair[1] = (ADDRINT *)malloc(sizeof(ADDRINT));
|
|
ToolRaiseAccessInvalidAddressException(addressPair, 0x12345);
|
|
PIN_TryEnd(PIN_ThreadId());
|
|
}
|
|
|
|
// Catch a SIGFPE signal generated by a div zero in the application.
|
|
// This should return an exception address in the application's native code, not the instrumented code in the codecache.
|
|
// Fix the problem by advancing the IP to the next instruction - advance the IP in the context (native code) and let Pin
|
|
// translate to the actual address in the codecache.
|
|
static bool onSIGFPE(THREADID tid, INT32 sig, CONTEXT* ctxt, BOOL hasHandler, const EXCEPTION_INFO* exptInfo, VOID* v) {
|
|
ADDRINT exptAddr = PIN_GetExceptionAddress(exptInfo);
|
|
ADDRINT ip = PIN_GetContextReg(ctxt, REG_INST_PTR);
|
|
list<ADDRINT>::const_iterator it = inslist.begin();
|
|
list<ADDRINT>::const_iterator end = inslist.end();
|
|
for (; it != end; ++it) {
|
|
if (*it == ip) {
|
|
cerr << "TOOL: Identified div zero instruction in the application, fixing the problem..." << endl;
|
|
++it; // Advance the iterator to the next instruction.
|
|
PIN_SetContextReg(ctxt, REG_INST_PTR, *it); // Load the new IP.
|
|
if (exptAddr == ip) {
|
|
handledApplicationDivZero = true;
|
|
}
|
|
else {
|
|
cerr << hex << "TOOL ERROR: Exception address 0x" << exptAddr << " does not match ip 0x" << ip << endl;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Instrument the application functions - intentionally generate exceptions in the proper places and build the instList.
|
|
static VOID onRoutine(RTN rtn, VOID *) {
|
|
if (RTN_Name(rtn).find("pinException") != string::npos) {
|
|
RTN_Open(rtn);
|
|
RTN_InsertCall(rtn, IPOINT_AFTER, AFUNPTR(generatePinException), IARG_ADDRINT, RTN_Address(rtn), IARG_END);
|
|
RTN_Close(rtn);
|
|
}
|
|
|
|
else if (RTN_Name(rtn).find("toolException") != string::npos) {
|
|
RTN_Open(rtn);
|
|
RTN_InsertCall(rtn, IPOINT_AFTER, AFUNPTR(generateToolException), IARG_END);
|
|
RTN_Close(rtn);
|
|
}
|
|
|
|
else if (RTN_Name(rtn).find("appException") != string::npos) {
|
|
RTN_Open(rtn);
|
|
|
|
// Build a list of all the instrucions in the routine.
|
|
// The tool will use this to fix the div zero exception by advancing the IP to the next instruction.
|
|
for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)) {
|
|
inslist.push_back(INS_Address(ins));
|
|
}
|
|
|
|
RTN_Close(rtn);
|
|
}
|
|
}
|
|
|
|
// Check that all four scenarios were handled.
|
|
VOID Fini(INT32 code, VOID* v) {
|
|
bool failed = false;
|
|
if (!handledPinException) {
|
|
cerr << "TOOL ERROR: PIN_SafeCopy exception was not handled properly in the test." << endl;
|
|
failed = true;
|
|
}
|
|
if (!handledToolAccessInvalidAddress) {
|
|
cerr << "TOOL ERROR: Tool access invalid address exception was not handled properly in the test." << endl;
|
|
failed = true;
|
|
}
|
|
if (!handledToolIntDivZero) {
|
|
cerr << "TOOL ERROR: Tool int div zero exception was not handled properly in the test." << endl;
|
|
failed = true;
|
|
}
|
|
if (!handledApplicationDivZero) {
|
|
cerr << "TOOL ERROR: Application div zero exception was not handled properly in the test." << endl;
|
|
failed = true;
|
|
}
|
|
if (failed) {
|
|
exit(-1);
|
|
}
|
|
else {
|
|
cerr << "TOOL: Test completed successfully!" << endl;
|
|
}
|
|
}
|
|
|
|
// Tool's main function
|
|
int main(int argc, char *argv[]) {
|
|
PIN_InitSymbols();
|
|
PIN_Init(argc, argv);
|
|
|
|
toolExceptions[TEE_ACCESS_INVALID_ADDRESS].ip = reinterpret_cast < ADDRINT > (&ToolIpAccessInvalidAddressException);
|
|
toolExceptions[TEE_ACCESS_INVALID_ADDRESS].fixIp = reinterpret_cast < ADDRINT > (&ToolCatchAccessInvalidAddressException);
|
|
toolExceptions[TEE_ACCESS_INVALID_ADDRESS].name = "access invalid address";
|
|
toolExceptions[TEE_ACCESS_INVALID_ADDRESS].handled = &handledToolAccessInvalidAddress;
|
|
|
|
toolExceptions[TEE_INT_DIV_ZERO].ip = reinterpret_cast < ADDRINT > (&ToolIpIntDivideByZeroException);
|
|
toolExceptions[TEE_INT_DIV_ZERO].fixIp = reinterpret_cast < ADDRINT > (&ToolCatchIntDivideByZeroException);
|
|
toolExceptions[TEE_INT_DIV_ZERO].name = "int div zero";
|
|
toolExceptions[TEE_INT_DIV_ZERO].handled = &handledToolIntDivZero;
|
|
|
|
PIN_AddInternalExceptionHandler(onException, 0);
|
|
RTN_AddInstrumentFunction(onRoutine, 0);
|
|
PIN_InterceptSignal(SIGFPE, onSIGFPE, 0);
|
|
PIN_AddFiniFunction(Fini, 0);
|
|
|
|
PIN_StartProgram();
|
|
return 0;
|
|
}
|