Skip to content

Update callstack_instr to track binary names #1580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion panda/plugins/callstack_instr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ uint32_t get_callers(target_ulong *callers, uint32_t n, CPUState *env);
// Return value is the number of callers actually retrieved
uint32_t get_functions(target_ulong *functions, uint32_t n, CPUState *env);

// Get up to n binaries from the given stack in use at this moment
// Binaries are returned in libs[], most recent first
// Return value is the number of binaries actually retrieved
// Must have OSI enabled for this api to work.
uint32_t get_binaries(char **libs, uint32_t n, CPUState *cpu);

// Must be called by plugins which intend to call get_binaries.
void callstack_enable_binary_tracking(void);

// Get the current program point: (Caller, PC, stack ID)
// This isn't quite the right place for it, but since it's awkward
// right now to have a "utilities" library, this will have to do
Expand Down Expand Up @@ -96,10 +105,13 @@ Example

int some_plugin_fn(CPUState *env) {
target_ulong callers[16];
char *binaries[16];
int n;
n = get_callers(callers, 16, env);
get_binaries(binaries, 16, env);
for (int i = 0; i < n; i++)
printf("Callstack entry: " TARGET_FMT_lx "\n", callers[i]);
printf("Callstack entry: " TARGET_FMT_lx " %s\n", callers[i],
binaries[i]);
return 0;
}

Expand All @@ -108,5 +120,6 @@ int some_plugin_fn(CPUState *env) {
bool init_plugin(void *self) {
panda_require("callstack_instr");
if (!init_callstack_instr_api()) return false;
callstack_enable_binary_tracking();
}
```
72 changes: 72 additions & 0 deletions panda/plugins/callstack_instr/callstack_instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ PANDAENDCOMMENT */

#include <algorithm>
#include <map>
#include <memory>
#include <set>
#include <vector>

Expand Down Expand Up @@ -79,6 +80,7 @@ bool old_capstone=false; // Should we use fallback instruction group detection l

// callstack_instr arguments
static bool verbose = false;
static bool include_binary_info = false;

enum instr_type {
INSTR_UNKNOWN = 0,
Expand Down Expand Up @@ -124,6 +126,8 @@ std::map<stackid, std::vector<target_ulong>> function_stacks;
std::map<target_ulong, instr_type> call_cache;
// stackid -> address of Stopped block
std::map<stackid, target_ulong> stoppedInfo;
// stackid -> (stack entry pc -> binary)
std::map<stackid, std::map<target_ulong, std::vector<char>>> binary_info_stacks;

int last_ret_size = 0;

Expand Down Expand Up @@ -379,13 +383,26 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
return;
}

std::map<target_ulong, std::vector<char>> *binary_info_stack = nullptr;

if(include_binary_info) {
binary_info_stack = &binary_info_stacks[cur_stackid];
}

// Search up to 10 down
for (int i = v.size() - 1; i > ((int)(v.size() - 10)) && i >= 0; i--) {
if (tb->pc == v[i].pc) {
// printf("Matched at depth %d\n", v.size()-i);
// v.erase(v.begin()+i, v.end());

PPP_RUN_CB(on_ret, cpu, w[i]);

if(include_binary_info) {
for (std::vector<stack_entry>::iterator it = v.begin() + i; it != v.end(); ++it) {
binary_info_stack->erase(it->pc);
}
}

v.erase(v.begin() + i, v.end());
w.erase(w.begin() + i, w.end());

Expand All @@ -395,6 +412,29 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
}
}

std::vector<char> getLib(CPUState* cpu, target_ulong pc) {

std::shared_ptr<OsiProc> proc(get_current_process(cpu), free_osiproc);

OsiModule *module = get_mapping_by_addr(cpu, proc.get(), pc);

if(nullptr != module) {
const char *lib = "";
if (nullptr != module->file) {
lib = module->file;
} else if (nullptr != module->name) {
lib = module->name;
}
std::size_t len = strlen(lib);
std::vector<char> lib_str_buf(len + 1);
std::snprintf(lib_str_buf.data(), lib_str_buf.size(), "%s", lib);
free_osimodule(module);
return lib_str_buf;
}

return std::vector<char>(1, '\0');
}

void after_block_exec(CPUState* cpu, TranslationBlock *tb, uint8_t exitCode) {
target_ulong pc = 0x0;
target_ulong cs_base = 0x0;
Expand All @@ -410,6 +450,9 @@ void after_block_exec(CPUState* cpu, TranslationBlock *tb, uint8_t exitCode) {
if (tb_type == INSTR_CALL) {
stack_entry se = {tb->pc + tb->size, tb_type};
callstacks[curStackid].push_back(se);
if(include_binary_info) {
binary_info_stacks[curStackid][se.pc] = getLib(cpu, se.pc);
}

// Also track the function that gets called
// This retrieves the pc in an architecture-neutral way
Expand Down Expand Up @@ -455,6 +498,31 @@ uint32_t get_callers(target_ulong callers[], uint32_t n, CPUState* cpu) {
return get_callers_priv(callers, n, cpu, get_stackid(cpu));
}

uint32_t get_binaries(char **libs, uint32_t n, CPUState *cpu) {
static bool warning_shown = false;
for(uint32_t i=0; i<n; libs[i++] = nullptr);
if(include_binary_info) {
stackid stack_id = get_stackid(cpu);
std::vector<stack_entry> &call_stack = callstacks[stack_id];
std::map<target_ulong, std::vector<char>> &binary_info_stack = binary_info_stacks[stack_id];

n = std::min((uint32_t) call_stack.size(), n);
for (uint32_t i = 0; i < n; ++i) {
libs[i] = binary_info_stack[call_stack[call_stack.size() - 1 - i].pc].data();
}
} else {
if(!warning_shown) {
fprintf(stderr, "WARNING: callstack_instr: get_binaries called "
"but binary tracking not enabled. %s\n",
(nullptr == panda_get_plugin_by_name("osi") ?
"OSI plugin not loaded." : ""));
warning_shown = true;
}
n = 0;
}

return n;
}

#define CALLSTACK_MAX_SIZE 16
/**
Expand Down Expand Up @@ -681,6 +749,10 @@ bool init_plugin(void *self) {
return setup_ok;
}

void callstack_enable_binary_tracking() {
include_binary_info = (nullptr != panda_get_plugin_by_name("osi"));
}

void uninit_plugin(void *self) {
// nothing to do
}
Expand Down
7 changes: 7 additions & 0 deletions panda/plugins/callstack_instr/callstack_instr_int_fns.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ uint32_t get_callers(target_ulong *callers, uint32_t n, CPUState *cpu);
// Functions are returned in functions[], most recent first
uint32_t get_functions(target_ulong *functions, uint32_t n, CPUState *cpu);

// Get up to n binaries from the given stack in use at this moment
// Binaries are returned in libs[], most recent first
uint32_t get_binaries(char **libs, uint32_t n, CPUState *cpu);

// Called by plugins that intend to call get_binaries.
void callstack_enable_binary_tracking(void);

// END_PYPANDA_NEEDS_THIS -- do not delete this comment!

// NB: prog_point is c++, so beware
Expand Down
Loading