You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
8.1 KiB
304 lines
8.1 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*! @file
|
|
* This file contains an ISA-portable PIN tool for tracing instructions
|
|
*/
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <map>
|
|
#include <unistd.h>
|
|
#include "pin.H"
|
|
using std::pair;
|
|
using std::map;
|
|
using std::cerr;
|
|
using std::string;
|
|
using std::endl;
|
|
|
|
|
|
/* ===================================================================== */
|
|
/* Commandline Switches */
|
|
/* ===================================================================== */
|
|
|
|
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
|
|
"o", "edgcnt.out", "specify trace file name");
|
|
KNOB<INT32> KnobFilterByHighNibble(KNOB_MODE_WRITEONCE, "pintool",
|
|
"f", "-1", "only instrument instructions with a code address matching the filter");
|
|
KNOB<BOOL> KnobPid(KNOB_MODE_WRITEONCE, "pintool",
|
|
"i", "0", "append pid to output");
|
|
|
|
/* ===================================================================== */
|
|
/* Print Help Message */
|
|
/* ===================================================================== */
|
|
|
|
static INT32 Usage()
|
|
{
|
|
cerr << "This pin tool collects an edge profile for an application\n";
|
|
cerr << "The edge profile is partial as it only considers control flow changes (taken\n";
|
|
cerr << "branch edges, etc.). It is the left to the profile consumer to compute the missing counts.\n";
|
|
cerr << "\n";
|
|
|
|
cerr << "The pin tool *does* keep track of edges from indirect jumps within, out of, and into\n";
|
|
cerr << "the application. Traps to the OS a recorded with a target of -1.\n";
|
|
|
|
cerr << KNOB_BASE::StringKnobSummary() << endl;
|
|
return -1;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
/* Global Variables */
|
|
/* ===================================================================== */
|
|
|
|
class COUNTER
|
|
{
|
|
public:
|
|
UINT64 _count; // number of times the edge was traversed
|
|
|
|
COUNTER() : _count(0) {}
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
ETYPE_INVALID,
|
|
ETYPE_CALL,
|
|
ETYPE_ICALL,
|
|
ETYPE_BRANCH,
|
|
ETYPE_IBRANCH,
|
|
ETYPE_RETURN,
|
|
ETYPE_SYSCALL,
|
|
ETYPE_LAST
|
|
}ETYPE;
|
|
|
|
class EDGE
|
|
{
|
|
public:
|
|
ADDRINT _src;
|
|
ADDRINT _dst;
|
|
ADDRINT _next_ins;
|
|
ETYPE _type; // must be integer to make stl happy
|
|
|
|
EDGE(ADDRINT s, ADDRINT d, ADDRINT n, ETYPE t) :
|
|
_src(s),_dst(d), _next_ins(n),_type(t) {}
|
|
|
|
bool operator <(const EDGE& edge) const
|
|
{
|
|
return _src < edge._src || (_src == edge._src && _dst < edge._dst);
|
|
}
|
|
|
|
};
|
|
|
|
string StringFromEtype( ETYPE etype)
|
|
{
|
|
switch(etype)
|
|
{
|
|
case ETYPE_CALL:
|
|
return "C";
|
|
case ETYPE_ICALL:
|
|
return "c";
|
|
case ETYPE_BRANCH:
|
|
return "B";
|
|
case ETYPE_IBRANCH:
|
|
return "b";
|
|
case ETYPE_RETURN:
|
|
return "r";
|
|
case ETYPE_SYSCALL:
|
|
return "s";
|
|
default:
|
|
ASSERTX(0);
|
|
return "INVALID";
|
|
}
|
|
}
|
|
|
|
typedef map< EDGE, COUNTER*> EDG_HASH_SET;
|
|
|
|
static EDG_HASH_SET EdgeSet;
|
|
|
|
/* ===================================================================== */
|
|
|
|
/*!
|
|
An Edge might have been previously instrumented, If so reuse the previous entry
|
|
otherwise create a new one.
|
|
*/
|
|
|
|
static COUNTER * Lookup( EDGE edge)
|
|
{
|
|
COUNTER *& ref = EdgeSet[ edge ];
|
|
|
|
if( ref == 0 )
|
|
{
|
|
ref = new COUNTER();
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
|
|
|
|
VOID docount( COUNTER *pedg )
|
|
{
|
|
pedg->_count++;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
// for indirect control flow we do not know the edge in advance and
|
|
// therefore must look it up
|
|
|
|
VOID docount2( ADDRINT src, ADDRINT dst, ADDRINT n, ETYPE type, INT32 taken )
|
|
{
|
|
if(!taken) return;
|
|
COUNTER *pedg = Lookup( EDGE(src,dst,n,type) );
|
|
pedg->_count++;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
|
|
VOID Instruction(INS ins, void *v)
|
|
{
|
|
if (INS_IsDirectControlFlow(ins))
|
|
{
|
|
ETYPE type = INS_IsCall(ins) ? ETYPE_CALL : ETYPE_BRANCH;
|
|
|
|
// static targets can map here once
|
|
COUNTER *pedg = Lookup( EDGE(INS_Address(ins), INS_DirectControlFlowTargetAddress(ins),
|
|
INS_NextAddress(ins), type) );
|
|
INS_InsertCall(ins, IPOINT_TAKEN_BRANCH, (AFUNPTR) docount, IARG_ADDRINT, pedg, IARG_END);
|
|
}
|
|
else if( INS_IsIndirectControlFlow(ins) )
|
|
{
|
|
ETYPE type = ETYPE_IBRANCH;
|
|
|
|
if( INS_IsRet(ins) )
|
|
{
|
|
type = ETYPE_RETURN;
|
|
}
|
|
else if (INS_IsCall(ins) )
|
|
{
|
|
type = ETYPE_ICALL;
|
|
}
|
|
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) docount2,
|
|
IARG_INST_PTR,
|
|
IARG_BRANCH_TARGET_ADDR,
|
|
IARG_ADDRINT, INS_NextAddress(ins),
|
|
IARG_UINT32, type,
|
|
IARG_BRANCH_TAKEN,
|
|
IARG_END);
|
|
}
|
|
else if( INS_IsSyscall(ins) )
|
|
{
|
|
COUNTER *pedg = Lookup( EDGE(INS_Address(ins), ADDRINT(~0),INS_NextAddress(ins) ,ETYPE_SYSCALL) );
|
|
INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR) docount, IARG_ADDRINT, pedg, IARG_END);
|
|
}
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
|
|
inline INT32 AddressHighNibble(ADDRINT addr)
|
|
{
|
|
return 0xf & (addr >> (sizeof(ADDRINT)* 8 - 4));
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
static std::ofstream* out = 0;
|
|
|
|
VOID Fini(int n, void *v)
|
|
{
|
|
SetAddress0x(1);
|
|
|
|
const INT32 nibble = KnobFilterByHighNibble.Value();
|
|
|
|
*out << "EDGCOUNT 4.0 0\n"; // profile header, no md5sum
|
|
UINT32 count = 0;
|
|
|
|
for( EDG_HASH_SET::const_iterator it = EdgeSet.begin(); it != EdgeSet.end(); it++ )
|
|
{
|
|
const pair<EDGE, COUNTER*> tuple = *it;
|
|
// skip inter shared lib edges
|
|
|
|
if( nibble >= 0 && nibble != AddressHighNibble(tuple.first._dst) &&
|
|
nibble != AddressHighNibble(tuple.first._src) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( tuple.second->_count == 0 ) continue;
|
|
|
|
count++;
|
|
}
|
|
|
|
*out << "EDGs " << count << endl;
|
|
*out << "# src dst type count next-ins\n";
|
|
*out << "DATA:START" << endl;
|
|
|
|
|
|
for( EDG_HASH_SET::const_iterator it = EdgeSet.begin(); it != EdgeSet.end(); it++ )
|
|
{
|
|
const pair<EDGE, COUNTER*> tuple = *it;
|
|
|
|
// skip inter shared lib edges
|
|
|
|
if( nibble >= 0 && nibble != AddressHighNibble(tuple.first._dst) &&
|
|
nibble != AddressHighNibble(tuple.first._src) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( tuple.second->_count == 0 ) continue;
|
|
|
|
*out <<
|
|
StringFromAddrint( tuple.first._src) << " " <<
|
|
StringFromAddrint(tuple.first._dst) << " " <<
|
|
StringFromEtype(tuple.first._type) << " " <<
|
|
decstr(tuple.second->_count,12) << " " <<
|
|
StringFromAddrint( tuple.first._next_ins) << endl;
|
|
|
|
}
|
|
|
|
*out << "DATA:END" << endl;
|
|
*out << "## eof\n";
|
|
out->close();
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
/* Main */
|
|
/* ===================================================================== */
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
|
|
if( PIN_Init(argc,argv) )
|
|
{
|
|
return Usage();
|
|
}
|
|
|
|
|
|
string filename = KnobOutputFile.Value();
|
|
if (KnobPid)
|
|
{
|
|
filename += "." + decstr(getpid());
|
|
}
|
|
out = new std::ofstream(filename.c_str());
|
|
|
|
INS_AddInstrumentFunction(Instruction, 0);
|
|
PIN_AddFiniFunction(Fini, 0);
|
|
|
|
// Never returns
|
|
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ===================================================================== */
|
|
/* eof */
|
|
/* ===================================================================== */
|