Dyninst Binary Instrumentation Cheatsheet
# Debian/Ubuntu
sudo apt-get install build-essential cmake libelf-dev libdw-dev \
libboost-all-dev libiberty-dev
# Fedora/RHEL
sudo dnf install elfutils-devel boost-devel binutils-devel
git clone https://github.com/dyninst/dyninst.git
cd dyninst
mkdir build && cd build
cmake ..
make -j$( nproc)
sudo make install
#include " BPatch.h"
#include " BPatch_addressSpace.h"
#include " BPatch_process.h"
BPatch bpatch;
BPatch_addressSpace *app = bpatch.openBinary(" ./program" );
// Get image
BPatch_image *appImage = app->getImage ();
// Find functions
vector<BPatch_function *> functions;
appImage->findFunction (" main" , functions);
// Get entry point
BPatch_function *mainFunction = functions[0 ];
BPatch_Vector<BPatch_point *> *entries = mainFunction->findPoint (BPatch_entry);
// Insert at function entry
BPatch_point *entryPoint = entries->at (0 );
BPatchSnippetHandle *handle = app->insertSnippet (
snippet, *entryPoint);
// Insert at function exit
BPatch_Vector<BPatch_point *> *exits =
mainFunction->findPoint (BPatch_exit);
// Find memory accesses
BPatch_Vector<BPatch_point *> *reads =
mainFunction->findPoint (BPatch_memRead);
BPatch_Vector<BPatch_point *> *writes =
mainFunction->findPoint (BPatch_memWrite);
// Create function call snippet
vector<BPatch_function *> printfFuncs;
appImage->findFunction (" printf" , printfFuncs);
BPatch_function *printfFunc = printfFuncs[0 ];
// Create parameters
BPatch_Vector<BPatch_snippet *> args;
args.push_back(BPatch_constExpr(" Hello\n " ));
// Create call
BPatch_funcCallExpr printfCall (*printfFunc, args);
// Find variable
BPatch_variableExpr *var =
appImage->findVariable (" globalVar" );
// Read variable
BPatch_snippet *readVar =
new BPatch_varExpr(*var);
// Write variable
BPatch_snippet *writeVar =
new BPatch_arithExpr(BPatch_assign,
*var, BPatch_constExpr(42 ));
// Create process
BPatch_process *proc =
bpatch.processCreate(" ./program" , argv);
// Attach to process
BPatch_process *proc =
bpatch.processAttach(" program" , pid);
// Continue execution
proc->continueExecution ();
// Terminate process
proc->terminateExecution ();
// Create binary rewriter
BPatch_binaryEdit *appBin =
bpatch.openBinary(" program" , true );
// Save modified binary
appBin->writeFile (" program.modified" );
// Set error callback
BPatch::setErrorCallback (errorFunc);
// Error handling function
void errorFunc (BPatchErrorLevel level,
int num, const char * const * params) {
// Handle error
}
Always check function lookup results
Use error callbacks
Clean up resources properly
Handle instrumentation failures
Test on small programs first
Back up binaries before modification
Use appropriate instrumentation points
// Find target function
vector<BPatch_function *> funcs;
appImage->findFunction (" targetFunc" , funcs);
// Create wrapper
BPatch_function *wrapper =
createWrapperFunction (funcs[0 ]);
// Replace calls
replaceCallSites (funcs[0 ], wrapper);
// Insert timing code
BPatch_timestamp startTime;
insertSnippet (startTime, entry);
BPatch_timestamp endTime;
insertSnippet (endTime, exit);
// Calculate duration
BPatch_arithExpr duration (BPatch_subtract,
endTime, startTime);
Use BPatch debug flags
Check symbol table availability
Verify function signatures
Monitor memory usage
Test instrumentations incrementally
Use process tracing
Validate binary modifications
Performance Considerations
Minimize instrumentation points
Use efficient snippets
Batch modifications
Consider overhead
Use appropriate analysis levels
Cache commonly used data
Clean up unused instruments