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