Skip to content

Commit

Permalink
pt: Add call-stack sources
Browse files Browse the repository at this point in the history
  • Loading branch information
aewag committed Mar 2, 2023
1 parent c29367e commit 701d7a3
Show file tree
Hide file tree
Showing 2 changed files with 870 additions and 0 deletions.
241 changes: 241 additions & 0 deletions pintool/callstack.H
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*BEGIN_LEGAL
Intel Open Source License
Copyright (c) 2002-2018 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. Redistributions
in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. Neither the name of
the Intel Corporation nor the names of its contributors may be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
END_LEGAL */

#if !defined(_EMX_CALL_STACK_H_)
#define _EMX_CALL_STACK_H_

#include "pin.H"
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
extern "C" {
#include "xed-interface.h"
}

namespace CALLSTACK {

// struct that holds the instruction pointer address and the corresponding name
// of the image
typedef struct {
std::string name;
ADDRINT ipaddr;
} ipobj_t;

typedef std::vector<ipobj_t> IPVEC;

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, std::vector<std::string> &out, IPVEC &ipvec);

// 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(std::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 std::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;
std::string _function_name;
std::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 std::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 std::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;

std::vector<CallStackHandlerParams> _enter_func_handlers;
std::vector<CallStackHandlerParams> _exit_func_handlers;

// map of ip to a vector of handlers
typedef std::vector<CallStackHandlerParams *> CallStackHandlerVec;
typedef std::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
std::set<ADDRINT> _marked_ip_for_exit;
};
} // namespace CALLSTACK
#endif
Loading

0 comments on commit 701d7a3

Please sign in to comment.