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 218