]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/rdi-share/logging.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / gdb / rdi-share / logging.c
1 /*
2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3 *
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
6 * software.
7 */
8
9 /* -*-C-*-
10 *
11 * $Revision$
12 * $Date$
13 *
14 *
15 * logging.c - methods for logging warnings, errors and trace info
16 *
17 */
18
19 #include <stdarg.h> /* ANSI varargs support */
20
21 #ifdef TARGET
22 # include "angel.h"
23 # include "devconf.h"
24 #else
25 # include "host.h"
26 #endif
27
28 #include "logging.h" /* Header file for this source code */
29
30 #ifndef UNUSED
31 # define UNUSED(x) ((x)=(x))
32 #endif
33
34 /*
35 * __rt_warning
36 * ------------
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,
40 * debug message, etc.
41 */
42
43 #ifdef DEBUG
44
45 # ifdef DEBUG_METHOD
46
47 # define STRINGIFY2(x) #x
48 # define STRINGIFY(x) STRINGIFY2(x)
49 # define DEBUG_METHOD_HEADER STRINGIFY(DEBUG_METHOD##.h)
50
51 # include DEBUG_METHOD_HEADER
52
53 # define METHOD_EXPAND_2(m, p, c) m##p(c)
54 # define METHOD_EXPAND(m, p, c) METHOD_EXPAND_2(m, p, c)
55
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))
59
60 # else
61 # error Must define DEBUG_METHOD
62 # endif
63
64 #endif /* def DEBUG */
65
66 /*
67 * the guts of __rt_warning
68 */
69
70 #pragma no_check_stack
71 #ifdef DEBUG
72
73 static const char hextab[] = "0123456789ABCDEF";
74
75 /*
76 * If debugging, then we break va_warn into sub-functions which
77 * allow us to get an easy breakpoint on the formatted string
78 */
79 static int va_warn0(char *format, va_list args)
80 {
81 int len = 0;
82
83 while ((format != NULL) && (*format != '\0'))
84 {
85 if (*format == '%')
86 {
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 */
92
93 /*
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.
99 */
100 if ((fch >= '0') && (fch <= '9'))
101 {
102 if (fch == '0')
103 {
104 /* Leading zeroes padding */
105 padzero = TRUE;
106 fch = *(++format);
107 }
108
109 while ((fch >= '0') && (fch <= '9'))
110 {
111 width = ((width * 10) + (fch - '0'));
112 fch = *(++format);
113 }
114 }
115
116 if (fch == 'l')
117 /* skip 'l' in "%lx", etc. */
118 fch = *(++format);
119
120 switch (fch)
121 {
122 case 'c':
123 /* char */
124 ival = va_arg(args, int);
125 CHAROUT((char)ival);
126 len++;
127 break;
128
129 case 'x':
130 case 'X':
131 {
132 /* hexadecimal */
133 unsigned int uval = va_arg(args, unsigned int);
134 int loop;
135
136 UNUSED(uval);
137
138 if ((width == 0) || (width > 8))
139 width = 8;
140
141 for(loop = (width * 4); (loop != 0); loop -= 4)
142 {
143 CHAROUT(hextab[(uval >> (loop - 4)) & 0xF]);
144 len++;
145 }
146 }
147
148 break;
149
150 case 'd':
151 /* decimal */
152 ival = va_arg(args, int);
153
154 if (ival < 0)
155 {
156 ival = -ival;
157 CHAROUT('-');
158 len++;
159 }
160
161 if (ival == 0)
162 {
163 CHAROUT('0');
164 len++;
165 }
166 else
167 {
168 /*
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.
178 */
179 char buffer[16]; /* stack space used to hold number */
180 int count = 0; /* pointer into buffer */
181
182 /*
183 * Place the conversion into the buffer in
184 * reverse order:
185 */
186 while (ival != 0)
187 {
188 buffer[count++] = ('0' + ((unsigned int)ival % 10));
189 ival = ((unsigned int)ival / 10);
190 }
191
192 /*
193 * Check if we are placing the data in a
194 * fixed width field:
195 */
196 if (width != 0)
197 {
198 width -= count;
199
200 for (; (width != 0); width--)
201 {
202 CHAROUT(padzero ? '0': ' ');
203 len++;
204 }
205 }
206
207 /* then display the buffer in reverse order */
208 for (; (count != 0); count--)
209 {
210 CHAROUT(buffer[count - 1]);
211 len++;
212 }
213 }
214
215 break;
216
217 case 's':
218 /* string */
219 string = va_arg(args, char *);
220
221 /* we only need this test once */
222 if (string != NULL)
223 /* whilst we check this for every character */
224 while (*string)
225 {
226 CHAROUT(*string);
227 len++;
228 string++;
229
230 /*
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.
234 */
235 }
236
237 break;
238
239 case '\0':
240 /*
241 * string terminated by '%' character, bodge things
242 * to prepare for default "format++" below
243 */
244 format--;
245
246 break;
247
248 default:
249 /* just display the character */
250 CHAROUT(*format);
251 len++;
252
253 break;
254 }
255
256 format++; /* step over format character */
257 }
258 else
259 {
260 CHAROUT(*format);
261 len++;
262 format++;
263 }
264 }
265 return len;
266 }
267
268 /*
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.
271 */
272 # ifdef DEBUG_NEED_VA_WARN1
273 static void va_warn1(int len, char *msg)
274 {
275 UNUSED(len); UNUSED(msg);
276 }
277 # endif
278
279 void va_warn(WarnLevel level, char *format, va_list args)
280 {
281 int len;
282
283 if ( PRE_DEBUG( level ) )
284 {
285 len = va_warn0(format, args);
286 POST_DEBUG( len );
287 }
288 }
289
290 #else /* ndef DEBUG */
291
292 void va_warn(WarnLevel level, char *format, va_list args)
293 {
294 UNUSED(level); UNUSED(format); UNUSED(args);
295 }
296
297 #endif /* ... else ndef(DEBUG) ... */
298 #pragma check_stack
299
300 #pragma no_check_stack
301 void __rt_warning(char *format, ...)
302 {
303 va_list args;
304
305 /*
306 * For a multi-threaded system we should provide a lock at this point
307 * to ensure that the warning messages are sequenced properly.
308 */
309
310 va_start(args, format);
311 va_warn(WL_WARN, format, args);
312 va_end(args);
313
314 return;
315 }
316 #pragma check_stack
317
318 #ifdef TARGET
319
320 #pragma no_check_stack
321 void __rt_uninterruptable_loop( void ); /* in suppasm.s */
322
323 void __rt_error(char *format, ...)
324 {
325 va_list args;
326
327 va_start(args, format);
328
329 /* Display warning message */
330 va_warn(WL_ERROR, format, args);
331
332 __rt_uninterruptable_loop();
333
334 va_end(args);
335 return;
336 }
337 #pragma check_stack
338
339 #endif /* def TARGET */
340
341 #ifdef DO_TRACE
342
343 static bool trace_on = FALSE; /* must be set true in debugger if req'd */
344
345 #pragma no_check_stack
346 void __rt_trace(char *format, ...)
347 {
348 va_list args;
349
350 /*
351 * For a multi-threaded system we should provide a lock at this point
352 * to ensure that the warning messages are sequenced properly.
353 */
354
355 if (trace_on)
356 {
357 va_start(args, format);
358 va_warn(WL_TRACE, format, args);
359 va_end(args);
360 }
361
362 return;
363 }
364 #pragma check_stack
365
366 #endif /* def DO_TRACE */
367
368
369 /* EOF logging.c */