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