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

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

unix.superglobalmegacorp.com

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