|
|
1.1 ! root 1: /* ! 2: Hatari - debuginfo.c ! 3: ! 4: This file is distributed under the GNU Public License, version 2 or at ! 5: your option any later version. Read the file gpl.txt for details. ! 6: ! 7: debuginfo.c - functions needed to show info about the atari HW & OS ! 8: components and "lock" that info to be shown on entering the debugger. ! 9: */ ! 10: const char DebugInfo_fileid[] = "Hatari debuginfo.c : " __DATE__ " " __TIME__; ! 11: ! 12: #include <stdio.h> ! 13: #include <assert.h> ! 14: #include <ctype.h> ! 15: #include "main.h" ! 16: #include "configuration.h" ! 17: #include "debugInfo.h" ! 18: #include "debugcpu.h" ! 19: #include "debugui.h" ! 20: #include "evaluate.h" ! 21: #include "file.h" ! 22: #include "ioMem.h" ! 23: #include "m68000.h" ! 24: #include "nextMemory.h" ! 25: #include "screen.h" ! 26: #include "video.h" ! 27: ! 28: /* ------------------------------------------------------------------ ! 29: * Next HW information ! 30: */ ! 31: ! 32: char* get_rtc_ram_info(void); ! 33: ! 34: /** ! 35: * DebugInfo_Rtc : display the Videl registers values. ! 36: */ ! 37: static void DebugInfo_Rtc(Uint32 dummy) { ! 38: Update_StatusBar(); ! 39: fprintf(stdout,"%s",get_rtc_ram_info()); ! 40: } ! 41: ! 42: /* ------------------------------------------------------------------ ! 43: * CPU and DSP information wrappers ! 44: */ ! 45: ! 46: /** ! 47: * Helper to call debugcpu.c and debugdsp.c debugger commands ! 48: */ ! 49: static void DebugInfo_CallCommand(int (*func)(int, char* []), const char *command, Uint32 arg) ! 50: { ! 51: char cmdbuffer[16], argbuffer[12]; ! 52: char *argv[] = { cmdbuffer, NULL }; ! 53: int argc = 1; ! 54: ! 55: assert(strlen(command) < sizeof(cmdbuffer)); ! 56: strcpy(cmdbuffer, command); ! 57: if (arg) { ! 58: sprintf(argbuffer, "$%x", arg); ! 59: argv[argc++] = argbuffer; ! 60: } ! 61: func(argc, argv); ! 62: } ! 63: ! 64: static void DebugInfo_CpuRegister(Uint32 arg) ! 65: { ! 66: DebugInfo_CallCommand(DebugCpu_Register, "register", arg); ! 67: } ! 68: static void DebugInfo_CpuDisAsm(Uint32 arg) ! 69: { ! 70: DebugInfo_CallCommand(DebugCpu_DisAsm, "disasm", arg); ! 71: } ! 72: static void DebugInfo_CpuMemDump(Uint32 arg) ! 73: { ! 74: DebugInfo_CallCommand(DebugCpu_MemDump, "memdump", arg); ! 75: } ! 76: ! 77: static void DebugInfo_DspRegister(Uint32 arg) ! 78: { ! 79: } ! 80: static void DebugInfo_DspDisAsm(Uint32 arg) ! 81: { ! 82: } ! 83: ! 84: static void DebugInfo_DspMemDump(Uint32 arg) ! 85: { ! 86: } ! 87: ! 88: /** ! 89: * Convert arguments to Uint32 arg suitable for DSP memdump callback ! 90: */ ! 91: static Uint32 DebugInfo_DspMemArgs(int argc, char *argv[]) ! 92: { ! 93: Uint32 value; ! 94: char space; ! 95: if (argc != 2) { ! 96: return 0; ! 97: } ! 98: space = toupper(argv[0][0]); ! 99: if ((space != 'X' && space != 'Y' && space != 'P') || argv[0][1]) { ! 100: fprintf(stderr, "ERROR: invalid DSP address space '%s'!\n", argv[0]); ! 101: return 0; ! 102: } ! 103: if (!Eval_Number(argv[1], &value) || value > 0xffff) { ! 104: fprintf(stderr, "ERROR: invalid DSP address '%s'!\n", argv[1]); ! 105: return 0; ! 106: } ! 107: return ((Uint32)space<<16) | value; ! 108: } ! 109: ! 110: ! 111: static void DebugInfo_RegAddr(Uint32 arg) ! 112: { ! 113: } ! 114: ! 115: /** ! 116: * Convert arguments to Uint32 arg suitable for RegAddr callback ! 117: */ ! 118: static Uint32 DebugInfo_RegAddrArgs(int argc, char *argv[]) ! 119: { ! 120: Uint32 value, *regaddr; ! 121: if (argc != 2) { ! 122: return 0; ! 123: } ! 124: ! 125: if (strcmp(argv[0], "disasm") == 0) { ! 126: value = 'D'; ! 127: } else if (strcmp(argv[0], "memdump") == 0) { ! 128: value = 'M'; ! 129: } else { ! 130: fprintf(stderr, "ERROR: regaddr operation can be only 'disasm' or 'memdump', not '%s'!\n", argv[0]); ! 131: return 0; ! 132: } ! 133: ! 134: if (strlen(argv[1]) != 2 || ! 135: (!DebugCpu_GetRegisterAddress(argv[1], ®addr) && ! 136: (toupper(argv[1][0]) != 'R' || !isdigit(argv[1][1]) || argv[1][2]))) { ! 137: /* not CPU register or Rx DSP register */ ! 138: fprintf(stderr, "ERROR: invalid address/data register '%s'!\n", argv[1]); ! 139: return 0; ! 140: } ! 141: ! 142: value |= argv[1][0] << 24; ! 143: value |= argv[1][1] << 16; ! 144: value &= 0xffff00ff; ! 145: return value; ! 146: } ! 147: ! 148: ! 149: /* ------------------------------------------------------------------ ! 150: * wrappers for command to parse debugger input file ! 151: */ ! 152: ! 153: /* file name to be given before calling the Parse function, ! 154: * needs to be set separately as it's a host pointer which ! 155: * can be 64-bit i.e. may not fit into Uint32. ! 156: */ ! 157: static char *parse_filename; ! 158: ! 159: /** ! 160: * Parse and exec commands in the previously given debugger input file ! 161: */ ! 162: static void DebugInfo_FileParse(Uint32 dummy) ! 163: { ! 164: if (parse_filename) { ! 165: DebugUI_ParseFile(parse_filename); ! 166: } else { ! 167: // fputs("ERROR: debugger input file name to parse isn't set!\n", stderr); ! 168: } ! 169: } ! 170: ! 171: /** ! 172: * Set which input file to parse. ! 173: * Return true if file exists, false on error ! 174: */ ! 175: static Uint32 DebugInfo_FileArgs(int argc, char *argv[]) ! 176: { ! 177: if (argc != 1) { ! 178: return false; ! 179: } ! 180: if (!File_Exists(argv[0])) { ! 181: fprintf(stderr, "ERROR: given file '%s' doesn't exist!\n", argv[0]); ! 182: return false; ! 183: } ! 184: if (parse_filename) { ! 185: free(parse_filename); ! 186: } ! 187: parse_filename = strdup(argv[0]); ! 188: return true; ! 189: } ! 190: ! 191: /* ------------------------------------------------------------------ ! 192: * Debugger & readline TAB completion integration ! 193: */ ! 194: ! 195: /** ! 196: * Default information on entering the debugger ! 197: */ ! 198: static void DebugInfo_Default(Uint32 dummy) ! 199: { ! 200: fprintf(stderr, "\nCPU=$%x, DSP=", ! 201: M68000_GetPC()); ! 202: fprintf(stderr, "N/A\n"); ! 203: } ! 204: ! 205: static const struct { ! 206: /* if overlaps with other functionality, list only for lock command */ ! 207: bool lock; ! 208: const char *name; ! 209: void (*func)(Uint32 arg); ! 210: /* convert args in argv into single Uint32 for func */ ! 211: Uint32 (*args)(int argc, char *argv[]); ! 212: const char *info; ! 213: } infotable[] = { ! 214: { true, "default", DebugInfo_Default, NULL, "Show default debugger entry information" }, ! 215: { true, "disasm", DebugInfo_CpuDisAsm, NULL, "Disasm CPU from PC or given <address>" }, ! 216: { true, "dspdisasm", DebugInfo_DspDisAsm, NULL, "Disasm DSP from given <address>" }, ! 217: { true, "dspmemdump",DebugInfo_DspMemDump, DebugInfo_DspMemArgs, "Dump DSP memory from given <space> <address>" }, ! 218: { true, "dspregs", DebugInfo_DspRegister,NULL, "Show DSP registers values" }, ! 219: { true, "file", DebugInfo_FileParse, DebugInfo_FileArgs, "Parse commands from given debugger input <file>" }, ! 220: { true, "memdump", DebugInfo_CpuMemDump, NULL, "Dump CPU memory from given <address>" }, ! 221: { true, "regaddr", DebugInfo_RegAddr, DebugInfo_RegAddrArgs, "Show <disasm|memdump> from CPU/DSP address pointed by <register>" }, ! 222: { true, "registers", DebugInfo_CpuRegister,NULL, "Show CPU registers values" }, ! 223: { false,"rtc", DebugInfo_Rtc, NULL, "Show Next's RTC registers" } ! 224: }; ! 225: ! 226: static int LockedFunction = 4; /* index for the "default" function */ ! 227: static Uint32 LockedArgument; ! 228: ! 229: /** ! 230: * Show selected debugger session information ! 231: * (when debugger is (again) entered) ! 232: */ ! 233: void DebugInfo_ShowSessionInfo(void) ! 234: { ! 235: infotable[LockedFunction].func(LockedArgument); ! 236: } ! 237: ! 238: ! 239: /** ! 240: * Readline match callback for info subcommand name completion. ! 241: * STATE = 0 -> different text from previous one. ! 242: * Return next match or NULL if no matches. ! 243: */ ! 244: static char *DebugInfo_Match(const char *text, int state, bool lock) ! 245: { ! 246: static int i, len; ! 247: const char *name; ! 248: ! 249: if (!state) { ! 250: /* first match */ ! 251: len = strlen(text); ! 252: i = 0; ! 253: } ! 254: /* next match */ ! 255: while (i++ < ARRAYSIZE(infotable)) { ! 256: if (!lock && infotable[i-1].lock) { ! 257: continue; ! 258: } ! 259: name = infotable[i-1].name; ! 260: if (strncmp(name, text, len) == 0) ! 261: return (strdup(name)); ! 262: } ! 263: return NULL; ! 264: } ! 265: char *DebugInfo_MatchLock(const char *text, int state) ! 266: { ! 267: return DebugInfo_Match(text, state, true); ! 268: } ! 269: char *DebugInfo_MatchInfo(const char *text, int state) ! 270: { ! 271: return DebugInfo_Match(text, state, false); ! 272: } ! 273: ! 274: ! 275: /** ! 276: * Show requested command information. ! 277: */ ! 278: int DebugInfo_Command(int nArgc, char *psArgs[]) ! 279: { ! 280: Uint32 value; ! 281: const char *cmd; ! 282: bool ok, lock; ! 283: int i, sub; ! 284: ! 285: sub = -1; ! 286: if (nArgc > 1) { ! 287: cmd = psArgs[1]; ! 288: /* which subcommand? */ ! 289: for (i = 0; i < ARRAYSIZE(infotable); i++) { ! 290: if (strcmp(cmd, infotable[i].name) == 0) { ! 291: sub = i; ! 292: break; ! 293: } ! 294: } ! 295: } ! 296: ! 297: if (infotable[sub].args) { ! 298: /* value needs callback specific conversion */ ! 299: value = infotable[sub].args(nArgc-2, psArgs+2); ! 300: ok = !!value; ! 301: } else { ! 302: if (nArgc > 2) { ! 303: /* value is normal number */ ! 304: ok = Eval_Number(psArgs[2], &value); ! 305: } else { ! 306: value = 0; ! 307: ok = true; ! 308: } ! 309: } ! 310: ! 311: lock = (strcmp(psArgs[0], "lock") == 0); ! 312: ! 313: if (sub < 0 || !ok) { ! 314: /* no subcommand or something wrong with value, show info */ ! 315: fprintf(stderr, "%s subcommands are:\n", psArgs[0]); ! 316: for (i = 0; i < ARRAYSIZE(infotable); i++) { ! 317: if (!lock && infotable[i].lock) { ! 318: continue; ! 319: } ! 320: fprintf(stderr, "- %s: %s\n", ! 321: infotable[i].name, infotable[i].info); ! 322: } ! 323: return DEBUGGER_CMDDONE; ! 324: } ! 325: ! 326: if (lock) { ! 327: /* lock given subcommand and value */ ! 328: LockedFunction = sub; ! 329: LockedArgument = value; ! 330: fprintf(stderr, "Locked %s output.\n", psArgs[1]); ! 331: } else { ! 332: /* do actual work */ ! 333: infotable[sub].func(value); ! 334: } ! 335: return DEBUGGER_CMDDONE; ! 336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.