summaryrefslogtreecommitdiff
path: root/gdb/rdi-share/logging.c
blob: 79b70ef348f1d5248846ed14f63dec09a49fd43b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/* 
 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
 * 
 * This software may be freely used, copied, modified, and distributed
 * provided that the above copyright notice is preserved in all copies of the
 * software.
 */

/* -*-C-*-
 *
 * $Revision$
 *     $Date$
 *
 *
 * logging.c - methods for logging warnings, errors and trace info
 *
 */

#include <stdarg.h>     /* ANSI varargs support */

#ifdef TARGET
# include "angel.h"
# include "devconf.h"
#else
# include "host.h"
#endif

#include "logging.h"    /* Header file for this source code */

#ifndef UNUSED
# define UNUSED(x) ((x)=(x))
#endif

/*
 * __rt_warning
 * ------------
 * This routine is provided as a standard method of generating
 * run-time system warnings. The actual action taken by this code can
 * be board or target application specific, e.g. internal logging,
 * debug message, etc.
 */

#ifdef DEBUG

# ifdef DEBUG_METHOD

#  define  STRINGIFY2(x) #x
#  define  STRINGIFY(x)  STRINGIFY2(x)
#  define  DEBUG_METHOD_HEADER        STRINGIFY(DEBUG_METHOD##.h)

#  include DEBUG_METHOD_HEADER

#  define  METHOD_EXPAND_2(m, p, c) m##p(c)
#  define  METHOD_EXPAND(m, p, c)   METHOD_EXPAND_2(m, p, c)

#  define  CHAROUT(c)    METHOD_EXPAND(DEBUG_METHOD, _PutChar,  (c))
#  define  PRE_DEBUG(l)  METHOD_EXPAND(DEBUG_METHOD, _PreWarn,  (l))
#  define  POST_DEBUG(n) METHOD_EXPAND(DEBUG_METHOD, _PostWarn, (n))

# else
#  error Must define DEBUG_METHOD
# endif

#endif /* def DEBUG */

/*
 * the guts of __rt_warning
 */

#pragma no_check_stack
#ifdef DEBUG

static const char hextab[] = "0123456789ABCDEF";

/*
 * If debugging, then we break va_warn into sub-functions which
 * allow us to get an easy breakpoint on the formatted string
 */
static int va_warn0(char *format, va_list args)
{
    int len = 0;

    while ((format != NULL) && (*format != '\0'))
    {
        if (*format == '%')
        {
            char fch = *(++format); /* get format character (skipping '%') */
            int ival; /* holder for integer arguments */
            char *string; /* holder for string arguments */
            int width = 0; /* No field width by default */
            int padzero = FALSE; /* By default we pad with spaces */

            /*
             * Check if the format has a width specified. NOTE: We do
             * not use the "isdigit" function here, since it will
             * require run-time support. The current ARM Ltd header
             * defines "isdigit" as a macro, that uses a fixed
             * character description table.
             */
            if ((fch >= '0') && (fch <= '9'))
            {
                if (fch == '0')
                {
                    /* Leading zeroes padding */
                    padzero = TRUE;
                    fch = *(++format);
                }

                while ((fch >= '0') && (fch <= '9'))
                {
                    width = ((width * 10) + (fch - '0'));
                    fch = *(++format);
                }
            }

            if (fch == 'l')
                /* skip 'l' in "%lx", etc. */
                fch = *(++format);

            switch (fch)
            {
              case 'c':
                  /* char */
                  ival = va_arg(args, int);
                  CHAROUT((char)ival);
                  len++;
                  break;

              case 'x':
              case 'X':
              {
                  /* hexadecimal */
                  unsigned int uval = va_arg(args, unsigned int);
                  int loop;

                  UNUSED(uval);

                  if ((width == 0) || (width > 8))
                      width = 8;

                  for(loop = (width * 4); (loop != 0); loop -= 4)
                  {
                      CHAROUT(hextab[(uval >> (loop - 4)) & 0xF]);
                      len++;
                  }
              }

              break;

              case 'd':
                  /* decimal */
                  ival = va_arg(args, int);

                  if (ival < 0)
                  {
                      ival = -ival;
                      CHAROUT('-');
                      len++;
                  }

                  if (ival == 0)
                  {
                      CHAROUT('0');
                      len++;
                  }
                  else
                  {
                      /*
                       * The simplest method of displaying numbers is
                       * to provide a small recursive routine, that
                       * nests until the most-significant digit is
                       * reached, and then falls back out displaying
                       * individual digits. However, we want to avoid
                       * using recursive code within the lo-level
                       * parts of Angel (to minimise the stack
                       * usage). The following number conversion is a
                       * non-recursive solution.
                       */
                      char buffer[16]; /* stack space used to hold number */
                      int count = 0; /* pointer into buffer */

                      /*
                       * Place the conversion into the buffer in
                       * reverse order:
                       */
                      while (ival != 0)
                      {
                          buffer[count++] = ('0' + ((unsigned int)ival % 10));
                          ival = ((unsigned int)ival / 10);
                      }

                      /*
                       * Check if we are placing the data in a
                       * fixed width field:
                       */
                      if (width != 0)
                      {
                          width -= count;

                          for (; (width != 0); width--)
                          {
                              CHAROUT(padzero ? '0': ' ');
                              len++;
                          }
                      }

                      /* then display the buffer in reverse order */
                      for (; (count != 0); count--)
                      {
                          CHAROUT(buffer[count - 1]);
                          len++;
                      }
                  }

                  break;

              case 's':
                  /* string */
                  string = va_arg(args, char *);

                  /* we only need this test once */
                  if (string != NULL)
                      /* whilst we check this for every character */
                      while (*string)
                      {
                          CHAROUT(*string);
                          len++;
                          string++;

                          /*
                           * NOTE: We do not use "*string++" as the macro
                           * parameter, since we do not know how many times
                           *the parameter may be expanded within the macro.
                           */
                      }

                  break;

              case '\0':
                  /*
                   * string terminated by '%' character, bodge things
                   * to prepare for default "format++" below
                   */
                  format--;

                  break;

              default:
                  /* just display the character */
                  CHAROUT(*format);
                  len++;

                  break;
            }

            format++; /* step over format character */
        }
        else
        {
            CHAROUT(*format);
            len++;
            format++;
        }
    }
    return len;
}

/*
 * this routine is simply here as a good breakpoint for dumping msg -
 * can be used by DEBUG_METHOD macros or functions, if required.
 */
# ifdef DEBUG_NEED_VA_WARN1
static void va_warn1(int len, char *msg)
{
    UNUSED(len); UNUSED(msg);
}
# endif

void va_warn(WarnLevel level, char *format, va_list args)
{
    int len;

    if ( PRE_DEBUG( level ) )
    {
        len = va_warn0(format, args);
        POST_DEBUG( len );
    }
}

#else /* ndef DEBUG */

void va_warn(WarnLevel level, char *format, va_list args)
{
    UNUSED(level); UNUSED(format); UNUSED(args);
}

#endif /* ... else ndef(DEBUG) ... */
#pragma check_stack

#pragma no_check_stack
void __rt_warning(char *format, ...)
{
    va_list args;

    /*
     * For a multi-threaded system we should provide a lock at this point
     * to ensure that the warning messages are sequenced properly.
     */

    va_start(args, format);
    va_warn(WL_WARN, format, args);
    va_end(args);

    return;
}
#pragma check_stack

#ifdef TARGET

#pragma no_check_stack
void __rt_uninterruptable_loop( void ); /* in suppasm.s */

void __rt_error(char *format, ...)
{
    va_list args;

    va_start(args, format);

    /* Display warning message */
    va_warn(WL_ERROR, format, args);

    __rt_uninterruptable_loop();

    va_end(args);
    return;
}
#pragma check_stack

#endif /* def TARGET */

#ifdef DO_TRACE

static bool trace_on = FALSE; /* must be set true in debugger if req'd */

#pragma no_check_stack
void __rt_trace(char *format, ...)
{
    va_list args;

    /*
     * For a multi-threaded system we should provide a lock at this point
     * to ensure that the warning messages are sequenced properly.
     */

    if (trace_on)
    {
        va_start(args, format);
        va_warn(WL_TRACE, format, args);
        va_end(args);
    }

    return;
}
#pragma check_stack

#endif /* def DO_TRACE */


/* EOF logging.c */