|
|
1.1 root 1: /*
2: * Hatari - history.c
3: *
1.1.1.3 ! root 4: * Copyright (C) 2011-2013 by Eero Tamminen
1.1 root 5: *
1.1.1.2 root 6: * This file is distributed under the GNU General Public License, version 2
7: * or at your option any later version. Read the file gpl.txt for details.
1.1 root 8: *
9: * history.c - functions for debugger entry & breakpoint history
10: */
11: const char History_fileid[] = "Hatari history.c : " __DATE__ " " __TIME__;
12:
13: #include <assert.h>
14:
15: #include "main.h"
16: #include "debugui.h"
17: #include "debug_priv.h"
18: #include "dsp.h"
19: #include "dsp_core.h"
20: #include "evaluate.h"
21: #include "history.h"
22: #include "m68000.h"
23: #include "68kDisass.h"
24:
1.1.1.3 ! root 25: #define HISTORY_ITEMS_MIN 64
1.1.1.2 root 26:
27: history_type_t HistoryTracking;
1.1 root 28:
29: typedef struct {
30: bool shown:1;
31: bool valid:1;
32: bool for_dsp:1;
33: /* reason for debugger entry/breakpoint hit */
34: debug_reason_t reason:8;
35: union {
36: Uint16 dsp;
37: Uint32 cpu;
38: } pc;
39: } hist_item_t;
40:
41: static struct {
1.1.1.3 ! root 42: unsigned idx; /* index to current history item */
! 43: unsigned count; /* how many items of history are collected */
! 44: unsigned limit; /* ring-buffer size */
! 45: hist_item_t *item; /* ring-buffer */
1.1 root 46: } History;
47:
48:
49: /**
50: * Convert debugger entry/breakpoint entry reason to a string
51: */
1.1.1.2 root 52: static const char* History_ReasonStr(debug_reason_t reason)
1.1 root 53: {
54: switch(reason) {
55: case REASON_CPU_EXCEPTION:
56: return "CPU exception";
57: case REASON_CPU_BREAKPOINT:
58: return "CPU breakpoint";
59: case REASON_DSP_BREAKPOINT:
60: return "DSP breakpoint";
61: case REASON_CPU_STEPS:
62: return "CPU steps";
63: case REASON_DSP_STEPS:
64: return "DSP steps";
65: case REASON_USER:
66: return "User break";
67: default:
68: return "Unknown reason";
69: }
70: }
71:
72:
73: /**
1.1.1.2 root 74: * Set what kind of history is collected.
75: * Clear history if tracking type changes as rest of
76: * data wouldn't then be anymore valid.
1.1 root 77: */
1.1.1.3 ! root 78: static void History_Enable(history_type_t track, unsigned limit)
1.1 root 79: {
1.1.1.2 root 80: const char *msg;
1.1.1.3 ! root 81: if (track != HistoryTracking || limit != History.limit) {
! 82: fprintf(stderr, "Re-allocating & zeroing history due to type/limit change.\n");
! 83: if (History.item) {
! 84: free(History.item);
! 85: }
1.1 root 86: memset(&History, 0, sizeof(History));
1.1.1.3 ! root 87: History.item = calloc(limit, sizeof(History.item[0]));
! 88: History.limit = limit;
1.1 root 89: }
1.1.1.2 root 90: switch (track) {
91: case HISTORY_TRACK_NONE:
92: msg = "disabled";
93: break;
94: case HISTORY_TRACK_CPU:
95: msg = "enabled for CPU";
96: break;
97: case HISTORY_TRACK_DSP:
98: msg = "enabled for DSP";
99: break;
100: case HISTORY_TRACK_ALL:
101: msg = "enabled for CPU & DSP";
102: break;
103: default:
104: msg = "error";
105: }
106: HistoryTracking = track;
1.1.1.3 ! root 107: fprintf(stderr, "History tracking %s (max. %d instructions).\n", msg, limit);
1.1 root 108: }
109:
110: /**
111: * Advance & initialize next history item in ring buffer
112: */
113: static void History_Advance(void)
114: {
115: History.idx++;
1.1.1.3 ! root 116: History.idx %= History.limit;
1.1 root 117: History.item[History.idx].valid = true;
118: History.item[History.idx].shown = false;
119: History.item[History.idx].reason = REASON_NONE;
120: History.count++;
121: }
122:
123: /**
124: * Add CPU PC to history
125: */
126: void History_AddCpu(void)
127: {
128: Uint32 pc = M68000_GetPC();
129:
130: History_Advance();
131: History.item[History.idx].for_dsp = false;
132: History.item[History.idx].pc.cpu = pc;
133: }
134:
135: /**
136: * Add DSP PC to history
137: */
138: void History_AddDsp(void)
139: {
140: Uint16 pc = DSP_GetPC();
141:
142: History_Advance();
143: History.item[History.idx].for_dsp = true;
144: History.item[History.idx].pc.dsp = pc;
145: }
146:
147: /**
148: * Flag last history entry as debugger entry point, with given reason
149: */
150: void History_Mark(debug_reason_t reason)
151: {
1.1.1.3 ! root 152: if (History.item) {
! 153: History.item[History.idx].reason = reason;
! 154: }
1.1 root 155: }
156:
157: /**
158: * Show collected CPU/DSP debugger/breakpoint history
159: */
160: void History_Show(Uint32 count)
161: {
162: bool show_all;
163: int i;
164:
1.1.1.3 ! root 165: if (History.count > History.limit) {
! 166: History.count = History.limit;
1.1 root 167: }
168: if (count > History.count) {
169: count = History.count;
170: } else {
171: if (!count) {
172: /* default to all */
173: count = History.count;
174: }
175: }
176: if (count <= 0) {
177: fprintf(stderr, "No history items to show.\n");
178: return;
179: }
180:
181: i = History.idx;
182: show_all = false;
183: if (History.item[i].shown) {
184: /* even last item already shown, show all again */
185: show_all = true;
186: }
1.1.1.3 ! root 187: i = (i + History.limit - count) % History.limit;
1.1 root 188:
189: while (count-- > 0) {
190: i++;
1.1.1.3 ! root 191: i %= History.limit;
1.1 root 192: if (!History.item[i].valid) {
193: fprintf(stderr, "ERROR: invalid history item %d!", count);
194: }
195: if (History.item[i].shown && !show_all) {
196: continue;
197: }
198: History.item[i].shown = true;
199:
200: if (History.item[i].for_dsp) {
201: Uint16 pc = History.item[i].pc.dsp;
1.1.1.2 root 202: DSP_DisasmAddress(stderr, pc, pc);
1.1 root 203: } else {
204: Uint32 dummy;
1.1.1.2 root 205: Disasm(stderr, History.item[i].pc.cpu, &dummy, 1);
1.1 root 206: }
207: if (History.item[i].reason != REASON_NONE) {
208: fprintf(stderr, "Debugger: *%s*\n", History_ReasonStr(History.item[i].reason));
209: }
210: }
211: }
212:
1.1.1.3 ! root 213: /*
! 214: * Readline callback
! 215: */
! 216: char *History_Match(const char *text, int state)
! 217: {
! 218: static const char* cmds[] = { "cpu", "dsp", "off" };
! 219: return DebugUI_MatchHelper(cmds, ARRAYSIZE(cmds), text, state);
! 220: }
! 221:
1.1 root 222: /**
223: * Command: Show collected CPU/DSP debugger/breakpoint history
224: */
225: int History_Parse(int nArgc, char *psArgs[])
226: {
1.1.1.3 ! root 227: int count, limit = 0;
1.1 root 228:
1.1.1.3 ! root 229: if (nArgc < 2) {
! 230: return DebugUI_PrintCmdHelp(psArgs[0]);
! 231: }
! 232: if (nArgc > 2) {
! 233: limit = atoi(psArgs[2]);
! 234: }
! 235: /* make sure value is valid & positive */
! 236: if (!limit) {
! 237: limit = History.limit;
! 238: }
! 239: if (limit < HISTORY_ITEMS_MIN) {
! 240: limit = HISTORY_ITEMS_MIN;
1.1 root 241: }
242: count = atoi(psArgs[1]);
1.1.1.3 ! root 243:
! 244: if (count <= 0) {
1.1 root 245: /* no count -> enable or disable? */
246: if (strcmp(psArgs[1], "on") == 0) {
1.1.1.3 ! root 247: History_Enable(HISTORY_TRACK_ALL, limit);
1.1 root 248: return DEBUGGER_CMDDONE;
249: }
250: if (strcmp(psArgs[1], "off") == 0) {
1.1.1.3 ! root 251: History_Enable(HISTORY_TRACK_NONE, limit);
1.1.1.2 root 252: return DEBUGGER_CMDDONE;
253: }
254: if (strcmp(psArgs[1], "cpu") == 0) {
1.1.1.3 ! root 255: History_Enable(HISTORY_TRACK_CPU, limit);
1.1.1.2 root 256: return DEBUGGER_CMDDONE;
257: }
258: if (strcmp(psArgs[1], "dsp") == 0) {
1.1.1.3 ! root 259: History_Enable(HISTORY_TRACK_DSP, limit);
1.1 root 260: return DEBUGGER_CMDDONE;
261: }
1.1.1.3 ! root 262: fprintf(stderr, "History range is 1-<limit>\n");
! 263: return DebugUI_PrintCmdHelp(psArgs[0]);
1.1 root 264: }
265:
266: History_Show(count);
267: return DEBUGGER_CMDDONE;
268: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.