Set up go function pointer table
[akaros.git] / user / electric-fence / print.c
1 #include "efence.h"
2 #include <signal.h>
3 #include <stdarg.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7
8 /*
9  * These routines do their printing without using stdio. Stdio can't
10  * be used because it calls malloc(). Internal routines of a malloc()
11  * debugger should not re-enter malloc(), so stdio is out.
12  */
13
14 /*
15  * NUMBER_BUFFER_SIZE is the longest character string that could be needed
16  * to represent an unsigned integer, assuming we might print in base 2.
17  */
18 #define NUMBER_BUFFER_SIZE (sizeof(ef_number) * NBBY)
19
20 static void printNumber(ef_number number, ef_number base)
21 {
22         char buffer[NUMBER_BUFFER_SIZE];
23         char *s = &buffer[NUMBER_BUFFER_SIZE];
24         int size;
25
26         do {
27                 ef_number digit;
28
29                 if (--s == buffer)
30                         EF_Abort("Internal error printing number.");
31
32                 digit = number % base;
33
34                 if (digit < 10)
35                         *s = '0' + digit;
36                 else
37                         *s = 'a' + digit - 10;
38
39         } while ((number /= base) > 0);
40
41         size = &buffer[NUMBER_BUFFER_SIZE] - s;
42
43         if (size > 0)
44                 write(2, s, size);
45 }
46
47 static void vprint(const char *pattern, va_list args)
48 {
49         static const char bad_pattern[] =
50             "\nBad pattern specifier %%%c in EF_Print().\n";
51         const char *s = pattern;
52         char c;
53
54         while ((c = *s++) != '\0') {
55                 if (c == '%') {
56                         c = *s++;
57                         switch (c) {
58                         case '%':
59                                 (void)write(2, &c, 1);
60                                 break;
61                         case 'a':
62                                 /*
63                                  * Print an address passed as a void pointer.
64                                  * The type of ef_number must be set so that
65                                  * it is large enough to contain all of the
66                                  * bits of a void pointer.
67                                  */
68                                 printNumber((ef_number)va_arg(args, void *), 0x10);
69                                 break;
70                         case 's': {
71                                 const char *string;
72                                 size_t length;
73
74                                 string = va_arg(args, char *);
75                                 length = strlen(string);
76
77                                 (void)write(2, string, length);
78                         } break;
79                         case 'd': {
80                                 int n = va_arg(args, int);
81
82                                 if (n < 0) {
83                                         char c = '-';
84                                         write(2, &c, 1);
85                                         n = -n;
86                                 }
87                                 printNumber(n, 10);
88                         } break;
89                         case 'x':
90                                 printNumber(va_arg(args, u_int), 0x10);
91                                 break;
92                         case 'c': { /*Cast used, since char gets promoted to int in ... */
93                                 char c = (char)va_arg(args, int);
94
95                                 (void)write(2, &c, 1);
96                         } break;
97                         default: {
98                                 EF_Print(bad_pattern, c);
99                         }
100                         }
101                 } else
102                         (void)write(2, &c, 1);
103         }
104 }
105
106 void EF_Abort(const char *pattern, ...)
107 {
108         va_list args;
109
110         va_start(args, pattern);
111
112         EF_Print("\nElectricFence Aborting: ");
113         vprint(pattern, args);
114         EF_Print("\n");
115
116         va_end(args);
117
118         /*
119          * I use kill(getpid(), SIGILL) instead of abort() because some
120          * mis-guided implementations of abort() flush stdio, which can
121          * cause malloc() or free() to be called.
122          */
123         kill(getpid(), SIGILL);
124         /* Just in case something handles SIGILL and returns, exit here. */
125         _exit(-1);
126 }
127
128 void EF_Exit(const char *pattern, ...)
129 {
130         va_list args;
131
132         va_start(args, pattern);
133
134         EF_Print("\nElectricFence Exiting: ");
135         vprint(pattern, args);
136         EF_Print("\n");
137
138         va_end(args);
139
140         /*
141          * I use _exit() because the regular exit() flushes stdio,
142          * which may cause malloc() or free() to be called.
143          */
144         _exit(-1);
145 }
146
147 void EF_Print(const char *pattern, ...)
148 {
149         va_list args;
150
151         va_start(args, pattern);
152         vprint(pattern, args);
153         va_end(args);
154 }