--- hatari/src/debug/debugui.c 2019/04/09 08:55:36 1.1.1.8 +++ hatari/src/debug/debugui.c 2019/04/09 08:59:20 1.1.1.11 @@ -13,6 +13,7 @@ const char DebugUI_fileid[] = "Hatari de #include #include #include +#include #include "config.h" @@ -44,6 +45,7 @@ const char DebugUI_fileid[] = "Hatari de #include "evaluate.h" #include "history.h" #include "symbols.h" +#include "vars.h" FILE *debugOutput; @@ -56,6 +58,9 @@ static char lastResult[10]; /* parse debugger commands from here on init */ static const char *parseFileName; +/* to which directory to change after (potentially recursed) scripts parsing finishes */ +static char *finalDir; + /** * Save/Restore snapshot of debugging session variables @@ -112,17 +117,25 @@ static void DebugUI_SetLogDefault(void) */ static int DebugUI_SetLogFile(int nArgc, char *psArgs[]) { - File_Close(debugOutput); - debugOutput = NULL; + if (debugOutput != stderr) + { + fprintf(stderr, "Debug log closed.\n"); + File_Close(debugOutput); + } + debugOutput = stderr; if (nArgc > 1) - debugOutput = File_Open(psArgs[1], "w"); - - if (debugOutput) - fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]); - else - debugOutput = stderr; - + { + if ((debugOutput = File_Open(psArgs[1], "w"))) + { + fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]); + } + else + { + fprintf(stderr, "Debug log '%s' opening FAILED.\n", psArgs[1]); + debugOutput = stderr; + } + } return DEBUGGER_CMDDONE; } @@ -139,7 +152,7 @@ static void DebugUI_PrintValue(Uint32 va ones = false; for (bit = 31; bit >= 0; bit--) { - one = value & (1<= ARRAY_SIZE(psArgs)) + { + fprintf(stderr, "Error: too many arguments (currently up to %d supported)\n", + ARRAY_SIZE(psArgs)); + retval = DEBUGGER_CMDCONT; + } + else + { + /* ... and execute the function */ + retval = debugCommand[i].pFunction(nArgc, psArgs); } - - /* ... and execute the function */ - retval = debugCommand[i].pFunction(nArgc, psArgs); /* Save commando string if it can be repeated */ if (retval == DEBUGGER_CMDCONT) { @@ -794,8 +820,12 @@ static void DebugUI_FreeCommand(char *in */ static char *DebugUI_GetCommand(char *input) { + /* We need this indirection for libedit's rl_readline_name which is + * not declared as "const char *" (i.e. this is necessary for macOS) */ + static char hatari_readline_name[] = "Hatari"; + /* Allow conditional parsing of the ~/.inputrc file. */ - rl_readline_name = "Hatari"; + rl_readline_name = hatari_readline_name; /* Tell the completer that we want a crack first. */ rl_attempted_completion_function = DebugUI_Completion; @@ -803,6 +833,14 @@ static char *DebugUI_GetCommand(char *in return Str_Trim(readline("> ")); } +/** + * Get readlines idea of the terminal size + */ +static void DebugUI_GetScreenSize(int *rows, int *cols) +{ + rl_get_screen_size(rows, cols); +} + #else /* !HAVE_LIBREADLINE */ /** @@ -810,8 +848,22 @@ static char *DebugUI_GetCommand(char *in */ static void DebugUI_FreeCommand(char *input) { - if (input) - free(input); + free(input); +} + +/** + * Get number of lines/columns for terminal output + */ +static void DebugUI_GetScreenSize(int *rows, int *cols) +{ + const char *p; + + *rows = 24; + *cols = 80; + if ((p = getenv("LINES")) != NULL) + *rows = (int)strtol(p, NULL, 0); + if ((p = getenv("COLUMS")) != NULL) + *cols = (int)strtol(p, NULL, 0); } /** @@ -840,6 +892,29 @@ static char *DebugUI_GetCommand(char *in #endif /* !HAVE_LIBREADLINE */ +/** + * How many lines to "page" when user invokes calling command. + * + * If config value is >=0, use that. If it's negative, get number of lines + * from screensize. If even that's not defined, fall back to default value. + * + * @return Number of lines to output at the time. + */ +int DebugUI_GetPageLines(int config, int defvalue) +{ + int rows, cols; + + if (config >= 0) { + return config; + } + DebugUI_GetScreenSize(&rows, &cols); + /* leave 1 line for pager prompt */ + if (--rows > 0) { + return rows; + } + return defvalue; +} + static const dbgcommand_t uicommand[] = { @@ -848,17 +923,18 @@ static const dbgcommand_t uicommand[] = { DebugUI_ChangeDir, NULL, "cd", "", "change directory", - "\n" - "\tChange Hatari work directory.", + " [-f]\n" + "\tChange Hatari work directory. With '-f', directory is\n" + "\tchanged only after all script files have been parsed.", false }, - { DebugUI_Evaluate, Symbols_MatchCpuAddress, + { DebugUI_Evaluate, Vars_MatchCpuVariable, "evaluate", "e", "evaluate an expression", "\n" "\tEvaluate an expression and show the result. Expression can\n" - "\tinclude CPU register and symbol names, those are replaced\n" - "\tby their values. Supported operators in expressions are,\n" - "\tin the decending order of precedence:\n" + "\tinclude CPU register & symbol and Hatari variable names.\n" + "\tThose are replaced by their values. Supported operators in\n" + "\texpressions are, in the decending order of precedence:\n" "\t\t(), +, -, ~, *, /, +, -, >>, <<, ^, &, |\n" "\tParenthesis will fetch a _long_ value from the address\n" "\tto what the value inside it evaluates to. Prefixes can be\n" @@ -909,7 +985,10 @@ static const dbgcommand_t uicommand[] = "parse", "p", "get debugger commands from file", "[filename]\n" - "\tRead debugger commands from given file and do them.", + "\tRead debugger commands from given file and do them.\n" + "\tCurrent directory is script directory during this.\n" + "\tTo specify directory to be used also for breakpoint\n" + "\tscripts execution, use '-f' option for 'cd' command.", false }, { DebugUI_Rename, NULL, "rename", "", @@ -950,6 +1029,13 @@ static const dbgcommand_t uicommand[] = "\tsettings. For example, to enable CPU disassembly and VBL\n" "\ttracing, use:\n\t\ttrace cpu_disasm,video_hbl", false }, + { Vars_List, NULL, + "variables", "v", + "List builtin symbols / variables", + "\n" + "\tList Hatari debugger builtin symbols / variables and their values.\n" + "\tThey're accepted by breakpoints and evaluate command.", + false }, { DebugUI_QuitEmu, NULL, "quit", "q", "quit emulator", @@ -971,6 +1057,9 @@ void DebugUI_Init(void) if (debugCommands) return; + if (!debugOutput) + DebugUI_SetLogDefault(); + /* if you want disassembly or memdumping to start/continue from * specific address, you can set them in these functions. */ @@ -978,7 +1067,7 @@ void DebugUI_Init(void) cpucmds = DebugCpu_Init(&cpucmd); /* on first time copy the command structures to a single table */ - debugCommands = ARRAYSIZE(uicommand); + debugCommands = ARRAY_SIZE(uicommand); debugCommand = malloc(sizeof(dbgcommand_t) * (dspcmds + cpucmds + debugCommands)); assert(debugCommand); @@ -1087,7 +1176,6 @@ void DebugUI(debug_reason_t reason) DebugUI_FreeCommand(psCmd); Log_SetAlertLevel(alertLevel); - DebugUI_SetLogDefault(); DebugCpu_SetDebugging(); DebugDsp_SetDebugging(); @@ -1103,6 +1191,8 @@ void DebugUI(debug_reason_t reason) */ bool DebugUI_ParseFile(const char *path, bool reinit) { + int recurse; + static int recursing; char *olddir, *dir, *cmd, *input, *expanded, *slash; FILE *fp; @@ -1129,8 +1219,7 @@ bool DebugUI_ParseFile(const char *path, if (chdir(dir) != 0) { perror("ERROR"); - if (olddir) - free(olddir); + free(olddir); free(dir); fclose(fp); return false; @@ -1139,6 +1228,9 @@ bool DebugUI_ParseFile(const char *path, } free(dir); + recurse = recursing; + recursing = true; + input = NULL; for (;;) { @@ -1165,6 +1257,7 @@ bool DebugUI_ParseFile(const char *path, DebugUI_ParseCommand(cmd); free(expanded); } + recursing = false; free(input); fclose(fp); @@ -1178,10 +1271,27 @@ bool DebugUI_ParseFile(const char *path, free(olddir); } - if (reinit) + if (!recurse) { - DebugCpu_SetDebugging(); - DebugDsp_SetDebugging(); + /* current script (or something called by it) specified final dir */ + if (finalDir) + { + if (chdir(finalDir) != 0) + perror("ERROR"); + else + fprintf(stderr, "Delayed change to '%s' dir.\n", finalDir); + free(finalDir); + finalDir = NULL; + } + /* only top-level (non-recursed) call has valid re-init info, + * as that's the only one that can get directly called from + * breakpoints + */ + if (reinit) + { + DebugCpu_SetDebugging(); + DebugDsp_SetDebugging(); + } } return true; } @@ -1227,10 +1337,11 @@ void DebugUI_Exceptions(int nr, long pc) { EXCEPT_ZERODIV, "Div by zero" }, /* 5 */ { EXCEPT_CHK, "CHK" }, /* 6 */ { EXCEPT_TRAPV, "TRAPV" }, /* 7 */ - { EXCEPT_PRIVILEGE, "Privilege violation" } /* 8 */ + { EXCEPT_PRIVILEGE, "Privilege violation" }, /* 8 */ + { EXCEPT_TRACE, "Trace" } /* 9 */ }; nr -= 2; - if (nr < 0 || nr >= ARRAYSIZE(ex)) + if (nr < 0 || nr >= ARRAY_SIZE(ex)) return; if (!(ExceptionDebugMask & ex[nr].flag)) return;