diff --git a/TODO.txt b/TODO.txt index a49be5b..ecf6a5e 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,7 +3,10 @@ * fix fx9860 support @update +* context: refacto printXY() ! * hexdump: search commands +* callgraph: improve user interface. +* disasm: set manually multiple breakpoint * savefile * load saved file * list color scheme on SMEM. diff --git a/gintrace.g3a b/gintrace.g3a index 73c19b6..f309e1f 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 d0f068d..bb34e91 100644 --- a/include/gintrace/gui/menu.h +++ b/include/gintrace/gui/menu.h @@ -8,12 +8,12 @@ /* define menu information */ struct menu { - void (*ctor)(void); - void (*init)(struct ucontext *ctx); - void (*display)(struct ucontext *ctx); - int (*keyboard)(struct ucontext *ctx, int key); - void (*command)(struct ucontext *ctx, int argc, char **argv); - void (*dtor)(void); + void (*ctor)(void *data); + void (*init)(void *data); + void (*display)(void *data); + int (*keyboard)(void *data, int key); + void (*command)(void *data, int argc, char **argv); + void (*dtor)(void *data); }; /* menu group information */ @@ -42,7 +42,7 @@ enum { }; /* menu_create(): Create a group of menus */ -extern int menu_create(struct menu_group **gmenu); +extern int menu_create(struct menu_group **gmenu, volatile void *arg); /* menu_register(): Register a new menu to the internal menu table */ extern int menu_register(struct menu_group *gmenus, @@ -56,7 +56,7 @@ extern int menu_unregister(struct menu_group *gmenus, const char *name); extern int menu_is_open(struct menu_group *gmenu); /* menu_init(): Initialize all menu */ -extern int menu_init(struct menu_group *gmenus, volatile void *arg); +extern int menu_init(struct menu_group *gmenus); /* menu_draw(): Draw menu specific information and menu abstraction overlay */ extern int menu_draw(struct menu_group *gmenus); diff --git a/include/gintrace/menu/context.h b/include/gintrace/menu/context.h index 3679f0d..a221df3 100644 --- a/include/gintrace/menu/context.h +++ b/include/gintrace/menu/context.h @@ -5,7 +5,7 @@ #include /* mcontext: menu context internal structure */ -struct mcontext { +struct context { struct { int hoffset; int voffset; diff --git a/include/gintrace/menu/disasm.h b/include/gintrace/menu/disasm.h index e319083..d985956 100644 --- a/include/gintrace/menu/disasm.h +++ b/include/gintrace/menu/disasm.h @@ -1,5 +1,5 @@ -#ifndef __GINTRACE_TRACER_H__ -# define __GINTRACE_TRACER_H__ +#ifndef __GINTRACE_DISASM_H__ +# define __GINTRACE_DISASM_H__ #include #include @@ -17,7 +17,7 @@ struct buffcursor { }; /* tracer: internal information used to display disassembly view */ -struct tracer { +struct disasm { /* circular buffer information. * Note that the circular buffer is very special, it refert, on the * first level, the "instruction address" then, the second level its @@ -53,4 +53,4 @@ struct tracer { /* extern menu information */ extern struct menu menu_disasm; -#endif /*__GINTRACE_TRACER_H__*/ +#endif /*__GINTRACE_DISASM_H__*/ diff --git a/include/gintrace/tracer.h b/include/gintrace/tracer.h new file mode 100644 index 0000000..8594440 --- /dev/null +++ b/include/gintrace/tracer.h @@ -0,0 +1,55 @@ +#ifndef __GINTRACE_TRACER_H__ +# define __GINTRACE_TRACER_H__ + +#include +#include + +#include "gintrace/menu/hexdump.h" +#include "gintrace/menu/callgraph.h" +#include "gintrace/menu/disasm.h" +#include "gintrace/menu/context.h" +#include "gintrace/ubc.h" + +/* tsession: define the trace session information */ +struct tsession { + /* session information */ + struct { + void *starting; + struct ucontext *context; + } info; + + /* display information */ + struct { + struct menu_group *gmenu; + } display; + + /* menu information */ + struct { + struct disasm disasm; + struct callgraph callgraph; + struct context context; + struct hexdump hexdump; + } menu; +}; + +//--- +// User API +//--- +/* tracer_new_session(): Create a new session + * @note + * This function will create a new session based on the given menu + * information and the firt breakpoint address. + * */ +#define TRACER_DISASM (1 << 0) +#define TRACER_CONTEXT (1 << 1) +#define TRACER_HEXDUMP (1 << 2) +#define TRACER_CALLGRAPH (1 << 3) +extern struct tsession *tracer_create_session(void *address, int menu); + +/* tracer_get_session(): Get the current session. */ +extern struct tsession *tracer_get_session(void); + +/* tracer_get_session(): Set the current session. */ +extern struct tsession *tracer_set_session(struct tsession *session); + +#endif /*__GINTRACE_TRACER_H__*/ diff --git a/src/gui/menu.c b/src/gui/menu.c index 5c613d6..cf2b92c 100644 --- a/src/gui/menu.c +++ b/src/gui/menu.c @@ -12,11 +12,12 @@ #include /* menu_create(): Create a group of menus */ -int menu_create(struct menu_group **gmenu) +int menu_create(struct menu_group **gmenu, volatile void *arg) { *gmenu = calloc(sizeof(struct menu_group), 1); if (*gmenu == NULL) return (menu_retval_enomem); + (*gmenu)->arg = arg; return (menu_retval_success); } @@ -38,7 +39,7 @@ int menu_register(struct menu_group *gmenu, if (*node == NULL) return (menu_retval_enomem); if (menu != NULL && menu->ctor != NULL) - menu->ctor(); + menu->ctor((void*)gmenu->arg); if (gmenu->selected == NULL) gmenu->selected = menu; (*node)->menu = menu; @@ -71,7 +72,7 @@ int menu_unregister(struct menu_group *gmenu, const char *name) } /* menu_init(): Initialize all menu */ -int menu_init(struct menu_group *gmenu, volatile void *arg) +int menu_init(struct menu_group *gmenu) { struct menu_list *node; @@ -80,10 +81,9 @@ int menu_init(struct menu_group *gmenu, volatile void *arg) node = gmenu->list; while (node != NULL) { if (node->menu != NULL && node->menu->init != NULL) - node->menu->init((void*)arg); + node->menu->init((void*)gmenu->arg); node = node->next; } - gmenu->arg = arg; gmenu->is_open = 0; return (menu_retval_success); diff --git a/src/main.c b/src/main.c index 171cb8e..12ec687 100644 --- a/src/main.c +++ b/src/main.c @@ -1,90 +1,62 @@ -#include "gintrace/gui/menu.h" -#include "gintrace/menu/disasm.h" -#include "gintrace/menu/context.h" -#include "gintrace/menu/hexdump.h" -#include "gintrace/menu/callgraph.h" -#include "gintrace/ubc.h" +#include "gintrace/tracer.h" -#include -#include -#include #include +#include +#include +#include -/* workaround test */ -extern struct tracer tracer; - -/* save the selected menu */ -static struct menu_group *gmenu = NULL; - -/* syscall address */ -static void *syscall = NULL; - -/* gintrac_handler(): UBC handler - * @note: - * 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. */ -static void gintrace_handler(struct ucontext *context) -{ - static uintptr_t breakpoint = 0x00000000; - static uintptr_t spc = 0x00000000; - - /* force disable the UBC to avoid error */ - ubc_block(); - - /* check callgraph job */ - if (breakpoint != 0x00000000 - && spc != 0x00000000 - && spc != breakpoint) { - menu_callgraph.init(context); - spc = context->spc; - ubc_set_breakpoint(0, (void*)context->spc, NULL); - ubc_unblock(); - return; - } - - /* user break point */ - gint_switch_to_gint(); - menu_init(gmenu, context); - while (menu_is_open(gmenu) == 0) { - menu_draw(gmenu); - menu_keyboard(gmenu); - } - - /* if no instruction skip, restore */ - if (tracer.skip == 0) { - spc = context->spc; - ubc_set_breakpoint(0, (void*)context->spc, NULL); - breakpoint = tracer.next_break; - } else { - ubc_set_breakpoint(0, (void*)tracer.next_break, NULL); - breakpoint = tracer.next_break; - spc = tracer.next_break; - } - - - /* unblock UBC interrupt */ - ubc_unblock(); - gint_switch_to_casio(); -} - -/* casio_handler(): Casio handler */ -static void casio_handler(void) -{ - void (*bfile_openfile_os)(const uint16_t *filename, int mode, int p3); - - bfile_openfile_os = syscall; - bfile_openfile_os(u"\\\\fls0\\abcdefgijklmn", BFile_ReadOnly, 0); - -#if 0 - void (*debug_menu_filesystem)(void) = syscall; - debug_menu_filesystem(); -#endif -} /* main(): User entry */ int main(void) { + struct tsession *session; + void **systab; + void *syscall; + + /* get syscall address */ + systab = *(void ***)0x8002007c; + //syscall = systab[0x1e48]; // Fugue_debug_menu + syscall = systab[0x1da3]; // Bfile_OpenFile_OS + + + /* prepare tracer */ + session = tracer_create_session(syscall, + TRACER_DISASM | TRACER_CONTEXT | TRACER_HEXDUMP); + if (session == NULL) { + dclear(C_WHITE); + dtext(0, 0, C_BLACK, "Unable to create tracer session"); + dtext(0, 10, C_BLACK, "Press [MENU]..."); + dupdate(); + while (1) { getkey(); } + } + tracer_set_session(session); + + + + //--- + // TEST part + //--- + void (*bfile_openfile_os)(const uint16_t *filename, int mode, int p3); + + gint_switch_to_casio(); + bfile_openfile_os = syscall; + bfile_openfile_os(u"\\\\fls0\\abcdefgijklmn", BFile_ReadOnly, 0); + gint_switch_to_gint(); + + + + //--- + // Epilogue + // TODO: restart the trace ? + //--- + dclear(C_WHITE); + dtext(0, 0, C_BLACK, "session come to the end"); + dtext(0, 10, C_BLACK, "Press [MENU] to exit"); + dupdate(); + while (1) { getkey(); } + return (0); + +#if 0 /* initialize all internal menu and get the "first" menu to display */ menu_create(&gmenu); menu_register(gmenu, &menu_disasm, "Disasm"); @@ -97,6 +69,8 @@ int main(void) //syscall = systab[0x1e48]; // Fugue_debug_menu syscall = systab[0x1da3]; // Bfile_OpenFile_OS + /* prepare tracer */ + tracer_create_session(syscall, TRACER_DISASM | TRACER_CONTEXT | TRACER_HEXDUMP); /* intialize UBC information */ ubc_install(); @@ -108,4 +82,5 @@ int main(void) //TODO : destructor part !! return (0); +#endif } diff --git a/src/menu/callgraph.c b/src/menu/callgraph.c index 3b29b96..8044d8c 100644 --- a/src/menu/callgraph.c +++ b/src/menu/callgraph.c @@ -1,5 +1,6 @@ #include "gintrace/menu/callgraph.h" #include "gintrace/ubc.h" +#include "gintrace/tracer.h" #include "gintrace/gui/menu.h" #include "gintrace/gui/display.h" #include "gintrace/gui/input.h" @@ -13,13 +14,6 @@ #include "./src/menu/internal/dictionary.h" -/* define the menu information */ -/* TODO: find a way to have local information (session) */ -struct callgraph callgraph; - -/* internal buffer */ -static char line[256]; - //--- // callode management //--- @@ -85,7 +79,7 @@ static size_t callnode_generate_info(char *buf, } /* callnode_get_size(): Count the number of bytes that the callgraph take */ -static size_t callnode_export(int fd, struct callnode *node) +static size_t callnode_export(int fd, struct callnode *node, char line[]) { if (node == NULL) return (0); @@ -103,14 +97,19 @@ static size_t callnode_export(int fd, struct callnode *node) } /* check other node */ - size += callnode_export(fd, node->child); - size += callnode_export(fd, node->sibling); + size += callnode_export(fd, node->child, line); + size += callnode_export(fd, node->sibling, line); return (size); } /* callnode_display(): Display callnode information */ -static void callnode_display(struct callnode *node, uint32_t bitmap[4], - int *row, int depth) +struct cdinfo { + struct callgraph *callgraph; + uint32_t bitmap[4]; + int row; +}; +static void callnode_display(struct callnode *node, + struct cdinfo *info, int depth, char line[]) { char shift; char pipe; @@ -119,8 +118,11 @@ static void callnode_display(struct callnode *node, uint32_t bitmap[4], int x; int y; - if (node == NULL || *row + callgraph.cursor.voffset >= GUI_DISP_NB_ROW) + if (node == NULL + || info->row + info->callgraph->cursor.voffset >= GUI_DISP_NB_ROW) { return; + } + /* handle the bitmap (ugly / 20) */ i = -1; idx = 0; @@ -129,40 +131,40 @@ static void callnode_display(struct callnode *node, uint32_t bitmap[4], if (idx >= 4) break; shift = i & 0x1f; - if ((bitmap[idx] & (1 << shift)) != 0 - && *row + callgraph.cursor.voffset >= 0) { - x = callgraph.cursor.hoffset + (i << 2) + 2; - y = callgraph.cursor.voffset + (*row); + if ((info->bitmap[idx] & (1 << shift)) != 0 + && info->row + info->callgraph->cursor.voffset >= 0) { + x = info->callgraph->cursor.hoffset + (i << 2) + 2; + y = info->callgraph->cursor.voffset + info->row; gtextXY(x, y, "| "); } } /* generate the line */ pipe = '|'; - bitmap[idx] |= 1 << (depth & 0x1f); + info->bitmap[idx] |= 1 << (depth & 0x1f); if (node->type == callnode_type_jmp || node->type == callnode_type_rte || node->type == callnode_type_rts) { - bitmap[idx] &= ~(1 << (depth & 0x1f)); + info->bitmap[idx] &= ~(1 << (depth & 0x1f)); pipe = '`'; } /* display the line then check child and siblig */ - if (*row + callgraph.cursor.voffset >= 0) { + if (info->row + info->callgraph->cursor.voffset >= 0) { callnode_generate_info(line, 256, node); if (depth < 0) { - x = callgraph.cursor.hoffset + (i << 2); - y = callgraph.cursor.voffset + (*row); + x = info->callgraph->cursor.hoffset + (i << 2); + y = info->callgraph->cursor.voffset + info->row; gtextXY(x, y, line); } else { - x = callgraph.cursor.hoffset + (i << 2) + 2; - y = callgraph.cursor.voffset + (*row); + x = info->callgraph->cursor.hoffset + (i << 2) + 2; + y = info->callgraph->cursor.voffset + info->row; gprintXY(x, y, "%c-- %s", pipe, line); } } - *row = *row + 1; - callnode_display(node->child, bitmap, row, depth + 1); - callnode_display(node->sibling, bitmap, row, depth); + info->row = info->row + 1; + callnode_display(node->child, info, depth + 1, line); + callnode_display(node->sibling, info, depth, line); } //--- @@ -170,16 +172,15 @@ static void callnode_display(struct callnode *node, uint32_t bitmap[4], //--- /* callgraph_ctor: Menu constructor */ -static void callgraph_ctor(void) +static void callgraph_ctor(struct tsession *session) { - callgraph.cursor.hoffset = 0; - callgraph.cursor.voffset = 0; - callgraph.root = NULL; + session->menu.callgraph.cursor.hoffset = 0; + session->menu.callgraph.cursor.voffset = 0; + session->menu.callgraph.root = NULL; } /* callgraph_init(): Invoked each time a break point occur */ -/* FIXME: recursive !! */ -static void callgraph_init(struct ucontext *context) +static void callgraph_init(struct tsession *session) { struct callnode *node; uintptr_t address; @@ -188,114 +189,114 @@ static void callgraph_init(struct ucontext *context) int type; /* check root node */ - if (callgraph.root == NULL) { - node = callnode_create(NULL, context, - callnode_type_root, context->spc); + if (session->menu.callgraph.root == NULL) { + node = callnode_create(NULL, session->info.context, + callnode_type_root, session->info.context->spc); if (node == NULL) return; - callgraph.root = node; - callgraph.parent = callgraph.root; + session->menu.callgraph.root = node; + session->menu.callgraph.parent = session->menu.callgraph.root; } /* check error */ - if (callgraph.parent == NULL) + if (session->menu.callgraph.parent == NULL) return; /* check opcode */ type = -1; - pc = (void*)(uintptr_t)context->spc; + pc = (void*)(uintptr_t)session->info.context->spc; if ((pc[0] & 0xf000) == 0xb000) { type = callnode_type_bsr; b = pc[0] & 0x0fff; if ((b & 0x800) != 0) b = (0xfffff000 | b); - address = context->spc + 4 + (b << 1); + address = session->info.context->spc + 4 + (b << 1); } if ((pc[0] & 0xf0ff) == 0x0003) { type = callnode_type_bsrf; b = (pc[0] & 0x0f00) >> 8; - address = context->reg[b]; + address = session->info.context->reg[b]; } if ((pc[0] & 0xf0ff) == 0x400b) { type = callnode_type_jsr; b = (pc[0] & 0x0f00) >> 8; - address = context->reg[b]; + address = session->info.context->reg[b]; } if ((pc[0] & 0xf0ff) == 0x402b) { type = callnode_type_jmp; b = (pc[0] & 0x0f00) >> 8; - address = context->reg[b]; + address = session->info.context->reg[b]; } if ((pc[0] & 0xffff) == 0x002b) { type = callnode_type_rte; - address = context->spc; + address = session->info.context->spc; } if ((pc[0] & 0xffff) == 0x000b) { type = callnode_type_rts; - address = context->spc; + address = session->info.context->spc; } if (type == -1) return; /* generate the node then link with its sibling */ - node = callnode_create(callgraph.parent, context, type, address); + node = callnode_create(session->menu.callgraph.parent, + session->info.context, type, address); if (node == NULL) return; - callnode_add_child(callgraph.parent, node); + callnode_add_child(session->menu.callgraph.parent, node); /* find the next "current" node */ if (node->type == callnode_type_bsr || node->type == callnode_type_jsr || node->type == callnode_type_bsrf || node->type == callnode_type_jmp) { - callgraph.parent = node; + session->menu.callgraph.parent = node; return; } - while (callgraph.parent != NULL) { - if (callgraph.parent->type == callnode_type_jmp) { - callgraph.parent = callgraph.parent->parent; + while (session->menu.callgraph.parent != NULL) { + if (session->menu.callgraph.parent->type == callnode_type_jmp){ + session->menu.callgraph.parent = + session->menu.callgraph.parent->parent; continue; } - callgraph.parent = callgraph.parent->parent; + session->menu.callgraph.parent = + session->menu.callgraph.parent->parent; return; } } /* callgraph_display(); Display trace information */ -static void callgraph_display(struct ucontext *context) +static void callgraph_display(struct tsession *session) { - uint32_t bitmap[4]; - int row; + struct cdinfo info; + char line[256]; - (void)context; - row = 0; - memset(bitmap, 0x00, sizeof(bitmap)); - callnode_display(callgraph.root, bitmap, &row, -1); + memset(&info, 0x00, sizeof(info)); + info.callgraph = &session->menu.callgraph; + callnode_display(session->menu.callgraph.root, &info, -1, line); } /* callgraph_keyboard(): Handle one key event */ -static int callgraph_keyboard(struct ucontext *context, int key) +static int callgraph_keyboard(struct tsession *session, int key) { - (void)context; if (key == KEY_LEFT) - callgraph.cursor.hoffset += 1; + session->menu.callgraph.cursor.hoffset += 1; if (key == KEY_RIGHT) - callgraph.cursor.hoffset -= 1; + session->menu.callgraph.cursor.hoffset -= 1; if (key == KEY_UP) - callgraph.cursor.voffset += 1; + session->menu.callgraph.cursor.voffset += 1; if (key == KEY_DOWN) - callgraph.cursor.voffset -= 1; + session->menu.callgraph.cursor.voffset -= 1; return (0); } /* callgraph_command(): handle user command */ -static void callgraph_command(struct ucontext *context, int argc, char **argv) +static void callgraph_command(struct tsession *session, int argc, char **argv) { /* check useless export */ - (void)context; - if (callgraph.root == NULL) { + if (session->menu.callgraph.root == NULL) { input_write("nothing to export"); return; } @@ -311,7 +312,6 @@ static void callgraph_command(struct ucontext *context, int argc, char **argv) } /* convert the filename (arg2) into Bfile pathname */ - /* TODO: handle special extention */ int i = -1; uint16_t pathname[14 + strlen(argv[1]) + 1]; memcpy(pathname, u"\\\\fls0\\", 14); @@ -322,6 +322,7 @@ static void callgraph_command(struct ucontext *context, int argc, char **argv) /* check if the file exist */ input_write_noint("Check if the file exist"); gint_switch_to_casio(); + char line[256]; int fd = BFile_Open(pathname, BFile_ReadOnly); if (fd >= 0) { gint_switch_to_gint(); @@ -345,7 +346,7 @@ static void callgraph_command(struct ucontext *context, int argc, char **argv) /* create the file then dump information */ gint_switch_to_gint(); - int size = callnode_export(-1, callgraph.root); + int size = callnode_export(-1, session->menu.callgraph.root, line); input_write_noint("Create the file (%d)", size); gint_switch_to_casio(); fd = BFile_Create(pathname, BFile_File, &size); @@ -367,7 +368,7 @@ static void callgraph_command(struct ucontext *context, int argc, char **argv) gint_switch_to_gint(); input_write_noint("Open success, now write..."); gint_switch_to_casio(); - callnode_export(fd, callgraph.root); + callnode_export(fd, session->menu.callgraph.root, line); BFile_Close(fd); gint_switch_to_gint(); input_write("success"); @@ -377,10 +378,10 @@ static void callgraph_command(struct ucontext *context, int argc, char **argv) // Define the menu //--- struct menu menu_callgraph = { - .ctor = &callgraph_ctor, - .init = &callgraph_init, - .display = &callgraph_display, - .keyboard = &callgraph_keyboard, - .command = &callgraph_command, + .ctor = (void*)&callgraph_ctor, + .init = (void*)&callgraph_init, + .display = (void*)&callgraph_display, + .keyboard = (void*)&callgraph_keyboard, + .command = (void*)&callgraph_command, .dtor = NULL }; diff --git a/src/menu/context.c b/src/menu/context.c index 84a90c3..331b701 100644 --- a/src/menu/context.c +++ b/src/menu/context.c @@ -1,5 +1,6 @@ #include "gintrace/menu/context.h" #include "gintrace/ubc.h" +#include "gintrace/tracer.h" #include "gintrace/gui/menu.h" #include "gintrace/gui/display.h" @@ -8,9 +9,6 @@ #include "./src/menu/internal/dictionary.h" -/* define the menu information */ -/* TODO: find a way to have local information (session) */ -struct mcontext mcontext; //--- // Internal information @@ -50,58 +48,57 @@ static void printXY(int column, int row, const char *text, uintptr_t reg) } /* context_ctor: Menu constructor */ -static void context_ctor(void) +static void context_ctor(struct tsession *session) { - mcontext.cursor.hoffset = 0; - mcontext.cursor.voffset = 0; + session->menu.context.cursor.hoffset = 0; + session->menu.context.cursor.voffset = 0; } /* context_display(); Display trace information */ -static void context_display(struct ucontext *context) +static void context_display(struct tsession *session) { int x; int y; - x = mcontext.cursor.hoffset; - y = mcontext.cursor.voffset; - printXY(0 + x, 0 + y, "gbr : %p", context->gbr); - printXY(0 + x, 1 + y, "macl : %p", context->mach); - printXY(0 + x, 2 + y, "mach : %p", context->macl); - printXY(0 + x, 3 + y, "ssr : %p", context->ssr); - printXY(0 + x, 4 + y, "pr : %p", context->pr); - printXY(0 + x, 5 + y, "spc : %p", context->spc); + x = session->menu.context.cursor.hoffset; + y = session->menu.context.cursor.voffset; + printXY(0 + x, 0 + y, "gbr : %p", session->info.context->gbr); + printXY(0 + x, 1 + y, "macl : %p", session->info.context->mach); + printXY(0 + x, 2 + y, "mach : %p", session->info.context->macl); + printXY(0 + x, 3 + y, "ssr : %p", session->info.context->ssr); + printXY(0 + x, 4 + y, "pr : %p", session->info.context->pr); + printXY(0 + x, 5 + y, "spc : %p", session->info.context->spc); - printXY(0 + x, 7 + y, "r0 : %p", context->reg[0]); - printXY(0 + x, 8 + y, "r1 : %p", context->reg[1]); - printXY(0 + x, 9 + y, "r2 : %p", context->reg[2]); - printXY(0 + x, 10 + y, "r3 : %p", context->reg[3]); - printXY(0 + x, 11 + y, "r4 : %p", context->reg[4]); - printXY(0 + x, 12 + y, "r5 : %p", context->reg[5]); - printXY(0 + x, 13 + y, "r6 : %p", context->reg[6]); - printXY(0 + x, 14 + y, "r7 : %p", context->reg[7]); - printXY(0 + x, 15 + y, "r8 : %p", context->reg[8]); - printXY(0 + x, 16 + y, "r9 : %p", context->reg[9]); - printXY(0 + x, 17 + y, "r10 : %p", context->reg[10]); - printXY(0 + x, 18 + y, "r11 : %p", context->reg[11]); - printXY(0 + x, 19 + y, "r12 : %p", context->reg[12]); - printXY(0 + x, 20 + y, "r13 : %p", context->reg[13]); - printXY(0 + x, 21 + y, "r14 : %p", context->reg[14]); - printXY(0 + x, 22 + y, "r15 : %p", context->reg[15]); + printXY(0 + x, 7 + y, "r0 : %p", session->info.context->reg[0]); + printXY(0 + x, 8 + y, "r1 : %p", session->info.context->reg[1]); + printXY(0 + x, 9 + y, "r2 : %p", session->info.context->reg[2]); + printXY(0 + x, 10 + y, "r3 : %p", session->info.context->reg[3]); + printXY(0 + x, 11 + y, "r4 : %p", session->info.context->reg[4]); + printXY(0 + x, 12 + y, "r5 : %p", session->info.context->reg[5]); + printXY(0 + x, 13 + y, "r6 : %p", session->info.context->reg[6]); + printXY(0 + x, 14 + y, "r7 : %p", session->info.context->reg[7]); + printXY(0 + x, 15 + y, "r8 : %p", session->info.context->reg[8]); + printXY(0 + x, 16 + y, "r9 : %p", session->info.context->reg[9]); + printXY(0 + x, 17 + y, "r10 : %p", session->info.context->reg[10]); + printXY(0 + x, 18 + y, "r11 : %p", session->info.context->reg[11]); + printXY(0 + x, 19 + y, "r12 : %p", session->info.context->reg[12]); + printXY(0 + x, 20 + y, "r13 : %p", session->info.context->reg[13]); + printXY(0 + x, 21 + y, "r14 : %p", session->info.context->reg[14]); + printXY(0 + x, 22 + y, "r15 : %p", session->info.context->reg[15]); } /* context_keyboard(): Handle one key event */ -static int context_keyboard(struct ucontext *context, int key) +static int context_keyboard(struct tsession *session, int key) { - (void)context; if (key == KEY_LEFT) - mcontext.cursor.hoffset += 1; + session->menu.context.cursor.hoffset += 1; if (key == KEY_RIGHT) - mcontext.cursor.hoffset -= 1; + session->menu.context.cursor.hoffset -= 1; if (key == KEY_UP) - mcontext.cursor.voffset += 1; + session->menu.context.cursor.voffset += 1; if (key == KEY_DOWN) - mcontext.cursor.voffset -= 1; + session->menu.context.cursor.voffset -= 1; return (0); } @@ -110,10 +107,10 @@ static int context_keyboard(struct ucontext *context, int key) // Define the menu //--- struct menu menu_context = { - .ctor = &context_ctor, + .ctor = (void*)&context_ctor, .init = NULL, - .display = &context_display, - .keyboard = &context_keyboard, + .display = (void*)&context_display, + .keyboard = (void*)&context_keyboard, .command = NULL, .dtor = NULL }; diff --git a/src/menu/disasm.c b/src/menu/disasm.c index 140090f..9c8bc88 100644 --- a/src/menu/disasm.c +++ b/src/menu/disasm.c @@ -1,5 +1,6 @@ #include "gintrace/menu/disasm.h" #include "gintrace/ubc.h" +#include "gintrace/tracer.h" #include "gintrace/gui/menu.h" #include "gintrace/gui/display.h" #include "gintrace/gui/input.h" @@ -12,10 +13,6 @@ #include #include -/* define the menu information */ -/* TODO: find a way to have local information (session) */ -struct tracer tracer; - /* disasm_util_line_update(): Little helper to update the line index * @nte: @@ -28,16 +25,17 @@ struct tracer tracer; * * @return * - the new line index */ -static int disasm_util_line_update(int line_idx, int direction) +static int disasm_util_line_update(struct disasm *disasm, + int line_idx, int direction) { line_idx = line_idx + direction; while (1) { if (line_idx < 0) { - line_idx += (int)tracer.buffer.size.height; + line_idx += (int)disasm->buffer.size.height; continue; } - if (line_idx >= (int)tracer.buffer.size.height) { - line_idx -= (int)tracer.buffer.size.height; + if (line_idx >= (int)disasm->buffer.size.height) { + line_idx -= (int)disasm->buffer.size.height; continue; } break; @@ -59,9 +57,9 @@ static int disasm_util_line_update(int line_idx, int direction) * type & 1 -> check hardware module register * type & 2 -> check syscall address * type & 4 -> check OS-specific address */ -static void disasm_check_special_addr(char *buffer, void *address, int type) +static void disasm_check_special_addr(struct disasm *disasm, + char *buffer, void *address, int type) { - extern struct tracer tracer; const char *addrname; addrname = NULL; @@ -73,7 +71,7 @@ static void disasm_check_special_addr(char *buffer, void *address, int type) addrname = dictionary_notes_check(address); if (addrname == NULL) return; - snprintf(buffer, tracer.buffer.size.width, + snprintf(buffer, disasm->buffer.size.width, "@note: %p -> %s\n", address, addrname); } @@ -91,7 +89,8 @@ static void disasm_check_special_addr(char *buffer, void *address, int type) * @arg: * - line Line index, used to find the buffer line to store information * - pc Current Program Counter which store the instruction address */ -static void disasm_get_mnemonic_info(int line, uint16_t *pc) +static void disasm_get_mnemonic_info(struct disasm *disasm, + int line, uint16_t *pc) { const struct opcode *opcode_info; uint16_t opcode; @@ -99,29 +98,29 @@ static void disasm_get_mnemonic_info(int line, uint16_t *pc) int note; /* Wipe note */ - tracer.buffer.raw[line][0][0] = '\0'; - tracer.buffer.raw[line][1][0] = '\0'; - tracer.buffer.raw[line][2][0] = '\0'; - tracer.buffer.raw[line][3][0] = '\0'; - tracer.buffer.raw[line][4][0] = '\0'; + disasm->buffer.raw[line][0][0] = '\0'; + disasm->buffer.raw[line][1][0] = '\0'; + disasm->buffer.raw[line][2][0] = '\0'; + disasm->buffer.raw[line][3][0] = '\0'; + disasm->buffer.raw[line][4][0] = '\0'; /* check special address (register, syscall, ...) */ note = 1; - disasm_check_special_addr(tracer.buffer.raw[line][note], pc, 6); - if (tracer.buffer.raw[line][note][0] != '\0') + disasm_check_special_addr(disasm, disasm->buffer.raw[line][note], pc, 6); + if (disasm->buffer.raw[line][note][0] != '\0') note += 1; /* generate the "default" string info (only the address and word) */ - snprintf(&tracer.buffer.raw[line][0][0], - tracer.buffer.size.width, "%.8lx %.4x ", + snprintf(&disasm->buffer.raw[line][0][0], + disasm->buffer.size.width, "%.8lx %.4x ", (uintptr_t)pc, (unsigned int)pc[0]); /* Try to get the current opcode */ opcode = pc[0]; opcode_info = dictionary_opcodes_check(opcode); if (opcode_info == NULL) { - snprintf(&tracer.buffer.raw[line][0][14], - tracer.buffer.size.width - 14, + snprintf(&disasm->buffer.raw[line][0][14], + disasm->buffer.size.width - 14, ".word\t%#.4x", (int)opcode); return; } @@ -131,13 +130,14 @@ static void disasm_get_mnemonic_info(int line, uint16_t *pc) arg[i] = dictionary_opcodes_get_arg(opcode_info, opcode, i, pc); if (arg[i] == 0x00000000) continue; - disasm_check_special_addr(tracer.buffer.raw[line][note++], + disasm_check_special_addr(disasm, + disasm->buffer.raw[line][note++], (void*)arg[i], 7); } /* generate the complete mnemonic information */ - snprintf(&tracer.buffer.raw[line][0][14], - tracer.buffer.size.width - 14, + snprintf(&disasm->buffer.raw[line][0][14], + disasm->buffer.size.width - 14, opcode_info->name, arg[0], arg[1], arg[2]); } @@ -152,13 +152,13 @@ static void disasm_get_mnemonic_info(int line, uint16_t *pc) * * @return * The note index max of the line_idx */ -static int disasm_util_note_counter(int line_idx) +static int disasm_util_note_counter(struct disasm *disasm, int line_idx) { int note_idx; note_idx = 0; while (++note_idx < 5) { - if (tracer.buffer.raw[line_idx][note_idx][0] == '\0') + if (disasm->buffer.raw[line_idx][note_idx][0] == '\0') break; } return (note_idx - 1); @@ -188,12 +188,13 @@ static int disasm_util_row_update(int *row, int direction) * - line_idx Line index * - pc Memory address * - direction Direction to push the limit */ -static void disasm_util_line_fetch(int line_idx, uint16_t *pc, int direction) +static void disasm_util_line_fetch(struct disasm *disasm, int line_idx, + uint16_t *pc, int direction) { - if (tracer.buffer.raw[line_idx][0][0] == '\0') { - disasm_get_mnemonic_info(line_idx, pc); - line_idx = disasm_util_line_update(line_idx, direction); - tracer.buffer.raw[line_idx][0][0] = '\0'; + if (disasm->buffer.raw[line_idx][0][0] == '\0') { + disasm_get_mnemonic_info(disasm, line_idx, pc); + line_idx = disasm_util_line_update(disasm, line_idx, direction); + disasm->buffer.raw[line_idx][0][0] = '\0'; } } @@ -217,43 +218,44 @@ static void disasm_util_line_fetch(int line_idx, uint16_t *pc, int direction) * @return * - 0 Row is still on the screen * - 1 Row is out-of-screen */ -int disasm_display_addr_info(int *row, struct buffcursor *cursor, - struct ucontext *context, int direction, int pc) +int disasm_display_addr_info(struct tsession *session, int *row, + struct buffcursor *cursor, int direction, int pc) { + struct disasm *disasm = &session->menu.disasm; int note_max_idx; void *ptr; /* generate the line if missing and move the limit */ - disasm_util_line_fetch(cursor->line_idx, - &tracer.buffer.anchor.addr[pc], direction); + disasm_util_line_fetch(disasm, cursor->line_idx, + &disasm->buffer.anchor.addr[pc], direction); /* get the last note index if downward */ note_max_idx = 5; if (direction == 1) - note_max_idx = disasm_util_note_counter(cursor->line_idx); + note_max_idx = disasm_util_note_counter(disasm, cursor->line_idx); /* walk trough the notes */ while (cursor->note_idx <= note_max_idx && cursor->note_idx >= 0) { /* check loop condition */ - ptr = tracer.buffer.raw[cursor->line_idx][cursor->note_idx]; + ptr = disasm->buffer.raw[cursor->line_idx][cursor->note_idx]; if (((char*)ptr)[0] == '\0') break; /* check note */ if (cursor->note_idx != 0) { - gnoteXY(tracer.disp.hoffset, *row, ptr); + gnoteXY(disasm->disp.hoffset, *row, ptr); } else { /* check instruction */ - gtextXY(tracer.disp.hoffset, *row, ptr); + gtextXY(disasm->disp.hoffset, *row, ptr); /* highlight SPC if possible */ - ptr = &tracer.buffer.anchor.addr[pc]; - if ((uintptr_t)ptr == context->spc) + ptr = &disasm->buffer.anchor.addr[pc]; + if ((uintptr_t)ptr == session->info.context->spc) ghreverse((*row) * (FHEIGHT+1) - 1, FHEIGHT+2); /* draw next break / instruction */ - if (tracer.next_break != context->spc - && ptr == (void*)tracer.next_break) { + if (disasm->next_break != session->info.context->spc + && ptr == (void*)disasm->next_break) { ghline(((*row) + 0) * (FHEIGHT + 1) - 1); ghline(((*row) + 1) * (FHEIGHT + 1) - 1); } @@ -273,67 +275,75 @@ int disasm_display_addr_info(int *row, struct buffcursor *cursor, // Menu functions //--- /* disasm_ctor(): disasm menu constructor */ -static void disasm_ctor(void) +static void disasm_ctor(struct tsession *session) { - memset(&tracer, 0x00, sizeof(struct tracer)); - tracer.buffer.size.width = GUI_DISP_NB_COLUMN * 2; - tracer.buffer.size.height = GUI_DISP_NB_ROW * 2 + 2; - tracer.buffer.raw = calloc(sizeof(void*), tracer.buffer.size.height); - for (size_t i = 0; i < tracer.buffer.size.height; ++i) { - tracer.buffer.raw[i] = calloc(sizeof(char*), 5); - tracer.buffer.raw[i][0] = calloc(tracer.buffer.size.width, 1); - tracer.buffer.raw[i][1] = calloc(tracer.buffer.size.width, 1); - tracer.buffer.raw[i][2] = calloc(tracer.buffer.size.width, 1); - tracer.buffer.raw[i][3] = calloc(tracer.buffer.size.width, 1); - tracer.buffer.raw[i][4] = calloc(tracer.buffer.size.width, 1); + struct disasm *disasm = &session->menu.disasm; + + memset(disasm, 0x00, sizeof(struct disasm)); + disasm->buffer.size.width = GUI_DISP_NB_COLUMN * 2; + disasm->buffer.size.height = GUI_DISP_NB_ROW * 2 + 2; + disasm->buffer.raw = calloc(sizeof(void*), disasm->buffer.size.height); + for (size_t i = 0; i < disasm->buffer.size.height; ++i) { + disasm->buffer.raw[i] = calloc(sizeof(char*), 5); + disasm->buffer.raw[i][0] = calloc(disasm->buffer.size.width, 1); + disasm->buffer.raw[i][1] = calloc(disasm->buffer.size.width, 1); + disasm->buffer.raw[i][2] = calloc(disasm->buffer.size.width, 1); + disasm->buffer.raw[i][3] = calloc(disasm->buffer.size.width, 1); + disasm->buffer.raw[i][4] = calloc(disasm->buffer.size.width, 1); } - tracer.buffer.cursor.line_idx = 0; - tracer.buffer.cursor.note_idx = 0; - tracer.disp.hoffset = 0; - tracer.disp.voffset = 0; + disasm->buffer.cursor.line_idx = 0; + disasm->buffer.cursor.note_idx = 0; + disasm->disp.hoffset = 0; + disasm->disp.voffset = 0; } /* disasm_dtor(): disasm menu destructor */ -static void disasm_dtor(void) +static void disasm_dtor(struct tsession *session) { - if (tracer.buffer.raw != NULL) { - for (size_t i = 0; i < tracer.buffer.size.height; ++i) { - if (tracer.buffer.raw[i] == NULL) + struct disasm *disasm; + + disasm = &session->menu.disasm; + if (disasm->buffer.raw != NULL) { + for (size_t i = 0; i < disasm->buffer.size.height; ++i) { + if (disasm->buffer.raw[i] == NULL) continue; - free(tracer.buffer.raw[i][0]); - free(tracer.buffer.raw[i][1]); - free(tracer.buffer.raw[i][2]); - free(tracer.buffer.raw[i][3]); - free(tracer.buffer.raw[i][4]); - free(tracer.buffer.raw[i]); + free(disasm->buffer.raw[i][0]); + free(disasm->buffer.raw[i][1]); + free(disasm->buffer.raw[i][2]); + free(disasm->buffer.raw[i][3]); + free(disasm->buffer.raw[i][4]); + free(disasm->buffer.raw[i]); } - free(tracer.buffer.raw); + free(disasm->buffer.raw); } - memset(&tracer, 0x00, sizeof(struct tracer)); + memset(disasm, 0x00, sizeof(struct disasm)); } /* disasm_init(): Called at each breakpoint, update the internal buffer */ -static void disasm_init(struct ucontext *context) +static void disasm_init(struct tsession *session) { + struct disasm *disasm = &session->menu.disasm; int a; - tracer.skip = 0; - tracer.buffer.anchor.addr = (void*)(uintptr_t)((context->spc + 1) & ~1); - tracer.next_break = context->spc; - tracer.next_instruction = context->spc; + disasm->skip = 0; + disasm->buffer.anchor.addr = + (void*)(uintptr_t)((session->info.context->spc + 1) & ~1); + disasm->next_break = session->info.context->spc; + disasm->next_instruction = session->info.context->spc; - tracer.buffer.cursor.note_idx = 0; - tracer.buffer.cursor.line_idx = 0; - a = disasm_util_line_update(tracer.buffer.cursor.line_idx, -1); - tracer.buffer.raw[a][0][0] = '\0'; - tracer.buffer.raw[tracer.buffer.cursor.line_idx][0][0] = '\0'; - disasm_util_line_fetch(tracer.buffer.cursor.line_idx, - &tracer.buffer.anchor.addr[0], 1); + disasm->buffer.cursor.note_idx = 0; + disasm->buffer.cursor.line_idx = 0; + a = disasm_util_line_update(disasm, disasm->buffer.cursor.line_idx, -1); + disasm->buffer.raw[a][0][0] = '\0'; + disasm->buffer.raw[disasm->buffer.cursor.line_idx][0][0] = '\0'; + disasm_util_line_fetch(disasm, disasm->buffer.cursor.line_idx, + &disasm->buffer.anchor.addr[0], 1); } /* disasm_display(); Display trace information */ -static void disasm_display(struct ucontext *context) +static void disasm_display(struct tsession *session) { + struct disasm *disasm = &session->menu.disasm; struct buffcursor cursor; int row; int pc; @@ -341,12 +351,12 @@ static void disasm_display(struct ucontext *context) /* display the first part (current middle line and before, upward) */ pc = 0; row = GUI_DISP_NB_ROW / 2; - cursor.line_idx = tracer.buffer.cursor.line_idx; - cursor.note_idx = tracer.buffer.cursor.note_idx; - disasm_display_addr_info(&row, &cursor, context, -1, pc); + cursor.line_idx = disasm->buffer.cursor.line_idx; + cursor.note_idx = disasm->buffer.cursor.note_idx; + disasm_display_addr_info(session, &row, &cursor, -1, pc); while (row >= 0) { - disasm_display_addr_info(&row, &cursor, context, -1, pc); - cursor.line_idx = disasm_util_line_update(cursor.line_idx, -1); + disasm_display_addr_info(session, &row, &cursor, -1, pc); + cursor.line_idx = disasm_util_line_update(disasm, cursor.line_idx, -1); cursor.note_idx = 0; pc = pc - 1; } @@ -360,82 +370,82 @@ static void disasm_display(struct ucontext *context) * information, get the note index max then start displaying lines. */ pc = 0; row = (GUI_DISP_NB_ROW / 2) + 1; - cursor.line_idx = tracer.buffer.cursor.line_idx; - cursor.note_idx = tracer.buffer.cursor.note_idx - 1; + cursor.line_idx = disasm->buffer.cursor.line_idx; + cursor.note_idx = disasm->buffer.cursor.note_idx - 1; if (cursor.note_idx < 0) { pc = 1; - cursor.line_idx = disasm_util_line_update(cursor.line_idx, 1); - disasm_util_line_fetch(cursor.line_idx, - &tracer.buffer.anchor.addr[pc], 1); - cursor.note_idx = disasm_util_note_counter(cursor.line_idx); + cursor.line_idx = disasm_util_line_update(disasm, cursor.line_idx, 1); + disasm_util_line_fetch(disasm, cursor.line_idx, + &disasm->buffer.anchor.addr[pc], 1); + cursor.note_idx = disasm_util_note_counter(disasm, cursor.line_idx); } while (row <= GUI_DISP_NB_ROW) { - disasm_display_addr_info(&row, &cursor, context, 1, pc); + disasm_display_addr_info(session, &row, &cursor, 1, pc); pc = pc + 1; - cursor.line_idx = disasm_util_line_update(cursor.line_idx, 1); - disasm_util_line_fetch(cursor.line_idx, - &tracer.buffer.anchor.addr[pc], 1); - cursor.note_idx = disasm_util_note_counter(cursor.line_idx); + cursor.line_idx = disasm_util_line_update(disasm, cursor.line_idx, 1); + disasm_util_line_fetch(disasm, cursor.line_idx, + &disasm->buffer.anchor.addr[pc], 1); + cursor.note_idx = disasm_util_note_counter(disasm, cursor.line_idx); } } /* disasm_keyboard(): Handle one key event */ -static int disasm_keyboard(struct ucontext *context, int key) +static int disasm_keyboard(struct tsession *session, int key) { + struct disasm *disasm = &session->menu.disasm; int note_idx; int line_idx; /* horizontal update */ - (void)context; if (key == KEY_LEFT) - tracer.disp.hoffset += 1; + disasm->disp.hoffset += 1; if (key == KEY_RIGHT) - tracer.disp.hoffset -= 1; + disasm->disp.hoffset -= 1; /* vertical update */ if (key == KEY_UP) { - tracer.buffer.cursor.note_idx += 1; - note_idx = tracer.buffer.cursor.note_idx; - line_idx = tracer.buffer.cursor.line_idx; + disasm->buffer.cursor.note_idx += 1; + note_idx = disasm->buffer.cursor.note_idx; + line_idx = disasm->buffer.cursor.line_idx; if (note_idx >= 5 - || tracer.buffer.raw[line_idx][note_idx][0] == '\0') { - tracer.buffer.anchor.addr = - &tracer.buffer.anchor.addr[-1]; - line_idx = disasm_util_line_update(line_idx, -1); - tracer.buffer.cursor.line_idx = line_idx; - tracer.buffer.cursor.note_idx = 0; + || disasm->buffer.raw[line_idx][note_idx][0] == '\0') { + disasm->buffer.anchor.addr = + &disasm->buffer.anchor.addr[-1]; + line_idx = disasm_util_line_update(disasm, line_idx, -1); + disasm->buffer.cursor.line_idx = line_idx; + disasm->buffer.cursor.note_idx = 0; } } if (key == KEY_DOWN) { - tracer.buffer.cursor.note_idx -= 1; - note_idx = tracer.buffer.cursor.note_idx; - line_idx = tracer.buffer.cursor.line_idx; + disasm->buffer.cursor.note_idx -= 1; + note_idx = disasm->buffer.cursor.note_idx; + line_idx = disasm->buffer.cursor.line_idx; if (note_idx < 0) { - tracer.buffer.anchor.addr = - &tracer.buffer.anchor.addr[1]; - line_idx = disasm_util_line_update(line_idx, 1); - disasm_util_line_fetch(line_idx, tracer.memory, 1); - note_idx = disasm_util_note_counter(line_idx); - tracer.buffer.cursor.line_idx = line_idx; - tracer.buffer.cursor.note_idx = note_idx; + disasm->buffer.anchor.addr = + &disasm->buffer.anchor.addr[1]; + line_idx = disasm_util_line_update(disasm, line_idx, 1); + disasm_util_line_fetch(disasm, line_idx, disasm->memory, 1); + note_idx = disasm_util_note_counter(disasm, line_idx); + disasm->buffer.cursor.line_idx = line_idx; + disasm->buffer.cursor.note_idx = note_idx; } } /* move break point */ if (key == KEY_PLUS) - tracer.next_break += 2; + disasm->next_break += 2; if (key == KEY_MINUS) - tracer.next_break -= 2; + disasm->next_break -= 2; if (key == KEY_NEG) - tracer.next_break = (uintptr_t)tracer.buffer.anchor.addr; + disasm->next_break = (uintptr_t)disasm->buffer.anchor.addr; /* skip instruction */ if (key == KEY_OPTN) { - context->spc = tracer.next_break; + session->info.context->spc = disasm->next_break; return (1); } if (key == KEY_VARS) { - tracer.skip = 1; + disasm->skip = 1; return (1); } @@ -443,8 +453,9 @@ static int disasm_keyboard(struct ucontext *context, int key) } /* disasm_command(): Handle user command */ -static void disasm_command(struct ucontext *context, int argc, char **argv) +static void disasm_command(struct tsession *session, int argc, char **argv) { + struct disasm *disasm; uintptr_t address; uint8_t action; int idx; @@ -501,27 +512,28 @@ static void disasm_command(struct ucontext *context, int argc, char **argv) if ((action & 2) != 0) { if (address >= 0x1fff) goto error_part; -#ifdef FXCG50 + #ifdef FXCG50 uintptr_t *systab = *(uintptr_t **)0x8002007c; -#endif -#ifdef FX9860 + #endif + #ifdef FX9860 uintptr_t *systab = *(uintptr_t **)0x8001007c; -#endif + #endif if (idx == 2) { input_write("syscall %x: %p", address, systab[address]); return; } address = systab[address]; } - tracer.buffer.anchor.addr = (void*)(address & ~1); - tracer.buffer.cursor.note_idx = 0; - tracer.buffer.cursor.line_idx = 0; - i = disasm_util_line_update(tracer.buffer.cursor.line_idx, -1); - tracer.buffer.raw[i][0][0] = '\0'; - tracer.buffer.raw[tracer.buffer.cursor.line_idx][0][0] = '\0'; - disasm_util_line_fetch(tracer.buffer.cursor.line_idx, - &tracer.buffer.anchor.addr[0], 1); - disasm_display(context); + disasm = &session->menu.disasm; + disasm->buffer.anchor.addr = (void*)(address & ~1); + disasm->buffer.cursor.note_idx = 0; + disasm->buffer.cursor.line_idx = 0; + i = disasm_util_line_update(disasm, disasm->buffer.cursor.line_idx, -1); + disasm->buffer.raw[i][0][0] = '\0'; + disasm->buffer.raw[disasm->buffer.cursor.line_idx][0][0] = '\0'; + disasm_util_line_fetch(disasm, disasm->buffer.cursor.line_idx, + &disasm->buffer.anchor.addr[0], 1); + disasm_display(session); return; /* error part */ @@ -533,10 +545,10 @@ error_part: // Define the menu //--- struct menu menu_disasm = { - .ctor = &disasm_ctor, - .init = &disasm_init, - .display = &disasm_display, - .keyboard = &disasm_keyboard, - .command = &disasm_command, - .dtor = &disasm_dtor + .ctor = (void*)&disasm_ctor, + .init = (void*)&disasm_init, + .display = (void*)&disasm_display, + .keyboard = (void*)&disasm_keyboard, + .command = (void*)&disasm_command, + .dtor = (void*)&disasm_dtor }; diff --git a/src/menu/hexdump.c b/src/menu/hexdump.c index 684d674..065247e 100644 --- a/src/menu/hexdump.c +++ b/src/menu/hexdump.c @@ -1,5 +1,6 @@ #include "gintrace/menu/hexdump.h" #include "gintrace/ubc.h" +#include "gintrace/tracer.h" #include "gintrace/gui/menu.h" #include "gintrace/gui/display.h" #include "gintrace/gui/input.h" @@ -8,29 +9,24 @@ #include #include -/* define the menu information */ -/* TODO: find a way to have local information (session) */ -struct hexdump hexdump; - /* hexdump_ctor: Menu constructor */ -static void hexdump_ctor(void) +static void hexdump_ctor(struct tsession *session) { - hexdump.cursor.hoffset = 0; - hexdump.cursor.voffset = 0; - hexdump.addr = (void*)0x88000000; + session->menu.hexdump.cursor.hoffset = 0; + session->menu.hexdump.cursor.voffset = 0; + session->menu.hexdump.addr = (void*)0x88000000; } /* hexdump_display(); Display trace information */ -static void hexdump_display(struct ucontext *context) +static void hexdump_display(struct tsession *session) { uint8_t *record; int x; int y; - (void)context; - record = hexdump.addr; - x = hexdump.cursor.hoffset; - y = hexdump.cursor.voffset; + record = session->menu.hexdump.addr; + x = session->menu.hexdump.cursor.hoffset; + y = session->menu.hexdump.cursor.voffset; for (int i = 0; i < GUI_DISP_NB_ROW; ++i) { gprintXY(x - 2, y + i, "%p", record); for (int j = 0; j < 8; ++j) { @@ -48,29 +44,27 @@ static void hexdump_display(struct ucontext *context) } /* hexdump_keyboard(): Handle one key event */ -static int hexdump_keyboard(struct ucontext *context, int key) +static int hexdump_keyboard(struct tsession *session, int key) { - (void)context; if (key == KEY_LEFT) - hexdump.cursor.hoffset += 1; + session->menu.hexdump.cursor.hoffset += 1; if (key == KEY_RIGHT) - hexdump.cursor.hoffset -= 1; + session->menu.hexdump.cursor.hoffset -= 1; if (key == KEY_UP) - hexdump.addr = &hexdump.addr[-8]; + session->menu.hexdump.addr = &session->menu.hexdump.addr[-8]; if (key == KEY_DOWN) - hexdump.addr = &hexdump.addr[8]; + session->menu.hexdump.addr = &session->menu.hexdump.addr[8]; return (0); } /* hexdump_command(): Handle user command */ -static void hexdump_command(struct ucontext *context, int argc, char **argv) +static void hexdump_command(struct tsession *session, int argc, char **argv) { uintptr_t address; int i; - (void)context; if (argc != 2) return; if (strcmp(argv[0], "jmp") != 0) { @@ -96,17 +90,17 @@ static void hexdump_command(struct ucontext *context, int argc, char **argv) input_write("'%s': second argument error", argv[0]); return; } - hexdump.addr = (void*)(address & ~3); + session->menu.hexdump.addr = (void*)(address & ~3); } //--- // Define the menu //--- struct menu menu_hexdump = { - .ctor = &hexdump_ctor, + .ctor = (void*)&hexdump_ctor, .init = NULL, - .display = &hexdump_display, - .keyboard = &hexdump_keyboard, - .command = &hexdump_command, + .display = (void*)&hexdump_display, + .keyboard = (void*)&hexdump_keyboard, + .command = (void*)&hexdump_command, .dtor = NULL }; diff --git a/src/tracer.c b/src/tracer.c new file mode 100644 index 0000000..08ce18f --- /dev/null +++ b/src/tracer.c @@ -0,0 +1,58 @@ +#include "gintrace/tracer.h" + +#include +#include + +/* global session (TODO: thread-safe) */ +struct tsession *session = NULL; + +/* tracer_new_session(): Create a new session */ +struct tsession *tracer_create_session(void *address, int menu) +{ + extern void gintrace_handler(struct ucontext *context); + struct tsession *session; + + if (address == NULL || (menu & (TRACER_DISASM + | TRACER_CONTEXT + | TRACER_HEXDUMP + | TRACER_CALLGRAPH)) == 0) { + return(NULL); + } + + session = calloc(sizeof(struct tsession), 1); + if (session == NULL) + return (NULL); + if (menu_create(&session->display.gmenu, session) != 0) { + free(session); + return (NULL); + } + if ((menu & TRACER_DISASM) != 0) + menu_register(session->display.gmenu, &menu_disasm, "Disasm"); + if ((menu & TRACER_CONTEXT) != 0) + menu_register(session->display.gmenu, &menu_context, "Context"); + if ((menu & TRACER_HEXDUMP) != 0) + menu_register(session->display.gmenu, &menu_hexdump, "Hexdump"); + if ((menu & TRACER_CALLGRAPH) != 0) + menu_register(session->display.gmenu, &menu_callgraph, "CallG"); + + ubc_install(); + ubc_set_handler(&gintrace_handler); + ubc_set_breakpoint(0, address, NULL); + return (session); +} + +/* tracer_get_session(): Get the current session. */ +struct tsession *tracer_get_session(void) +{ + return (session); +} + +/* tracer_get_session(): Set the current session. */ +struct tsession *tracer_set_session(struct tsession *new) +{ + void *old; + + old = session; + session = new; + return (old); +} diff --git a/src/ubc/handler.c b/src/ubc/handler.c new file mode 100644 index 0000000..688f6ba --- /dev/null +++ b/src/ubc/handler.c @@ -0,0 +1,69 @@ +#include "gintrace/gui/menu.h" +#include "gintrace/menu/disasm.h" +#include "gintrace/menu/context.h" +#include "gintrace/menu/hexdump.h" +#include "gintrace/menu/callgraph.h" +#include "gintrace/ubc.h" +#include "gintrace/tracer.h" + +#include + +/* gintrac_handler(): UBC handler + * @note: + * 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; + + /* force disable the UBC to avoid error */ + ubc_block(); + + /* check session validity */ + session = tracer_get_session(); + if (session == NULL) { + ubc_unblock(); + return; + } + session->info.context = context; + + /* check callgraph job */ + if (breakpoint != 0x00000000 + && spc != 0x00000000 + && spc != breakpoint) { + menu_callgraph.init(session); + spc = context->spc; + ubc_set_breakpoint(0, (void*)context->spc, NULL); + ubc_unblock(); + return; + } + + /* user break point */ + gint_switch_to_gint(); + 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 */ + 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; + } + + + /* unblock UBC interrupt */ + ubc_unblock(); + gint_switch_to_casio(); +} diff --git a/utils/a.out b/utils/a.out new file mode 100755 index 0000000..a262e58 Binary files /dev/null and b/utils/a.out differ diff --git a/utils/abcd b/utils/abcd new file mode 100644 index 0000000..b5b0e93 Binary files /dev/null and b/utils/abcd differ diff --git a/utils/main.c b/utils/main.c new file mode 100644 index 0000000..bc51dee --- /dev/null +++ b/utils/main.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +struct callnode { + struct callnode *parent; + struct callnode *sibling; + struct callnode *child; +}; + +static uint32_t get_lword(uint8_t *file) +{ + return (file[0] << 24 | file[1] << 16 | file[2] << 8 | file[3]); +} + +static void generate_binary_tree(struct callnode **node, uint8_t *file) +{ + *node = calloc(sizeof(struct callnode), 1); + if (*node == NULL) { + fprintf(stderr, "ENOMEM\n"); + exit(84); + } + size_t size = get_lword(file); + printf("size: %lx\n", size); + generate_binary_tree(node, &file[size]); +} + +int main(int argc, char **argv) +{ + if (argc != 2) + return (84); + int fd = open(argv[1], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "unable to open '%s'\n", argv[1]); + return (84); + } + uint8_t *map = calloc(512 * 1024, 1); + if (map == NULL) { + fprintf(stderr, "ENOMEM\n"); + return (84); + } + size_t size = read(fd, map, 512 * 1024); + printf("file size: %ld\n", size); + printf("lword = %x\n", get_lword(map)); + + for (size_t i = 0; i < size; i++) { + if (i != 0 && (i & 7) == 0) + printf("\n"); + printf("%.2x", map[i]); + } + return (0); +}