diff --git a/demo/main.c b/demo/main.c index 52e6383..ecda3e9 100644 --- a/demo/main.c +++ b/demo/main.c @@ -44,7 +44,7 @@ int main(void) /* prepare tracer */ session = tracer_create_session(syscall, - TRACER_DISASM | TRACER_CONTEXT | TRACER_HEXDUMP); + TRACER_DISASM | TRACER_CONTEXT | TRACER_HEXDUMP | TRACER_CALLGRAPH); if (session == NULL) { dclear(C_WHITE); dtext(0, 0, C_BLACK, "Unable to create tracer session"); diff --git a/gintrace.g3a b/gintrace.g3a index 4a392eb..0351cf7 100644 Binary files a/gintrace.g3a and b/gintrace.g3a differ diff --git a/include/gintrace/gui/menu.h b/include/gintrace/gui/menu.h index bb34e91..4c34908 100644 --- a/include/gintrace/gui/menu.h +++ b/include/gintrace/gui/menu.h @@ -14,6 +14,11 @@ struct menu { int (*keyboard)(void *data, int key); void (*command)(void *data, int argc, char **argv); void (*dtor)(void *data); + + struct { + int (*ctor)(void *data); + int (*dtor)(void *data); + } special; }; /* menu group information */ @@ -55,6 +60,11 @@ extern int menu_unregister(struct menu_group *gmenus, const char *name); /* menu_is_open(): Return the menu status */ extern int menu_is_open(struct menu_group *gmenu); +/* menu_special_ctor(): Involve special contructor */ +extern int menu_special_ctor(struct menu_group *gmenu); +/* menu_special_dtor(): Involve special destructor */ +extern int menu_special_dtor(struct menu_group *gmenu); + /* menu_init(): Initialize all menu */ extern int menu_init(struct menu_group *gmenus); diff --git a/include/gintrace/menu/callgraph.h b/include/gintrace/menu/callgraph.h index f551ee5..af35522 100644 --- a/include/gintrace/menu/callgraph.h +++ b/include/gintrace/menu/callgraph.h @@ -30,6 +30,10 @@ struct callgraph { } cursor; struct callnode *root; struct callnode *parent; + struct { + uintptr_t breakpoint; + uintptr_t spc; + } special; }; /* extern menu information */ diff --git a/include/gintrace/tracer.h b/include/gintrace/tracer.h index 6581020..5473b62 100644 --- a/include/gintrace/tracer.h +++ b/include/gintrace/tracer.h @@ -17,6 +17,7 @@ struct tsession { void *starting; void *removed; struct ucontext *context; + void *buffctx; } info; /* display information */ diff --git a/libgintrace-cg.a b/libgintrace-cg.a index 5666350..e7297ef 100644 Binary files a/libgintrace-cg.a and b/libgintrace-cg.a differ diff --git a/src/gui/menu.c b/src/gui/menu.c index cf2b92c..6708358 100644 --- a/src/gui/menu.c +++ b/src/gui/menu.c @@ -71,6 +71,41 @@ int menu_unregister(struct menu_group *gmenu, const char *name) return (menu_retval_unregistered); } +/* menu_special_ctor(): Involve special contructor */ +int menu_special_ctor(struct menu_group *gmenu) +{ + struct menu_list *node; + int a; + + if (gmenu == NULL) + return (menu_retval_efault); + a = 0; + node = gmenu->list; + while (node != NULL) { + if (node->menu != NULL && node->menu->special.ctor != NULL) + a += node->menu->special.ctor((void*)gmenu->arg); + node = node->next; + } + return (a); +} +/* menu_special_ctor(): Involve special contructor */ +int menu_special_dtor(struct menu_group *gmenu) +{ + struct menu_list *node; + int a; + + if (gmenu == NULL) + return (menu_retval_efault); + a = 0; + node = gmenu->list; + while (node != NULL) { + if (node->menu != NULL && node->menu->special.dtor != NULL) + a += node->menu->special.dtor((void*)gmenu->arg); + node = node->next; + } + return (a); +} + /* menu_init(): Initialize all menu */ int menu_init(struct menu_group *gmenu) { diff --git a/src/menu/callgraph.c b/src/menu/callgraph.c index 04f6703..603674d 100644 --- a/src/menu/callgraph.c +++ b/src/menu/callgraph.c @@ -379,6 +379,42 @@ static void callgraph_command(struct tsession *session, int argc, char **argv) input_write("success"); } +/* callgraph_special_ctor(): Special constructor used to generate the graph */ +static int callgraph_special_ctor(struct tsession *session) +{ + struct callgraph *callgraph = &session->menu.callgraph; + + if (callgraph->special.breakpoint != 0x00000000 + && callgraph->special.spc != 0x00000000 + && callgraph->special.spc != callgraph->special.breakpoint) { + callgraph_init(session); + callgraph->special.spc = session->info.context->spc; + ubc_set_breakpoint(0, (void*)callgraph->special.spc, NULL); + return (1); + } + return (0); +} + +/* callgraph_special_dtor(): Special destructor used to bypass the breakpoint*/ +//TODO: update, bad interconnection with the disasm menu :( +static int callgraph_special_dtor(struct tsession *session) +{ + struct callgraph *callgraph = &session->menu.callgraph; + uintptr_t breakpoint; + + breakpoint = session->menu.disasm.next_break; + if (session->menu.disasm.skip == 0) { + callgraph->special.spc = session->info.context->spc; + ubc_set_breakpoint(0, (void*)callgraph->special.spc, NULL); + callgraph->special.breakpoint = breakpoint; + } else { + callgraph->special.breakpoint = breakpoint; + ubc_set_breakpoint(0, (void*)breakpoint, NULL); + callgraph->special.spc = breakpoint; + } + return (1); +} + //--- // Define the menu //--- @@ -388,5 +424,10 @@ struct menu menu_callgraph = { .display = (void*)&callgraph_display, .keyboard = (void*)&callgraph_keyboard, .command = (void*)&callgraph_command, - .dtor = NULL + .dtor = NULL, + + .special = { + .ctor = (void*)&callgraph_special_ctor, + .dtor = (void*)&callgraph_special_dtor, + } }; diff --git a/src/ubc/handler.c b/src/ubc/handler.c index 2c09362..2a1c07a 100644 --- a/src/ubc/handler.c +++ b/src/ubc/handler.c @@ -6,10 +6,7 @@ #include "gintrace/ubc.h" #include "gintrace/tracer.h" -#include - -// custom function -extern void *kernel_env_gint; +/* world information */ extern void *kernel_env_tracer; extern void *gint_switch_to_world(void *buffctx); @@ -18,14 +15,9 @@ extern void *gint_switch_to_world(void *buffctx); * To force generate the callgraph, we use a dirty workaround to force break * at each instruction. But, the disassembler menu can skip one instruction * using OPTN key, so you should not "unskip" the user action. */ -//FIXME: move breakpoint -//FIXME: move spc void gintrace_handler(struct ucontext *context) { - static uintptr_t breakpoint = 0x00000000; - static uintptr_t spc = 0x00000000; struct tsession *session; - void *buffctx; /* force disable the UBC to avoid error */ ubc_block(); @@ -38,39 +30,31 @@ void gintrace_handler(struct ucontext *context) } session->info.context = context; - /* check callgraph job */ - //FIXME: move me - if (breakpoint != 0x00000000 - && spc != 0x00000000 - && spc != breakpoint) { - menu_callgraph.init(session); - spc = context->spc; - ubc_set_breakpoint(0, (void*)context->spc, NULL); + /* check if the special job force skip the breakpoint + * @note: + * This feature is used by the callgraph menu to force the call graph + * generation.*/ + if (menu_special_ctor(session->display.gmenu) != 0) { ubc_unblock(); return; } /* user break point */ - buffctx = gint_switch_to_world(kernel_env_tracer); + session->info.buffctx = gint_switch_to_world(kernel_env_tracer); menu_init(session->display.gmenu); while (menu_is_open(session->display.gmenu) == 0) { menu_draw(session->display.gmenu); menu_keyboard(session->display.gmenu); } - /* if no instruction skip, restore */ - //FIXME: move me - if (session->menu.disasm.skip == 0) { - spc = context->spc; - ubc_set_breakpoint(0, (void*)context->spc, NULL); - breakpoint = session->menu.disasm.next_break; - } else { - breakpoint = session->menu.disasm.next_break; - ubc_set_breakpoint(0, (void*)breakpoint, NULL); - spc = breakpoint; + /* check if a special destructor overwrite the default breakpoint + * generation. If not, set the next break point. */ + if (menu_special_dtor(session->display.gmenu) == 0) { + ubc_set_breakpoint(0, + (void*)session->menu.disasm.next_break, NULL); } /* unblock UBC interrupt */ ubc_unblock(); - gint_switch_to_world(buffctx); + gint_switch_to_world(session->info.buffctx); }