2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
4 * This software may be freely used, copied, modified, and distributed
5 * provided that the above copyright notice is preserved in all copies of the
15 * logging.c - methods for logging warnings, errors and trace info
19 #include <stdarg.h> /* ANSI varargs support */
28 #include "logging.h" /* Header file for this source code */
31 # define UNUSED(x) ((x)=(x))
37 * This routine is provided as a standard method of generating
38 * run-time system warnings. The actual action taken by this code can
39 * be board or target application specific, e.g. internal logging,
47 # define STRINGIFY2(x) #x
48 # define STRINGIFY(x) STRINGIFY2(x)
49 # define DEBUG_METHOD_HEADER STRINGIFY(DEBUG_METHOD##.h)
51 # include DEBUG_METHOD_HEADER
53 # define METHOD_EXPAND_2(m, p, c) m##p(c)
54 # define METHOD_EXPAND(m, p, c) METHOD_EXPAND_2(m, p, c)
56 # define CHAROUT(c) METHOD_EXPAND(DEBUG_METHOD, _PutChar, (c))
57 # define PRE_DEBUG(l) METHOD_EXPAND(DEBUG_METHOD, _PreWarn, (l))
58 # define POST_DEBUG(n) METHOD_EXPAND(DEBUG_METHOD, _PostWarn, (n))
61 # error Must define DEBUG_METHOD
64 #endif /* def DEBUG */
67 * the guts of __rt_warning
70 #pragma no_check_stack
73 static const char hextab
[] = "0123456789ABCDEF";
76 * If debugging, then we break va_warn into sub-functions which
77 * allow us to get an easy breakpoint on the formatted string
79 static int va_warn0(char *format
, va_list args
)
83 while ((format
!= NULL
) && (*format
!= '\0'))
87 char fch
= *(++format
); /* get format character (skipping '%') */
88 int ival
; /* holder for integer arguments */
89 char *string
; /* holder for string arguments */
90 int width
= 0; /* No field width by default */
91 int padzero
= FALSE
; /* By default we pad with spaces */
94 * Check if the format has a width specified. NOTE: We do
95 * not use the "isdigit" function here, since it will
96 * require run-time support. The current ARM Ltd header
97 * defines "isdigit" as a macro, that uses a fixed
98 * character description table.
100 if ((fch
>= '0') && (fch
<= '9'))
104 /* Leading zeroes padding */
109 while ((fch
>= '0') && (fch
<= '9'))
111 width
= ((width
* 10) + (fch
- '0'));
117 /* skip 'l' in "%lx", etc. */
124 ival
= va_arg(args
, int);
133 unsigned int uval
= va_arg(args
, unsigned int);
138 if ((width
== 0) || (width
> 8))
141 for(loop
= (width
* 4); (loop
!= 0); loop
-= 4)
143 CHAROUT(hextab
[(uval
>> (loop
- 4)) & 0xF]);
152 ival
= va_arg(args
, int);
169 * The simplest method of displaying numbers is
170 * to provide a small recursive routine, that
171 * nests until the most-significant digit is
172 * reached, and then falls back out displaying
173 * individual digits. However, we want to avoid
174 * using recursive code within the lo-level
175 * parts of Angel (to minimise the stack
176 * usage). The following number conversion is a
177 * non-recursive solution.
179 char buffer
[16]; /* stack space used to hold number */
180 int count
= 0; /* pointer into buffer */
183 * Place the conversion into the buffer in
188 buffer
[count
++] = ('0' + ((unsigned int)ival
% 10));
189 ival
= ((unsigned int)ival
/ 10);
193 * Check if we are placing the data in a
200 for (; (width
!= 0); width
--)
202 CHAROUT(padzero
? '0': ' ');
207 /* then display the buffer in reverse order */
208 for (; (count
!= 0); count
--)
210 CHAROUT(buffer
[count
- 1]);
219 string
= va_arg(args
, char *);
221 /* we only need this test once */
223 /* whilst we check this for every character */
231 * NOTE: We do not use "*string++" as the macro
232 * parameter, since we do not know how many times
233 *the parameter may be expanded within the macro.
241 * string terminated by '%' character, bodge things
242 * to prepare for default "format++" below
249 /* just display the character */
256 format
++; /* step over format character */
269 * this routine is simply here as a good breakpoint for dumping msg -
270 * can be used by DEBUG_METHOD macros or functions, if required.
272 # ifdef DEBUG_NEED_VA_WARN1
273 static void va_warn1(int len
, char *msg
)
275 UNUSED(len
); UNUSED(msg
);
279 void va_warn(WarnLevel level
, char *format
, va_list args
)
283 if ( PRE_DEBUG( level
) )
285 len
= va_warn0(format
, args
);
290 #else /* ndef DEBUG */
292 void va_warn(WarnLevel level
, char *format
, va_list args
)
294 UNUSED(level
); UNUSED(format
); UNUSED(args
);
297 #endif /* ... else ndef(DEBUG) ... */
300 #pragma no_check_stack
301 void __rt_warning(char *format
, ...)
306 * For a multi-threaded system we should provide a lock at this point
307 * to ensure that the warning messages are sequenced properly.
310 va_start(args
, format
);
311 va_warn(WL_WARN
, format
, args
);
320 #pragma no_check_stack
321 void __rt_uninterruptable_loop( void ); /* in suppasm.s */
323 void __rt_error(char *format
, ...)
327 va_start(args
, format
);
329 /* Display warning message */
330 va_warn(WL_ERROR
, format
, args
);
332 __rt_uninterruptable_loop();
339 #endif /* def TARGET */
343 static bool trace_on
= FALSE
; /* must be set true in debugger if req'd */
345 #pragma no_check_stack
346 void __rt_trace(char *format
, ...)
351 * For a multi-threaded system we should provide a lock at this point
352 * to ensure that the warning messages are sequenced properly.
357 va_start(args
, format
);
358 va_warn(WL_TRACE
, format
, args
);
366 #endif /* def DO_TRACE */