Gintracer v0.7.0 - Tracing sessions
@add * support multiple sessions * support multiple color schematics (night, day, ...) * support OS-specific notes information @update * add stability * syscall information * wrap gint display API * menus interface
This commit is contained in:
parent
19e46a55f0
commit
8dba715297
3
TODO.txt
3
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.
|
||||
|
|
BIN
gintrace.g3a
BIN
gintrace.g3a
Binary file not shown.
|
@ -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);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
/* mcontext: menu context internal structure */
|
||||
struct mcontext {
|
||||
struct context {
|
||||
struct {
|
||||
int hoffset;
|
||||
int voffset;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef __GINTRACE_TRACER_H__
|
||||
# define __GINTRACE_TRACER_H__
|
||||
#ifndef __GINTRACE_DISASM_H__
|
||||
# define __GINTRACE_DISASM_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
@ -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__*/
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef __GINTRACE_TRACER_H__
|
||||
# define __GINTRACE_TRACER_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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__*/
|
|
@ -12,11 +12,12 @@
|
|||
#include <gint/keyboard.h>
|
||||
|
||||
/* 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);
|
||||
|
||||
|
|
135
src/main.c
135
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 <gint/gint.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/gint.h>
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
|
|
@ -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 <gint/std/string.h>
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#include "gintrace/tracer.h"
|
||||
|
||||
#include <gint/std/string.h>
|
||||
#include <gint/std/stdlib.h>
|
||||
|
||||
/* 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);
|
||||
}
|
|
@ -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 <gint/gint.h>
|
||||
|
||||
/* 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();
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,54 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
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);
|
||||
}
|
Loading…
Reference in New Issue