--- hatari/src/debug/debugui.c 2019/04/09 08:54:23 1.1.1.7 +++ 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" @@ -29,6 +30,7 @@ const char DebugUI_fileid[] = "Hatari de #include "m68000.h" #include "memorySnapShot.h" #include "options.h" +#include "reset.h" #include "screen.h" #include "statusbar.h" #include "str.h" @@ -43,8 +45,7 @@ const char DebugUI_fileid[] = "Hatari de #include "evaluate.h" #include "history.h" #include "symbols.h" - -int bExceptionDebugging; +#include "vars.h" FILE *debugOutput; @@ -57,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 @@ -113,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; } @@ -140,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) { if (psArgs[0] != sLastCmd) - strncpy(sLastCmd, psArgs[0], sizeof(sLastCmd)); + strlcpy(sLastCmd, psArgs[0], sizeof(sLastCmd)); } else sLastCmd[0] = '\0'; @@ -772,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; @@ -781,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 */ /** @@ -788,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); } /** @@ -818,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[] = { @@ -826,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" @@ -855,7 +953,7 @@ static const dbgcommand_t uicommand[] = { History_Parse, History_Match, "history", "hi", "show last CPU/DSP PC values & executed instructions", - "cpu|dsp|on|off| [limit]\n" + "cpu|dsp|on|off| [limit]|save \n" "\t'cpu' and 'dsp' enable instruction history tracking for just given\n" "\tprocessor, 'on' tracks them both, 'off' will disable history.\n" "\tOptional 'limit' will set how many past instructions are tracked.\n" @@ -887,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", "", @@ -895,14 +996,18 @@ static const dbgcommand_t uicommand[] = "old new\n" "\tRenames file with 'old' name to 'new'.", false }, + { DebugUI_Reset, DebugUI_MatchReset, + "reset", "", + "reset emulation", + "\n", + false }, { DebugUI_SetOptions, Opt_MatchOption, "setopt", "o", "set Hatari command line and debugger options", "[bin|dec|hex|]\n" - "\tSet Hatari options. For example to enable exception catching,\n" - "\tuse following command line option: 'setopt --debug'. Special\n" - "\t'bin', 'dec' and 'hex' arguments change the default number base\n" - "\tused in debugger.", + "\tSpecial 'bin', 'dec' and 'hex' arguments change the default\n" + "\tnumber base used in debugger. lists available command\n" + "\tline options, 'setopt --help' their descriptions.", false }, { DebugUI_DoMemorySnap, NULL, "stateload", "", @@ -924,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", @@ -945,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. */ @@ -952,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); @@ -995,6 +1110,15 @@ void DebugUI(debug_reason_t reason) static const char *welcome = "\n----------------------------------------------------------------------" "\nYou have entered debug mode. Type c to continue emulation, h for help.\n"; + static bool recursing; + + if (recursing) + { + fprintf(stderr, "WARNING: recursive call to DebugUI (through profiler debug option?)!\n"); + recursing = false; + return; + } + recursing = true; History_Mark(reason); @@ -1052,10 +1176,11 @@ void DebugUI(debug_reason_t reason) DebugUI_FreeCommand(psCmd); Log_SetAlertLevel(alertLevel); - DebugUI_SetLogDefault(); DebugCpu_SetDebugging(); DebugDsp_SetDebugging(); + + recursing = false; } @@ -1066,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; @@ -1092,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; @@ -1102,6 +1228,9 @@ bool DebugUI_ParseFile(const char *path, } free(dir); + recurse = recursing; + recursing = true; + input = NULL; for (;;) { @@ -1128,6 +1257,7 @@ bool DebugUI_ParseFile(const char *path, DebugUI_ParseCommand(cmd); free(expanded); } + recursing = false; free(input); fclose(fp); @@ -1141,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; } @@ -1190,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;