/* * 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 #include #include #include #include #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& 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& out); private: typedef std::vector 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 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 CallStackInfoMap; CallStackInfoMap _call_stack_info; PIN_LOCK _lock; BOOL _use_ctxt; vector _enter_func_handlers; vector _exit_func_handlers; //map of ip to a vector of handlers typedef vector CallStackHandlerVec; typedef map 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 DepthFuncHandlersMap; typedef std::vector 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 _marked_ip_for_exit; }; } //namespace #endif