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