Skip to content

Commit 42648a9

Browse files
MarkMankinslacraig2
authored andcommitted
Optimize binary tracking in callstack_instr.
Updated README.md with an example of how to use the new api.
1 parent 902c66f commit 42648a9

File tree

3 files changed

+65
-49
lines changed

3 files changed

+65
-49
lines changed

panda/plugins/callstack_instr/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ uint32_t get_functions(target_ulong *functions, uint32_t n, CPUState *env);
6565
// Must have OSI enabled for this api to work.
6666
uint32_t get_binaries(char **libs, uint32_t n, CPUState *cpu);
6767

68+
// Must be called by plugins which intend to call get_binaries.
69+
void callstack_enable_binary_tracking(void);
70+
6871
// Get the current program point: (Caller, PC, stack ID)
6972
// This isn't quite the right place for it, but since it's awkward
7073
// right now to have a "utilities" library, this will have to do
@@ -102,10 +105,13 @@ Example
102105
103106
int some_plugin_fn(CPUState *env) {
104107
target_ulong callers[16];
108+
char *binaries[16];
105109
int n;
106110
n = get_callers(callers, 16, env);
111+
get_binaries(binaries, 16, env);
107112
for (int i = 0; i < n; i++)
108-
printf("Callstack entry: " TARGET_FMT_lx "\n", callers[i]);
113+
printf("Callstack entry: " TARGET_FMT_lx " %s\n", callers[i],
114+
binaries[i]);
109115
return 0;
110116
}
111117
@@ -114,5 +120,6 @@ int some_plugin_fn(CPUState *env) {
114120
bool init_plugin(void *self) {
115121
panda_require("callstack_instr");
116122
if (!init_callstack_instr_api()) return false;
123+
callstack_enable_binary_tracking();
117124
}
118125
```

panda/plugins/callstack_instr/callstack_instr.cpp

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ PANDAENDCOMMENT */
3030
#include <memory>
3131
#include <set>
3232
#include <vector>
33-
#include <utility>
3433

3534
#include <capstone/capstone.h>
3635
#if defined(TARGET_I386)
@@ -82,8 +81,6 @@ bool old_capstone=false; // Should we use fallback instruction group detection l
8281
// callstack_instr arguments
8382
static bool verbose = false;
8483
static bool include_binary_info = false;
85-
static std::string no_osi_msg = "OSI is not enabled";
86-
static std::vector<char> no_osi_msg_vector(no_osi_msg.begin(), no_osi_msg.end());
8784

8885
enum instr_type {
8986
INSTR_UNKNOWN = 0,
@@ -382,12 +379,15 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
382379
if (need_to_check) {
383380
std::vector<stack_entry> &v = callstacks[cur_stackid];
384381
std::vector<target_ulong> &w = function_stacks[cur_stackid];
385-
386382
if (v.empty()) {
387383
return;
388384
}
389385

390-
std::map<target_ulong, std::vector<char>> &binary_info_stack = binary_info_stacks[cur_stackid];
386+
std::map<target_ulong, std::vector<char>> *binary_info_stack = nullptr;
387+
388+
if(include_binary_info) {
389+
binary_info_stack = &binary_info_stacks[cur_stackid];
390+
}
391391

392392
// Search up to 10 down
393393
for (int i = v.size() - 1; i > ((int)(v.size() - 10)) && i >= 0; i--) {
@@ -397,8 +397,10 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
397397

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

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

404406
v.erase(v.begin() + i, v.end());
@@ -412,38 +414,22 @@ void before_block_exec(CPUState *cpu, TranslationBlock *tb) {
412414

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

415-
target_ulong end_addr;
416-
417417
std::shared_ptr<OsiProc> proc(get_current_process(cpu), free_osiproc);
418418

419-
std::shared_ptr<GArray> mappings(get_mappings(cpu, proc.get()),
420-
[](GArray *a) {
421-
if (a != nullptr) {
422-
g_array_free(a, true);
423-
}
424-
});
425-
426-
if(nullptr != mappings) {
427-
for(uint32_t i = 0; i < mappings->len; i++) {
428-
OsiModule *osimodule = &g_array_index(mappings.get(), OsiModule, i);
429-
end_addr = osimodule->base + (osimodule->size - 1);
430-
431-
if (pc >= osimodule->base && pc < end_addr) {
432-
if (nullptr != osimodule->file) {
433-
std::size_t len = strlen(osimodule->file);
434-
std::vector<char> lib_str_buf(len + 1);
435-
std::snprintf(lib_str_buf.data(), lib_str_buf.size(), "%s", osimodule->file);
436-
return lib_str_buf;
437-
} else if (nullptr != osimodule->name) {
438-
std::size_t len = strlen(osimodule->name);
439-
std::vector<char> lib_str_buf(len + 1);
440-
std::snprintf(lib_str_buf.data(), lib_str_buf.size(), "%s", osimodule->name);
441-
return lib_str_buf;
442-
} else {
443-
return std::vector<char>(1, '\0');
444-
}
445-
}
446-
}
419+
OsiModule *module = get_mapping_by_addr(cpu, proc.get(), pc);
420+
421+
if(nullptr != module) {
422+
const char *lib = "";
423+
if (nullptr != module->file) {
424+
lib = module->file;
425+
} else if (nullptr != module->name) {
426+
lib = module->name;
427+
}
428+
std::size_t len = strlen(lib);
429+
std::vector<char> lib_str_buf(len + 1);
430+
std::snprintf(lib_str_buf.data(), lib_str_buf.size(), "%s", lib);
431+
free_osimodule(module);
432+
return lib_str_buf;
447433
}
448434

449435
return std::vector<char>(1, '\0');
@@ -464,8 +450,9 @@ void after_block_exec(CPUState* cpu, TranslationBlock *tb, uint8_t exitCode) {
464450
if (tb_type == INSTR_CALL) {
465451
stack_entry se = {tb->pc + tb->size, tb_type};
466452
callstacks[curStackid].push_back(se);
467-
binary_info_stacks[curStackid][se.pc] =
468-
include_binary_info ? getLib(cpu, se.pc) : no_osi_msg_vector;
453+
if(include_binary_info) {
454+
binary_info_stacks[curStackid][se.pc] = getLib(cpu, se.pc);
455+
}
469456

470457
// Also track the function that gets called
471458
// This retrieves the pc in an architecture-neutral way
@@ -494,6 +481,7 @@ void after_block_exec(CPUState* cpu, TranslationBlock *tb, uint8_t exitCode) {
494481
}
495482
}
496483

484+
497485
static uint32_t get_callers_priv(target_ulong callers[], uint32_t n,
498486
CPUState* cpu, stackid stackid) {
499487
std::vector<stack_entry> &v = callstacks[stackid];
@@ -511,13 +499,26 @@ uint32_t get_callers(target_ulong callers[], uint32_t n, CPUState* cpu) {
511499
}
512500

513501
uint32_t get_binaries(char **libs, uint32_t n, CPUState *cpu) {
514-
stackid stack_id = get_stackid(cpu);
515-
std::vector<stack_entry> &call_stack = callstacks[stack_id];
516-
std::map<target_ulong, std::vector<char>> &binary_info_stack = binary_info_stacks[stack_id];
517-
518-
n = std::min((uint32_t) call_stack.size(), n);
519-
for (uint32_t i = 0; i < n; ++i) {
520-
libs[i] = binary_info_stack[call_stack[call_stack.size() - 1 - i].pc].data();
502+
static bool warning_shown = false;
503+
for(uint32_t i=0; i<n; libs[i++] = nullptr);
504+
if(include_binary_info) {
505+
stackid stack_id = get_stackid(cpu);
506+
std::vector<stack_entry> &call_stack = callstacks[stack_id];
507+
std::map<target_ulong, std::vector<char>> &binary_info_stack = binary_info_stacks[stack_id];
508+
509+
n = std::min((uint32_t) call_stack.size(), n);
510+
for (uint32_t i = 0; i < n; ++i) {
511+
libs[i] = binary_info_stack[call_stack[call_stack.size() - 1 - i].pc].data();
512+
}
513+
} else {
514+
if(!warning_shown) {
515+
fprintf(stderr, "WARNING: callstack_instr: get_binaries called "
516+
"but binary tracking not enabled. %s\n",
517+
(nullptr == panda_get_plugin_by_name("osi") ?
518+
"OSI plugin not loaded." : ""));
519+
warning_shown = true;
520+
}
521+
n = 0;
521522
}
522523

523524
return n;
@@ -541,6 +542,7 @@ Panda__CallStack *pandalog_callstack_create() {
541542
return cs;
542543
}
543544

545+
544546
/**
545547
* @brief Frees a pandalog entry containing callstack information.
546548
*/
@@ -549,6 +551,7 @@ void pandalog_callstack_free(Panda__CallStack *cs) {
549551
free(cs);
550552
}
551553

554+
552555
/**
553556
* @brief Fills preallocated buffer \p functions with up to \p n function addresses.
554557
*/
@@ -623,6 +626,7 @@ bool setup_osi() {
623626
#endif
624627
}
625628

629+
626630
bool init_plugin(void *self) {
627631

628632
// get arguments to this plugin
@@ -742,11 +746,13 @@ bool init_plugin(void *self) {
742746
printf("callstack_instr: using heuristic stack_type\n");
743747
}
744748

745-
include_binary_info = setup_ok && (nullptr != panda_get_plugin_by_name("osi"));
746-
747749
return setup_ok;
748750
}
749751

752+
void callstack_enable_binary_tracking() {
753+
include_binary_info = (nullptr != panda_get_plugin_by_name("osi"));
754+
}
755+
750756
void uninit_plugin(void *self) {
751757
// nothing to do
752758
}

panda/plugins/callstack_instr/callstack_instr_int_fns.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ uint32_t get_functions(target_ulong *functions, uint32_t n, CPUState *cpu);
2222
// Binaries are returned in libs[], most recent first
2323
uint32_t get_binaries(char **libs, uint32_t n, CPUState *cpu);
2424

25+
// Called by plugins that intend to call get_binaries.
26+
void callstack_enable_binary_tracking(void);
27+
2528
// END_PYPANDA_NEEDS_THIS -- do not delete this comment!
2629

2730
// NB: prog_point is c++, so beware

0 commit comments

Comments
 (0)