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