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:
Yatis 2021-03-08 21:38:09 +01:00
parent 19e46a55f0
commit 8dba715297
17 changed files with 609 additions and 391 deletions

View File

@ -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.

Binary file not shown.

View File

@ -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);

View File

@ -5,7 +5,7 @@
#include <stdint.h>
/* mcontext: menu context internal structure */
struct mcontext {
struct context {
struct {
int hoffset;
int voffset;

View File

@ -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__*/

55
include/gintrace/tracer.h Normal file
View File

@ -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__*/

View File

@ -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);

View File

@ -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
}

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

58
src/tracer.c Normal file
View File

@ -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);
}

69
src/ubc/handler.c Normal file
View File

@ -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();
}

BIN
utils/a.out Executable file

Binary file not shown.

BIN
utils/abcd Normal file

Binary file not shown.

54
utils/main.c Normal file
View File

@ -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);
}