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