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