|
|
1.1 root 1: /*
2: * Hatari - log.c
3: *
1.1.1.4 root 4: * This file is distributed under the GNU General Public License, version 2
5: * or at your option any later version. Read the file gpl.txt for details.
1.1 root 6: *
7: * Logger functions.
8: *
9: * When Hatari runs, it can output information, debug, warning and error texts
10: * to the error log file and/or displays them in alert dialog boxes.
11: *
12: * It can also dynamically output trace messages, based on the content
13: * of LogTraceFlags. Multiple trace levels can be set at once, by setting
14: * the corresponding bits in LogTraceFlags.
15: */
16: const char Log_fileid[] = "Hatari log.c : " __DATE__ " " __TIME__;
17:
18: #include <stdio.h>
19: #include <stdarg.h>
20: #include <stdlib.h>
21: #include <string.h>
22: #include <ctype.h>
1.1.1.9 ! root 23: #include <assert.h>
1.1 root 24:
25: #include "main.h"
26: #include "configuration.h"
27: #include "dialog.h"
28: #include "log.h"
29: #include "screen.h"
30: #include "file.h"
1.1.1.2 root 31: #include "vdi.h"
1.1.1.6 root 32: #include "options.h"
1.1 root 33:
1.1.1.5 root 34: int ExceptionDebugMask;
35:
36: typedef struct {
37: Uint64 flag;
38: const char *name;
39: } flagname_t;
40:
41: static flagname_t ExceptionFlags[] = {
42: { EXCEPT_NONE, "none" },
43:
44: { EXCEPT_BUS, "bus" },
45: { EXCEPT_ADDRESS, "address" },
46: { EXCEPT_ILLEGAL, "illegal" },
47: { EXCEPT_ZERODIV, "zerodiv" },
48: { EXCEPT_CHK, "chk" },
49: { EXCEPT_TRAPV, "trapv" },
50: { EXCEPT_PRIVILEGE, "privilege" },
1.1.1.7 root 51: { EXCEPT_TRACE, "trace" },
1.1.1.5 root 52: { EXCEPT_NOHANDLER, "nohandler" },
53:
54: { EXCEPT_DSP, "dsp" },
55:
56: { EXCEPT_AUTOSTART, "autostart" },
57:
58: { EXCEPT_ALL, "all" }
59: };
60:
1.1.1.3 root 61: #if ENABLE_TRACING
1.1.1.5 root 62: static flagname_t TraceFlags[] = {
1.1 root 63: { TRACE_NONE , "none" },
64:
65: { TRACE_VIDEO_SYNC , "video_sync" } ,
66: { TRACE_VIDEO_RES , "video_res" } ,
67: { TRACE_VIDEO_COLOR , "video_color" } ,
68: { TRACE_VIDEO_BORDER_V , "video_border_v" } ,
69: { TRACE_VIDEO_BORDER_H , "video_border_h" } ,
70: { TRACE_VIDEO_ADDR , "video_addr" } ,
71: { TRACE_VIDEO_HBL , "video_hbl" } ,
72: { TRACE_VIDEO_VBL , "video_vbl" } ,
73: { TRACE_VIDEO_STE , "video_ste" } ,
74: { TRACE_VIDEO_ALL , "video_all" } ,
75:
76: { TRACE_MFP_EXCEPTION , "mfp_exception" } ,
77: { TRACE_MFP_START , "mfp_start" } ,
78: { TRACE_MFP_READ , "mfp_read" } ,
79: { TRACE_MFP_WRITE , "mfp_write" } ,
80: { TRACE_MFP_ALL , "mfp_all" } ,
81:
82: { TRACE_PSG_READ , "psg_read" } ,
83: { TRACE_PSG_WRITE , "psg_write" } ,
84: { TRACE_PSG_ALL , "psg_all" } ,
85:
86: { TRACE_CPU_PAIRING , "cpu_pairing" } ,
87: { TRACE_CPU_DISASM , "cpu_disasm" } ,
88: { TRACE_CPU_EXCEPTION , "cpu_exception" } ,
1.1.1.8 root 89: { TRACE_CPU_REGS , "cpu_regs" } ,
1.1 root 90: { TRACE_CPU_ALL , "cpu_all" } ,
91:
92: { TRACE_INT , "int" } ,
93:
94: { TRACE_FDC , "fdc" } ,
95:
1.1.1.4 root 96: { TRACE_ACIA , "acia" } ,
97:
1.1 root 98: { TRACE_IKBD_CMDS , "ikbd_cmds" } ,
99: { TRACE_IKBD_ACIA , "ikbd_acia" } ,
100: { TRACE_IKBD_EXEC , "ikbd_exec" } ,
101: { TRACE_IKBD_ALL , "ikbd_all" } ,
102:
103: { TRACE_BLITTER , "blitter" } ,
104:
105: { TRACE_OS_BIOS , "bios" },
106: { TRACE_OS_XBIOS , "xbios" },
107: { TRACE_OS_GEMDOS , "gemdos" },
108: { TRACE_OS_VDI , "vdi" },
1.1.1.2 root 109: { TRACE_OS_AES , "aes" },
1.1 root 110: { TRACE_OS_ALL , "os_all" } ,
111:
112: { TRACE_IOMEM_RD , "io_read" } ,
113: { TRACE_IOMEM_WR , "io_write" } ,
114: { TRACE_IOMEM_ALL , "io_all" } ,
115:
116: { TRACE_DMASND , "dmasound" } ,
117:
118: { TRACE_CROSSBAR , "crossbar" } ,
119:
1.1.1.2 root 120: { TRACE_VIDEL , "videl" } ,
121:
122: { TRACE_DSP_HOST_INTERFACE, "dsp_host_interface" },
123: { TRACE_DSP_HOST_COMMAND , "dsp_host_command" },
124: { TRACE_DSP_HOST_SSI , "dsp_host_ssi" },
125: { TRACE_DSP_INTERRUPT , "dsp_interrupt" },
126: { TRACE_DSP_DISASM , "dsp_disasm" },
127: { TRACE_DSP_DISASM_REG , "dsp_disasm_reg" },
128: { TRACE_DSP_DISASM_MEM , "dsp_disasm_mem" },
129: { TRACE_DSP_STATE , "dsp_state" },
130: { TRACE_DSP_ALL , "dsp_all" },
131:
1.1.1.3 root 132: { TRACE_DSP_SYMBOLS , "dsp_symbols" },
133: { TRACE_CPU_SYMBOLS , "cpu_symbols" },
134:
1.1.1.5 root 135: { TRACE_NVRAM , "nvram" } ,
136:
137: { TRACE_SCSI_CMD , "scsi_cmd" } ,
138:
139: { TRACE_NATFEATS , "natfeats" } ,
1.1.1.4 root 140:
1.1.1.6 root 141: { TRACE_KEYMAP , "keymap" } ,
142:
143: { TRACE_MIDI , "midi" } ,
144:
145: { TRACE_IDE , "ide" } ,
146:
147: { TRACE_OS_BASE , "os_base" } ,
148:
1.1.1.7 root 149: { TRACE_SCSIDRV , "scsidrv" } ,
150:
1.1.1.8 root 151: { TRACE_MEM , "mem" } ,
152:
1.1 root 153: { TRACE_ALL , "all" }
154: };
1.1.1.3 root 155: #endif /* ENABLE_TRACING */
1.1 root 156:
157:
1.1.1.2 root 158: Uint64 LogTraceFlags = TRACE_NONE;
1.1 root 159: FILE *TraceFile = NULL;
160:
161: static FILE *hLogFile = NULL;
1.1.1.9 ! root 162:
! 163: /* local settings, to be able change them temporarily */
1.1 root 164: static LOGTYPE TextLogLevel;
165: static LOGTYPE AlertDlgLogLevel;
166:
167: /*-----------------------------------------------------------------------*/
168: /**
1.1.1.6 root 169: * Set default files to stderr (used at the very start, before parsing options)
170: */
171: void Log_Default(void)
172: {
173: hLogFile = stderr;
174: TraceFile = stderr;
1.1.1.7 root 175: TextLogLevel = LOG_INFO;
1.1.1.6 root 176: }
177:
1.1.1.9 ! root 178: /**
! 179: * Set local log levels from configuration values
! 180: */
! 181: void Log_SetLevels(void)
! 182: {
! 183: TextLogLevel = ConfigureParams.Log.nTextLogLevel;
! 184: AlertDlgLogLevel = ConfigureParams.Log.nAlertDlgLogLevel;
! 185: }
! 186:
1.1.1.6 root 187: /*-----------------------------------------------------------------------*/
188: /**
1.1 root 189: * Initialize the logging and tracing functionality (open the log files etc.).
190: *
191: * Return zero if that fails.
192: */
193: int Log_Init(void)
194: {
1.1.1.9 ! root 195: Log_SetLevels();
1.1 root 196:
197: hLogFile = File_Open(ConfigureParams.Log.sLogFileName, "w");
198: TraceFile = File_Open(ConfigureParams.Log.sTraceFileName, "w");
199:
200: return (hLogFile && TraceFile);
201: }
202:
203: /**
204: * Set Alert log level temporarily without config change.
205: *
206: * Return old level for restoring the original level with this.
207: */
208: int Log_SetAlertLevel(int level)
209: {
210: int old = AlertDlgLogLevel;
211: AlertDlgLogLevel = level;
212: return old;
213: }
214:
215:
216: /*-----------------------------------------------------------------------*/
217: /**
218: * Un-Initialize - close log files etc.
219: */
220: void Log_UnInit(void)
221: {
222: hLogFile = File_Close(hLogFile);
223: TraceFile = File_Close(TraceFile);
224: }
225:
226:
227: /*-----------------------------------------------------------------------*/
228: /**
1.1.1.9 ! root 229: * Print log prefix when needed
! 230: */
! 231: static void Log_PrintPrefix(FILE *fp, LOGTYPE idx)
! 232: {
! 233: static const char* prefix[] = LOG_NAMES;
! 234:
! 235: assert(idx >= 0 && idx < ARRAY_SIZE(prefix));
! 236: if (prefix[idx])
! 237: fprintf(fp, "%s: ", prefix[idx]);
! 238: }
! 239:
! 240:
! 241: /*-----------------------------------------------------------------------*/
! 242: /**
1.1 root 243: * Output string to log file
244: */
245: void Log_Printf(LOGTYPE nType, const char *psFormat, ...)
246: {
247: va_list argptr;
248:
249: if (hLogFile && nType <= TextLogLevel)
250: {
1.1.1.9 ! root 251: Log_PrintPrefix(hLogFile, nType);
1.1 root 252: va_start(argptr, psFormat);
253: vfprintf(hLogFile, psFormat, argptr);
254: va_end(argptr);
255: /* Add a new-line if necessary: */
256: if (psFormat[strlen(psFormat)-1] != '\n')
257: fputs("\n", hLogFile);
258: }
259: }
260:
261:
262: /*-----------------------------------------------------------------------*/
263: /**
264: * Show logging alert dialog box and output string to log file
265: */
266: void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
267: {
268: va_list argptr;
269:
270: /* Output to log file: */
271: if (hLogFile && nType <= TextLogLevel)
272: {
1.1.1.9 ! root 273: Log_PrintPrefix(hLogFile, nType);
1.1 root 274: va_start(argptr, psFormat);
275: vfprintf(hLogFile, psFormat, argptr);
276: va_end(argptr);
277: /* Add a new-line if necessary: */
278: if (psFormat[strlen(psFormat)-1] != '\n')
279: fputs("\n", hLogFile);
280: }
281:
282: /* Show alert dialog box: */
283: if (sdlscrn && nType <= AlertDlgLogLevel)
284: {
285: char *psTmpBuf;
286: psTmpBuf = malloc(2048);
287: if (!psTmpBuf)
288: {
289: perror("Log_AlertDlg");
290: return;
291: }
292: va_start(argptr, psFormat);
293: vsnprintf(psTmpBuf, 2048, psFormat, argptr);
294: va_end(argptr);
295: DlgAlert_Notice(psTmpBuf);
296: free(psTmpBuf);
297: }
298: }
299:
300:
301: /*-----------------------------------------------------------------------*/
302: /**
303: * parse what log level should be used and return it
304: */
305: LOGTYPE Log_ParseOptions(const char *arg)
306: {
307: const char *levels[] = {
308: "fatal", "error", "warn", "info", "todo", "debug", NULL
309: };
310: LOGTYPE level = LOG_FATAL;
311: const char **level_str;
312: char *input, *str;
313:
314: input = strdup(arg);
315: str = input;
316: while (*str)
317: {
1.1.1.5 root 318: *str++ = tolower((unsigned char)*arg++);
1.1 root 319: }
320: for (level_str = levels; *level_str; level_str++, level++)
321: {
322: if (strcmp(input, *level_str) == 0)
323: {
324: free(input);
325: return level;
326: }
327: }
328: free(input);
329: return level;
330: }
331:
332:
333: /*-----------------------------------------------------------------------*/
334: /**
335: * Parse a list of comma separated strings.
336: * If the string is prefixed with an optional '+',
1.1.1.5 root 337: * corresponding mask flag is turned on.
1.1 root 338: * If the string is prefixed with a '-',
1.1.1.5 root 339: * corresponding mask flag is turned off.
1.1 root 340: * Return error string (""=silent 'error') or NULL for success.
341: */
1.1.1.5 root 342: static const char*
343: Log_ParseOptionFlags (const char *FlagsStr, flagname_t *Flags, int MaxFlags, Uint64 *Mask)
1.1 root 344: {
1.1.1.5 root 345: char *FlagsCopy;
1.1 root 346: char *cur, *sep;
347: int i;
348: int Mode; /* 0=add, 1=del */
349:
1.1.1.5 root 350: /* special case for "help" : display the list of possible settings */
351: if (strcmp (FlagsStr, "help") == 0)
1.1 root 352: {
1.1.1.5 root 353: fprintf(stderr, "\nList of available option flags :\n");
1.1 root 354:
1.1.1.5 root 355: for (i = 0; i < MaxFlags; i++)
356: fprintf(stderr, " %s\n", Flags[i].name);
1.1 root 357:
1.1.1.5 root 358: fprintf(stderr, "Multiple flags can be separated by ','.\n");
359: fprintf(stderr, "They can be prefixed by '+' or '-' to be mixed.\n");
360: fprintf(stderr, "Giving just 'none' flag disables all of them.\n\n");
1.1 root 361: return "";
362: }
363:
1.1.1.5 root 364: if (strcmp (FlagsStr, "none") == 0)
1.1 root 365: {
366: return NULL;
367: }
368:
1.1.1.5 root 369: FlagsCopy = strdup(FlagsStr);
370: if (!FlagsCopy)
1.1 root 371: {
1.1.1.5 root 372: return "strdup error in Log_OptionFlags";
1.1 root 373: }
374:
1.1.1.5 root 375: cur = FlagsCopy;
1.1 root 376: while (cur)
377: {
378: sep = strchr(cur, ',');
379: if (sep) /* end of next options */
380: *sep++ = '\0';
381:
382: Mode = 0; /* default is 'add' */
383: if (*cur == '+')
384: { Mode = 0; cur++; }
385: else if (*cur == '-')
386: { Mode = 1; cur++; }
387:
1.1.1.5 root 388: for (i = 0; i < MaxFlags; i++)
1.1 root 389: {
1.1.1.5 root 390: if (strcmp(cur, Flags[i].name) == 0)
1.1 root 391: break;
392: }
393:
1.1.1.5 root 394: if (i < MaxFlags) /* option found */
1.1 root 395: {
396: if (Mode == 0)
1.1.1.5 root 397: *Mask |= Flags[i].flag;
1.1 root 398: else
1.1.1.5 root 399: *Mask &= (~Flags[i].flag);
1.1 root 400: }
401: else
402: {
1.1.1.5 root 403: fprintf(stderr, "Unknown flag type '%s'\n", cur);
404: free(FlagsCopy);
405: return "Unknown flag type.";
1.1 root 406: }
407:
408: cur = sep;
409: }
1.1.1.2 root 410:
1.1.1.5 root 411: //fprintf(stderr, "flags parse <%x>\n", Mask);
1.1 root 412:
1.1.1.5 root 413: free (FlagsCopy);
1.1 root 414: return NULL;
415: }
416:
1.1.1.5 root 417: /**
418: * Parse exception flags and store results in ExceptionDebugMask.
419: * Return error string or NULL for success.
420: *
421: * See Log_ParseOptionFlags() for details.
422: */
423: const char* Log_SetExceptionDebugMask (const char *FlagsStr)
424: {
425: const char *errstr;
426:
427: Uint64 mask = EXCEPT_NONE;
1.1.1.7 root 428: errstr = Log_ParseOptionFlags(FlagsStr, ExceptionFlags, ARRAY_SIZE(ExceptionFlags), &mask);
1.1.1.8 root 429: ConfigureParams.Debugger.nExceptionDebugMask = mask;
1.1.1.5 root 430: return errstr;
431: }
432:
433:
434: #if ENABLE_TRACING
435:
436: /**
437: * Parse trace flags and store results in LogTraceFlags.
438: * Return error string or NULL for success.
439: *
440: * See Log_ParseOptionFlags() for details.
441: */
442: const char* Log_SetTraceOptions (const char *FlagsStr)
443: {
444: const char *errstr;
445:
446: LogTraceFlags = TRACE_NONE;
1.1.1.7 root 447: errstr = Log_ParseOptionFlags(FlagsStr, TraceFlags, ARRAY_SIZE(TraceFlags), &LogTraceFlags);
1.1.1.5 root 448:
449: /* Enable Hatari flags needed for tracing selected items */
450: if (LogTraceFlags & (TRACE_OS_AES|TRACE_OS_VDI))
451: bVdiAesIntercept = true;
452:
1.1.1.6 root 453: if ((LogTraceFlags & TRACE_OS_BASE) && ConOutDevice == CONOUT_DEVICE_NONE)
454: ConOutDevice = 2;
455:
1.1.1.5 root 456: return errstr;
457: }
1.1 root 458:
459: /**
460: * Readline match callback for trace type name completion.
461: * STATE = 0 -> different text from previous one.
462: * Return next match or NULL if no matches.
463: */
464: char *Log_MatchTrace(const char *text, int state)
465: {
466: static int i, len;
467: const char *name;
468:
469: if (!state) {
470: /* first match */
471: len = strlen(text);
472: i = 0;
473: }
474: /* next match */
1.1.1.7 root 475: while (i < ARRAY_SIZE(TraceFlags)) {
1.1.1.5 root 476: name = TraceFlags[i++].name;
1.1 root 477: if (strncasecmp(name, text, len) == 0)
478: return (strdup(name));
479: }
480: return NULL;
481: }
482:
483: #else /* !ENABLE_TRACING */
484:
485: /** dummy */
1.1.1.5 root 486: const char* Log_SetTraceOptions (const char *FlagsStr)
1.1 root 487: {
488: return "Hatari has been compiled without ENABLE_TRACING!";
489: }
490:
491: /** dummy */
492: char *Log_MatchTrace(const char *text, int state)
493: {
494: return NULL;
495: }
496:
497: #endif /* !ENABLE_TRACING */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.