129
Using Pin++ To Author Highly Configurable Pintools for Pin Dr. James H. Hill Dept. Computer & Information Science Indiana University-Purdue University Indianapolis [email protected] http://www.cs.iupui.edu/~ hillj http:// g ithub.com /SEDS/ PinPP

Using Pin++ to Author Highly Configurable Pintools for Pin

Embed Size (px)

Citation preview

Using Pin++ To Author Highly Configurable

Pintools for PinDr. James H. Hill

Dept. Computer & Information ScienceIndiana University-Purdue University Indianapolis

[email protected]://www.cs.iupui.edu/~hilljhttp://github.com/SEDS/PinPP

PrefaceThis tutorial is designed to teach developers how to use Pin++ to author Pintools for Pin. We believe Pin is a great dynamic binary instrumentation tool, and one can write powerful analysis tools for it. We, however, have experienced difficulties using Pin in the past. We (and Pin++) aim is to alleviate the many problems we have encountered. In no way is this tutorial meant to negatively critique Pin. Instead, we want this tutorial (and Pin++) to complement Pin, and enable developers to use Pin in new, exciting ways as we are doing.

Happy Coding!

Tutorial Outline

What is All This “Pin” About?!

Creating a Traditional Pintool

Goals of Pin++

Creating our First Pintool using Pin++

Using Data In Our Callbacks

Requesting Contextual Information in Callbacks

Others Features of Pin++

What is All This “Pin” About?!

http://www.pintool.org

Dynamic Binary Instrumentation

Dynamic Binary Instrumentation (DBI) is a method of analyzing the behavior of a binary application at runtime through the injection of instrumentation code. This instrumentation code executes as part of the normal instruction stream after being injected. In most cases, the instrumentation code will be entirely transparent to the application that it's been injected to. Analyzing an application at runtime makes it possible to gain insight into the behavior and state of an application at various points in execution.

PinPin is a dynamic binary instrumentation tool

http://www.pintool.org

Supported PlatformsLinuxWindowsMacOS XAndroidEtc…

Creating a Traditional Pintool

Counting Instructions (1/3)#include <iostream>#include <fstream>#include "pin.H"

ofstream OutFile;

// The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every instruction is executedVOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to docount before every instruction, no arguments are passed INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "inscount.out", "specify output file name");

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Counting Instructions (1/3)#include <iostream>#include <fstream>#include "pin.H"

ofstream OutFile;

// The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every instruction is executedVOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to docount before every instruction, no arguments are passed INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "inscount.out", "specify output file name");

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Analysis function that increments a

counter variable

Counting Instructions (1/3)#include <iostream>#include <fstream>#include "pin.H"

ofstream OutFile;

// The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every instruction is executedVOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to docount before every instruction, no arguments are passed INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "inscount.out", "specify output file name");

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Function that adds analysis function before each new

instruction

Counting Instructions (1/3)#include <iostream>#include <fstream>#include "pin.H"

ofstream OutFile;

// The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every instruction is executedVOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to docount before every instruction, no arguments are passed INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "inscount.out", "specify output file name");

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Pintool arguments (i.e., knobs), similar to command-line

arguments

Counting Instructions (2/3)// This function is called when the application exitsVOID Fini(INT32 code, VOID *v){ // Write to a file since cout and cerr maybe closed by the application OutFile.setf(ios::showbase); OutFile << "Count " << icount << endl; OutFile.close();}

/* ===================================================================== *//* Print Help Message *//* ===================================================================== */

INT32 Usage(){ cerr << "This tool counts the number of dynamic instructions executed" << endl; cerr << endl << KNOB_BASE::StringKnobSummary() << endl; return -1;}

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Counting Instructions (2/3)// This function is called when the application exitsVOID Fini(INT32 code, VOID *v){ // Write to a file since cout and cerr maybe closed by the application OutFile.setf(ios::showbase); OutFile << "Count " << icount << endl; OutFile.close();}

/* ===================================================================== *//* Print Help Message *//* ===================================================================== */

INT32 Usage(){ cerr << "This tool counts the number of dynamic instructions executed" << endl; cerr << endl << KNOB_BASE::StringKnobSummary() << endl; return -1;}

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

A “finalize” function that prints the final count

Counting Instructions (3/3)/* ===================================================================== *//* Main *//* ===================================================================== *//* argc, argv are the entire command line: pin -t <toolname> -- ... *//* ===================================================================== */

int main(int argc, char * argv[]){ // Initialize pin if (PIN_Init(argc, argv)) return Usage();

OutFile.open(KnobOutputFile.Value().c_str());

// Register Instruction to be called to instrument instructions INS_AddInstrumentFunction(Instruction, 0);

// Register Fini to be called when the application exits PIN_AddFiniFunction(Fini, 0); // Start the program, never returns PIN_StartProgram(); return 0;}

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Counting Instructions (3/3)/* ===================================================================== *//* Main *//* ===================================================================== *//* argc, argv are the entire command line: pin -t <toolname> -- ... *//* ===================================================================== */

int main(int argc, char * argv[]){ // Initialize pin if (PIN_Init(argc, argv)) return Usage();

OutFile.open(KnobOutputFile.Value().c_str());

// Register Instruction to be called to instrument instructions INS_AddInstrumentFunction(Instruction, 0);

// Register Fini to be called when the application exits PIN_AddFiniFunction(Fini, 0); // Start the program, never returns PIN_StartProgram(); return 0;}

https://software.intel.com/sites/landingpage/pintool/docs/71313/Pin/html/index.html#SimpleCount

Required bootstrapping code for

the pintool

Developer Challenges1. It is hard to see the design of a Pintool

2. There are many hidden complexities in a Pintool

3. It is hard to reuse components of a Pintool

4. Constant reinvention of required behavior in a Pintool

5. Bad software engineering practices

Seeing the Designofstream OutFile ("inscount.out");static UINT64 icount = 0;

VOID docount() { icount++; }

VOID Instruction(INS ins, VOID *v) { INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

VOID Fini(INT32 code, VOID *v) { OutFile.setf(ios::showbase); OutFile << "Count " << icount << endl; OutFile.close();}

int main(int argc, char * argv[]) { if (PIN_Init(argc, argv)) return 1; INS_AddInstrumentFunction(Instruction, 0); PIN_AddFiniFunction(Fini, 0); PIN_StartProgram(); return 0;}

Based on this code:• What is the design

of a Pintool?• What entities are

involved in the Pintool, and their relations?

Hidden ComplexitiesVOID docount() { icount++; }

VOID Instruction(INS ins, VOID *v) { INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

Developer must remember the arguments used to register analysis function must match the number of arguments, and type, expected by the analysis function.

Reuse?ofstream OutFile ("inscount.out");static UINT64 icount = 0;

VOID docount() { icount++; }

VOID Instruction(INS ins, VOID *v) { INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);}

VOID Fini(INT32 code, VOID *v) { OutFile.setf(ios::showbase); OutFile << "Count " << icount << endl; OutFile.close();}

int main(int argc, char * argv[]) { if (PIN_Init(argc, argv)) return 1; INS_AddInstrumentFunction(Instruction, 0); PIN_AddFiniFunction(Fini, 0); PIN_StartProgram(); return 0;}

Tight coupling makes it hard to use any part of Pintool in another Pintool, especially with the global variable! This approach is common in Pintools.

Continuous Reinventionstatic UINT64 icount = 0;

VOID docount() { icount++; }

int main(int argc, char * argv[]) { if (PIN_Init(argc, argv)) return 1; INS_AddInstrumentFunction(Instruction, 0); PIN_AddFiniFunction(Fini, 0); PIN_StartProgram(); return 0;}

Most bootstrapping code is similar in all Pintools.

Lack of reuse also leads to reinvention of core logic.

I want to use this again, must I reinvent

it?

Here lies the reinvented

bootstrapping code

Bad Software Engineer!ofstream OutFile ("inscount.out");static UINT64 icount = 0;

VOID docount() { icount++; }

Current mechanisms guide developers to use bad software engineering practices, like using global variables!

Goals of Pin++http://github.com/SEDS/PinPP

Pin++ Aims to…Be 100% object-oriented

Use design patterns to promote reuse and reduce complexity of Pintools

Uses template-metaprogramming to reduce potential development errors and optimize the performance of a Pintool at compile time

Promote reuse of different components in a Pintool

Codify many requirements of a Pintool so developers to not have to re-implement them for each and every tool e.g., bootstrapping, initialization, registration, & etc

Pin++ Framework

Pin

Pintool

Pin

Pin++

Pintool

Pin++ is a framework that sits between Pin, and the application logic of a Pintool

And We Achieved…

James H. Hill and Dennis C. Feiock. 2014. Pin++: an object-oriented framework for writing pintools. In Proceedings of the 2014 International Conference on Generative Programming: Concepts and Experiences (GPCE 2014). ACM, New York, NY, USA, 133-141

And…

James H. Hill and Dennis C. Feiock. 2014. Pin++: an object-oriented framework for writing pintools. In Proceedings of the 2014 International Conference on Generative Programming: Concepts and Experiences (GPCE 2014). ACM, New York, NY, USA, 133-141

And…

James H. Hill and Dennis C. Feiock. 2014. Pin++: an object-oriented framework for writing pintools. In Proceedings of the 2014 International Conference on Generative Programming: Concepts and Experiences (GPCE 2014). ACM, New York, NY, USA, 133-141

And…

James H. Hill and Dennis C. Feiock. 2014. Pin++: an object-oriented framework for writing pintools. In Proceedings of the 2014 International Conference on Generative Programming: Concepts and Experiences (GPCE 2014). ACM, New York, NY, USA, 133-141

Creating Our First Pintool using Pin++

https://github.com/SEDS/PinPP/wiki/Creating-a-Pintool-using-Pin

System RequirementsPerl, on Windows we suggest ActivePerl

GIT

Pin (build 61206 to 67254)

Makefile, Project, Workspace Creator (master) from its GitHub repository.https://github.com/DOCGroup/MPC

C++11 compliant compiler for examples*

Pin++ is has been tested on Windows, Linux, and MacOS X

* Coming soon. C++11 compliant compiler will be need for all of Pin++.

Environment Setup (1/2)Pin

PIN_ROOT set to location of Pin

PATH (and LD_LIBRARY_PATH or DYLD_LIBRARY_PATH) must be set correctly

Pin++

PINPP_ROOT set to location of Pin++

$PINPP_ROOT/bin in PATH

$PINPP_ROOT/lib in library path

Environment Setup (2/2)Windows

PINPP_ROOT=[location of Pin++]

PATH=%PATH%;%PINPP_ROOT%\bin;%PINPP_ROOT%\lib

Linux

PINPP_ROOT=[location of Pin++]

PATH=$PATH:$PINPP_ROOT/bin

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PINPP_ROOT/lib

MacOS X Users. Use the Linux approach above, but replace LD_LIBRARY_PATH with DYLD_LIBRARY_PATH

Building Pin++We use Makefile, Workspace, Project Creator (MPC)

to assist with building Pin++ on different platformsMPC allows us to write generic project files that are

used to generate build scripts for the target platformE.g., Makefiles, Visual Studio Workspaces, Eclipse,

etc.https://github.com/DOCGroup/MPC

Build Command

%> mwc.pl –type [type] pin++.mwc

%> open/build generated workspace

100% Object-Oriented

Everything in Pin++ is an object, which helps us see the design of the Pintool and address other challenges

e.g., reuse, tight coupling, etc.

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

C function is now an object…

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

Parameterized by self (i.e., Curiously recurring template pattern); uses static

polymorphism instead of dynamic polymorphism

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

Function pointer parameter determines signature of analysis

function

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

All callbacks must implement handle_analyze method; parameters

determined by Callback template parameter

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

Allows for type deduction and safety; We will discuss this later.

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;};

No more global variables; callback object is “self-

contained”

Callback ObjectThe callback object is responsible for performing

analysis at the instrumented location

class docount : public OASIS::Pin::Callback <docount (void)> {public: docount (void) : count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

UINT64 count (void) const { return this->count_; }

private: UINT64 count_;}; Callback can have

configuration/accessor methods, if needed

Instrumentation ObjectThe instrument object is a Bridge between the tool callback

object. The instrument inserts callback objects.

class Instruction : public OASIS::Pin::Instruction_Instrument <Instruction>{public: void handle_instrument (const OASIS::Pin::Ins & ins) { this->callback_.insert (IPOINT_BEFORE, ins); }

UINT64 count (void) const { return this->callback_.count (); }

private: docount callback_; // Analysis routine for instrument};

Instrument is an object, base class parameterized by sublcass

Instrumentation ObjectThe instrument object is a Bridge between the tool callback

object. The instrument inserts callback objects.

class Instruction : public OASIS::Pin::Instruction_Instrument <Instruction>{public: void handle_instrument (const OASIS::Pin::Ins & ins) { this->callback_.insert (IPOINT_BEFORE, ins); }

UINT64 count (void) const { return this->callback_.count (); }

private: docount callback_; // Analysis routine for instrument};

All instruments must implement handle_instrument method.

Instrumentation ObjectThe instrument object is a Bridge between the tool callback

object. The instrument inserts callback objects.

class Instruction : public OASIS::Pin::Instruction_Instrument <Instruction>{public: void handle_instrument (const OASIS::Pin::Ins & ins) { this->callback_.insert (IPOINT_BEFORE, ins); }

UINT64 count (void) const { return this->callback_.count (); }

private: docount callback_; // Analysis routine for instrument};

Instrument contains one or more callback objects

Instrumentation ObjectThe instrument object is a Bridge between the tool callback

object. The instrument inserts callback objects.

class Instruction : public OASIS::Pin::Instruction_Instrument <Instruction>{public: void handle_instrument (const OASIS::Pin::Ins & ins) { this->callback_.insert (IPOINT_BEFORE, ins); }

UINT64 count (void) const { return this->callback_.count (); }

private: docount callback_; // Analysis routine for instrument};

Callback object have insert method for inserting callback at

target

Instrumentation ObjectThe instrument object is a Bridge between the tool callback

object. The instrument inserts callback objects.

class Instruction : public OASIS::Pin::Instruction_Instrument <Instruction>{public: void handle_instrument (const OASIS::Pin::Ins & ins) { this->callback_.insert (IPOINT_BEFORE, ins); }

UINT64 count (void) const { return this->callback_.count (); }

private: docount callback_; // Analysis routine for instrument}; Instrument can have configuration/accessor methods,

if needed

Instrumentation ObjectThe instrument object is a Bridge between the tool callback

object. The instrument inserts callback objects.

class Instruction : public OASIS::Pin::Instruction_Instrument <Instruction>{public: void handle_instrument (const OASIS::Pin::Ins & ins) { this->callback_.insert (IPOINT_BEFORE, ins); }

UINT64 count (void) const { return this->callback_.count (); }

private: docount callback_; // Analysis routine for instrument};

Instrument is self-contained, and can be reused across Pintools since it contains callbacks to make it work correctly

Instrumentation Types

Type Handle Method

Instruction_Instrument handle_instrument (const Ins &)

Trace_Instrument handle_instrument (const Trace &)

Routine_Instrument handle_instrument (const Routine &)

Image_Instrument handle_instrument (const Image &)

Each instrumentation type corresponds to an Pin type that supports instrumentation i.e., INS, TRACE, RTN, and IMAGE

Tool ObjectThe tool object bootstraps the Pintool & registers

its instrumentsclass inscount : public OASIS::Pin::Tool <inscount>{public: inscount (void) { this->enable_fini_callback (); }

void handle_fini (INT32 code) { std::ofstream fout ("inscount.out"); fout.setf (ios::showbase); fout << "Count " << this->instruction_.count () << std::endl;

fout.close (); }

private: Instruction instruction_;};

Tool ObjectThe tool object bootstraps the Pintool & registers

its instrumentsclass inscount : public OASIS::Pin::Tool <inscount>{public: inscount (void) { this->enable_fini_callback (); }

void handle_fini (INT32 code) { std::ofstream fout ("inscount.out"); fout.setf (ios::showbase); fout << "Count " << this->instruction_.count () << std::endl;

fout.close (); }

private: Instruction instruction_;};

Tool base class is parameterized by the

sublcass

Tool ObjectThe tool object bootstraps the Pintool & registers

its instrumentsclass inscount : public OASIS::Pin::Tool <inscount>{public: inscount (void) { this->enable_fini_callback (); }

void handle_fini (INT32 code) { std::ofstream fout ("inscount.out"); fout.setf (ios::showbase); fout << "Count " << this->instruction_.count () << std::endl;

fout.close (); }

private: Instruction instruction_;};

Register tool-specific notifications

Tool ObjectThe tool object bootstraps the Pintool & registers

its instrumentsclass inscount : public OASIS::Pin::Tool <inscount>{public: inscount (void) { this->enable_fini_callback (); }

void handle_fini (INT32 code) { std::ofstream fout ("inscount.out"); fout.setf (ios::showbase); fout << "Count " << this->instruction_.count () << std::endl;

fout.close (); }

private: Instruction instruction_;};

Implement tool-specific notifications

Tool ObjectThe tool object bootstraps the Pintool & registers

its instrumentsclass inscount : public OASIS::Pin::Tool <inscount>{public: inscount (void) { this->enable_fini_callback (); }

void handle_fini (INT32 code) { std::ofstream fout ("inscount.out"); fout.setf (ios::showbase); fout << "Count " << this->instruction_.count () << std::endl;

fout.close (); }

private: Instruction instruction_;};

Instantiating instrument automatically registers its with Pin

Tool ObjectThe tool object bootstraps the Pintool & registers

its instrumentsclass inscount : public OASIS::Pin::Tool <inscount>{public: inscount (void) { this->enable_fini_callback (); }

void handle_fini (INT32 code) { std::ofstream fout ("inscount.out"); fout.setf (ios::showbase); fout << "Count " << this->instruction_.count () << std::endl;

fout.close (); }

private: Instruction instruction_;};

Now, the entire Pintool is “self-contained” and can be reused in-part or in-whole

Required main function We use macros to create the define the main

function, and create the Tool objectDECLARE_PINTOOLDELCARE_PINTOOL_PROBED

// Declare the inscount PintoolDECLARE_PINTOOL (inscount)

Building Your PintoolMPC is also used to build the Pintool

You must use one of the following base projects:oasis_pintool — regular Pintooloasis_static_pintool — static Pintool

// pintool.mwcworkspace { cmdline += -include $PINPP_ROOT/MPC/config}

// inscount0.mpcproject (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./

Source_Files { inscount0.cpp }}

Building Your PintoolMPC is also used to build the Pintool

You must use one of the following base projects:oasis_pintool — regular Pintooloasis_static_pintool — static Pintool

// pintool.mwcworkspace { cmdline += -include $PINPP_ROOT/MPC/config}

The MPC workspace tells MPC where to locate Pin++ base

projects

// inscount0.mpcproject (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./

Source_Files { inscount0.cpp }}

Building Your PintoolMPC is also used to build the Pintool

You must use one of the following base projects:oasis_pintool — regular Pintooloasis_static_pintool — static Pintool

// pintool.mwcworkspace { cmdline += -include $PINPP_ROOT/MPC/config}

The MPC project contains the settings for building the Pintool

// inscount0.mpcproject (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./

Source_Files { inscount0.cpp }}

Building Your PintoolMPC is also used to build the Pintool

You must use one of the following base projects:oasis_pintool — regular Pintooloasis_static_pintool — static Pintool

// pintool.mwcworkspace { cmdline += -include $PINPP_ROOT/MPC/config}

The base project for the project configuration

// inscount0.mpcproject (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./

Source_Files { inscount0.cpp }}

Building Your PintoolMPC is also used to build the Pintool

You must use one of the following base projects:oasis_pintool — regular Pintooloasis_static_pintool — static Pintool

// inscount0.mpcproject (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./

Source_Files { inscount0.cpp }}

// pintool.mwcworkspace { cmdline += -include $PINPP_ROOT/MPC/config}

sharedname means we are building a shared library; expected

by Pin

Building Your Pintool%> mwc.pl -type [type] inscount.mwc

%> build workspace/open solution

Running Your PintoolLinux

%> pin –t inscount.so -- ls

MacOS X

%> pin –t inscount.dylib -- ls

Windows

%> pin –t inscount.dll -- dir .

MPC manages the extensions of the shared library on each platform

Using Data In Our Callbackshttps://github.com/SEDS/PinPP/wiki/Using-data-in-callbacks

Analysis Function w/ Data

/ The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every blockVOID docount(UINT32 c) { icount += c; }

// Pin calls this function every time a new basic block is encountered// It inserts a call to docountVOID Trace (TRACE trace, VOID *v) { // Visit every basic block in the trace for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { // Insert a call to docount before every bbl, passing number of instructions BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END); }}

Analysis tools can accept data

Analysis tools can accept data/ The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every blockVOID docount(UINT32 c) { icount += c; }

// Pin calls this function every time a new basic block is encountered// It inserts a call to docountVOID Trace (TRACE trace, VOID *v) { // Visit every basic block in the trace for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { // Insert a call to docount before every bbl, passing number of instructions BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END); }}

Analysis Function w/ Data

The analysis function is expecting a 32-bit integer

Analysis tools can accept data/ The running count of instructions is kept here// make it static to help the compiler optimize docountstatic UINT64 icount = 0;

// This function is called before every blockVOID docount(UINT32 c) { icount += c; }

// Pin calls this function every time a new basic block is encountered// It inserts a call to docountVOID Trace (TRACE trace, VOID *v) { // Visit every basic block in the trace for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { // Insert a call to docount before every bbl, passing number of instructions BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END); }}

Analysis Function w/ Data

Insert call specifies callback wants an integer

data

The Pintool is registering a constant with Pine.g., IARG_UINT32, IARG_PTR, IARG_BOOL,

IARG_ADDRINT

Pin must manage this state, and pass to analysis function

Somewhat limits the kind of data that can be registered with analysis function IARG_PTR is void *, but not type safe!

// Insert a call to docount before every bbl, passing number of instructionsBBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END);

Potential Problems

Callbacks w/ DataWe use configuration methods to configure data

in callbacksclass docount : public OASIS::Pin::Callback <docount (void)>{public: docount (void) : count_ (0), ins_count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

void ins_count (UINT64 count) { this->ins_count_ = count; }

UINT64 count (void) const { return this->ins_count_ * this->count_; }

private: UINT64 count_; UINT64 ins_count_;};

Callbacks w/ DataWe use configuration methods to configure data

in callbacksclass docount : public OASIS::Pin::Callback <docount (void)>{public: docount (void) : count_ (0), ins_count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

void ins_count (UINT64 count) { this->ins_count_ = count; }

UINT64 count (void) const { return this->ins_count_ * this->count_; }

private: UINT64 count_; UINT64 ins_count_;};

Data associated with callback is stored in callback, not in Pin

Callbacks w/ DataWe use configuration methods to configure data

in callbacksclass docount : public OASIS::Pin::Callback <docount (void)>{public: docount (void) : count_ (0), ins_count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

void ins_count (UINT64 count) { this->ins_count_ = count; }

UINT64 count (void) const { return this->ins_count_ * this->count_; }

private: UINT64 count_; UINT64 ins_count_;};

We continue incrementing count as

usual

Callbacks w/ DataWe use configuration methods to configure data

in callbacksclass docount : public OASIS::Pin::Callback <docount (void)>{public: docount (void) : count_ (0), ins_count_ (0) { }

void handle_analyze (void) { ++ this->count_; }

void ins_count (UINT64 count) { this->ins_count_ = count; }

UINT64 count (void) const { return this->ins_count_ * this->count_; }

private: UINT64 count_; UINT64 ins_count_;};

We calculate total count when requested

Instruments w/ DataWe must dynamically allocate a new callback for

each new insertionclass Trace : public OASIS::Pin::Trace_Instrument <Trace> {public: void handle_instrument (const OASIS::Pin::Trace & trace){ OASIS::Pin::Buffer <docount> item (trace.num_bbl ()); item_type::iterator callback = item.begin ();

for (const OASIS::Pin::Bbl & bbl : trace) { callback->ins_count (bbl.ins_count ()); callback->insert (IPOINT_BEFORE, bbl);

++ callback; }

this->traces_.push_back (item); }

// ...private: std::list <OASIS::Pin::Buffer <docount>> traces_;};

Allocate a buffer of docount callback objects

Instruments w/ DataWe must dynamically allocate a new callback for

each new insertionclass Trace : public OASIS::Pin::Trace_Instrument <Trace> {public: void handle_instrument (const OASIS::Pin::Trace & trace){ OASIS::Pin::Buffer <docount> item (trace.num_bbl ()); item_type::iterator callback = item.begin ();

for (const OASIS::Pin::Bbl & bbl : trace) { callback->ins_count (bbl.ins_count ()); callback->insert (IPOINT_BEFORE, bbl);

++ callback; }

this->traces_.push_back (item); }

// ...private: std::list <OASIS::Pin::Buffer <docount>> traces_;};

Iterate over each BBL in the Trace, and configure the callback object

Instruments w/ DataWe must dynamically allocate a new callback for

each new insertionclass Trace : public OASIS::Pin::Trace_Instrument <Trace> {public: void handle_instrument (const OASIS::Pin::Trace & trace){ OASIS::Pin::Buffer <docount> item (trace.num_bbl ()); item_type::iterator callback = item.begin ();

for (const OASIS::Pin::Bbl & bbl : trace) { callback->ins_count (bbl.ins_count ()); callback->insert (IPOINT_BEFORE, bbl);

++ callback; }

this->traces_.push_back (item); }

// ...private: std::list <OASIS::Pin::Buffer <docount>> traces_;};

Insert the callback object before the BBL

Instruments w/ DataWe must dynamically allocate a new callback for

each new insertionclass Trace : public OASIS::Pin::Trace_Instrument <Trace> {public: void handle_instrument (const OASIS::Pin::Trace & trace){ OASIS::Pin::Buffer <docount> item (trace.num_bbl ()); item_type::iterator callback = item.begin ();

for (const OASIS::Pin::Bbl & bbl : trace) { callback->ins_count (bbl.ins_count ()); callback->insert (IPOINT_BEFORE, bbl);

++ callback; }

this->traces_.push_back (item); }

// ...private: std::list <OASIS::Pin::Buffer <docount>> traces_;};

Save the callbacks for recall later

class Trace : public OASIS::Pin::Trace_Instrument <Trace> {public: // ... UINT64 count (void) const { UINT64 count = 0;

for (auto trace : this->traces_) for (auto item : trace) count += item.count ();

return count; }

private: std::list <OASIS::Pin::Buffer <docount>> traces_;};

Instruments w/ DataWe must dynamically allocate a new callback for

each new insertion

class Trace : public OASIS::Pin::Trace_Instrument <Trace> {public: // ... UINT64 count (void) const { UINT64 count = 0;

for (auto trace : this->traces_) for (auto item : trace) count += item.count ();

return count; }

private: std::list <OASIS::Pin::Buffer <docount>> traces_;};

Instruments w/ DataWe must dynamically allocate a new callback for

each new insertion

Iterate over callbacks to get current count

Design Question?Does Pin really need the data arguments (e.g.,

IARG_UINT32, IARG_PTR, IARG_BOOL, and IARG_ADDRINT) if we are able to store the data in a callback object?

The allocations performed in the instrument are similar to the “potential” allocations used to manage the data in Pin

This approach would not require Pin to worry about application-level details.

But, it does require an extra allocation…

Requesting Contextual Information in Callbacks

https://github.com/SEDS/PinPP/wiki/Requesting-contextual-data-in-callbacks

Contextual DataContext data is anything about the program

under instrumentation, or the machine running the program, needed by the analysis function to perform its analysisThread idProcess idRegister valuesArguments to a functionReturn valueEtc.

Traditional Approach to Get Context Data

Contextual data is requested similar to how you associate data with an analysis function in Pin i.e., the IARG_* parameters for insertion

// This code is from itrace.cpp in the Pin manual examples.

// This function is called before every instruction is executed// and prints the IPVOID printip (VOID *ip) { fprintf(trace, "%p\n", ip); }

// Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to printip before every instruction, and pass it the IP INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);}

Traditional Approach to Get Context Data

Contextual data is requested similar to how you associate data with an analysis function in Pin i.e., the IARG_* parameters for insertion

// This code is from itrace.cpp in the Pin manual examples.

// This function is called before every instruction is executed// and prints the IPVOID printip (VOID *ip) { fprintf(trace, "%p\n", ip); }

// Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to printip before every instruction, and pass it the IP INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);}

We need the instruction pointer (IP)

Traditional Approach to Get Context Data

Contextual data is requested similar to how you associate data with an analysis function in Pin i.e., the IARG_* parameters for insertion

// This code is from itrace.cpp in the Pin manual examples.

// This function is called before every instruction is executed// and prints the IPVOID printip (VOID *ip) { fprintf(trace, "%p\n", ip); }

// Pin calls this function every time a new instruction is encounteredVOID Instruction(INS ins, VOID *v) { // Insert a call to printip before every instruction, and pass it the IP INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);}

So, we request it…

Potential ProblemsThe analysis function must have the correct

number of parameters, and have the correct type

Some contextual data require extra arguments, and making sure the extra argument is included at insertion is not guaranteed

Requesting different context data type requires the developer to make the necessary changes to the analysis function parameters

Context Data in Pin++Context data in Pin++ is as simple as adding

parameters to the function pointer that parameterizes the Callback object

class printip : public OASIS::Pin::Callback < printip (OASIS::Pin::ARG_INST_PTR) >{public: printip (FILE * file) : file_ (file) { }

void handle_analyze (param_type1 addr) { ::fprintf (this->file_, "0x%p\n", addr); }

private: FILE * file_;};

Context Data in Pin++Context data in Pin++ is as simple as adding

parameters to the function pointer that parameterizes the Callback object

class printip : public OASIS::Pin::Callback < printip (OASIS::Pin::ARG_INST_PTR) >{public: printip (FILE * file) : file_ (file) { }

void handle_analyze (param_type1 addr) { ::fprintf (this->file_, "0x%p\n", addr); }

private: FILE * file_;};

This argument means the callback is expecting instruction pointer

Context Data in Pin++Context data in Pin++ is as simple as adding

parameters to the function pointer that parameterizes the Callback object

class printip : public OASIS::Pin::Callback < printip (OASIS::Pin::ARG_INST_PTR) >{public: printip (FILE * file) : file_ (file) { }

void handle_analyze (param_type1 addr) { ::fprintf (this->file_, "0x%p\n", addr); }

private: FILE * file_;};

Callbacks have typedefs that manage the correct type for each parameter

Context Types in Pin++Pin++ has its own argument type system that

maps to the corresponding Pin IARG_* types

Allows Pin++ to control what arguments it supports as context datae.g., non-data arguments

Context Data w/ ParamsSome context data requires an extra parameter

at insertion time

// with PinRTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before, IARG_ADDRINT, MALLOC, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END);

// with Pin++this->arg1_before_.insert (IPOINT_BEFORE, rtn, 0);

Context Data w/ ParamsSome context data requires an extra parameter

at insertion time

// with PinRTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before, IARG_ADDRINT, MALLOC, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END);

// with Pin++this->arg1_before_.insert (IPOINT_BEFORE, rtn, 0);

The extra parameters go after the target object

Context Data w/ ParamsSome context data requires an extra parameter

at insertion time

// with PinRTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before, IARG_ADDRINT, MALLOC, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END);

// with Pin++this->arg1_before_.insert (IPOINT_BEFORE, rtn, 0);

If any extra parameter is missing, there will be compilation errors

Other Features of Pin++

Range-based For LoopsRange-based for-loops are easy way to iterate

over a list of valuesNow available in C++11

Supported with Image, Section, Routine, Bbl, and Symbol in Pin++

void handle_instrument (const OASIS::Pin::Image & img){ int count = 0;

for (OASIS::Pin::Section & section : img) { for (OASIS::Pin::Routine & rtn : section) { OASIS::Pin::Routine_Guard guard (rtn); for (OASIS::Pin::Ins & ins : rtn) ++ count; } }

std::cerr << "Image " << img.name () << " has " << count << " instructions" << std::endl;}

To Analyze… Not to Analyze?

Pin supports conditional analysis*_InsertIfCall*_InsertThenCall

Developer must call both functions (in order) to enable conditional analysis

// CountDown() is called for every instruction executedINS_InsertIfCall(ins, IPOINT_BEFORE, (AFUNPTR)CountDown, IARG_END); // PrintIp() is called only when the last CountDown() returns a non-zero value.INS_InsertThenCall(ins, IPOINT_BEFORE, (AFUNPTR)PrintIp, IARG_INST_PTR, IARG_END);

Conditional Analysis in Pin++

Conditional callback has method that determines if Pin is to analysis target

class countdown : public OASIS::Pin::Conditional_Callback < countdown (void) >{public: countdown (void) : counter_ (1) { }

void reset_counter (INT32 counter) { this->counter_ = counter; }

bool do_next (void) { return (-- this->counter_ == 0); }

private: INT32 counter_;};

Conditional Analysis in Pin++

Conditional callback has method that determines if Pin is to analysis target

class countdown : public OASIS::Pin::Conditional_Callback < countdown (void) >{public: countdown (void) : counter_ (1) { }

void reset_counter (INT32 counter) { this->counter_ = counter; }

bool do_next (void) { return (-- this->counter_ == 0); }

private: INT32 counter_;}; All conditional callbacks must

implement the do_next method

Conditional Analysis in Pin++

Conditional callback has method that determines if Pin is to analysis target

class Instrument : public OASIS::Pin::Instruction_Instrument <Instrument>{public: Instrument (FILE * file) : printip_ (file, countdown_) { }

void handle_instrument (const OASIS::Pin::Ins & ins) { this->printip_[this->countdown_].insert (IPOINT_BEFORE, ins); }

private: /// The countdown guard protecting \a printip_. countdown countdown_;

/// The analysis callback object printip printip_;};

Conditional Analysis in Pin++

Conditional callback has method that determines if Pin is to analysis target

class Instrument : public OASIS::Pin::Instruction_Instrument <Instrument>{public: Instrument (FILE * file) : printip_ (file, countdown_) { }

void handle_instrument (const OASIS::Pin::Ins & ins) { this->printip_[this->countdown_].insert (IPOINT_BEFORE, ins); }

private: /// The countdown guard protecting \a printip_. countdown countdown_;

/// The analysis callback object printip printip_;};

Conditional is placed in brackets after the standard callback

object

Conditional Analysis in Pin++

Conditional callback has method that determines if Pin is to analysis target

class Instrument : public OASIS::Pin::Instruction_Instrument <Instrument>{public: Instrument (FILE * file) : printip_ (file, countdown_) { }

void handle_instrument (const OASIS::Pin::Ins & ins) { this->printip_[this->countdown_].insert (IPOINT_BEFORE, ins); }

private: /// The countdown guard protecting printip_. countdown countdown_;

/// The analysis callback object printip printip_;};

This approach allows us to quickly enable/disable conditional analysis

Replacement RoutinesReplacement routines allow the developer to replace

existing functions in the image with functions from the Pintool and intercept calls to the original function

Traditional approach tool too complicated to show on slides See replacesigprobed.cpp in ManualExamples

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

Replacement routine is an object parameterized by subclass, and signature of method to replace

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

All replacement routines objects must implement an execute

method; entry point for replaced routine

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

Type definitions ensure type safety based on function pointer in

parameter

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

It is possible to get the address of the original

function

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

It is possible to call the original function that the routine replaced

Replacement Routines in Pin++

class new_malloc : public OASIS::Pin::Replacement_Routine <new_malloc, void * (int)>{public: static return_type execute (param1_type n) { std::cout << "NewMalloc (" << std::hex << ADDRINT (new_malloc::original_funcptr ()) << ", " << std::dec << n << ")" << std::endl << flush;

return new_malloc::call_original (n); }};

class Instrument : public OASIS::Pin::Image_Instrument <Instrument>{public: void handle_instrument (const OASIS::Pin::Image & img) { OASIS::Pin::Routine rtn = img.find_routine ("malloc");

if (rtn.valid ()) rtn.replace_signature_probed <new_malloc> (CALLINGSTD_DEFAULT); }};

The routine is replaced just by calling the replace_* method on the routine

with the replacement routine as a parameter

Locks and GuardsPin has many different locking primitives

LOCK, MUTEX, RW_MUTEX, SEMAPHORE

In Pin++, we created wrapper classes for each locking primitive

We also implement Guard class to automatically release locking primitives when scope is leftAlso have guard for Routine since it must be

opened and closed for usage

Locks and GuardsPin has many different locking primitives

LOCK, MUTEX, RW_MUTEX, SEMAPHORE

In Pin++, we created wrapper classes for each locking primitive

We also implement Guard class to automatically release locking primitives when scope is leftAlso have guard for Routine since it must be

opened and closed for usage

do { OASIS::Pin::Guard <OASIS::Pin::Lock> guard (this->lock_); ++ this->num_threads_;} while (false);

Locks and GuardsPin has many different locking primitives

LOCK, MUTEX, RW_MUTEX, SEMAPHORE

In Pin++, we created wrapper classes for each locking primitive

We also implement Guard class to automatically release locking primitives when scope is leftAlso have guard for Routine since it must be

opened and closed for usage

do { OASIS::Pin::Guard <OASIS::Pin::Lock> guard (this->lock_); ++ this->num_threads_;} while (false);

Acquire lock, and release when scope is

left

Thread-local StoragePin supports Thread-local Storage (TLS) via C

functionsPIN_CreateThreadDataKeyPIN_DeleteThreadDataKeyPIN_SetThreadData PIN_GetThreadData

Pin++ uses a type-safe TLS class to improve the robustness of TLS in Pin

Thread-local Storage, Pin++

Supports registering factory (coming soon) & destruction functionFactory function called if TLS data does not existDestruction function called if TLS data exists when

thread terminates

struct thread_data_t { static void __release (void * data) { delete (thread_data_t *)data; } thread_data_t (UINT64 init_count): count_ (init_count) { } thread_data_t (void): count_ (0) { } UINT64 count_; UINT8 pad_[PADSIZE];};

// UsageTLS <thread_data_t> tls (&thread_data_t::__release);tls.get_with_create ([] (void) { return new thread_data_t (); });tls.get (thr_id)->count_ ++;

Thread-local Storage, Pin++

Supports registering factory (coming soon) & destruction functionFactory function called if TLS data does not existDestruction function called if TLS data exists when

thread terminates

struct thread_data_t { static void __release (void * data) { delete (thread_data_t *)data; } thread_data_t (UINT64 init_count): count_ (init_count) { } thread_data_t (void): count_ (0) { } UINT64 count_; UINT8 pad_[PADSIZE];};

// UsageTLS <thread_data_t> tls (&thread_data_t::__release);tls.get_with_create ([] (void) { return new thread_data_t (); });tls.get (thr_id)->count_ ++;

Destruction function for TLS object type

Thread-local Storage, Pin++

Supports registering factory (coming soon) & destruction functionFactory function called if TLS data does not existDestruction function called if TLS data exists when

thread terminates

struct thread_data_t { static void __release (void * data) { delete (thread_data_t *)data; } thread_data_t (UINT64 init_count): count_ (init_count) { } thread_data_t (void): count_ (0) { } UINT64 count_; UINT8 pad_[PADSIZE];};

// UsageTLS <thread_data_t> tls (&thread_data_t::__release);tls.get_with_create ([] (void) { return new thread_data_t (); });tls.get (thr_id)->count_ ++;

Creating TLS object & registering lifecycle

functions

Thread-local Storage, Pin++

Supports registering factory (coming soon) & destruction functionFactory function called if TLS data does not existDestruction function called if TLS data exists when

thread terminates

struct thread_data_t { static void __release (void * data) { delete (thread_data_t *)data; } thread_data_t (UINT64 init_count): count_ (init_count) { } thread_data_t (void): count_ (0) { } UINT64 count_; UINT8 pad_[PADSIZE];};

// UsageTLS <thread_data_t> tls (&thread_data_t::__release);tls.get_with_create ([] (void) { return new thread_data_t (); });tls.get (thr_id)->count_ ++;

Creating TLS object & registering lifecycle

functions

Thread-local Storage, Pin++

Supports registering factory (coming soon) & destruction functionFactory function called if TLS data does not existDestruction function called if TLS data exists when

thread terminates

struct thread_data_t { static void __release (void * data) { delete (thread_data_t *)data; } thread_data_t (UINT64 init_count): count_ (init_count) { } thread_data_t (void): count_ (0) { } UINT64 count_; UINT8 pad_[PADSIZE];};

// UsageTLS <thread_data_t> tls (&thread_data_t::__release);tls.get_with_create ([] (void) { return new thread_data_t (); });tls.get (thr_id)->count_ ++;

Accessing data, creating if no data exists at time of

access

Thread-local Storage, Pin++

Supports registering factory (coming soon) & destruction functionFactory function called if TLS data does not existDestruction function called if TLS data exists when

thread terminates

struct thread_data_t { static void __release (void * data) { delete (thread_data_t *)data; } thread_data_t (UINT64 init_count): count_ (init_count) { } thread_data_t (void): count_ (0) { } UINT64 count_; UINT8 pad_[PADSIZE];};

// UsageTLS <thread_data_t> tls (&thread_data_t::__release);tls.get_with_create ([] (void) { return new thread_data_t (); });tls.get (thr_id)->count_ ++;

Accessing data, assumes it already exists

Multi-threaded PintoolsPin supports threads in a Pintool

PIN_SpawnInternalThreadPIN_WaitForThreadTerminationPIN_ExitThread (called only by spawned thread)…

Uses a C approach for spawning threads

Threads in Pin++

Pin++ uses Java-like Thread object to spawn threads

class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

Can subclass Thread, must implement run

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

Can instantiate with object that realizes

Runnable

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

Can get the current thread as an object, will a subclass if applicable

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

Can get OS information about the Thread

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

Global methods are now static methods on Thread

class

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

Lifecycle methods for the Thread

Threads in Pin++class Thread : public Runnable Thread (void); virtual void run (void); Thread (Runnable * runnable); static Thread * current (void);

THREADID id (void); PIN_THREAD_UID uid (void); OS_THREAD_ID os_id (void); OS_THREAD_ID parent_id (void);

static void sleep (UINT32 millis); static void yield (void); static bool is_application_thread (void);

State start (size_t stack_size = DEFAULT_THREAD_STACK_SIZE); bool wait (UINT32 millis = PIN_INFINITE_TIMEOUT, INT32 * exit_code = 0); State state (void) const; protected: void terminate (INT32 exit_code = 0); //...};

Pin++ uses Java-like Thread object to spawn threads

The terminate method contained to the Thread

subclass

Concluding RemarksPin++ increases the level of abstraction for

authoring Pintools

The 100% object-oriented philosophy allows us to create reusable Callback, Instruction, & Tool components that can be easily composed

Pin++ wants to build a library of reusable components that solve problems

We welcome contributions to Pin++

Questions