Skip to content

Commit

Permalink
Added new api call to callstack_instr plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
marco.cendejas committed Oct 30, 2024
1 parent 772b6d8 commit 3f135e0
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 4 deletions.
6 changes: 6 additions & 0 deletions panda/plugins/callstack_instr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ 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);

// 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
74 changes: 70 additions & 4 deletions panda/plugins/callstack_instr/callstack_instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ PANDAENDCOMMENT */

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

#include <capstone/capstone.h>
#if defined(TARGET_I386)
Expand Down Expand Up @@ -79,6 +81,9 @@ 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;
static std::string no_osi_msg = "OSI is not enabled";
static std::vector<char> no_osi_msg_vector(no_osi_msg.begin(), no_osi_msg.end());

enum instr_type {
INSTR_UNKNOWN = 0,
Expand Down Expand Up @@ -124,6 +129,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 @@ -375,17 +382,25 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
if (need_to_check) {
std::vector<stack_entry> &v = callstacks[cur_stackid];
std::vector<target_ulong> &w = function_stacks[cur_stackid];

if (v.empty()) {
return;
}

std::map<target_ulong, std::vector<char>> &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]);

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 +410,45 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
}
}

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

target_ulong end_addr;

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

std::shared_ptr<GArray> mappings(get_mappings(cpu, proc.get()),
[](GArray *a) {
if (a != nullptr) {
g_array_free(a, true);
}
});

if(nullptr != mappings) {
for(uint32_t i = 0; i < mappings->len; i++) {
OsiModule *osimodule = &g_array_index(mappings.get(), OsiModule, i);
end_addr = osimodule->base + (osimodule->size - 1);

if (pc >= osimodule->base && pc < end_addr) {
if (nullptr != osimodule->file) {
std::size_t len = strlen(osimodule->file);
std::vector<char> lib_str_buf(len + 1);
std::snprintf(lib_str_buf.data(), lib_str_buf.size(), "%s", osimodule->file);
return lib_str_buf;
} else if (nullptr != osimodule->name) {
std::size_t len = strlen(osimodule->name);
std::vector<char> lib_str_buf(len + 1);
std::snprintf(lib_str_buf.data(), lib_str_buf.size(), "%s", osimodule->name);
return lib_str_buf;
} else {
return std::vector<char>(1, '\0');
}
}
}
}

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 +464,8 @@ 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);
binary_info_stacks[curStackid][se.pc] =
include_binary_info ? getLib(cpu, se.pc) : no_osi_msg_vector;

// Also track the function that gets called
// This retrieves the pc in an architecture-neutral way
Expand Down Expand Up @@ -438,7 +494,6 @@ void after_block_exec(CPUState* cpu, TranslationBlock *tb, uint8_t exitCode) {
}
}


static uint32_t get_callers_priv(target_ulong callers[], uint32_t n,
CPUState* cpu, stackid stackid) {
std::vector<stack_entry> &v = callstacks[stackid];
Expand All @@ -455,6 +510,18 @@ 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) {
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();
}

return n;
}

#define CALLSTACK_MAX_SIZE 16
/**
Expand All @@ -474,7 +541,6 @@ Panda__CallStack *pandalog_callstack_create() {
return cs;
}


/**
* @brief Frees a pandalog entry containing callstack information.
*/
Expand All @@ -483,7 +549,6 @@ void pandalog_callstack_free(Panda__CallStack *cs) {
free(cs);
}


/**
* @brief Fills preallocated buffer \p functions with up to \p n function addresses.
*/
Expand Down Expand Up @@ -558,7 +623,6 @@ bool setup_osi() {
#endif
}


bool init_plugin(void *self) {

// get arguments to this plugin
Expand Down Expand Up @@ -678,6 +742,8 @@ bool init_plugin(void *self) {
printf("callstack_instr: using heuristic stack_type\n");
}

include_binary_info = setup_ok && (nullptr != panda_get_plugin_by_name("osi"));

return setup_ok;
}

Expand Down
4 changes: 4 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,10 @@ 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);

// END_PYPANDA_NEEDS_THIS -- do not delete this comment!

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

0 comments on commit 3f135e0

Please sign in to comment.