| #include "efence.h" |
| #include <signal.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| /* |
| * These routines do their printing without using stdio. Stdio can't |
| * be used because it calls malloc(). Internal routines of a malloc() |
| * debugger should not re-enter malloc(), so stdio is out. |
| */ |
| |
| /* |
| * NUMBER_BUFFER_SIZE is the longest character string that could be needed |
| * to represent an unsigned integer, assuming we might print in base 2. |
| */ |
| #define NUMBER_BUFFER_SIZE (sizeof(ef_number) * NBBY) |
| |
| static void printNumber(ef_number number, ef_number base) |
| { |
| char buffer[NUMBER_BUFFER_SIZE]; |
| char *s = &buffer[NUMBER_BUFFER_SIZE]; |
| int size; |
| |
| do { |
| ef_number digit; |
| |
| if (--s == buffer) |
| EF_Abort("Internal error printing number."); |
| |
| digit = number % base; |
| |
| if (digit < 10) |
| *s = '0' + digit; |
| else |
| *s = 'a' + digit - 10; |
| |
| } while ((number /= base) > 0); |
| |
| size = &buffer[NUMBER_BUFFER_SIZE] - s; |
| |
| if (size > 0) |
| write(2, s, size); |
| } |
| |
| static void vprint(const char *pattern, va_list args) |
| { |
| static const char bad_pattern[] = |
| "\nBad pattern specifier %%%c in EF_Print().\n"; |
| const char *s = pattern; |
| char c; |
| |
| while ((c = *s++) != '\0') { |
| if (c == '%') { |
| c = *s++; |
| switch (c) { |
| case '%': |
| (void)write(2, &c, 1); |
| break; |
| case 'a': |
| /* |
| * Print an address passed as a void pointer. |
| * The type of ef_number must be set so that |
| * it is large enough to contain all of the |
| * bits of a void pointer. |
| */ |
| printNumber((ef_number)va_arg(args, void *), |
| 0x10); |
| break; |
| case 's': { |
| const char *string; |
| size_t length; |
| |
| string = va_arg(args, char *); |
| length = strlen(string); |
| |
| (void)write(2, string, length); |
| } break; |
| case 'd': { |
| int n = va_arg(args, int); |
| |
| if (n < 0) { |
| char c = '-'; |
| write(2, &c, 1); |
| n = -n; |
| } |
| printNumber(n, 10); |
| } break; |
| case 'x': |
| printNumber(va_arg(args, u_int), 0x10); |
| break; |
| case 'c': { |
| /*Cast used, since char gets promoted to int in ... */ |
| char c = (char)va_arg(args, int); |
| |
| (void)write(2, &c, 1); |
| } break; |
| default: { |
| EF_Print(bad_pattern, c); |
| } |
| } |
| } else |
| (void)write(2, &c, 1); |
| } |
| } |
| |
| void EF_Abort(const char *pattern, ...) |
| { |
| va_list args; |
| |
| va_start(args, pattern); |
| |
| EF_Print("\nElectricFence Aborting: "); |
| vprint(pattern, args); |
| EF_Print("\n"); |
| |
| va_end(args); |
| |
| /* |
| * I use kill(getpid(), SIGILL) instead of abort() because some |
| * mis-guided implementations of abort() flush stdio, which can |
| * cause malloc() or free() to be called. |
| */ |
| kill(getpid(), SIGILL); |
| /* Just in case something handles SIGILL and returns, exit here. */ |
| _exit(-1); |
| } |
| |
| void EF_Exit(const char *pattern, ...) |
| { |
| va_list args; |
| |
| va_start(args, pattern); |
| |
| EF_Print("\nElectricFence Exiting: "); |
| vprint(pattern, args); |
| EF_Print("\n"); |
| |
| va_end(args); |
| |
| /* |
| * I use _exit() because the regular exit() flushes stdio, |
| * which may cause malloc() or free() to be called. |
| */ |
| _exit(-1); |
| } |
| |
| void EF_Print(const char *pattern, ...) |
| { |
| va_list args; |
| |
| va_start(args, pattern); |
| vprint(pattern, args); |
| va_end(args); |
| } |