Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libsanitizer / sanitizer_common / sanitizer_printf.cc
1 //===-- sanitizer_printf.cc -----------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is shared between AddressSanitizer and ThreadSanitizer.
9 //
10 // Internal printf function, used inside run-time libraries.
11 // We can't use libc printf because we intercept some of the functions used
12 // inside it.
13 //===----------------------------------------------------------------------===//
14
15
16 #include "sanitizer_common.h"
17 #include "sanitizer_libc.h"
18
19 #include <stdio.h>
20 #include <stdarg.h>
21
22 namespace __sanitizer {
23
24 static int AppendChar(char **buff, const char *buff_end, char c) {
25   if (*buff < buff_end) {
26     **buff = c;
27     (*buff)++;
28   }
29   return 1;
30 }
31
32 // Appends number in a given base to buffer. If its length is less than
33 // "minimal_num_length", it is padded with leading zeroes.
34 static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
35                           u8 base, u8 minimal_num_length) {
36   uptr const kMaxLen = 30;
37   RAW_CHECK(base == 10 || base == 16);
38   RAW_CHECK(minimal_num_length < kMaxLen);
39   uptr num_buffer[kMaxLen];
40   uptr pos = 0;
41   do {
42     RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
43     num_buffer[pos++] = num % base;
44     num /= base;
45   } while (num > 0);
46   if (pos < minimal_num_length) {
47     // Make sure compiler doesn't insert call to memset here.
48     internal_memset(&num_buffer[pos], 0,
49                     sizeof(num_buffer[0]) * (minimal_num_length - pos));
50     pos = minimal_num_length;
51   }
52   int result = 0;
53   while (pos-- > 0) {
54     uptr digit = num_buffer[pos];
55     result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
56                                                       : 'a' + digit - 10);
57   }
58   return result;
59 }
60
61 static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
62                                u8 minimal_num_length) {
63   int result = 0;
64   if (num < 0) {
65     result += AppendChar(buff, buff_end, '-');
66     num = -num;
67     if (minimal_num_length)
68       --minimal_num_length;
69   }
70   result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length);
71   return result;
72 }
73
74 static int AppendString(char **buff, const char *buff_end, const char *s) {
75   if (s == 0)
76     s = "<null>";
77   int result = 0;
78   for (; *s; s++) {
79     result += AppendChar(buff, buff_end, *s);
80   }
81   return result;
82 }
83
84 static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
85   int result = 0;
86   result += AppendString(buff, buff_end, "0x");
87   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
88                            (SANITIZER_WORDSIZE == 64) ? 12 : 8);
89   return result;
90 }
91
92 int VSNPrintf(char *buff, int buff_length,
93               const char *format, va_list args) {
94   static const char *kPrintfFormatsHelp =
95     "Supported Printf formats: %(0[0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
96   RAW_CHECK(format);
97   RAW_CHECK(buff_length > 0);
98   const char *buff_end = &buff[buff_length - 1];
99   const char *cur = format;
100   int result = 0;
101   for (; *cur; cur++) {
102     if (*cur != '%') {
103       result += AppendChar(&buff, buff_end, *cur);
104       continue;
105     }
106     cur++;
107     bool have_width = (*cur == '0');
108     int width = 0;
109     if (have_width) {
110       while (*cur >= '0' && *cur <= '9') {
111         have_width = true;
112         width = width * 10 + *cur++ - '0';
113       }
114     }
115     bool have_z = (*cur == 'z');
116     cur += have_z;
117     bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
118     cur += have_ll * 2;
119     s64 dval;
120     u64 uval;
121     bool have_flags = have_width | have_z | have_ll;
122     switch (*cur) {
123       case 'd': {
124         dval = have_ll ? va_arg(args, s64)
125              : have_z ? va_arg(args, sptr)
126              : va_arg(args, int);
127         result += AppendSignedDecimal(&buff, buff_end, dval, width);
128         break;
129       }
130       case 'u':
131       case 'x': {
132         uval = have_ll ? va_arg(args, u64)
133              : have_z ? va_arg(args, uptr)
134              : va_arg(args, unsigned);
135         result += AppendUnsigned(&buff, buff_end, uval,
136                                  (*cur == 'u') ? 10 : 16, width);
137         break;
138       }
139       case 'p': {
140         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
141         result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
142         break;
143       }
144       case 's': {
145         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
146         result += AppendString(&buff, buff_end, va_arg(args, char*));
147         break;
148       }
149       case 'c': {
150         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
151         result += AppendChar(&buff, buff_end, va_arg(args, int));
152         break;
153       }
154       case '%' : {
155         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
156         result += AppendChar(&buff, buff_end, '%');
157         break;
158       }
159       default: {
160         RAW_CHECK_MSG(false, kPrintfFormatsHelp);
161       }
162     }
163   }
164   RAW_CHECK(buff <= buff_end);
165   AppendChar(&buff, buff_end + 1, '\0');
166   return result;
167 }
168
169 static void (*PrintfAndReportCallback)(const char *);
170 void SetPrintfAndReportCallback(void (*callback)(const char *)) {
171   PrintfAndReportCallback = callback;
172 }
173
174 void Printf(const char *format, ...) {
175   const int kLen = 16 * 1024;
176   InternalScopedBuffer<char> buffer(kLen);
177   va_list args;
178   va_start(args, format);
179   int needed_length = VSNPrintf(buffer.data(), kLen, format, args);
180   va_end(args);
181   RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
182   RawWrite(buffer.data());
183   if (PrintfAndReportCallback)
184     PrintfAndReportCallback(buffer.data());
185 }
186
187 // Writes at most "length" symbols to "buffer" (including trailing '\0').
188 // Returns the number of symbols that should have been written to buffer
189 // (not including trailing '\0'). Thus, the string is truncated
190 // iff return value is not less than "length".
191 int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
192   va_list args;
193   va_start(args, format);
194   int needed_length = VSNPrintf(buffer, length, format, args);
195   va_end(args);
196   return needed_length;
197 }
198
199 // Like Printf, but prints the current PID before the output string.
200 void Report(const char *format, ...) {
201   const int kLen = 16 * 1024;
202   InternalScopedBuffer<char> buffer(kLen);
203   int needed_length = internal_snprintf(buffer.data(),
204                                         kLen, "==%d== ", GetPid());
205   RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
206   va_list args;
207   va_start(args, format);
208   needed_length += VSNPrintf(buffer.data() + needed_length,
209                              kLen - needed_length, format, args);
210   va_end(args);
211   RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
212   RawWrite(buffer.data());
213   if (PrintfAndReportCallback)
214     PrintfAndReportCallback(buffer.data());
215 }
216
217 }  // namespace __sanitizer