Annotation of hatari/src/debug/history.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * Hatari - history.c
                      3:  * 
1.1.1.4   root        4:  * Copyright (C) 2011-2014 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>
1.1.1.4   root       14: #include <errno.h>
1.1       root       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"
1.1.1.4   root       21: #include "file.h"
1.1       root       22: #include "history.h"
                     23: #include "m68000.h"
                     24: #include "68kDisass.h"
                     25: 
1.1.1.3   root       26: #define HISTORY_ITEMS_MIN 64
1.1.1.2   root       27: 
                     28: history_type_t HistoryTracking;
1.1       root       29: 
                     30: typedef struct {
                     31:        bool shown:1;
                     32:        bool valid:1;
                     33:        bool for_dsp:1;
                     34:        /* reason for debugger entry/breakpoint hit */
                     35:        debug_reason_t reason:8;
                     36:        union {
                     37:                Uint16 dsp;
                     38:                Uint32 cpu;
                     39:        } pc;
                     40: } hist_item_t;
                     41: 
                     42: static struct {
1.1.1.3   root       43:        unsigned idx;      /* index to current history item */
                     44:        unsigned count;    /* how many items of history are collected */
                     45:        unsigned limit;    /* ring-buffer size */
                     46:        hist_item_t *item; /* ring-buffer */
1.1       root       47: } History;
                     48: 
                     49: 
                     50: /**
                     51:  * Convert debugger entry/breakpoint entry reason to a string
                     52:  */
1.1.1.2   root       53: static const char* History_ReasonStr(debug_reason_t reason)
1.1       root       54: {
                     55:        switch(reason) {
                     56:        case REASON_CPU_EXCEPTION:
                     57:                return "CPU exception";
                     58:        case REASON_CPU_BREAKPOINT:
                     59:                return "CPU breakpoint";
                     60:        case REASON_DSP_BREAKPOINT:
                     61:                return "DSP breakpoint";
                     62:        case REASON_CPU_STEPS:
                     63:                return "CPU steps";
                     64:        case REASON_DSP_STEPS:
                     65:                return "DSP steps";
1.1.1.5 ! root       66:        case REASON_PROGRAM:
        !            67:                return "Program break";
1.1       root       68:        case REASON_USER:
                     69:                return "User break";
                     70:        default:
                     71:                return "Unknown reason";
                     72:        }
                     73: }
                     74: 
                     75: 
                     76: /**
1.1.1.2   root       77:  * Set what kind of history is collected.
                     78:  * Clear history if tracking type changes as rest of
                     79:  * data wouldn't then be anymore valid.
1.1       root       80:  */
1.1.1.3   root       81: static void History_Enable(history_type_t track, unsigned limit)
1.1       root       82: {
1.1.1.2   root       83:        const char *msg;
1.1.1.3   root       84:        if (track != HistoryTracking || limit != History.limit) {
                     85:                fprintf(stderr, "Re-allocating & zeroing history due to type/limit change.\n");
                     86:                if (History.item) {
                     87:                        free(History.item);
                     88:                }
1.1       root       89:                memset(&History, 0, sizeof(History));
1.1.1.3   root       90:                History.item = calloc(limit, sizeof(History.item[0]));
                     91:                History.limit = limit;
1.1       root       92:        }
1.1.1.2   root       93:        switch (track) {
                     94:        case HISTORY_TRACK_NONE:
                     95:                msg = "disabled";
                     96:                break;
                     97:        case HISTORY_TRACK_CPU:
                     98:                msg = "enabled for CPU";
                     99:                break;
                    100:        case HISTORY_TRACK_DSP:
                    101:                msg = "enabled for DSP";
                    102:                break;
                    103:        case HISTORY_TRACK_ALL:
                    104:                msg = "enabled for CPU & DSP";
                    105:                break;
                    106:        default:
                    107:                msg = "error";
                    108:        }
                    109:        HistoryTracking = track;
1.1.1.3   root      110:        fprintf(stderr, "History tracking %s (max. %d instructions).\n", msg, limit);
1.1       root      111: }
                    112: 
                    113: /**
                    114:  * Advance & initialize next history item in ring buffer
                    115:  */
                    116: static void History_Advance(void)
                    117: {
                    118:        History.idx++;
1.1.1.3   root      119:        History.idx %= History.limit;
1.1       root      120:        History.item[History.idx].valid = true;
                    121:        History.item[History.idx].shown = false;
                    122:        History.item[History.idx].reason = REASON_NONE;
                    123:        History.count++;
                    124: }
                    125: 
                    126: /**
                    127:  * Add CPU PC to history
                    128:  */
                    129: void History_AddCpu(void)
                    130: {
                    131:        Uint32 pc = M68000_GetPC();
                    132: 
                    133:        History_Advance();
                    134:        History.item[History.idx].for_dsp = false;
                    135:        History.item[History.idx].pc.cpu = pc;
                    136: }
                    137: 
                    138: /**
                    139:  * Add DSP PC to history
                    140:  */
                    141: void History_AddDsp(void)
                    142: {
                    143:        Uint16 pc = DSP_GetPC();
                    144: 
                    145:        History_Advance();
                    146:        History.item[History.idx].for_dsp = true;
                    147:        History.item[History.idx].pc.dsp = pc;
                    148: }
                    149: 
                    150: /**
                    151:  * Flag last history entry as debugger entry point, with given reason
                    152:  */
                    153: void History_Mark(debug_reason_t reason)
                    154: {
1.1.1.3   root      155:        if (History.item) {
                    156:                History.item[History.idx].reason = reason;
                    157:        }
1.1       root      158: }
                    159: 
                    160: /**
1.1.1.4   root      161:  * Output collected CPU/DSP debugger/breakpoint history
1.1       root      162:  */
1.1.1.4   root      163: static Uint32 History_Output(Uint32 count, FILE *fp)
1.1       root      164: {
                    165:        bool show_all;
1.1.1.4   root      166:        Uint32 retval;
1.1       root      167:        int i;
                    168: 
1.1.1.3   root      169:        if (History.count > History.limit) {
                    170:                History.count = History.limit;
1.1       root      171:        }
                    172:        if (count > History.count) {
                    173:                count = History.count;
                    174:        } else {
                    175:                if (!count) {
                    176:                        /* default to all */
                    177:                        count = History.count;
                    178:                }
                    179:        }
                    180:        if (count <= 0) {
1.1.1.4   root      181:                fprintf(stderr, "No history items to show.\n");
                    182:                return 0;
1.1       root      183:        }
1.1.1.4   root      184:        retval = count;
1.1       root      185: 
                    186:        i = History.idx;
                    187:        show_all = false;
                    188:        if (History.item[i].shown) {
                    189:                /* even last item already shown, show all again */
                    190:                show_all = true;
                    191:        }
1.1.1.3   root      192:        i = (i + History.limit - count) % History.limit;
1.1       root      193: 
                    194:        while (count-- > 0) {
                    195:                i++;
1.1.1.3   root      196:                i %= History.limit;
1.1       root      197:                if (!History.item[i].valid) {
1.1.1.4   root      198:                        fprintf(fp, "ERROR: invalid history item %d!", count);
1.1       root      199:                }
                    200:                if (History.item[i].shown && !show_all) {
                    201:                        continue;
                    202:                }
                    203:                History.item[i].shown = true;
                    204: 
                    205:                if (History.item[i].for_dsp) {
                    206:                        Uint16 pc = History.item[i].pc.dsp;
1.1.1.4   root      207:                        DSP_DisasmAddress(fp, pc, pc);
1.1       root      208:                } else {
                    209:                        Uint32 dummy;
1.1.1.4   root      210:                        Disasm(fp, History.item[i].pc.cpu, &dummy, 1);
1.1       root      211:                }
                    212:                if (History.item[i].reason != REASON_NONE) {
1.1.1.4   root      213:                        fprintf(fp, "Debugger: *%s*\n", History_ReasonStr(History.item[i].reason));
1.1       root      214:                }
                    215:        }
1.1.1.4   root      216:        return retval;
                    217: }
                    218: 
                    219: /* History_Output() helper for "info" & "lock" commands */
                    220: void History_Show(FILE *fp, Uint32 count)
                    221: {
                    222:        History_Output(count, fp);
                    223: }
                    224: 
                    225: /*
                    226:  * save all history to given file
                    227:  */
                    228: static void History_Save(const char *name)
                    229: {
                    230:        Uint32 count;
                    231:        FILE *fp;
                    232: 
                    233:        if (File_Exists(name)) {
                    234:                fprintf(stderr, "ERROR: file '%s' already exists!\n", name);
                    235: 
                    236:        } else if ((fp = fopen(name, "w"))) {
                    237:                count = History_Output(0, fp);
                    238:                fprintf(stderr, "%d history items saved to '%s'.\n", count, name);
                    239:                fclose(fp);
                    240:        } else {
                    241:                fprintf(stderr, "ERROR: opening '%s' failed (%d).\n", name, errno);
                    242:        }
1.1       root      243: }
                    244: 
1.1.1.3   root      245: /*
                    246:  * Readline callback
                    247:  */
                    248: char *History_Match(const char *text, int state)
                    249: {
1.1.1.4   root      250:        static const char* cmds[] = { "cpu", "dsp", "off", "save" };
1.1.1.5 ! root      251:        return DebugUI_MatchHelper(cmds, ARRAY_SIZE(cmds), text, state);
1.1.1.3   root      252: }
                    253: 
1.1       root      254: /**
                    255:  * Command: Show collected CPU/DSP debugger/breakpoint history
                    256:  */
                    257: int History_Parse(int nArgc, char *psArgs[])
                    258: {
1.1.1.3   root      259:        int count, limit = 0;
1.1       root      260: 
1.1.1.3   root      261:        if (nArgc < 2) {
                    262:                return DebugUI_PrintCmdHelp(psArgs[0]);
                    263:        }
                    264:        if (nArgc > 2) {
                    265:                limit = atoi(psArgs[2]);
                    266:        }
                    267:        /* make sure value is valid & positive */
                    268:        if (!limit) {
                    269:                limit = History.limit;
                    270:        }
                    271:        if (limit < HISTORY_ITEMS_MIN) {
                    272:                limit = HISTORY_ITEMS_MIN;
1.1       root      273:        }
                    274:        count = atoi(psArgs[1]);
1.1.1.3   root      275: 
                    276:        if (count <= 0) {
1.1       root      277:                /* no count -> enable or disable? */
                    278:                if (strcmp(psArgs[1], "on") == 0) {
1.1.1.3   root      279:                        History_Enable(HISTORY_TRACK_ALL, limit);
1.1       root      280:                        return DEBUGGER_CMDDONE;
                    281:                }
                    282:                if (strcmp(psArgs[1], "off") == 0) {
1.1.1.3   root      283:                        History_Enable(HISTORY_TRACK_NONE, limit);
1.1.1.2   root      284:                        return DEBUGGER_CMDDONE;
                    285:                }
                    286:                if (strcmp(psArgs[1], "cpu") == 0) {
1.1.1.3   root      287:                        History_Enable(HISTORY_TRACK_CPU, limit);
1.1.1.2   root      288:                        return DEBUGGER_CMDDONE;
                    289:                }
                    290:                if (strcmp(psArgs[1], "dsp") == 0) {
1.1.1.3   root      291:                        History_Enable(HISTORY_TRACK_DSP, limit);
1.1       root      292:                        return DEBUGGER_CMDDONE;
                    293:                }
1.1.1.4   root      294:                if (nArgc == 3 && strcmp(psArgs[1], "save") == 0) {
                    295:                        History_Save(psArgs[2]);
                    296:                        return DEBUGGER_CMDDONE;
                    297:                }
1.1.1.3   root      298:                fprintf(stderr,  "History range is 1-<limit>\n");
                    299:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      300:        }
                    301: 
1.1.1.4   root      302:        History_Show(stderr, count);
1.1       root      303:        return DEBUGGER_CMDDONE;
                    304: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.