/* * 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 #include #include #include #include #include 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 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 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 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 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; }