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: 1.2 $
* $Date: 2003/01/16 10:40:14 $
*
*
* 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 */
|