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.

215 lines
6.7 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.
*/
#if !defined(_EMX_CALL_STACK_H_)
#define _EMX_CALL_STACK_H_
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
#include "pin.H"
using std::vector;
using std::list;
using std::string;
using std::map;
using std::set;
extern "C"{
#include "xed-interface.h"
}
namespace CALLSTACK{
class CallEntry {
private:
ADDRINT _current_sp;
ADDRINT _target;
public:
CallEntry(): _current_sp(0),_target(0) { }
CallEntry(ADDRINT current_sp, ADDRINT target):
_current_sp(current_sp),
_target(target)
{ }
bool operator==( const CallEntry& a) const {
return(_current_sp == a._current_sp);
}
ADDRINT sp() const {return _current_sp;}
ADDRINT target() const {return _target;}
};
class CallStack {
public:
// print the call stack, emit only 'depth' entries
void emit_stack(UINT32 depth, vector<string>& out);
// return the depth of the call stack
UINT32 depth();
// add the current_sp and the target to the top of the call stack
void push_head(ADDRINT current_sp, ADDRINT target);
// return the ip target of the latest call
ADDRINT top_target();
// return the ip target of call per depth
ADDRINT depth_target(UINT32 depth);
// capture the info for each ip in the call stack
// see CallStackInfo
void save_all_ips_info();
void process_call(ADDRINT current_sp, ADDRINT target);
void process_return(ADDRINT current_sp, ADDRINT ip);
// print the call stack, emit only 'depth' entries
void get_targets(list<ADDRINT>& out);
private:
typedef std::vector<CallEntry> CallVec;
CallVec _call_vec;
void create_entry(ADDRINT current_sp, ADDRINT target);
void adjust_stack( ADDRINT current_sp);
};
typedef void (*CALL_STACK_HANDLER)(CONTEXT* ctxt, ADDRINT ip, THREADID tid, VOID *v);
class CallStackHandlerParams{
public:
CallStackHandlerParams(CALL_STACK_HANDLER h, const string& func_name, void* v,
ADDRINT func_ip = 0, BOOL name_handler = TRUE){
_handler = h;
_function_name = func_name;
_name_handler = name_handler;
_args = v;
_first_ip = 0;
}
CALL_STACK_HANDLER _handler;
string _function_name;
string _function_ip;
BOOL _name_handler;
void* _args;
ADDRINT _first_ip; //the first ip of the function, used for recursive function call
};
// this struct holds the informations need for emitting the call stack
// we hold a map of ip->CallStackInfo so we will no
// generate info for the same ip more than once
typedef struct CallStackInfoStruct {
char * func_name;
char * image_name;
char * file_name;
UINT32 rtn_id;
INT32 line;
INT32 column;
CallStackInfoStruct() : func_name(0), image_name(0), file_name(0), rtn_id(0), line(0), column(0) {}
} CallStackInfo;
// a singleton class
class CallStackManager{
public:
// return a pointer to an instance of the class
static CallStackManager* get_instance();
// return a copied CallStack of thread tid
CallStack get_stack(THREADID tid);
// activate the CallStackManager
void activate();
// fill in info with the information about the ip, see CallStackInfo
// if the the info does not exists we generated it first
void get_ip_info(ADDRINT ip, CallStackInfo& info);
//register a callback the will be called when entering to function: func_name
void on_function_enter(CALL_STACK_HANDLER handler, const string& func_name, void* v, BOOL use_ctxt);
//register a callback the will be called when returning from function: func_name
void on_function_exit(CALL_STACK_HANDLER handler, const string& func_name, void* v, BOOL use_ctxt);
// Register a callback that will be called when entering function: function_ip
// The parameters are: function handler
// function ip address
// parameter to the function
// flag if the function uses PIN context
void on_function_ip_enter(CALL_STACK_HANDLER handler, ADDRINT func_ip, void* v, BOOL use_ctxt);
// Register a callback that will be called when exiting function: function_ip
// The parameters are: function handler
// function ip address
// parameter to the function
// flag if the function uses PIN context
void on_function_ip_exit(CALL_STACK_HANDLER handler, ADDRINT func_ip, void* v, BOOL use_ctxt);
//// internal use ////
void on_call(THREADID tid, CONTEXT* ctxt, ADDRINT ip);
void on_ret_fire(THREADID tid, CONTEXT* ctxt, ADDRINT ip);
BOOL on_ret_should_fire(THREADID tid);
BOOL NeedContext();
BOOL TargetInteresting(ADDRINT ip);
private:
CallStackManager(): _activated(false),_use_ctxt(false),
_depth_func_handlers_tid_vec(PIN_MAX_THREADS){
PIN_InitLock(&_lock);
}
static void thread_begin(THREADID tid, CONTEXT* ctxt,
INT32 flags, void* v);
void add_stack(THREADID tid, CallStack* call_stack);
static void Img(IMG img, void* v);
static CallStackManager* _instance;
bool _activated;
//a map to threadid -> CallStack*
typedef std::map<THREADID, CallStack*> CallStackMap;
CallStackMap _call_stack_map;
PIN_LOCK _map_lock;
//map of ip to its info(file, func, line, ...)
//used to prevent collecting info about the same ip multiple times
typedef std::map<ADDRINT, CallStackInfo> CallStackInfoMap;
CallStackInfoMap _call_stack_info;
PIN_LOCK _lock;
BOOL _use_ctxt;
vector<CallStackHandlerParams> _enter_func_handlers;
vector<CallStackHandlerParams> _exit_func_handlers;
//map of ip to a vector of handlers
typedef vector<CallStackHandlerParams*> CallStackHandlerVec;
typedef map<ADDRINT, CallStackHandlerVec> IpFuncHnadlersMap;
IpFuncHnadlersMap _enter_func_handlers_map;
//map of ip to a vector of handlers
IpFuncHnadlersMap _exit_func_handlers_map;
//map of stack depth to a vector of handlers
typedef std::map<UINT32, CallStackHandlerVec> DepthFuncHandlersMap;
typedef std::vector<DepthFuncHandlersMap> DepthFuncHandlersTidVec;
//a vector with entry per thread
DepthFuncHandlersTidVec _depth_func_handlers_tid_vec;
//holds the ips that we have marked for exit, needed for recursive calls
set<ADDRINT> _marked_ip_for_exit;
};
} //namespace
#endif