diff --git a/panda/plugins/callstack_instr/README.md b/panda/plugins/callstack_instr/README.md index bf2e2f4c337..ddcd02e4da0 100644 --- a/panda/plugins/callstack_instr/README.md +++ b/panda/plugins/callstack_instr/README.md @@ -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 diff --git a/panda/plugins/callstack_instr/callstack_instr.cpp b/panda/plugins/callstack_instr/callstack_instr.cpp index 06410e32f98..fcbf8c98daa 100644 --- a/panda/plugins/callstack_instr/callstack_instr.cpp +++ b/panda/plugins/callstack_instr/callstack_instr.cpp @@ -27,8 +27,10 @@ PANDAENDCOMMENT */ #include #include +#include #include #include +#include #include #if defined(TARGET_I386) @@ -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 no_osi_msg_vector(no_osi_msg.begin(), no_osi_msg.end()); enum instr_type { INSTR_UNKNOWN = 0, @@ -124,6 +129,8 @@ std::map> function_stacks; std::map call_cache; // stackid -> address of Stopped block std::map stoppedInfo; +// stackid -> (stack entry pc -> binary) +std::map>> binary_info_stacks; int last_ret_size = 0; @@ -375,10 +382,13 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) { if (need_to_check) { std::vector &v = callstacks[cur_stackid]; std::vector &w = function_stacks[cur_stackid]; + if (v.empty()) { return; } + std::map> &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) { @@ -386,6 +396,11 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) { // v.erase(v.begin()+i, v.end()); PPP_RUN_CB(on_ret, cpu, w[i]); + + for (std::vector::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()); @@ -395,6 +410,45 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) { } } +std::vector getLib(CPUState* cpu, target_ulong pc) { + + target_ulong end_addr; + + std::shared_ptr proc(get_current_process(cpu), free_osiproc); + + std::shared_ptr 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 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 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(1, '\0'); + } + } + } + } + + return std::vector(1, '\0'); +} + void after_block_exec(CPUState* cpu, TranslationBlock *tb, uint8_t exitCode) { target_ulong pc = 0x0; target_ulong cs_base = 0x0; @@ -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 @@ -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 &v = callstacks[stackid]; @@ -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 &call_stack = callstacks[stack_id]; + std::map> &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 /** @@ -474,7 +541,6 @@ Panda__CallStack *pandalog_callstack_create() { return cs; } - /** * @brief Frees a pandalog entry containing callstack information. */ @@ -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. */ @@ -558,7 +623,6 @@ bool setup_osi() { #endif } - bool init_plugin(void *self) { // get arguments to this plugin @@ -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; } diff --git a/panda/plugins/callstack_instr/callstack_instr_int_fns.h b/panda/plugins/callstack_instr/callstack_instr_int_fns.h index cde5ca25806..1a6d2eca6a0 100644 --- a/panda/plugins/callstack_instr/callstack_instr_int_fns.h +++ b/panda/plugins/callstack_instr/callstack_instr_int_fns.h @@ -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