* configure.ac: Change target-libasan to target-libsanitizer.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_printf.cc
blobda4dc7f53a1860f1c0aa6d21d3ced0669218809d
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 //===----------------------------------------------------------------------===//
16 #include "sanitizer_common.h"
17 #include "sanitizer_libc.h"
19 #include <stdio.h>
20 #include <stdarg.h>
22 namespace __sanitizer {
24 static int AppendChar(char **buff, const char *buff_end, char c) {
25 if (*buff < buff_end) {
26 **buff = c;
27 (*buff)++;
29 return 1;
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 while (pos < minimal_num_length) num_buffer[pos++] = 0;
47 int result = 0;
48 while (pos-- > 0) {
49 uptr digit = num_buffer[pos];
50 result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
51 : 'a' + digit - 10);
53 return result;
56 static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num) {
57 int result = 0;
58 if (num < 0) {
59 result += AppendChar(buff, buff_end, '-');
60 num = -num;
62 result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
63 return result;
66 static int AppendString(char **buff, const char *buff_end, const char *s) {
67 if (s == 0)
68 s = "<null>";
69 int result = 0;
70 for (; *s; s++) {
71 result += AppendChar(buff, buff_end, *s);
73 return result;
76 static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
77 int result = 0;
78 result += AppendString(buff, buff_end, "0x");
79 result += AppendUnsigned(buff, buff_end, ptr_value, 16,
80 (__WORDSIZE == 64) ? 12 : 8);
81 return result;
84 int VSNPrintf(char *buff, int buff_length,
85 const char *format, va_list args) {
86 static const char *kPrintfFormatsHelp = "Supported Printf formats: "
87 "%%[z]{d,u,x}; %%p; %%s; %%c\n";
88 RAW_CHECK(format);
89 RAW_CHECK(buff_length > 0);
90 const char *buff_end = &buff[buff_length - 1];
91 const char *cur = format;
92 int result = 0;
93 for (; *cur; cur++) {
94 if (*cur != '%') {
95 result += AppendChar(&buff, buff_end, *cur);
96 continue;
98 cur++;
99 bool have_z = (*cur == 'z');
100 cur += have_z;
101 s64 dval;
102 u64 uval;
103 switch (*cur) {
104 case 'd': {
105 dval = have_z ? va_arg(args, sptr)
106 : va_arg(args, int);
107 result += AppendSignedDecimal(&buff, buff_end, dval);
108 break;
110 case 'u':
111 case 'x': {
112 uval = have_z ? va_arg(args, uptr)
113 : va_arg(args, unsigned);
114 result += AppendUnsigned(&buff, buff_end, uval,
115 (*cur == 'u') ? 10 : 16, 0);
116 break;
118 case 'p': {
119 RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
120 result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
121 break;
123 case 's': {
124 RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
125 result += AppendString(&buff, buff_end, va_arg(args, char*));
126 break;
128 case 'c': {
129 RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
130 result += AppendChar(&buff, buff_end, va_arg(args, int));
131 break;
133 case '%' : {
134 RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
135 result += AppendChar(&buff, buff_end, '%');
136 break;
138 default: {
139 RAW_CHECK_MSG(false, kPrintfFormatsHelp);
143 RAW_CHECK(buff <= buff_end);
144 AppendChar(&buff, buff_end + 1, '\0');
145 return result;
148 static void (*PrintfAndReportCallback)(const char *);
149 void SetPrintfAndReportCallback(void (*callback)(const char *)) {
150 PrintfAndReportCallback = callback;
153 void Printf(const char *format, ...) {
154 const int kLen = 1024 * 4;
155 InternalScopedBuffer<char> buffer(kLen);
156 va_list args;
157 va_start(args, format);
158 int needed_length = VSNPrintf(buffer.data(), kLen, format, args);
159 va_end(args);
160 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
161 RawWrite(buffer.data());
162 if (PrintfAndReportCallback)
163 PrintfAndReportCallback(buffer.data());
166 // Writes at most "length" symbols to "buffer" (including trailing '\0').
167 // Returns the number of symbols that should have been written to buffer
168 // (not including trailing '\0'). Thus, the string is truncated
169 // iff return value is not less than "length".
170 int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
171 va_list args;
172 va_start(args, format);
173 int needed_length = VSNPrintf(buffer, length, format, args);
174 va_end(args);
175 return needed_length;
178 // Like Printf, but prints the current PID before the output string.
179 void Report(const char *format, ...) {
180 const int kLen = 1024 * 4;
181 InternalScopedBuffer<char> buffer(kLen);
182 int needed_length = internal_snprintf(buffer.data(),
183 kLen, "==%d== ", GetPid());
184 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
185 va_list args;
186 va_start(args, format);
187 needed_length += VSNPrintf(buffer.data() + needed_length,
188 kLen - needed_length, format, args);
189 va_end(args);
190 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
191 RawWrite(buffer.data());
192 if (PrintfAndReportCallback)
193 PrintfAndReportCallback(buffer.data());
196 } // namespace __sanitizer