blob: bd331e4bd6b97869ee4a14d531b557d3c2a6fd41 [file] [log] [blame]
njnc44a6c22005-06-03 13:21:18 +00001
2/*--------------------------------------------------------------------*/
3/*--- Libc printing. m_libcprint.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardj4d474d02008-02-11 11:34:59 +000010 Copyright (C) 2000-2008 Julian Seward
njnc44a6c22005-06-03 13:21:18 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000032#include "pub_core_vki.h"
njnc44a6c22005-06-03 13:21:18 +000033#include "pub_core_debuglog.h"
34#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000035#include "pub_core_libcassert.h"
sewardj592ae092005-11-08 19:01:44 +000036#include "pub_core_libcfile.h" // VG_(write)(), VG_(write_socket)()
njnc44a6c22005-06-03 13:21:18 +000037#include "pub_core_libcprint.h"
sewardj592ae092005-11-08 19:01:44 +000038#include "pub_core_libcproc.h" // VG_(getpid)(), VG_(read_millisecond_timer()
njnc44a6c22005-06-03 13:21:18 +000039#include "pub_core_options.h"
njn24a6efb2005-06-20 03:36:51 +000040#include "valgrind.h" // For RUNNING_ON_VALGRIND
njnc44a6c22005-06-03 13:21:18 +000041
njnc44a6c22005-06-03 13:21:18 +000042
sewardja11553a2005-07-19 12:17:05 +000043
njnc44a6c22005-06-03 13:21:18 +000044/* ---------------------------------------------------------------------
45 Writing to file or a socket
46 ------------------------------------------------------------------ */
47
48/* Tell the logging mechanism whether we are logging to a file
49 descriptor or a socket descriptor. */
50Bool VG_(logging_to_socket) = False;
51
52/* Do the low-level send of a message to the logging sink. */
53static void send_bytes_to_logging_sink ( Char* msg, Int nbytes )
54{
55 if (!VG_(logging_to_socket)) {
sewardj6e31f802007-11-17 22:29:25 +000056 /* VG_(clo_log_fd) could have been set to -1 in the various
57 sys-wrappers for sys_fork, if --child-silent-after-fork=yes
58 is in effect. That is a signal that we should not produce
59 any more output. */
60 if (VG_(clo_log_fd) >= 0)
61 VG_(write)( VG_(clo_log_fd), msg, nbytes );
njnc44a6c22005-06-03 13:21:18 +000062 } else {
63 Int rc = VG_(write_socket)( VG_(clo_log_fd), msg, nbytes );
64 if (rc == -1) {
65 // For example, the listener process died. Switch back to stderr.
66 VG_(logging_to_socket) = False;
67 VG_(clo_log_fd) = 2;
68 VG_(write)( VG_(clo_log_fd), msg, nbytes );
69 }
70 }
71}
72
73/* ---------------------------------------------------------------------
74 printf() and friends
75 ------------------------------------------------------------------ */
76
sewardj45f4e7c2005-09-27 19:20:21 +000077typedef
78 struct {
bart1a0cb6a2008-04-14 16:35:32 +000079 HChar buf[128];
sewardj45f4e7c2005-09-27 19:20:21 +000080 Int n;
81 }
82 printf_buf;
njnc44a6c22005-06-03 13:21:18 +000083
bart1a0cb6a2008-04-14 16:35:32 +000084static UInt VG_(vprintf_to_buf) ( printf_buf *printf_buf,
85 const HChar *format, va_list vargs );
86static UInt VG_(printf_to_buf) ( printf_buf* prbuf, const HChar *format, ... );
87
njnc44a6c22005-06-03 13:21:18 +000088// Adds a single char to the buffer. When the buffer gets sufficiently
89// full, we write its contents to the logging sink.
90static void add_to_myprintf_buf ( HChar c, void *p )
91{
92 printf_buf *myprintf_buf = (printf_buf *)p;
93
bart1a0cb6a2008-04-14 16:35:32 +000094 if (myprintf_buf->n > sizeof(myprintf_buf->buf) - 2 ) {
njnc44a6c22005-06-03 13:21:18 +000095 send_bytes_to_logging_sink( myprintf_buf->buf, myprintf_buf->n );
96 myprintf_buf->n = 0;
97 }
98 myprintf_buf->buf[myprintf_buf->n++] = c;
99 myprintf_buf->buf[myprintf_buf->n] = 0;
bart1a0cb6a2008-04-14 16:35:32 +0000100 tl_assert(myprintf_buf->n < sizeof(myprintf_buf->buf));
njnc44a6c22005-06-03 13:21:18 +0000101}
102
103UInt VG_(vprintf) ( const HChar *format, va_list vargs )
104{
105 UInt ret = 0;
106 printf_buf myprintf_buf = {"",0};
107
bart1a0cb6a2008-04-14 16:35:32 +0000108 ret = VG_(vprintf_to_buf)(&myprintf_buf, format, vargs);
109 // Write out any chars left in the buffer.
110 if (myprintf_buf.n > 0) {
111 send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
112 }
113 return ret;
114}
115
116static UInt VG_(vprintf_to_buf) ( printf_buf *prbuf,
117 const HChar *format, va_list vargs )
118{
119 UInt ret = 0;
120
njnc44a6c22005-06-03 13:21:18 +0000121 if (VG_(clo_log_fd) >= 0) {
122 ret = VG_(debugLog_vprintf)
bart1a0cb6a2008-04-14 16:35:32 +0000123 ( add_to_myprintf_buf, prbuf, format, vargs );
njnc44a6c22005-06-03 13:21:18 +0000124 }
125 return ret;
126}
127
128UInt VG_(printf) ( const HChar *format, ... )
129{
130 UInt ret;
131 va_list vargs;
132
133 va_start(vargs, format);
134 ret = VG_(vprintf)(format, vargs);
135 va_end(vargs);
136
137 return ret;
138}
139
bart1a0cb6a2008-04-14 16:35:32 +0000140static UInt VG_(printf_to_buf) ( printf_buf* prbuf, const HChar *format, ... )
141{
142 UInt ret;
143 va_list vargs;
144
145 va_start(vargs, format);
146 ret = VG_(vprintf_to_buf)(prbuf, format, vargs);
147 va_end(vargs);
148
149 return ret;
150}
151
njnc44a6c22005-06-03 13:21:18 +0000152/* A general replacement for sprintf(). */
153static void add_to_vg_sprintf_buf ( HChar c, void *p )
154{
155 char **vg_sprintf_ptr = p;
156 *(*vg_sprintf_ptr)++ = c;
157}
158
159UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
160{
161 Int ret;
162 Char *vg_sprintf_ptr = buf;
163
164 ret = VG_(debugLog_vprintf)
165 ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
166 add_to_vg_sprintf_buf('\0', &vg_sprintf_ptr);
167
168 vg_assert(VG_(strlen)(buf) == ret);
169
170 return ret;
171}
172
173UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
174{
175 UInt ret;
176 va_list vargs;
177
178 va_start(vargs,format);
179 ret = VG_(vsprintf)(buf, format, vargs);
180 va_end(vargs);
181
182 return ret;
183}
184
sewardj45f4e7c2005-09-27 19:20:21 +0000185
186/* A replacement for snprintf. */
187typedef
188 struct {
189 HChar* buf;
190 Int buf_size;
191 Int buf_used;
192 }
193 snprintf_buf;
194
195static void add_to_vg_snprintf_buf ( HChar c, void* p )
196{
197 snprintf_buf* b = p;
198 if (b->buf_size > 0 && b->buf_used < b->buf_size) {
199 b->buf[b->buf_used++] = c;
200 if (b->buf_used < b->buf_size)
201 b->buf[b->buf_used] = 0;
sewardj03e2bb82006-12-24 03:02:18 +0000202 else
203 b->buf[b->buf_size-1] = 0; /* pre: b->buf_size > 0 */
sewardj45f4e7c2005-09-27 19:20:21 +0000204 }
205}
206
207UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
208{
209 Int ret;
210 snprintf_buf b;
211 b.buf = buf;
212 b.buf_size = size < 0 ? 0 : size;
213 b.buf_used = 0;
214
215 ret = VG_(debugLog_vprintf)
216 ( add_to_vg_snprintf_buf, &b, format, vargs );
217
218 return b.buf_used;
219}
220
221UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
222{
223 UInt ret;
224 va_list vargs;
225
226 va_start(vargs,format);
227 ret = VG_(vsnprintf)(buf, size, format, vargs);
228 va_end(vargs);
229
230 return ret;
231}
232
233
njnc44a6c22005-06-03 13:21:18 +0000234/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000235 percentify()
236 ------------------------------------------------------------------ */
237
njn7a5915e2005-07-17 16:12:59 +0000238// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000239// Right justifies in 'buf'.
240void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000241{
242 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000243 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000244 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000245
njn641e6162005-07-17 16:16:41 +0000246 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000247 // Have to generate the format string in order to be flexible about
248 // the width of the field.
njn8a7b41b2007-09-23 00:51:24 +0000249 VG_(sprintf)(fmt, "%%-%ds", n_buf);
njn5eaff2f2005-09-25 19:11:45 +0000250 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
251 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000252 return;
253 }
254
255 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000256
257 if (d == 0) {
258 VG_(sprintf)(buf, "%lld%%", p1);
259 } else {
260 ULong p2;
261 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000262 switch (d) {
263 case 1: ex = 10; break;
264 case 2: ex = 100; break;
265 case 3: ex = 1000; break;
266 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
267 }
268 p2 = ((100*n*ex) / m) % ex;
269 // Have to generate the format string in order to be flexible about
270 // the width of the post-decimal-point part.
271 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
272 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
273 VG_(sprintf)(buf, fmt, p1, p2);
274 }
275
276 len = VG_(strlen)(buf);
277 space = n_buf - len;
278 if (space < 0) space = 0; /* Allow for v. small field_width */
279 i = len;
280
281 /* Right justify in field */
282 for ( ; i >= 0; i--) buf[i + space] = buf[i];
283 for (i = 0; i < space; i++) buf[i] = ' ';
284}
285
sewardja11553a2005-07-19 12:17:05 +0000286
287/* ---------------------------------------------------------------------
sewardj592ae092005-11-08 19:01:44 +0000288 elapsed_wallclock_time()
sewardja11553a2005-07-19 12:17:05 +0000289 ------------------------------------------------------------------ */
290
sewardj592ae092005-11-08 19:01:44 +0000291/* Get the elapsed wallclock time since startup into buf, which must
292 16 chars long. This is unchecked. It also relies on the
293 millisecond timer having been set to zero by an initial read in
294 m_main during startup. */
sewardja11553a2005-07-19 12:17:05 +0000295
sewardj592ae092005-11-08 19:01:44 +0000296void VG_(elapsed_wallclock_time) ( /*OUT*/HChar* buf )
sewardja11553a2005-07-19 12:17:05 +0000297{
sewardj592ae092005-11-08 19:01:44 +0000298 UInt t, ms, s, mins, hours, days;
299
300 t = VG_(read_millisecond_timer)(); /* milliseconds */
301
302 ms = t % 1000;
303 t /= 1000; /* now in seconds */
304
305 s = t % 60;
306 t /= 60; /* now in minutes */
307
308 mins = t % 60;
309 t /= 60; /* now in hours */
310
311 hours = t % 24;
312 t /= 24; /* now in days */
313
314 days = t;
315
316 VG_(sprintf)(buf, "%02u:%02u:%02u:%02u.%03u", days, hours, mins, s, ms);
sewardja11553a2005-07-19 12:17:05 +0000317}
318
319
njn856c54e2005-06-26 18:43:40 +0000320/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000321 message()
322 ------------------------------------------------------------------ */
323
324UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
325{
sewardj45f4e7c2005-09-27 19:20:21 +0000326 UInt count = 0;
327 Char c;
328 Int i, depth;
bart1a0cb6a2008-04-14 16:35:32 +0000329 printf_buf myprintf_buf = {"",0};
njnc44a6c22005-06-03 13:21:18 +0000330
331 switch (kind) {
332 case Vg_UserMsg: c = '='; break;
333 case Vg_DebugMsg: c = '-'; break;
334 case Vg_DebugExtraMsg: c = '+'; break;
335 case Vg_ClientMsg: c = '*'; break;
336 default: c = '?'; break;
337 }
338
sewardj45f4e7c2005-09-27 19:20:21 +0000339 // Print one '>' in front of the messages for each level of self-hosting
340 // being performed.
341 depth = RUNNING_ON_VALGRIND;
342 for (i = 0; i < depth; i++) {
bart1a0cb6a2008-04-14 16:35:32 +0000343 count += VG_(printf_to_buf) (&myprintf_buf, ">");
sewardj45f4e7c2005-09-27 19:20:21 +0000344 }
345
njnc44a6c22005-06-03 13:21:18 +0000346 if (!VG_(clo_xml))
bart1a0cb6a2008-04-14 16:35:32 +0000347 count += VG_(printf_to_buf) (&myprintf_buf, "%c%c", c,c);
njnc44a6c22005-06-03 13:21:18 +0000348
349 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000350 HChar buf[50];
sewardj592ae092005-11-08 19:01:44 +0000351 VG_(elapsed_wallclock_time)(buf);
bart1a0cb6a2008-04-14 16:35:32 +0000352 count += VG_(printf_to_buf)(&myprintf_buf, "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000353 }
354
355 if (!VG_(clo_xml))
bart1a0cb6a2008-04-14 16:35:32 +0000356 count += VG_(printf_to_buf) (&myprintf_buf, "%d%c%c ", VG_(getpid)(), c,c);
njnc44a6c22005-06-03 13:21:18 +0000357
bart1a0cb6a2008-04-14 16:35:32 +0000358 count += VG_(vprintf_to_buf)(&myprintf_buf, format, vargs);
359 count += VG_(printf_to_buf) (&myprintf_buf, "\n");
360
361 if (myprintf_buf.n > 0) {
362 send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
363 }
364
njnc44a6c22005-06-03 13:21:18 +0000365 return count;
366}
367
368/* Send a simple single-part message. */
369UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
370{
371 UInt count;
372 va_list vargs;
373 va_start(vargs,format);
374 count = VG_(vmessage) ( kind, format, vargs );
375 va_end(vargs);
376 return count;
377}
378
379/*--------------------------------------------------------------------*/
380/*--- end ---*/
381/*--------------------------------------------------------------------*/
382