blob: a3d06ff67ad2c9e690633cd93bdc3a3de04aab3d [file] [log] [blame]
Kostya Serebryany1e172b42011-11-30 01:07:02 +00001//===-- asan_printf.cc ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Internal printf function, used inside ASan run-time library.
13// We can't use libc printf because we intercept some of the functions used
14// inside it.
15//===----------------------------------------------------------------------===//
16
17#include "asan_internal.h"
18#include "asan_interceptors.h"
19
20#include <stdarg.h>
21
22namespace __asan {
23
24void RawWrite(const char *buffer) {
25 static const char *kRawWriteError = "RawWrite can't output requested buffer!";
26 ssize_t length = (ssize_t)internal_strlen(buffer);
Kostya Serebryanyde496f42011-12-28 22:58:01 +000027 if (length != AsanWrite(2, buffer, length)) {
28 AsanWrite(2, kRawWriteError, internal_strlen(kRawWriteError));
Kostya Serebryany1e172b42011-11-30 01:07:02 +000029 ASAN_DIE;
30 }
31}
32
33static inline int AppendChar(char **buff, const char *buff_end, char c) {
34 if (*buff < buff_end) {
35 **buff = c;
36 (*buff)++;
37 }
38 return 1;
39}
40
41// Appends number in a given base to buffer. If its length is less than
42// "minimal_num_length", it is padded with leading zeroes.
43static int AppendUnsigned(char **buff, const char *buff_end, uint64_t num,
44 uint8_t base, uint8_t minimal_num_length) {
45 size_t const kMaxLen = 30;
46 RAW_CHECK(base == 10 || base == 16);
47 RAW_CHECK(minimal_num_length < kMaxLen);
48 size_t num_buffer[kMaxLen];
49 size_t pos = 0;
50 do {
51 RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
52 num_buffer[pos++] = num % base;
53 num /= base;
54 } while (num > 0);
55 while (pos < minimal_num_length) num_buffer[pos++] = 0;
56 int result = 0;
57 while (pos-- > 0) {
58 size_t digit = num_buffer[pos];
59 result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
60 : 'a' + digit - 10);
61 }
62 return result;
63}
64
65static inline int AppendSignedDecimal(char **buff, const char *buff_end,
66 int64_t num) {
67 int result = 0;
68 if (num < 0) {
69 result += AppendChar(buff, buff_end, '-');
70 num = -num;
71 }
72 result += AppendUnsigned(buff, buff_end, (uint64_t)num, 10, 0);
73 return result;
74}
75
76static inline int AppendString(char **buff, const char *buff_end,
77 const char *s) {
78 // Avoid library functions like stpcpy here.
79 RAW_CHECK(s);
80 int result = 0;
81 for (; *s; s++) {
82 result += AppendChar(buff, buff_end, *s);
83 }
84 return result;
85}
86
87static inline int AppendPointer(char **buff, const char *buff_end,
88 uint64_t ptr_value) {
89 int result = 0;
90 result += AppendString(buff, buff_end, "0x");
91 result += AppendUnsigned(buff, buff_end, ptr_value, 16,
92 (__WORDSIZE == 64) ? 12 : 8);
93 return result;
94}
95
96static int VSNPrintf(char *buff, int buff_length,
97 const char *format, va_list args) {
98 static const char *kPrintfFormatsHelp = "Supported Printf formats: "
99 "%%[l]{d,u,x}; %%p; %%s";
100 RAW_CHECK(format);
101 RAW_CHECK(buff_length > 0);
102 const char *buff_end = &buff[buff_length - 1];
103 const char *cur = format;
104 int result = 0;
105 for (; *cur; cur++) {
106 if (*cur == '%') {
107 cur++;
108 bool have_l = (*cur == 'l');
109 cur += have_l;
110 int64_t dval;
111 uint64_t uval, xval;
112 switch (*cur) {
113 case 'd': dval = have_l ? va_arg(args, intptr_t)
114 : va_arg(args, int);
115 result += AppendSignedDecimal(&buff, buff_end, dval);
116 break;
117 case 'u': uval = have_l ? va_arg(args, uintptr_t)
118 : va_arg(args, unsigned int);
119 result += AppendUnsigned(&buff, buff_end, uval, 10, 0);
120 break;
121 case 'x': xval = have_l ? va_arg(args, uintptr_t)
122 : va_arg(args, unsigned int);
123 result += AppendUnsigned(&buff, buff_end, xval, 16, 0);
124 break;
125 case 'p': RAW_CHECK_MSG(!have_l, kPrintfFormatsHelp);
126 result += AppendPointer(&buff, buff_end,
127 va_arg(args, uintptr_t));
128 break;
129 case 's': RAW_CHECK_MSG(!have_l, kPrintfFormatsHelp);
130 result += AppendString(&buff, buff_end, va_arg(args, char*));
131 break;
132 default: RAW_CHECK_MSG(false, kPrintfFormatsHelp);
133 }
134 } else {
135 result += AppendChar(&buff, buff_end, *cur);
136 }
137 }
138 RAW_CHECK(buff <= buff_end);
139 AppendChar(&buff, buff_end + 1, '\0');
140 return result;
141}
142
143void Printf(const char *format, ...) {
144 const int kLen = 1024 * 4;
145 char buffer[kLen];
146 va_list args;
147 va_start(args, format);
148 int needed_length = VSNPrintf(buffer, kLen, format, args);
149 va_end(args);
150 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
151 RawWrite(buffer);
152}
153
154// Writes at most "length" symbols to "buffer" (including trailing '\0').
155// Returns the number of symbols that should have been written to buffer
156// (not including trailing '\0'). Thus, the string is truncated
157// iff return value is not less than "length".
158int SNPrintf(char *buffer, size_t length, const char *format, ...) {
159 va_list args;
160 va_start(args, format);
161 int needed_length = VSNPrintf(buffer, length, format, args);
162 va_end(args);
163 return needed_length;
164}
165
166// Like Printf, but prints the current PID before the output string.
167void Report(const char *format, ...) {
168 const int kLen = 1024 * 4;
169 char buffer[kLen];
170 int needed_length = SNPrintf(buffer, kLen, "==%d== ", getpid());
171 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
172 va_list args;
173 va_start(args, format);
174 needed_length += VSNPrintf(buffer + needed_length, kLen - needed_length,
175 format, args);
176 va_end(args);
177 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
178 RawWrite(buffer);
179}
180
181} // namespace __asan