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.

320 lines
9.5 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.
*/
// This tool collects the dynamic counts of the behavior of the traces
// that are being generated by pin as the application executes.
#include "pin.H"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <map>
#include <algorithm>
#include <assert.h>
using std::dec;
using std::setw;
using std::hex;
using std::endl;
using std::ofstream;
using std::map;
using std::multimap;
using std::make_pair;
using std::pair;
/* ================================================================== */
/* Global Data Structures */
/* ================================================================== */
/* ================================================================== */
/* Information on every branch in a trace */
typedef struct BBL_INFO_STRUCT
{
UINT32 ins_cnt;
UINT32 exec_cnt;
UINT32 code_size;
UINT32 accum_code_size;
UINT32 bbl_exit_cnt;
BBL_INFO_STRUCT() : ins_cnt(0), exec_cnt(0), code_size(0), accum_code_size(0), bbl_exit_cnt(0) {}
} BBL_INFO;
typedef map<ADDRINT, BBL_INFO> BBL_MAP;
/* ================================================================== */
/* Information on every trace produced by pin */
typedef struct TRACE_INFO_STRUCT
{
UINT32 exec_cnt;
UINT32 bbl_cnt;
UINT32 ins_cnt;
UINT32 fall_cnt;
BBL_MAP bbl_info;
TRACE_INFO_STRUCT() : exec_cnt(0), bbl_cnt(0), ins_cnt(0), fall_cnt(0) {}
} TRACE_INFO;
typedef multimap <ADDRINT, TRACE_INFO> TRACE_MAP;
/* ================================================================== */
TRACE_MAP Trace_Information;
ofstream OutFile ("traceusage.trace");
/* ================================================================== */
/*
Inc. the counter for a trace when the trace is short and results
in the program falling off the trace and into a new trace
*/
VOID TraceFall_Info(ADDRINT trace_addr)
{
TRACE_MAP::iterator tr_it = Trace_Information.find(trace_addr);
assert( tr_it == Trace_Information.end() );
TRACE_INFO& tr_info = tr_it->second;
tr_info.fall_cnt++;
}
/* ================================================================== */
/*
Insert a new bbl record into the trace record
*/
VOID Bbl_Info(ADDRINT bbl_addr, UINT32 ins_cnt, ADDRINT trace_addr, UINT32 code_size, UINT32 accum_code_size)
{
TRACE_MAP::iterator tr_it = Trace_Information.find(trace_addr);
assert( tr_it != Trace_Information.end() );
TRACE_INFO& tr_info = tr_it->second;
BBL_MAP& Bbl_Information = tr_info.bbl_info;
BBL_MAP::iterator bbl_it = Bbl_Information.find(bbl_addr);
if (bbl_it == Bbl_Information.end())
{
BBL_INFO bbl_info;
bbl_info.ins_cnt = ins_cnt;
bbl_info.code_size = code_size;
bbl_info.accum_code_size = accum_code_size;
bbl_info.exec_cnt = 0;
bbl_info.bbl_exit_cnt = 0;
Bbl_Information.insert(make_pair(bbl_addr, bbl_info));
}
}
/* ================================================================== */
/*
Insert/Inc. the usage of bbls and the exit status of a bbl
*/
VOID BblExit_Info(ADDRINT bbl_addr, ADDRINT trace_addr)
{
TRACE_MAP::iterator tr_it = Trace_Information.find(trace_addr);
assert( tr_it != Trace_Information.end() );
TRACE_INFO& tr_info = tr_it->second;
BBL_MAP& Bbl_Information = tr_info.bbl_info;
BBL_MAP::iterator bbl_it = Bbl_Information.begin();
for (; bbl_it != Bbl_Information.end(); bbl_it++)
{
BBL_INFO& bbl_info = bbl_it->second;
/* Inc usage of every bbl above the exit bbl for it is utilized */
bbl_info.exec_cnt++;
/* The exit bbl itself */
if (bbl_addr == bbl_it->first)
{
bbl_info.bbl_exit_cnt++;
return;
}
}
assert( bbl_it != Bbl_Information.end() );
}
/* ================================================================== */
/*
Insert/Inc. the usage of a trace
*/
VOID Trace_Info(ADDRINT trace_addr, UINT32 bbl_cnt, UINT32 ins_cnt)
{
TRACE_MAP::iterator it = Trace_Information.find(trace_addr);
// First visit
if (it == Trace_Information.end())
{
TRACE_INFO tr_info;
tr_info.bbl_cnt = bbl_cnt;
tr_info.ins_cnt = ins_cnt;
tr_info.exec_cnt = 0;
Trace_Information.insert( make_pair(trace_addr, tr_info) );
}
else
{
it->second.exec_cnt++;
}
}
/* ================================================================== */
/*
Instrumentation function;
Track the trace, the usage of the code in the bbls and the bbl exits
*/
VOID Trace(TRACE trace, VOID *v)
{
/* Add trace to db */
Trace_Info(TRACE_Address(trace),
TRACE_NumBbl(trace),
TRACE_NumIns(trace));
/* Inc. trace execution count */
TRACE_InsertCall(trace, IPOINT_BEFORE,
(AFUNPTR) Trace_Info,
IARG_ADDRINT, TRACE_Address(trace),
IARG_UINT32, TRACE_NumBbl(trace),
IARG_UINT32, TRACE_NumIns(trace),
IARG_END);
USIZE accum_code_size = 0;
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
accum_code_size += BBL_Size(bbl);
/* Add bbl to db */
Bbl_Info(BBL_Address(bbl),
BBL_NumIns(bbl),
TRACE_Address(trace),
BBL_Size(bbl),
accum_code_size);
INS ins = BBL_InsTail(bbl);
if (INS_IsValidForIpointTakenBranch(ins))
{
/* Inc. bbl exit count */
INS_InsertCall(ins, IPOINT_TAKEN_BRANCH,
(AFUNPTR) BblExit_Info,
IARG_ADDRINT, BBL_Address(bbl),
IARG_ADDRINT, TRACE_Address(trace),
IARG_END);
}
}
/* Trace falloff in the case the bbl is too big and does not
necessarily end with a bbl terminating op */
INS ins = BBL_InsTail(TRACE_BblTail(trace));
if (!INS_IsControlFlow(ins))
{
/* Inc. trace falloff exit count */
INS_InsertCall(ins, IPOINT_BEFORE,
(AFUNPTR) TraceFall_Info,
IARG_ADDRINT, TRACE_Address(trace),
IARG_END);
}
}
/* ================================================================== */
/*
Print bbl exit info
*/
VOID PrintBblExit(pair<const ADDRINT, BBL_INFO> bbl_info)
{
OutFile << hex << "0x" << bbl_info.first << "\t"
<< setw(5)
<< dec << bbl_info.second.exec_cnt << "\t"
<< setw(5)
<< dec << bbl_info.second.ins_cnt << "\t"
<< setw(5)
<< dec << bbl_info.second.bbl_exit_cnt << "\t"
<< setw(5)
<< dec << bbl_info.second.code_size << "\t"
<< setw(5)
<< dec << bbl_info.second.accum_code_size << "\t"
<< endl;
}
/* ================================================================== */
/*
Print a trace
*/
VOID PrintTrace(pair<const ADDRINT, TRACE_INFO> trace_info)
{
/* Trace information */
OutFile << "==================================================================" << endl;
OutFile << "Trace:" << "\t"
<< setw(10)
<< "# Exe"<< "\t"
<< setw(5)
<< "# Bbl"<< "\t"
<< setw(5)
<< "# Ins"<< "\t"
<< endl;
OutFile << "==================================================================" << endl;
OutFile << hex << "0x" << trace_info.first << "\t"
<< setw(5)
<< dec << trace_info.second.exec_cnt << "\t"
<< setw(5)
<< dec << trace_info.second.bbl_cnt << "\t"
<< setw(5)
<< dec << trace_info.second.ins_cnt << "\t"
<< endl << endl;
/* Bbl information */
OutFile << "------------------------------------------------------------------" << endl;
OutFile << "Bbl:" << "\t"
<< setw(10)
<< "# Exe" << "\t"
<< setw(5)
<< "# Ins" << "\t"
<< setw(5)
<< "Exit" << "\t"
<< setw(5)
<< "Size" << "\t"
<< setw(5)
<< "ASize" << "\t"
<< endl;
OutFile << "------------------------------------------------------------------" << endl;
BBL_MAP& Bbl_Information = trace_info.second.bbl_info;
/* Bbl exit information */
for_each(Bbl_Information.begin(), Bbl_Information.end(), PrintBblExit);
OutFile << endl << endl;
}
/* ================================================================== */
/*
Output the trace usage to a file
*/
VOID DumpTraceInfo(INT32 code, VOID *v)
{
for_each(Trace_Information.begin(), Trace_Information.end(), PrintTrace);
}
/* ================================================================== */
/*
Initialize and begin program execution under the control of Pin
*/
int main(INT32 argc, CHAR **argv)
{
PIN_Init(argc, argv);
TRACE_AddInstrumentFunction(Trace, 0);
PIN_AddFiniFunction(DumpTraceInfo, 0);
PIN_StartProgram();
return 0;
}