xref: /openbsd-src/gnu/usr.bin/binutils/gdb/rdi-share/logging.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
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