Gintracer: v0.6.3 - Graphgraph export.

@update
* callgraph: add "export <filename>", to export callgraph information to the SMEM.
* input: input_display(): add meta information (cursor mode)
* input: input_read(): allow user to add prefix text.
* input: add input_write_noint(): display and doesn't wait user interaction.
This commit is contained in:
Yatis 2021-03-01 09:02:43 +01:00
parent f5c09c1a34
commit b4d3db625e
7 changed files with 293 additions and 99 deletions

View File

@ -1,10 +1,13 @@
@fix
* fix fixed size 'space' character
* fix tabulation
* fix destructor
* fix fx9860 support
@update
* hexdump: search commands
@feature
* call graph export for laptop
* night mode (refacto gui and handle color template)
* transform gintracer into a librairy
* handle session (send the session instead of ucontext !)

Binary file not shown.

View File

@ -4,10 +4,11 @@
#include <stddef.h>
#include <stdint.h>
/* intput(): Handle user input */
extern int input_read(char *buffer, size_t size);
/* intput_read(): Handle user input */
extern int input_read(char *buffer, size_t size, const char *prefix, ...);
/* intput(): display message then wait user event */
/* intput_write(): display message then wait user event */
extern int input_write(const char *format, ...);
/* intput(): display message */
extern int input_write_noint(const char *format, ...);
#endif /*__GINTRACE_GUI_INPUT_H__*/

View File

@ -30,7 +30,6 @@ struct callgraph {
} cursor;
struct callnode *root;
struct callnode *parent;
int callnode_counter;
};
/* extern menu information */

View File

@ -13,14 +13,16 @@
/* internal structure used to store many information */
struct {
struct {
int visible;
} cursor;
uint8_t cursor :1; /* display cursor */
uint8_t meta :1; /* display meta info */
uint8_t const :6;
} config;
struct {
uint8_t alpha: 1;
uint8_t shift: 1;
uint8_t ctrl: 1;
uint8_t exit: 1;
uint8_t const: 4;
uint8_t alpha :1;
uint8_t shift :1;
uint8_t ctrl :1;
uint8_t exit :1;
uint8_t const :4;
} mode;
struct {
size_t max;
@ -28,41 +30,35 @@ struct {
off_t cursor;
char *data;
} buffer;
struct {
size_t size;
char data[256];
} prefix;
} input_info;
//---
// Display management
//---
/* input_display(): Display the input area */
void input_display(void)
/* input_print(): Print line */
static void input_print(int *cursor_x, int *cursor_y, const char *str)
{
int cursor_x;
int cursor_y;
uint16_t tmp;
int cursor;
char c;
int x;
int y;
/* add cursor mark */
if (input_info.cursor.visible == 1)
input_info.buffer.data[input_info.buffer.cursor] |= 0x80;
/* display part */
cursor_x = 0;
cursor_y = GUI_DISP_NB_ROW - 1;
cursor_y -= input_info.buffer.size / GUI_DISP_NB_COLUMN;
drect(0, cursor_y * (FHEIGHT + 1) - 1, DWIDTH, DHEIGHT, C_WHITE);
dhline(cursor_y * (FHEIGHT + 1) - 3, C_BLACK);
dhline(cursor_y * (FHEIGHT + 1) - 2, C_BLACK);
for (size_t i = 0; i < input_info.buffer.size; ++i) {
if (str == NULL)
return;
for (size_t i = 0; str[i] != '\0'; ++i) {
/* get the cursor and remove the potential cursor marker */
cursor = ((input_info.buffer.data[i] & 0x80) != 0);
input_info.buffer.data[i] &= 0x7f;
cursor = ((str[i] & 0x80) != 0);
c = str[i] & 0x7f;
/* display part (character + cursor if needed) */
x = cursor_x * (FWIDTH + 1);
y = cursor_y * (FHEIGHT + 1);
tmp = input_info.buffer.data[i] << 8;
x = (*cursor_x) * (FWIDTH + 1);
y = (*cursor_y) * (FHEIGHT + 1);
tmp = c << 8;
dtext(x, y, C_BLACK, (void*)&tmp);
if (cursor != 0) {
dline(x, y + (FHEIGHT + 1), x + (FWIDTH + 1) - 2,
@ -70,16 +66,53 @@ void input_display(void)
}
/* update cursor if needed */
cursor_x += 1;
if (cursor_x >= GUI_DISP_NB_COLUMN) {
cursor_x = 0;
cursor_y += 1;
*cursor_x += 1;
if (*cursor_x >= GUI_DISP_NB_COLUMN) {
*cursor_x = 0;
*cursor_y += 1;
}
}
}
/* input_display(): Display the input area */
static void input_display(void)
{
int cursor_x;
int cursor_y;
size_t bytes;
/* add cursor mark */
if (input_info.config.cursor == 1)
input_info.buffer.data[input_info.buffer.cursor] |= 0x80;
/* calculate the number of bytes to display */
/* TODO: remove me, check line discipline */
bytes = input_info.buffer.size + input_info.prefix.size;
if (input_info.config.meta == 1)
bytes += 4;
/* calculate the X/Y position */
cursor_x = 0;
cursor_y = (GUI_DISP_NB_ROW - 1) - (bytes / GUI_DISP_NB_COLUMN);
/* display information */
drect(0, cursor_y * (FHEIGHT + 1) - 1, DWIDTH, DHEIGHT, C_WHITE);
dhline(cursor_y * (FHEIGHT + 1) - 3, C_BLACK);
dhline(cursor_y * (FHEIGHT + 1) - 2, C_BLACK);
if (input_info.config.meta == 1) {
char meta[] = "[l]:";
if (input_info.mode.alpha == 1)
meta[1] = 'L';
if (input_info.mode.shift == 1)
meta[1] = 'n';
input_print(&cursor_x, &cursor_y, meta);
}
input_print(&cursor_x, &cursor_y, input_info.prefix.data);
input_print(&cursor_x, &cursor_y, input_info.buffer.data);
dupdate();
/* remove cursor mark */
if (input_info.cursor.visible == 1)
if (input_info.config.cursor == 1)
input_info.buffer.data[input_info.buffer.cursor] &= ~0x80;
}
@ -210,7 +243,7 @@ static int input_key_buffer_update(key_event_t key_event)
}
/* input_read(): Handle user input */
int input_read(char *buffer, size_t size)
int input_read(char *buffer, size_t size, const char *prefix, ...)
{
key_event_t key;
uint16_t *secondary;
@ -226,10 +259,17 @@ int input_read(char *buffer, size_t size)
memset(&input_info, 0x00, sizeof(input_info));
memset(buffer, 0x00, size);
/* save terminal information */
/* setup internal information */
input_info.buffer.data = buffer;
input_info.buffer.size = 1;
input_info.buffer.max = size;
if (prefix != NULL) {
va_list _args;
va_start(_args, prefix);
input_info.prefix.size = vsnprintf(input_info.prefix.data,
32, prefix, _args);
va_end(_args);
}
/* Gint workaround to freeze the current display */
dgetvram(&main, &secondary);
@ -240,8 +280,10 @@ int input_read(char *buffer, size_t size)
}
memcpy(secondary, main, 2*396*224);
/* keyboard handling */
input_info.cursor.visible = 1;
input_info.config.cursor = 1;
input_info.config.meta = 1;
while (input_info.mode.exit == 0) {
input_display();
key = getkey_opt(GETKEY_REP_ALL | GETKEY_MENU, NULL);
@ -289,8 +331,46 @@ int input_write(const char *format, ...)
memcpy(secondary, main, 2*396*224);
/* display and wait user event */
input_info.cursor.visible = 0;
input_info.config.cursor = 0;
input_info.config.meta = 0;
input_display();
getkey();
return (0);
}
/* TODO: merge with input_write*/
int input_write_noint(const char *format, ...)
{
char buffer[512];
va_list _args;
uint16_t *secondary;
uint16_t *main;
size_t size;
void *tmp;
va_start(_args, format);
size = vsnprintf(buffer, 512, format, _args);
va_end(_args);
/* initialize internal data */
memset(&input_info, 0x00, sizeof(input_info));
/* save terminal information */
input_info.buffer.data = buffer;
input_info.buffer.size = size;
input_info.buffer.max = 512;
/* Gint workaround to freeze the current display */
dgetvram(&main, &secondary);
if (gint_vram == main) {
tmp = main;
main = secondary;
secondary = tmp;
}
memcpy(secondary, main, 2*396*224);
/* display and wait user event */
input_info.config.cursor = 0;
input_info.config.meta = 0;
input_display();
return (0);
}

View File

@ -154,7 +154,7 @@ int menu_keyboard(struct menu_group *gmenu)
goto check_fkeys;
}
char buf[256];
if (input_read(buf, 256) <= 0)
if (input_read(buf, 256, NULL) <= 0)
goto check_fkeys;
int ac;
char **av;

View File

@ -2,12 +2,15 @@
#include "gintrace/ubc.h"
#include "gintrace/gui/menu.h"
#include "gintrace/gui/display.h"
#include "gintrace/gui/input.h"
#include <gint/std/stdio.h>
#include <gint/std/stdlib.h>
#include <gint/std/string.h>
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/bfile.h>
#include <gint/gint.h>
#include "./src/menu/internal/dictionary.h"
@ -15,13 +18,15 @@
/* TODO: find a way to have local information (session) */
struct callgraph callgraph;
/* internal buffer */
static char line[256];
//---
// callode management
//---
/* callnode_create(): create a new callnode */
static struct callnode *callnode_create(struct callnode *parent,
struct ucontext *context,
int type, uintptr_t address)
struct ucontext *context, int type, uintptr_t address)
{
struct callnode *node;
@ -31,7 +36,6 @@ static struct callnode *callnode_create(struct callnode *parent,
node->type = type;
node->parent = parent;
node->address = address;
callgraph.callnode_counter += 1;
}
return (node);
}
@ -47,12 +51,70 @@ static void callnode_add_child(struct callnode *parent, struct callnode *child)
*sibling = child;
}
/* callnode_generate_info(): Genera information about a node */
static size_t callnode_generate_info(char *buf,
size_t max, struct callnode *node)
{
const char *addrname;
const char *type;
/* generate the line */
type = "(err)";
if (node->type == callnode_type_root)
type = "(root)";
if (node->type == callnode_type_bsr)
type = "(bsr)";
if (node->type == callnode_type_bsrf)
type = "(bsrf)";
if (node->type == callnode_type_jsr)
type = "(jsr)";
if (node->type == callnode_type_jmp)
type = "(jmp)";
if (node->type == callnode_type_rte)
type = "(rte)";
if (node->type == callnode_type_rts)
type = "(rts)";
/* check special address */
addrname = dictionary_syscalls_check((void*)node->address);
if (addrname == NULL)
addrname = dictionary_notes_check((void*)node->address);
if (addrname == NULL)
return(snprintf(buf, max, "%s %p", type, (void*)node->address));
return (snprintf(buf, max, "%s %p - %s",
type, (void*)node->address, addrname));
}
/* callnode_get_size(): Count the number of bytes that the callgraph take */
static size_t callnode_export(int fd, struct callnode *node)
{
if (node == NULL)
return (0);
size_t size = 0;
size += sizeof(size_t);
size += sizeof(uintptr_t);
size += sizeof(struct callnode);
size += callnode_generate_info(line, 256, node);
if (fd >= 0) {
BFile_Write(fd, &size, sizeof(size));
BFile_Write(fd, &node, sizeof(&node));
BFile_Write(fd, node, sizeof(struct callnode));
BFile_Write(fd, line, size);
}
/* check other node */
size += callnode_export(fd, node->child);
size += callnode_export(fd, node->sibling);
return (size);
}
/* callnode_display(): Display callnode information */
static void callnode_display(struct callnode *node, uint32_t bitmap[4],
int *row, int depth)
{
static char line[256];
char shift;
char pipe;
int idx;
int i;
@ -76,61 +138,28 @@ static void callnode_display(struct callnode *node, uint32_t bitmap[4],
}
/* generate the line */
char pipe = '|';
const char *type = "(err)";
pipe = '|';
bitmap[idx] |= 1 << (depth & 0x1f);
if (node->type == callnode_type_root)
type = "(root)";
if (node->type == callnode_type_bsr)
type = "(bsr)";
if (node->type == callnode_type_bsrf)
type = "(bsrf)";
if (node->type == callnode_type_jsr)
type = "(jsr)";
if (node->type == callnode_type_jmp) {
if (node->type == callnode_type_jmp
|| node->type == callnode_type_rte
|| node->type == callnode_type_rts) {
bitmap[idx] &= ~(1 << (depth & 0x1f));
type = "(jmp)";
pipe = '`';
}
if (node->type == callnode_type_rte) {
bitmap[idx] &= ~(1 << (depth & 0x1f));
type = "(rte)";
pipe = '`';
}
if (node->type == callnode_type_rts) {
bitmap[idx] &= ~(1 << (depth & 0x1f));
type = "(rts)";
pipe = '`';
}
/* skip display part */
if (*row + callgraph.cursor.voffset < 0) {
*row = *row + 1;
callnode_display(node->child, bitmap, row, depth + 1);
callnode_display(node->sibling, bitmap, row, depth);
return;
}
const char *addrname = dictionary_syscalls_check((void*)node->address);
if (addrname == NULL)
addrname = dictionary_notes_check((void*)node->address);
if (addrname == NULL) {
snprintf(line, 256, "%s %p", type, (void*)node->address);
} else {
snprintf(line, 256, "%s %p - %s",
type, (void*)node->address, addrname);
}
/* display the line then check child and siblig */
if (depth < 0) {
dtext((callgraph.cursor.hoffset + (i << 2)) * (FWIDTH + 1),
(*row + callgraph.cursor.voffset) * (FHEIGHT + 1),
C_BLACK, line);
} else {
dprint((2 + callgraph.cursor.hoffset + (i << 2)) * (FWIDTH + 1),
(*row + callgraph.cursor.voffset) * (FHEIGHT + 1), C_BLACK,
"%c-- %s", pipe, line);
if (*row + callgraph.cursor.voffset >= 0) {
callnode_generate_info(line, 256, node);
if (depth < 0) {
int a = callgraph.cursor.hoffset + (i << 2);
int b = callgraph.cursor.voffset + (*row);
dtext(a * (FWIDTH + 1), b * (FHEIGHT + 1), C_BLACK, line);
} else {
int a = callgraph.cursor.hoffset + (i << 2) + 2;
int b = callgraph.cursor.voffset + (*row);
dprint(a * (FWIDTH + 1), b * (FHEIGHT + 1),
C_BLACK, "%c-- %s", pipe, line);
}
}
*row = *row + 1;
callnode_display(node->child, bitmap, row, depth + 1);
@ -246,7 +275,6 @@ static void callgraph_display(struct ucontext *context)
}
/* callgraph_keyboard(): Handle one key event */
/* TODO: remove the cursor, handle node selection ! */
static int callgraph_keyboard(struct ucontext *context, int key)
{
(void)context;
@ -263,6 +291,89 @@ static int callgraph_keyboard(struct ucontext *context, int key)
return (0);
}
/* callgraph_command(): handle user command */
static void callgraph_command(struct ucontext *context, int argc, char **argv)
{
/* check useless export */
(void)context;
if (callgraph.root == NULL) {
input_write("nothing to export");
return;
}
/* check argument validity */
if (argc != 2) {
input_write("argument missing");
return;
}
if (strcmp(argv[0], "export") != 0) {
input_write("'%s': command unknown", argv[0]);
return;
}
/* 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);
while (argv[1][++i] != '\0')
pathname[7 + i] = argv[1][i];
pathname[7 + i] = 0x0000;
/* check if the file exist */
input_write_noint("Check if the file exist");
gint_switch_to_casio();
int fd = BFile_Open(pathname, BFile_ReadOnly);
if (fd >= 0) {
gint_switch_to_gint();
while (1) {
if (input_read(line, 3, "'%s' exist, erase ? [n/Y]:",
argv[1]) <= 0) {
input_write("export aborded");
return;
}
if (line[0] == 'n') {
input_write("export aborded");
return;
}
if (line[0] != 'Y')
continue;
gint_switch_to_casio();
BFile_Remove(pathname);
break;
}
}
/* create the file then dump information */
gint_switch_to_gint();
int size = callnode_export(-1, callgraph.root);
input_write_noint("Create the file (%d)", size);
gint_switch_to_casio();
fd = BFile_Create(pathname, BFile_File, &size);
if (fd != 0) {
gint_switch_to_gint();
input_write("Bfile_Create: error %d", fd);
return;
}
gint_switch_to_gint();
input_write_noint("Create success");
gint_switch_to_casio();
fd = BFile_Open(pathname, BFile_ReadWrite);
if (fd < 0) {
BFile_Remove(pathname);
gint_switch_to_gint();
input_write("BFile_Open: error %d", fd);
return;
}
gint_switch_to_gint();
input_write_noint("Open success, now write...");
gint_switch_to_casio();
callnode_export(fd, callgraph.root);
BFile_Close(fd);
gint_switch_to_gint();
input_write("success");
}
//---
// Define the menu
//---
@ -271,6 +382,6 @@ struct menu menu_callgraph = {
.init = &callgraph_init,
.display = &callgraph_display,
.keyboard = &callgraph_keyboard,
.command = NULL,
.command = &callgraph_command,
.dtor = NULL
};