blob: 5ba8bb11d5fbbcbe93130054d6f2f415cb0ae3a2 [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
sewardj9ebd6e02007-01-08 06:01:59 +000010 Copyright (C) 2000-2007 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 {
79 HChar buf[100];
80 Int n;
81 }
82 printf_buf;
njnc44a6c22005-06-03 13:21:18 +000083
84// Adds a single char to the buffer. When the buffer gets sufficiently
85// full, we write its contents to the logging sink.
86static void add_to_myprintf_buf ( HChar c, void *p )
87{
88 printf_buf *myprintf_buf = (printf_buf *)p;
89
90 if (myprintf_buf->n >= 100-10 /*paranoia*/ ) {
91 send_bytes_to_logging_sink( myprintf_buf->buf, myprintf_buf->n );
92 myprintf_buf->n = 0;
93 }
94 myprintf_buf->buf[myprintf_buf->n++] = c;
95 myprintf_buf->buf[myprintf_buf->n] = 0;
96}
97
98UInt VG_(vprintf) ( const HChar *format, va_list vargs )
99{
100 UInt ret = 0;
101 printf_buf myprintf_buf = {"",0};
102
103 if (VG_(clo_log_fd) >= 0) {
104 ret = VG_(debugLog_vprintf)
105 ( add_to_myprintf_buf, &myprintf_buf, format, vargs );
106
107 // Write out any chars left in the buffer.
108 if (myprintf_buf.n > 0) {
109 send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
110 }
111 }
112 return ret;
113}
114
115UInt VG_(printf) ( const HChar *format, ... )
116{
117 UInt ret;
118 va_list vargs;
119
120 va_start(vargs, format);
121 ret = VG_(vprintf)(format, vargs);
122 va_end(vargs);
123
124 return ret;
125}
126
127/* A general replacement for sprintf(). */
128static void add_to_vg_sprintf_buf ( HChar c, void *p )
129{
130 char **vg_sprintf_ptr = p;
131 *(*vg_sprintf_ptr)++ = c;
132}
133
134UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
135{
136 Int ret;
137 Char *vg_sprintf_ptr = buf;
138
139 ret = VG_(debugLog_vprintf)
140 ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
141 add_to_vg_sprintf_buf('\0', &vg_sprintf_ptr);
142
143 vg_assert(VG_(strlen)(buf) == ret);
144
145 return ret;
146}
147
148UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
149{
150 UInt ret;
151 va_list vargs;
152
153 va_start(vargs,format);
154 ret = VG_(vsprintf)(buf, format, vargs);
155 va_end(vargs);
156
157 return ret;
158}
159
sewardj45f4e7c2005-09-27 19:20:21 +0000160
161/* A replacement for snprintf. */
162typedef
163 struct {
164 HChar* buf;
165 Int buf_size;
166 Int buf_used;
167 }
168 snprintf_buf;
169
170static void add_to_vg_snprintf_buf ( HChar c, void* p )
171{
172 snprintf_buf* b = p;
173 if (b->buf_size > 0 && b->buf_used < b->buf_size) {
174 b->buf[b->buf_used++] = c;
175 if (b->buf_used < b->buf_size)
176 b->buf[b->buf_used] = 0;
sewardj03e2bb82006-12-24 03:02:18 +0000177 else
178 b->buf[b->buf_size-1] = 0; /* pre: b->buf_size > 0 */
sewardj45f4e7c2005-09-27 19:20:21 +0000179 }
180}
181
182UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
183{
184 Int ret;
185 snprintf_buf b;
186 b.buf = buf;
187 b.buf_size = size < 0 ? 0 : size;
188 b.buf_used = 0;
189
190 ret = VG_(debugLog_vprintf)
191 ( add_to_vg_snprintf_buf, &b, format, vargs );
192
193 return b.buf_used;
194}
195
196UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
197{
198 UInt ret;
199 va_list vargs;
200
201 va_start(vargs,format);
202 ret = VG_(vsnprintf)(buf, size, format, vargs);
203 va_end(vargs);
204
205 return ret;
206}
207
208
njnc44a6c22005-06-03 13:21:18 +0000209/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000210 percentify()
211 ------------------------------------------------------------------ */
212
njn7a5915e2005-07-17 16:12:59 +0000213// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000214// Right justifies in 'buf'.
215void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000216{
217 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000218 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000219 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000220
njn641e6162005-07-17 16:16:41 +0000221 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000222 // Have to generate the format string in order to be flexible about
223 // the width of the field.
njn8a7b41b2007-09-23 00:51:24 +0000224 VG_(sprintf)(fmt, "%%-%ds", n_buf);
njn5eaff2f2005-09-25 19:11:45 +0000225 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
226 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000227 return;
228 }
229
230 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000231
232 if (d == 0) {
233 VG_(sprintf)(buf, "%lld%%", p1);
234 } else {
235 ULong p2;
236 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000237 switch (d) {
238 case 1: ex = 10; break;
239 case 2: ex = 100; break;
240 case 3: ex = 1000; break;
241 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
242 }
243 p2 = ((100*n*ex) / m) % ex;
244 // Have to generate the format string in order to be flexible about
245 // the width of the post-decimal-point part.
246 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
247 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
248 VG_(sprintf)(buf, fmt, p1, p2);
249 }
250
251 len = VG_(strlen)(buf);
252 space = n_buf - len;
253 if (space < 0) space = 0; /* Allow for v. small field_width */
254 i = len;
255
256 /* Right justify in field */
257 for ( ; i >= 0; i--) buf[i + space] = buf[i];
258 for (i = 0; i < space; i++) buf[i] = ' ';
259}
260
sewardja11553a2005-07-19 12:17:05 +0000261
262/* ---------------------------------------------------------------------
sewardj592ae092005-11-08 19:01:44 +0000263 elapsed_wallclock_time()
sewardja11553a2005-07-19 12:17:05 +0000264 ------------------------------------------------------------------ */
265
sewardj592ae092005-11-08 19:01:44 +0000266/* Get the elapsed wallclock time since startup into buf, which must
267 16 chars long. This is unchecked. It also relies on the
268 millisecond timer having been set to zero by an initial read in
269 m_main during startup. */
sewardja11553a2005-07-19 12:17:05 +0000270
sewardj592ae092005-11-08 19:01:44 +0000271void VG_(elapsed_wallclock_time) ( /*OUT*/HChar* buf )
sewardja11553a2005-07-19 12:17:05 +0000272{
sewardj592ae092005-11-08 19:01:44 +0000273 UInt t, ms, s, mins, hours, days;
274
275 t = VG_(read_millisecond_timer)(); /* milliseconds */
276
277 ms = t % 1000;
278 t /= 1000; /* now in seconds */
279
280 s = t % 60;
281 t /= 60; /* now in minutes */
282
283 mins = t % 60;
284 t /= 60; /* now in hours */
285
286 hours = t % 24;
287 t /= 24; /* now in days */
288
289 days = t;
290
291 VG_(sprintf)(buf, "%02u:%02u:%02u:%02u.%03u", days, hours, mins, s, ms);
sewardja11553a2005-07-19 12:17:05 +0000292}
293
294
njn856c54e2005-06-26 18:43:40 +0000295/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000296 message()
297 ------------------------------------------------------------------ */
298
299UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
300{
sewardj45f4e7c2005-09-27 19:20:21 +0000301 UInt count = 0;
302 Char c;
303 Int i, depth;
njnc44a6c22005-06-03 13:21:18 +0000304
305 switch (kind) {
306 case Vg_UserMsg: c = '='; break;
307 case Vg_DebugMsg: c = '-'; break;
308 case Vg_DebugExtraMsg: c = '+'; break;
309 case Vg_ClientMsg: c = '*'; break;
310 default: c = '?'; break;
311 }
312
sewardj45f4e7c2005-09-27 19:20:21 +0000313 // Print one '>' in front of the messages for each level of self-hosting
314 // being performed.
315 depth = RUNNING_ON_VALGRIND;
316 for (i = 0; i < depth; i++) {
317 count += VG_(printf) (">");
318 }
319
njnc44a6c22005-06-03 13:21:18 +0000320 if (!VG_(clo_xml))
sewardj45f4e7c2005-09-27 19:20:21 +0000321 count += VG_(printf) ("%c%c", c,c);
njnc44a6c22005-06-03 13:21:18 +0000322
323 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000324 HChar buf[50];
sewardj592ae092005-11-08 19:01:44 +0000325 VG_(elapsed_wallclock_time)(buf);
sewardja11553a2005-07-19 12:17:05 +0000326 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000327 }
328
329 if (!VG_(clo_xml))
330 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
331
332 count += VG_(vprintf)(format, vargs);
333 count += VG_(printf) ("\n");
334 return count;
335}
336
337/* Send a simple single-part message. */
338UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
339{
340 UInt count;
341 va_list vargs;
342 va_start(vargs,format);
343 count = VG_(vmessage) ( kind, format, vargs );
344 va_end(vargs);
345 return count;
346}
347
348/*--------------------------------------------------------------------*/
349/*--- end ---*/
350/*--------------------------------------------------------------------*/
351