1b725ae77Skettenis /*
2b725ae77Skettenis * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3b725ae77Skettenis *
4b725ae77Skettenis * This software may be freely used, copied, modified, and distributed
5b725ae77Skettenis * provided that the above copyright notice is preserved in all copies of the
6b725ae77Skettenis * software.
7b725ae77Skettenis */
8b725ae77Skettenis
9b725ae77Skettenis /* -*-C-*-
10b725ae77Skettenis *
11*63addd46Skettenis * $Revision: 1.3 $
12*63addd46Skettenis * $Date: 2004/12/27 14:00:54 $
13b725ae77Skettenis *
14b725ae77Skettenis *
15b725ae77Skettenis * logging.c - methods for logging warnings, errors and trace info
16b725ae77Skettenis *
17b725ae77Skettenis */
18b725ae77Skettenis
19b725ae77Skettenis #include <stdarg.h> /* ANSI varargs support */
20b725ae77Skettenis
21b725ae77Skettenis #ifdef TARGET
22b725ae77Skettenis # include "angel.h"
23b725ae77Skettenis # include "devconf.h"
24b725ae77Skettenis #else
25b725ae77Skettenis # include "host.h"
26b725ae77Skettenis #endif
27b725ae77Skettenis
28b725ae77Skettenis #include "logging.h" /* Header file for this source code */
29b725ae77Skettenis
30b725ae77Skettenis #ifndef UNUSED
31b725ae77Skettenis # define UNUSED(x) ((x)=(x))
32b725ae77Skettenis #endif
33b725ae77Skettenis
34b725ae77Skettenis /*
35b725ae77Skettenis * __rt_warning
36b725ae77Skettenis * ------------
37b725ae77Skettenis * This routine is provided as a standard method of generating
38b725ae77Skettenis * run-time system warnings. The actual action taken by this code can
39b725ae77Skettenis * be board or target application specific, e.g. internal logging,
40b725ae77Skettenis * debug message, etc.
41b725ae77Skettenis */
42b725ae77Skettenis
43b725ae77Skettenis #ifdef DEBUG
44b725ae77Skettenis
45b725ae77Skettenis # ifdef DEBUG_METHOD
46b725ae77Skettenis
47b725ae77Skettenis # define STRINGIFY2(x) #x
48b725ae77Skettenis # define STRINGIFY(x) STRINGIFY2(x)
49b725ae77Skettenis # define DEBUG_METHOD_HEADER STRINGIFY(DEBUG_METHOD##.h)
50b725ae77Skettenis
51b725ae77Skettenis # include DEBUG_METHOD_HEADER
52b725ae77Skettenis
53b725ae77Skettenis # define METHOD_EXPAND_2(m, p, c) m##p(c)
54b725ae77Skettenis # define METHOD_EXPAND(m, p, c) METHOD_EXPAND_2(m, p, c)
55b725ae77Skettenis
56b725ae77Skettenis # define CHAROUT(c) METHOD_EXPAND(DEBUG_METHOD, _PutChar, (c))
57b725ae77Skettenis # define PRE_DEBUG(l) METHOD_EXPAND(DEBUG_METHOD, _PreWarn, (l))
58b725ae77Skettenis # define POST_DEBUG(n) METHOD_EXPAND(DEBUG_METHOD, _PostWarn, (n))
59b725ae77Skettenis
60b725ae77Skettenis # else
61b725ae77Skettenis # error Must define DEBUG_METHOD
62b725ae77Skettenis # endif
63b725ae77Skettenis
64b725ae77Skettenis #endif /* def DEBUG */
65b725ae77Skettenis
66b725ae77Skettenis /*
67b725ae77Skettenis * the guts of __rt_warning
68b725ae77Skettenis */
69b725ae77Skettenis
70b725ae77Skettenis #pragma no_check_stack
71b725ae77Skettenis #ifdef DEBUG
72b725ae77Skettenis
73b725ae77Skettenis static const char hextab[] = "0123456789ABCDEF";
74b725ae77Skettenis
75b725ae77Skettenis /*
76b725ae77Skettenis * If debugging, then we break va_warn into sub-functions which
77b725ae77Skettenis * allow us to get an easy breakpoint on the formatted string
78b725ae77Skettenis */
va_warn0(char * format,va_list args)79b725ae77Skettenis static int va_warn0(char *format, va_list args)
80b725ae77Skettenis {
81b725ae77Skettenis int len = 0;
82b725ae77Skettenis
83b725ae77Skettenis while ((format != NULL) && (*format != '\0'))
84b725ae77Skettenis {
85b725ae77Skettenis if (*format == '%')
86b725ae77Skettenis {
87b725ae77Skettenis char fch = *(++format); /* get format character (skipping '%') */
88b725ae77Skettenis int ival; /* holder for integer arguments */
89b725ae77Skettenis char *string; /* holder for string arguments */
90b725ae77Skettenis int width = 0; /* No field width by default */
91b725ae77Skettenis int padzero = FALSE; /* By default we pad with spaces */
92b725ae77Skettenis
93b725ae77Skettenis /*
94b725ae77Skettenis * Check if the format has a width specified. NOTE: We do
95b725ae77Skettenis * not use the "isdigit" function here, since it will
96b725ae77Skettenis * require run-time support. The current ARM Ltd header
97b725ae77Skettenis * defines "isdigit" as a macro, that uses a fixed
98b725ae77Skettenis * character description table.
99b725ae77Skettenis */
100b725ae77Skettenis if ((fch >= '0') && (fch <= '9'))
101b725ae77Skettenis {
102b725ae77Skettenis if (fch == '0')
103b725ae77Skettenis {
104b725ae77Skettenis /* Leading zeroes padding */
105b725ae77Skettenis padzero = TRUE;
106b725ae77Skettenis fch = *(++format);
107b725ae77Skettenis }
108b725ae77Skettenis
109b725ae77Skettenis while ((fch >= '0') && (fch <= '9'))
110b725ae77Skettenis {
111b725ae77Skettenis width = ((width * 10) + (fch - '0'));
112b725ae77Skettenis fch = *(++format);
113b725ae77Skettenis }
114b725ae77Skettenis }
115b725ae77Skettenis
116b725ae77Skettenis if (fch == 'l')
117b725ae77Skettenis /* skip 'l' in "%lx", etc. */
118b725ae77Skettenis fch = *(++format);
119b725ae77Skettenis
120b725ae77Skettenis switch (fch)
121b725ae77Skettenis {
122b725ae77Skettenis case 'c':
123b725ae77Skettenis /* char */
124b725ae77Skettenis ival = va_arg(args, int);
125b725ae77Skettenis CHAROUT((char)ival);
126b725ae77Skettenis len++;
127b725ae77Skettenis break;
128b725ae77Skettenis
129b725ae77Skettenis case 'x':
130b725ae77Skettenis case 'X':
131b725ae77Skettenis {
132b725ae77Skettenis /* hexadecimal */
133b725ae77Skettenis unsigned int uval = va_arg(args, unsigned int);
134b725ae77Skettenis int loop;
135b725ae77Skettenis
136b725ae77Skettenis UNUSED(uval);
137b725ae77Skettenis
138b725ae77Skettenis if ((width == 0) || (width > 8))
139b725ae77Skettenis width = 8;
140b725ae77Skettenis
141b725ae77Skettenis for(loop = (width * 4); (loop != 0); loop -= 4)
142b725ae77Skettenis {
143b725ae77Skettenis CHAROUT(hextab[(uval >> (loop - 4)) & 0xF]);
144b725ae77Skettenis len++;
145b725ae77Skettenis }
146b725ae77Skettenis }
147b725ae77Skettenis
148b725ae77Skettenis break;
149b725ae77Skettenis
150b725ae77Skettenis case 'd':
151b725ae77Skettenis /* decimal */
152b725ae77Skettenis ival = va_arg(args, int);
153b725ae77Skettenis
154b725ae77Skettenis if (ival < 0)
155b725ae77Skettenis {
156b725ae77Skettenis ival = -ival;
157b725ae77Skettenis CHAROUT('-');
158b725ae77Skettenis len++;
159b725ae77Skettenis }
160b725ae77Skettenis
161b725ae77Skettenis if (ival == 0)
162b725ae77Skettenis {
163b725ae77Skettenis CHAROUT('0');
164b725ae77Skettenis len++;
165b725ae77Skettenis }
166b725ae77Skettenis else
167b725ae77Skettenis {
168b725ae77Skettenis /*
169b725ae77Skettenis * The simplest method of displaying numbers is
170b725ae77Skettenis * to provide a small recursive routine, that
171b725ae77Skettenis * nests until the most-significant digit is
172b725ae77Skettenis * reached, and then falls back out displaying
173b725ae77Skettenis * individual digits. However, we want to avoid
174b725ae77Skettenis * using recursive code within the lo-level
175b725ae77Skettenis * parts of Angel (to minimise the stack
176b725ae77Skettenis * usage). The following number conversion is a
177b725ae77Skettenis * non-recursive solution.
178b725ae77Skettenis */
179b725ae77Skettenis char buffer[16]; /* stack space used to hold number */
180b725ae77Skettenis int count = 0; /* pointer into buffer */
181b725ae77Skettenis
182b725ae77Skettenis /*
183b725ae77Skettenis * Place the conversion into the buffer in
184b725ae77Skettenis * reverse order:
185b725ae77Skettenis */
186b725ae77Skettenis while (ival != 0)
187b725ae77Skettenis {
188b725ae77Skettenis buffer[count++] = ('0' + ((unsigned int)ival % 10));
189b725ae77Skettenis ival = ((unsigned int)ival / 10);
190b725ae77Skettenis }
191b725ae77Skettenis
192b725ae77Skettenis /*
193b725ae77Skettenis * Check if we are placing the data in a
194b725ae77Skettenis * fixed width field:
195b725ae77Skettenis */
196b725ae77Skettenis if (width != 0)
197b725ae77Skettenis {
198b725ae77Skettenis width -= count;
199b725ae77Skettenis
200b725ae77Skettenis for (; (width != 0); width--)
201b725ae77Skettenis {
202b725ae77Skettenis CHAROUT(padzero ? '0': ' ');
203b725ae77Skettenis len++;
204b725ae77Skettenis }
205b725ae77Skettenis }
206b725ae77Skettenis
207b725ae77Skettenis /* then display the buffer in reverse order */
208b725ae77Skettenis for (; (count != 0); count--)
209b725ae77Skettenis {
210b725ae77Skettenis CHAROUT(buffer[count - 1]);
211b725ae77Skettenis len++;
212b725ae77Skettenis }
213b725ae77Skettenis }
214b725ae77Skettenis
215b725ae77Skettenis break;
216b725ae77Skettenis
217b725ae77Skettenis case 's':
218b725ae77Skettenis /* string */
219b725ae77Skettenis string = va_arg(args, char *);
220b725ae77Skettenis
221b725ae77Skettenis /* we only need this test once */
222b725ae77Skettenis if (string != NULL)
223b725ae77Skettenis /* whilst we check this for every character */
224b725ae77Skettenis while (*string)
225b725ae77Skettenis {
226b725ae77Skettenis CHAROUT(*string);
227b725ae77Skettenis len++;
228b725ae77Skettenis string++;
229b725ae77Skettenis
230b725ae77Skettenis /*
231b725ae77Skettenis * NOTE: We do not use "*string++" as the macro
232b725ae77Skettenis * parameter, since we do not know how many times
233b725ae77Skettenis *the parameter may be expanded within the macro.
234b725ae77Skettenis */
235b725ae77Skettenis }
236b725ae77Skettenis
237b725ae77Skettenis break;
238b725ae77Skettenis
239b725ae77Skettenis case '\0':
240b725ae77Skettenis /*
241b725ae77Skettenis * string terminated by '%' character, bodge things
242b725ae77Skettenis * to prepare for default "format++" below
243b725ae77Skettenis */
244b725ae77Skettenis format--;
245b725ae77Skettenis
246b725ae77Skettenis break;
247b725ae77Skettenis
248b725ae77Skettenis default:
249b725ae77Skettenis /* just display the character */
250b725ae77Skettenis CHAROUT(*format);
251b725ae77Skettenis len++;
252b725ae77Skettenis
253b725ae77Skettenis break;
254b725ae77Skettenis }
255b725ae77Skettenis
256b725ae77Skettenis format++; /* step over format character */
257b725ae77Skettenis }
258b725ae77Skettenis else
259b725ae77Skettenis {
260b725ae77Skettenis CHAROUT(*format);
261b725ae77Skettenis len++;
262b725ae77Skettenis format++;
263b725ae77Skettenis }
264b725ae77Skettenis }
265b725ae77Skettenis return len;
266b725ae77Skettenis }
267b725ae77Skettenis
268b725ae77Skettenis /*
269b725ae77Skettenis * this routine is simply here as a good breakpoint for dumping msg -
270b725ae77Skettenis * can be used by DEBUG_METHOD macros or functions, if required.
271b725ae77Skettenis */
272b725ae77Skettenis # ifdef DEBUG_NEED_VA_WARN1
va_warn1(int len,char * msg)273b725ae77Skettenis static void va_warn1(int len, char *msg)
274b725ae77Skettenis {
275b725ae77Skettenis UNUSED(len); UNUSED(msg);
276b725ae77Skettenis }
277b725ae77Skettenis # endif
278b725ae77Skettenis
va_warn(WarnLevel level,char * format,va_list args)279b725ae77Skettenis void va_warn(WarnLevel level, char *format, va_list args)
280b725ae77Skettenis {
281b725ae77Skettenis int len;
282b725ae77Skettenis
283b725ae77Skettenis if ( PRE_DEBUG( level ) )
284b725ae77Skettenis {
285b725ae77Skettenis len = va_warn0(format, args);
286b725ae77Skettenis POST_DEBUG( len );
287b725ae77Skettenis }
288b725ae77Skettenis }
289b725ae77Skettenis
290b725ae77Skettenis #else /* ndef DEBUG */
291b725ae77Skettenis
va_warn(WarnLevel level,char * format,va_list args)292b725ae77Skettenis void va_warn(WarnLevel level, char *format, va_list args)
293b725ae77Skettenis {
294b725ae77Skettenis UNUSED(level); UNUSED(format); UNUSED(args);
295b725ae77Skettenis }
296b725ae77Skettenis
297b725ae77Skettenis #endif /* ... else ndef(DEBUG) ... */
298b725ae77Skettenis #pragma check_stack
299b725ae77Skettenis
300b725ae77Skettenis #pragma no_check_stack
__rt_warning(char * format,...)301b725ae77Skettenis void __rt_warning(char *format, ...)
302b725ae77Skettenis {
303b725ae77Skettenis va_list args;
304b725ae77Skettenis
305b725ae77Skettenis /*
306b725ae77Skettenis * For a multi-threaded system we should provide a lock at this point
307b725ae77Skettenis * to ensure that the warning messages are sequenced properly.
308b725ae77Skettenis */
309b725ae77Skettenis
310b725ae77Skettenis va_start(args, format);
311b725ae77Skettenis va_warn(WL_WARN, format, args);
312b725ae77Skettenis va_end(args);
313b725ae77Skettenis
314b725ae77Skettenis return;
315b725ae77Skettenis }
316b725ae77Skettenis #pragma check_stack
317b725ae77Skettenis
318b725ae77Skettenis #ifdef TARGET
319b725ae77Skettenis
320b725ae77Skettenis #pragma no_check_stack
321b725ae77Skettenis void __rt_uninterruptable_loop( void ); /* in suppasm.s */
322b725ae77Skettenis
__rt_error(char * format,...)323b725ae77Skettenis void __rt_error(char *format, ...)
324b725ae77Skettenis {
325b725ae77Skettenis va_list args;
326b725ae77Skettenis
327b725ae77Skettenis va_start(args, format);
328b725ae77Skettenis
329b725ae77Skettenis /* Display warning message */
330b725ae77Skettenis va_warn(WL_ERROR, format, args);
331b725ae77Skettenis
332b725ae77Skettenis __rt_uninterruptable_loop();
333b725ae77Skettenis
334b725ae77Skettenis va_end(args);
335b725ae77Skettenis return;
336b725ae77Skettenis }
337b725ae77Skettenis #pragma check_stack
338b725ae77Skettenis
339b725ae77Skettenis #endif /* def TARGET */
340b725ae77Skettenis
341b725ae77Skettenis #ifdef DO_TRACE
342b725ae77Skettenis
343b725ae77Skettenis static bool trace_on = FALSE; /* must be set true in debugger if req'd */
344b725ae77Skettenis
345b725ae77Skettenis #pragma no_check_stack
__rt_trace(char * format,...)346b725ae77Skettenis void __rt_trace(char *format, ...)
347b725ae77Skettenis {
348b725ae77Skettenis va_list args;
349b725ae77Skettenis
350b725ae77Skettenis /*
351b725ae77Skettenis * For a multi-threaded system we should provide a lock at this point
352b725ae77Skettenis * to ensure that the warning messages are sequenced properly.
353b725ae77Skettenis */
354b725ae77Skettenis
355b725ae77Skettenis if (trace_on)
356b725ae77Skettenis {
357b725ae77Skettenis va_start(args, format);
358b725ae77Skettenis va_warn(WL_TRACE, format, args);
359b725ae77Skettenis va_end(args);
360b725ae77Skettenis }
361b725ae77Skettenis
362b725ae77Skettenis return;
363b725ae77Skettenis }
364b725ae77Skettenis #pragma check_stack
365b725ae77Skettenis
366b725ae77Skettenis #endif /* def DO_TRACE */
367b725ae77Skettenis
368b725ae77Skettenis
369b725ae77Skettenis /* EOF logging.c */
370