blob: a9cc9060ad24bec9dcdc49e945f0e711cab0f986 [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
sewardje4b0bf02006-06-05 23:21:15 +000010 Copyright (C) 2000-2006 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)) {
56 VG_(write)( VG_(clo_log_fd), msg, nbytes );
57 } else {
58 Int rc = VG_(write_socket)( VG_(clo_log_fd), msg, nbytes );
59 if (rc == -1) {
60 // For example, the listener process died. Switch back to stderr.
61 VG_(logging_to_socket) = False;
62 VG_(clo_log_fd) = 2;
63 VG_(write)( VG_(clo_log_fd), msg, nbytes );
64 }
65 }
66}
67
68/* ---------------------------------------------------------------------
69 printf() and friends
70 ------------------------------------------------------------------ */
71
sewardj45f4e7c2005-09-27 19:20:21 +000072typedef
73 struct {
74 HChar buf[100];
75 Int n;
76 }
77 printf_buf;
njnc44a6c22005-06-03 13:21:18 +000078
79// Adds a single char to the buffer. When the buffer gets sufficiently
80// full, we write its contents to the logging sink.
81static void add_to_myprintf_buf ( HChar c, void *p )
82{
83 printf_buf *myprintf_buf = (printf_buf *)p;
84
85 if (myprintf_buf->n >= 100-10 /*paranoia*/ ) {
86 send_bytes_to_logging_sink( myprintf_buf->buf, myprintf_buf->n );
87 myprintf_buf->n = 0;
88 }
89 myprintf_buf->buf[myprintf_buf->n++] = c;
90 myprintf_buf->buf[myprintf_buf->n] = 0;
91}
92
93UInt VG_(vprintf) ( const HChar *format, va_list vargs )
94{
95 UInt ret = 0;
96 printf_buf myprintf_buf = {"",0};
97
98 if (VG_(clo_log_fd) >= 0) {
99 ret = VG_(debugLog_vprintf)
100 ( add_to_myprintf_buf, &myprintf_buf, format, vargs );
101
102 // Write out any chars left in the buffer.
103 if (myprintf_buf.n > 0) {
104 send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
105 }
106 }
107 return ret;
108}
109
110UInt VG_(printf) ( const HChar *format, ... )
111{
112 UInt ret;
113 va_list vargs;
114
115 va_start(vargs, format);
116 ret = VG_(vprintf)(format, vargs);
117 va_end(vargs);
118
119 return ret;
120}
121
122/* A general replacement for sprintf(). */
123static void add_to_vg_sprintf_buf ( HChar c, void *p )
124{
125 char **vg_sprintf_ptr = p;
126 *(*vg_sprintf_ptr)++ = c;
127}
128
129UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
130{
131 Int ret;
132 Char *vg_sprintf_ptr = buf;
133
134 ret = VG_(debugLog_vprintf)
135 ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
136 add_to_vg_sprintf_buf('\0', &vg_sprintf_ptr);
137
138 vg_assert(VG_(strlen)(buf) == ret);
139
140 return ret;
141}
142
143UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
144{
145 UInt ret;
146 va_list vargs;
147
148 va_start(vargs,format);
149 ret = VG_(vsprintf)(buf, format, vargs);
150 va_end(vargs);
151
152 return ret;
153}
154
sewardj45f4e7c2005-09-27 19:20:21 +0000155
156/* A replacement for snprintf. */
157typedef
158 struct {
159 HChar* buf;
160 Int buf_size;
161 Int buf_used;
162 }
163 snprintf_buf;
164
165static void add_to_vg_snprintf_buf ( HChar c, void* p )
166{
167 snprintf_buf* b = p;
168 if (b->buf_size > 0 && b->buf_used < b->buf_size) {
169 b->buf[b->buf_used++] = c;
170 if (b->buf_used < b->buf_size)
171 b->buf[b->buf_used] = 0;
sewardj03e2bb82006-12-24 03:02:18 +0000172 else
173 b->buf[b->buf_size-1] = 0; /* pre: b->buf_size > 0 */
sewardj45f4e7c2005-09-27 19:20:21 +0000174 }
175}
176
177UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
178{
179 Int ret;
180 snprintf_buf b;
181 b.buf = buf;
182 b.buf_size = size < 0 ? 0 : size;
183 b.buf_used = 0;
184
185 ret = VG_(debugLog_vprintf)
186 ( add_to_vg_snprintf_buf, &b, format, vargs );
187
188 return b.buf_used;
189}
190
191UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
192{
193 UInt ret;
194 va_list vargs;
195
196 va_start(vargs,format);
197 ret = VG_(vsnprintf)(buf, size, format, vargs);
198 va_end(vargs);
199
200 return ret;
201}
202
203
njnc44a6c22005-06-03 13:21:18 +0000204/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000205 percentify()
206 ------------------------------------------------------------------ */
207
njn7a5915e2005-07-17 16:12:59 +0000208// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000209// Right justifies in 'buf'.
210void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000211{
212 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000213 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000214 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000215
njn641e6162005-07-17 16:16:41 +0000216 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000217 // Have to generate the format string in order to be flexible about
218 // the width of the field.
219 VG_(sprintf)(fmt, "%%-%lds", n_buf);
220 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
221 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000222 return;
223 }
224
225 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000226
227 if (d == 0) {
228 VG_(sprintf)(buf, "%lld%%", p1);
229 } else {
230 ULong p2;
231 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000232 switch (d) {
233 case 1: ex = 10; break;
234 case 2: ex = 100; break;
235 case 3: ex = 1000; break;
236 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
237 }
238 p2 = ((100*n*ex) / m) % ex;
239 // Have to generate the format string in order to be flexible about
240 // the width of the post-decimal-point part.
241 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
242 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
243 VG_(sprintf)(buf, fmt, p1, p2);
244 }
245
246 len = VG_(strlen)(buf);
247 space = n_buf - len;
248 if (space < 0) space = 0; /* Allow for v. small field_width */
249 i = len;
250
251 /* Right justify in field */
252 for ( ; i >= 0; i--) buf[i + space] = buf[i];
253 for (i = 0; i < space; i++) buf[i] = ' ';
254}
255
sewardja11553a2005-07-19 12:17:05 +0000256
257/* ---------------------------------------------------------------------
sewardj592ae092005-11-08 19:01:44 +0000258 elapsed_wallclock_time()
sewardja11553a2005-07-19 12:17:05 +0000259 ------------------------------------------------------------------ */
260
sewardj592ae092005-11-08 19:01:44 +0000261/* Get the elapsed wallclock time since startup into buf, which must
262 16 chars long. This is unchecked. It also relies on the
263 millisecond timer having been set to zero by an initial read in
264 m_main during startup. */
sewardja11553a2005-07-19 12:17:05 +0000265
sewardj592ae092005-11-08 19:01:44 +0000266void VG_(elapsed_wallclock_time) ( /*OUT*/HChar* buf )
sewardja11553a2005-07-19 12:17:05 +0000267{
sewardj592ae092005-11-08 19:01:44 +0000268 UInt t, ms, s, mins, hours, days;
269
270 t = VG_(read_millisecond_timer)(); /* milliseconds */
271
272 ms = t % 1000;
273 t /= 1000; /* now in seconds */
274
275 s = t % 60;
276 t /= 60; /* now in minutes */
277
278 mins = t % 60;
279 t /= 60; /* now in hours */
280
281 hours = t % 24;
282 t /= 24; /* now in days */
283
284 days = t;
285
286 VG_(sprintf)(buf, "%02u:%02u:%02u:%02u.%03u", days, hours, mins, s, ms);
sewardja11553a2005-07-19 12:17:05 +0000287}
288
289
njn856c54e2005-06-26 18:43:40 +0000290/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000291 message()
292 ------------------------------------------------------------------ */
293
294UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
295{
sewardj45f4e7c2005-09-27 19:20:21 +0000296 UInt count = 0;
297 Char c;
298 Int i, depth;
njnc44a6c22005-06-03 13:21:18 +0000299
300 switch (kind) {
301 case Vg_UserMsg: c = '='; break;
302 case Vg_DebugMsg: c = '-'; break;
303 case Vg_DebugExtraMsg: c = '+'; break;
304 case Vg_ClientMsg: c = '*'; break;
305 default: c = '?'; break;
306 }
307
sewardj45f4e7c2005-09-27 19:20:21 +0000308 // Print one '>' in front of the messages for each level of self-hosting
309 // being performed.
310 depth = RUNNING_ON_VALGRIND;
311 for (i = 0; i < depth; i++) {
312 count += VG_(printf) (">");
313 }
314
njnc44a6c22005-06-03 13:21:18 +0000315 if (!VG_(clo_xml))
sewardj45f4e7c2005-09-27 19:20:21 +0000316 count += VG_(printf) ("%c%c", c,c);
njnc44a6c22005-06-03 13:21:18 +0000317
318 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000319 HChar buf[50];
sewardj592ae092005-11-08 19:01:44 +0000320 VG_(elapsed_wallclock_time)(buf);
sewardja11553a2005-07-19 12:17:05 +0000321 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000322 }
323
324 if (!VG_(clo_xml))
325 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
326
327 count += VG_(vprintf)(format, vargs);
328 count += VG_(printf) ("\n");
329 return count;
330}
331
332/* Send a simple single-part message. */
333UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
334{
335 UInt count;
336 va_list vargs;
337 va_start(vargs,format);
338 count = VG_(vmessage) ( kind, format, vargs );
339 va_end(vargs);
340 return count;
341}
342
343/*--------------------------------------------------------------------*/
344/*--- end ---*/
345/*--------------------------------------------------------------------*/
346