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: 1.3 $ 12 * $Date: 2004/12/27 14:00:54 $ 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 */ 370