SlideShare a Scribd company logo
1 of 129
Using Pin++ To Author
Highly Configurable
Pintools for Pin
Dr. James H. Hill
Dept. Computer & Information Science
Indiana University-Purdue University Indianapolis
hillj@cs.iupui.edu
http://www.cs.iupui.edu/~hillj
http://github.com/SEDS/PinPP
Preface
This 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.
Pin
 Pin is a dynamic binary instrumentation tool
 http://www.pintool.org
 Supported Platforms
 Linux
 Windows
 MacOS X
 Android
 Etc…
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 docount
static UINT64 icount = 0;
// This function is called before every instruction is executed
VOID docount(void) { icount++; }
// Pin calls this function every time a new instruction is encountered
VOID 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 docount
static UINT64 icount = 0;
// This function is called before every instruction is executed
VOID docount(void) { icount++; }
// Pin calls this function every time a new instruction is encountered
VOID 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 docount
static UINT64 icount = 0;
// This function is called before every instruction is executed
VOID docount(void) { icount++; }
// Pin calls this function every time a new instruction is encountered
VOID 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 docount
static UINT64 icount = 0;
// This function is called before every instruction is executed
VOID docount(void) { icount++; }
// Pin calls this function every time a new instruction is encountered
VOID 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 exits
VOID 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 exits
VOID 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 Challenges
1. 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 Design
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;
}
Based on this code:
• What is the design of a
Pintool?
• What entities are
involved in the Pintool,
and their relations?
Hidden Complexities
VOID 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 Reinvention
static 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…
0
5
10
15
20
detach
emudiv
follow_child_tool
fork_jit_tool
imageload
inscount_tls
inscount0
inscount1
inscount2
invocation
isampling
itrace
malloc_mt
malloctrace
nonstatica
pinatrace
proccount
replacesigprobed
statica
staticcount
strace
Complexity
Name of the Pintool
Cyclomatic Complexity of Pintools from Pin's User Manual
Traditional
Pin++
Pin++ w/ Reuse
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…
0
5
10
15
20
detach
emudiv
follow_child_tool
fork_jit_tool
imageload
inscount_tls
inscount0
inscount1
inscount2
invocation
isampling
itrace
malloc_mt
malloctrace
nonstatica
pinatrace
proccount
replacesigprobed
statica
staticcount
strace
Modularity
Name of the Pintool
Modularity of Pintools from Pin's User Manual
Traditional
Pin++
Pin++ w/ Reuse
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 Requirements
 Perl, 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 platforms
 MPC allows us to write generic project files that are used
to generate build scripts for the target platform
 E.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
Tool$
<Class>$
//$no, fica, on$methods$
Instrument$
<Class>$
//$instrumenta, on$methods$
Callback$
<Class>$
//$analysis$methods$
Pintool$
<SharedLibrary>$
1$
*$
*$
*$
*$
1$
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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The 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 Object
 The tool object bootstraps the Pintool & registers its
instruments
class 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 Object
 The tool object bootstraps the Pintool & registers its
instruments
class 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 Object
 The tool object bootstraps the Pintool & registers its
instruments
class 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 Object
 The tool object bootstraps the Pintool & registers its
instruments
class 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 Object
 The tool object bootstraps the Pintool & registers its
instruments
class 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 Object
 The tool object bootstraps the Pintool & registers its
instruments
class 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 object
 DECLARE_PINTOOL
 DELCARE_PINTOOL_PROBED
// Declare the inscount Pintool
DECLARE_PINTOOL (inscount)
Building Your Pintool
 MPC is also used to build the Pintool
 You must use one of the following base projects:
 oasis_pintool — regular Pintool
 oasis_static_pintool — static Pintool
// pintool.mwc
workspace {
cmdline += -include $PINPP_ROOT/MPC/config
}
// inscount0.mpc
project (inscount0) : oasis_pintool {
sharedname = inscount0
dllout = ./
Source_Files {
inscount0.cpp
}
}
Building Your Pintool
 MPC is also used to build the Pintool
 You must use one of the following base projects:
 oasis_pintool — regular Pintool
 oasis_static_pintool — static Pintool
// pintool.mwc
workspace {
cmdline += -include $PINPP_ROOT/MPC/config
}
The MPC workspace tells MPC where
to locate Pin++ base projects
// inscount0.mpc
project (inscount0) : oasis_pintool {
sharedname = inscount0
dllout = ./
Source_Files {
inscount0.cpp
}
}
Building Your Pintool
 MPC is also used to build the Pintool
 You must use one of the following base projects:
 oasis_pintool — regular Pintool
 oasis_static_pintool — static Pintool
// pintool.mwc
workspace {
cmdline += -include $PINPP_ROOT/MPC/config
}
The MPC project contains the settings
for building the Pintool
// inscount0.mpc
project (inscount0) : oasis_pintool {
sharedname = inscount0
dllout = ./
Source_Files {
inscount0.cpp
}
}
Building Your Pintool
 MPC is also used to build the Pintool
 You must use one of the following base projects:
 oasis_pintool — regular Pintool
 oasis_static_pintool — static Pintool
// pintool.mwc
workspace {
cmdline += -include $PINPP_ROOT/MPC/config
}
The base project for the
project configuration
// inscount0.mpc
project (inscount0) : oasis_pintool {
sharedname = inscount0
dllout = ./
Source_Files {
inscount0.cpp
}
}
Building Your Pintool
 MPC is also used to build the Pintool
 You must use one of the following base projects:
 oasis_pintool — regular Pintool
 oasis_static_pintool — static Pintool
// inscount0.mpc
project (inscount0) : oasis_pintool {
sharedname = inscount0
dllout = ./
Source_Files {
inscount0.cpp
}
}
// pintool.mwc
workspace {
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 Pintool
Linux
 %> 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 Callbacks
https://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 docount
static UINT64 icount = 0;
// This function is called before every block
VOID docount(UINT32 c) { icount += c; }
// Pin calls this function every time a new basic block is encountered
// It inserts a call to docount
VOID 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 docount
static UINT64 icount = 0;
// This function is called before every block
VOID docount(UINT32 c) { icount += c; }
// Pin calls this function every time a new basic block is encountered
// It inserts a call to docount
VOID 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 docount
static UINT64 icount = 0;
// This function is called before every block
VOID docount(UINT32 c) { icount += c; }
// Pin calls this function every time a new basic block is encountered
// It inserts a call to docount
VOID 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 Pin
 e.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 instructions
BBL_InsertCall(bbl,
IPOINT_BEFORE,
(AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl),
IARG_END);
Potential Problems
Callbacks w/ Data
 We use configuration methods to configure data in
callbacks
class 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/ Data
 We use configuration methods to configure data in
callbacks
class 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/ Data
 We use configuration methods to configure data in
callbacks
class 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/ Data
 We use configuration methods to configure data in
callbacks
class 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/ Data
 We must dynamically allocate a new callback for each
new insertion
class 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/ Data
 We must dynamically allocate a new callback for each
new insertion
class 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/ Data
 We must dynamically allocate a new callback for each
new insertion
class 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/ Data
 We must dynamically allocate a new callback for each
new insertion
class 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/ Data
 We 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/ Data
 We 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 Data
 Context data is anything about the program under
instrumentation, or the machine running the program,
needed by the analysis function to perform its analysis
 Thread id
 Process id
 Register values
 Arguments to a function
 Return value
 Etc.
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 IP
VOID printip (VOID *ip) { fprintf(trace, "%pn", ip); }
// Pin calls this function every time a new instruction is encountered
VOID 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 IP
VOID printip (VOID *ip) { fprintf(trace, "%pn", ip); }
// Pin calls this function every time a new instruction is encountered
VOID 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 IP
VOID printip (VOID *ip) { fprintf(trace, "%pn", ip); }
// Pin calls this function every time a new instruction is encountered
VOID 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 Problems
 The 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%pn", 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%pn", 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%pn", 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 data
 e.g., non-data arguments
Context Data w/ Params
 Some context data requires an extra parameter at
insertion time
// with Pin
RTN_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/ Params
 Some context data requires an extra parameter at
insertion time
// with Pin
RTN_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/ Params
 Some context data requires an extra parameter at
insertion time
// with Pin
RTN_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 Loops
 Range-based for-loops are easy way to iterate over a
list of values
 Now 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 executed
INS_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 Routines
 Replacement 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 Guards
 Pin 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 left
 Also have guard for Routine since it must be opened and
closed for usage
Locks and Guards
 Pin 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 left
 Also 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 Guards
 Pin 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 left
 Also 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 Storage
 Pin supports Thread-local Storage (TLS) via C
functions
 PIN_CreateThreadDataKey
 PIN_DeleteThreadDataKey
 PIN_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 function
 Factory function called if TLS data does not exist
 Destruction 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];
};
// Usage
TLS <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 function
 Factory function called if TLS data does not exist
 Destruction 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];
};
// Usage
TLS <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 function
 Factory function called if TLS data does not exist
 Destruction 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];
};
// Usage
TLS <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 function
 Factory function called if TLS data does not exist
 Destruction 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];
};
// Usage
TLS <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 function
 Factory function called if TLS data does not exist
 Destruction 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];
};
// Usage
TLS <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 function
 Factory function called if TLS data does not exist
 Destruction 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];
};
// Usage
TLS <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 Pintools
 Pin supports threads in a Pintool
 PIN_SpawnInternalThread
 PIN_WaitForThreadTermination
 PIN_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 Remarks
 Pin++ 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

More Related Content

Similar to Using Pin++ to Author Highly Configurable Pintools for Pin

Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015Windows Developer
 
OOPS using C++
OOPS using C++OOPS using C++
OOPS using C++cpjcollege
 
Introduction to Raspberry Pi and GPIO
Introduction to Raspberry Pi and GPIOIntroduction to Raspberry Pi and GPIO
Introduction to Raspberry Pi and GPIOKris Findlay
 
Practical basics on c++
Practical basics on c++Practical basics on c++
Practical basics on c++Marco Izzotti
 
Implementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphoresImplementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphoresGowtham Reddy
 
Notes about moving from python to c++ py contw 2020
Notes about moving from python to c++ py contw 2020Notes about moving from python to c++ py contw 2020
Notes about moving from python to c++ py contw 2020Yung-Yu Chen
 
HES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talk
HES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talkHES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talk
HES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talkHackito Ergo Sum
 
CorePy High-Productivity CellB.E. Programming
CorePy High-Productivity CellB.E. ProgrammingCorePy High-Productivity CellB.E. Programming
CorePy High-Productivity CellB.E. ProgrammingSlide_N
 
Arduino for Beginners
Arduino for BeginnersArduino for Beginners
Arduino for BeginnersSarwan Singh
 
Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -LynellBull52
 
Lab report 201001067_201001104
Lab report 201001067_201001104Lab report 201001067_201001104
Lab report 201001067_201001104swena_gupta
 
Lab report 201001067_201001104
Lab report 201001067_201001104Lab report 201001067_201001104
Lab report 201001067_201001104swena_gupta
 
Lab report 201001067_201001104
Lab report 201001067_201001104Lab report 201001067_201001104
Lab report 201001067_201001104swena_gupta
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive? Tomasz Kowalczewski
 

Similar to Using Pin++ to Author Highly Configurable Pintools for Pin (20)

Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
 
OOPS using C++
OOPS using C++OOPS using C++
OOPS using C++
 
Introduction to Raspberry Pi and GPIO
Introduction to Raspberry Pi and GPIOIntroduction to Raspberry Pi and GPIO
Introduction to Raspberry Pi and GPIO
 
Practical basics on c++
Practical basics on c++Practical basics on c++
Practical basics on c++
 
Canteen management
Canteen managementCanteen management
Canteen management
 
Function
FunctionFunction
Function
 
Implementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphoresImplementing of classical synchronization problem by using semaphores
Implementing of classical synchronization problem by using semaphores
 
Notes about moving from python to c++ py contw 2020
Notes about moving from python to c++ py contw 2020Notes about moving from python to c++ py contw 2020
Notes about moving from python to c++ py contw 2020
 
HES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talk
HES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talkHES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talk
HES 2011 - Gal Diskin - Binary instrumentation for hackers - Lightning-talk
 
Concurrent networking - made easy
Concurrent networking - made easyConcurrent networking - made easy
Concurrent networking - made easy
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
 
CorePy High-Productivity CellB.E. Programming
CorePy High-Productivity CellB.E. ProgrammingCorePy High-Productivity CellB.E. Programming
CorePy High-Productivity CellB.E. Programming
 
Arduino for Beginners
Arduino for BeginnersArduino for Beginners
Arduino for Beginners
 
Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -
 
Python on pi
Python on piPython on pi
Python on pi
 
Lecture2.ppt
Lecture2.pptLecture2.ppt
Lecture2.ppt
 
Lab report 201001067_201001104
Lab report 201001067_201001104Lab report 201001067_201001104
Lab report 201001067_201001104
 
Lab report 201001067_201001104
Lab report 201001067_201001104Lab report 201001067_201001104
Lab report 201001067_201001104
 
Lab report 201001067_201001104
Lab report 201001067_201001104Lab report 201001067_201001104
Lab report 201001067_201001104
 
Is writing performant code too expensive?
Is writing performant code too expensive? Is writing performant code too expensive?
Is writing performant code too expensive?
 

Recently uploaded

Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROmotivationalword821
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentationvaddepallysandeep122
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Developmentvyaparkranti
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 

Recently uploaded (20)

Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTRO
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentation
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Development
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 

Using Pin++ to Author Highly Configurable Pintools for Pin

  • 1. Using Pin++ To Author Highly Configurable Pintools for Pin Dr. James H. Hill Dept. Computer & Information Science Indiana University-Purdue University Indianapolis hillj@cs.iupui.edu http://www.cs.iupui.edu/~hillj http://github.com/SEDS/PinPP
  • 2. Preface This 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!
  • 3. 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++
  • 4. What is All This “Pin” About?! http://www.pintool.org
  • 5. 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.
  • 6. Pin  Pin is a dynamic binary instrumentation tool  http://www.pintool.org  Supported Platforms  Linux  Windows  MacOS X  Android  Etc…
  • 8. 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 docount static UINT64 icount = 0; // This function is called before every instruction is executed VOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encountered VOID 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
  • 9. 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 docount static UINT64 icount = 0; // This function is called before every instruction is executed VOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encountered VOID 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
  • 10. 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 docount static UINT64 icount = 0; // This function is called before every instruction is executed VOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encountered VOID 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
  • 11. 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 docount static UINT64 icount = 0; // This function is called before every instruction is executed VOID docount(void) { icount++; } // Pin calls this function every time a new instruction is encountered VOID 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
  • 12. Counting Instructions (2/3) // This function is called when the application exits VOID 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
  • 13. Counting Instructions (2/3) // This function is called when the application exits VOID 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
  • 14. 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
  • 15. 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
  • 16. Developer Challenges 1. 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
  • 17. Seeing the Design 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; } Based on this code: • What is the design of a Pintool? • What entities are involved in the Pintool, and their relations?
  • 18. Hidden Complexities VOID 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.
  • 19. 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.
  • 20. Continuous Reinvention static 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
  • 21. 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!
  • 23. 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
  • 24. Pin++ Framework Pin Pintool Pin Pin++ Pintool  Pin++ is a framework that sits between Pin, and the application logic of a Pintool
  • 25. And We Achieved… 0 5 10 15 20 detach emudiv follow_child_tool fork_jit_tool imageload inscount_tls inscount0 inscount1 inscount2 invocation isampling itrace malloc_mt malloctrace nonstatica pinatrace proccount replacesigprobed statica staticcount strace Complexity Name of the Pintool Cyclomatic Complexity of Pintools from Pin's User Manual Traditional Pin++ Pin++ w/ Reuse 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
  • 26. And… 0 5 10 15 20 detach emudiv follow_child_tool fork_jit_tool imageload inscount_tls inscount0 inscount1 inscount2 invocation isampling itrace malloc_mt malloctrace nonstatica pinatrace proccount replacesigprobed statica staticcount strace Modularity Name of the Pintool Modularity of Pintools from Pin's User Manual Traditional Pin++ Pin++ w/ Reuse 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
  • 27. 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
  • 28. 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
  • 29. Creating Our First Pintool using Pin++ https://github.com/SEDS/PinPP/wiki/Creating-a-Pintool-using-Pin
  • 30. System Requirements  Perl, 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++.
  • 31. 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
  • 32. 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
  • 33. Building Pin++  We use Makefile, Workspace, Project Creator (MPC) to assist with building Pin++ on different platforms  MPC allows us to write generic project files that are used to generate build scripts for the target platform  E.g., Makefiles, Visual Studio Workspaces, Eclipse, etc.  https://github.com/DOCGroup/MPC Build Command %> mwc.pl –type [type] pin++.mwc %> open/build generated workspace
  • 34. 100% Object-Oriented Tool$ <Class>$ //$no, fica, on$methods$ Instrument$ <Class>$ //$instrumenta, on$methods$ Callback$ <Class>$ //$analysis$methods$ Pintool$ <SharedLibrary>$ 1$ *$ *$ *$ *$ 1$ 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.
  • 35. Callback Object  The 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_; };
  • 36. Callback Object  The 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…
  • 37. Callback Object  The 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
  • 38. Callback Object  The 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
  • 39. Callback Object  The 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
  • 40. Callback Object  The 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.
  • 41. Callback Object  The 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”
  • 42. Callback Object  The 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
  • 43. Instrumentation Object  The 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
  • 44. Instrumentation Object  The 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.
  • 45. Instrumentation Object  The 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
  • 46. Instrumentation Object  The 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
  • 47. Instrumentation Object  The 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
  • 48. Instrumentation Object  The 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
  • 49. 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
  • 50. Tool Object  The tool object bootstraps the Pintool & registers its instruments class 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_; };
  • 51. Tool Object  The tool object bootstraps the Pintool & registers its instruments class 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
  • 52. Tool Object  The tool object bootstraps the Pintool & registers its instruments class 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
  • 53. Tool Object  The tool object bootstraps the Pintool & registers its instruments class 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
  • 54. Tool Object  The tool object bootstraps the Pintool & registers its instruments class 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
  • 55. Tool Object  The tool object bootstraps the Pintool & registers its instruments class 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
  • 56. Required main function  We use macros to create the define the main function, and create the Tool object  DECLARE_PINTOOL  DELCARE_PINTOOL_PROBED // Declare the inscount Pintool DECLARE_PINTOOL (inscount)
  • 57. Building Your Pintool  MPC is also used to build the Pintool  You must use one of the following base projects:  oasis_pintool — regular Pintool  oasis_static_pintool — static Pintool // pintool.mwc workspace { cmdline += -include $PINPP_ROOT/MPC/config } // inscount0.mpc project (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./ Source_Files { inscount0.cpp } }
  • 58. Building Your Pintool  MPC is also used to build the Pintool  You must use one of the following base projects:  oasis_pintool — regular Pintool  oasis_static_pintool — static Pintool // pintool.mwc workspace { cmdline += -include $PINPP_ROOT/MPC/config } The MPC workspace tells MPC where to locate Pin++ base projects // inscount0.mpc project (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./ Source_Files { inscount0.cpp } }
  • 59. Building Your Pintool  MPC is also used to build the Pintool  You must use one of the following base projects:  oasis_pintool — regular Pintool  oasis_static_pintool — static Pintool // pintool.mwc workspace { cmdline += -include $PINPP_ROOT/MPC/config } The MPC project contains the settings for building the Pintool // inscount0.mpc project (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./ Source_Files { inscount0.cpp } }
  • 60. Building Your Pintool  MPC is also used to build the Pintool  You must use one of the following base projects:  oasis_pintool — regular Pintool  oasis_static_pintool — static Pintool // pintool.mwc workspace { cmdline += -include $PINPP_ROOT/MPC/config } The base project for the project configuration // inscount0.mpc project (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./ Source_Files { inscount0.cpp } }
  • 61. Building Your Pintool  MPC is also used to build the Pintool  You must use one of the following base projects:  oasis_pintool — regular Pintool  oasis_static_pintool — static Pintool // inscount0.mpc project (inscount0) : oasis_pintool { sharedname = inscount0 dllout = ./ Source_Files { inscount0.cpp } } // pintool.mwc workspace { cmdline += -include $PINPP_ROOT/MPC/config } sharedname means we are building a shared library; expected by Pin
  • 62. Building Your Pintool  %> mwc.pl -type [type] inscount.mwc  %> build workspace/open solution
  • 63. Running Your Pintool Linux  %> 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
  • 64. Using Data In Our Callbacks https://github.com/SEDS/PinPP/wiki/Using-data-in-callbacks
  • 65. Analysis Function w/ Data / The running count of instructions is kept here // make it static to help the compiler optimize docount static UINT64 icount = 0; // This function is called before every block VOID docount(UINT32 c) { icount += c; } // Pin calls this function every time a new basic block is encountered // It inserts a call to docount VOID 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
  • 66.  Analysis tools can accept data / The running count of instructions is kept here // make it static to help the compiler optimize docount static UINT64 icount = 0; // This function is called before every block VOID docount(UINT32 c) { icount += c; } // Pin calls this function every time a new basic block is encountered // It inserts a call to docount VOID 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
  • 67.  Analysis tools can accept data / The running count of instructions is kept here // make it static to help the compiler optimize docount static UINT64 icount = 0; // This function is called before every block VOID docount(UINT32 c) { icount += c; } // Pin calls this function every time a new basic block is encountered // It inserts a call to docount VOID 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
  • 68.  The Pintool is registering a constant with Pin  e.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 instructions BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END); Potential Problems
  • 69. Callbacks w/ Data  We use configuration methods to configure data in callbacks class 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_; };
  • 70. Callbacks w/ Data  We use configuration methods to configure data in callbacks class 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
  • 71. Callbacks w/ Data  We use configuration methods to configure data in callbacks class 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
  • 72. Callbacks w/ Data  We use configuration methods to configure data in callbacks class 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
  • 73. Instruments w/ Data  We must dynamically allocate a new callback for each new insertion class 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
  • 74. Instruments w/ Data  We must dynamically allocate a new callback for each new insertion class 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
  • 75. Instruments w/ Data  We must dynamically allocate a new callback for each new insertion class 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
  • 76. Instruments w/ Data  We must dynamically allocate a new callback for each new insertion class 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
  • 77. 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/ Data  We must dynamically allocate a new callback for each new insertion
  • 78. 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/ Data  We must dynamically allocate a new callback for each new insertion Iterate over callbacks to get current count
  • 79. 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…
  • 80. Requesting Contextual Information in Callbacks https://github.com/SEDS/PinPP/wiki/Requesting-contextual-data-in-callbacks
  • 81. Contextual Data  Context data is anything about the program under instrumentation, or the machine running the program, needed by the analysis function to perform its analysis  Thread id  Process id  Register values  Arguments to a function  Return value  Etc.
  • 82. 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 IP VOID printip (VOID *ip) { fprintf(trace, "%pn", ip); } // Pin calls this function every time a new instruction is encountered VOID 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); }
  • 83. 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 IP VOID printip (VOID *ip) { fprintf(trace, "%pn", ip); } // Pin calls this function every time a new instruction is encountered VOID 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)
  • 84. 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 IP VOID printip (VOID *ip) { fprintf(trace, "%pn", ip); } // Pin calls this function every time a new instruction is encountered VOID 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…
  • 85. Potential Problems  The 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
  • 86. 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%pn", addr); } private: FILE * file_; };
  • 87. 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%pn", addr); } private: FILE * file_; }; This argument means the callback is expecting instruction pointer
  • 88. 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%pn", addr); } private: FILE * file_; }; Callbacks have typedefs that manage the correct type for each parameter
  • 89. 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 data  e.g., non-data arguments
  • 90. Context Data w/ Params  Some context data requires an extra parameter at insertion time // with Pin RTN_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);
  • 91. Context Data w/ Params  Some context data requires an extra parameter at insertion time // with Pin RTN_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
  • 92. Context Data w/ Params  Some context data requires an extra parameter at insertion time // with Pin RTN_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
  • 94. Range-based For Loops  Range-based for-loops are easy way to iterate over a list of values  Now 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; }
  • 95. 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 executed INS_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);
  • 96. 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_; };
  • 97. 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
  • 98. 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_; };
  • 99. 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
  • 100. 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
  • 101. Replacement Routines  Replacement 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
  • 102. 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); } };
  • 103. 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
  • 104. 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
  • 105. 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
  • 106. 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
  • 107. 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
  • 108. 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
  • 109. Locks and Guards  Pin 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 left  Also have guard for Routine since it must be opened and closed for usage
  • 110. Locks and Guards  Pin 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 left  Also 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);
  • 111. Locks and Guards  Pin 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 left  Also 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
  • 112. Thread-local Storage  Pin supports Thread-local Storage (TLS) via C functions  PIN_CreateThreadDataKey  PIN_DeleteThreadDataKey  PIN_SetThreadData  PIN_GetThreadData  Pin++ uses a type-safe TLS class to improve the robustness of TLS in Pin
  • 113. Thread-local Storage, Pin++  Supports registering factory (coming soon) & destruction function  Factory function called if TLS data does not exist  Destruction 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]; }; // Usage TLS <thread_data_t> tls (&thread_data_t::__release); tls.get_with_create ([] (void) { return new thread_data_t (); }); tls.get (thr_id)->count_ ++;
  • 114. Thread-local Storage, Pin++  Supports registering factory (coming soon) & destruction function  Factory function called if TLS data does not exist  Destruction 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]; }; // Usage TLS <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
  • 115. Thread-local Storage, Pin++  Supports registering factory (coming soon) & destruction function  Factory function called if TLS data does not exist  Destruction 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]; }; // Usage TLS <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
  • 116. Thread-local Storage, Pin++  Supports registering factory (coming soon) & destruction function  Factory function called if TLS data does not exist  Destruction 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]; }; // Usage TLS <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
  • 117. Thread-local Storage, Pin++  Supports registering factory (coming soon) & destruction function  Factory function called if TLS data does not exist  Destruction 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]; }; // Usage TLS <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
  • 118. Thread-local Storage, Pin++  Supports registering factory (coming soon) & destruction function  Factory function called if TLS data does not exist  Destruction 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]; }; // Usage TLS <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
  • 119. Multi-threaded Pintools  Pin supports threads in a Pintool  PIN_SpawnInternalThread  PIN_WaitForThreadTermination  PIN_ExitThread (called only by spawned thread)  …  Uses a C approach for spawning threads
  • 120. 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); //... };
  • 121. 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
  • 122. 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
  • 123. 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
  • 124. 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
  • 125. 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
  • 126. 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
  • 127. 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
  • 128. Concluding Remarks  Pin++ 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++