blob: e4255904051b69952f449169277f814daefac962 [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;
172 }
173}
174
175UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
176{
177 Int ret;
178 snprintf_buf b;
179 b.buf = buf;
180 b.buf_size = size < 0 ? 0 : size;
181 b.buf_used = 0;
182
183 ret = VG_(debugLog_vprintf)
184 ( add_to_vg_snprintf_buf, &b, format, vargs );
185
186 return b.buf_used;
187}
188
189UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
190{
191 UInt ret;
192 va_list vargs;
193
194 va_start(vargs,format);
195 ret = VG_(vsnprintf)(buf, size, format, vargs);
196 va_end(vargs);
197
198 return ret;
199}
200
201
njnc44a6c22005-06-03 13:21:18 +0000202/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000203 percentify()
204 ------------------------------------------------------------------ */
205
njn7a5915e2005-07-17 16:12:59 +0000206// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000207// Right justifies in 'buf'.
208void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000209{
210 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000211 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000212 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000213
njn641e6162005-07-17 16:16:41 +0000214 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000215 // Have to generate the format string in order to be flexible about
216 // the width of the field.
217 VG_(sprintf)(fmt, "%%-%lds", n_buf);
218 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
219 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000220 return;
221 }
222
223 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000224
225 if (d == 0) {
226 VG_(sprintf)(buf, "%lld%%", p1);
227 } else {
228 ULong p2;
229 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000230 switch (d) {
231 case 1: ex = 10; break;
232 case 2: ex = 100; break;
233 case 3: ex = 1000; break;
234 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
235 }
236 p2 = ((100*n*ex) / m) % ex;
237 // Have to generate the format string in order to be flexible about
238 // the width of the post-decimal-point part.
239 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
240 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
241 VG_(sprintf)(buf, fmt, p1, p2);
242 }
243
244 len = VG_(strlen)(buf);
245 space = n_buf - len;
246 if (space < 0) space = 0; /* Allow for v. small field_width */
247 i = len;
248
249 /* Right justify in field */
250 for ( ; i >= 0; i--) buf[i + space] = buf[i];
251 for (i = 0; i < space; i++) buf[i] = ' ';
252}
253
sewardja11553a2005-07-19 12:17:05 +0000254
255/* ---------------------------------------------------------------------
sewardj592ae092005-11-08 19:01:44 +0000256 elapsed_wallclock_time()
sewardja11553a2005-07-19 12:17:05 +0000257 ------------------------------------------------------------------ */
258
sewardj592ae092005-11-08 19:01:44 +0000259/* Get the elapsed wallclock time since startup into buf, which must
260 16 chars long. This is unchecked. It also relies on the
261 millisecond timer having been set to zero by an initial read in
262 m_main during startup. */
sewardja11553a2005-07-19 12:17:05 +0000263
sewardj592ae092005-11-08 19:01:44 +0000264void VG_(elapsed_wallclock_time) ( /*OUT*/HChar* buf )
sewardja11553a2005-07-19 12:17:05 +0000265{
sewardj592ae092005-11-08 19:01:44 +0000266 UInt t, ms, s, mins, hours, days;
267
268 t = VG_(read_millisecond_timer)(); /* milliseconds */
269
270 ms = t % 1000;
271 t /= 1000; /* now in seconds */
272
273 s = t % 60;
274 t /= 60; /* now in minutes */
275
276 mins = t % 60;
277 t /= 60; /* now in hours */
278
279 hours = t % 24;
280 t /= 24; /* now in days */
281
282 days = t;
283
284 VG_(sprintf)(buf, "%02u:%02u:%02u:%02u.%03u", days, hours, mins, s, ms);
sewardja11553a2005-07-19 12:17:05 +0000285}
286
287
njn856c54e2005-06-26 18:43:40 +0000288/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000289 message()
290 ------------------------------------------------------------------ */
291
292UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
293{
sewardj45f4e7c2005-09-27 19:20:21 +0000294 UInt count = 0;
295 Char c;
296 Int i, depth;
njnc44a6c22005-06-03 13:21:18 +0000297
298 switch (kind) {
299 case Vg_UserMsg: c = '='; break;
300 case Vg_DebugMsg: c = '-'; break;
301 case Vg_DebugExtraMsg: c = '+'; break;
302 case Vg_ClientMsg: c = '*'; break;
303 default: c = '?'; break;
304 }
305
sewardj45f4e7c2005-09-27 19:20:21 +0000306 // Print one '>' in front of the messages for each level of self-hosting
307 // being performed.
308 depth = RUNNING_ON_VALGRIND;
309 for (i = 0; i < depth; i++) {
310 count += VG_(printf) (">");
311 }
312
njnc44a6c22005-06-03 13:21:18 +0000313 if (!VG_(clo_xml))
sewardj45f4e7c2005-09-27 19:20:21 +0000314 count += VG_(printf) ("%c%c", c,c);
njnc44a6c22005-06-03 13:21:18 +0000315
316 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000317 HChar buf[50];
sewardj592ae092005-11-08 19:01:44 +0000318 VG_(elapsed_wallclock_time)(buf);
sewardja11553a2005-07-19 12:17:05 +0000319 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000320 }
321
322 if (!VG_(clo_xml))
323 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
324
325 count += VG_(vprintf)(format, vargs);
326 count += VG_(printf) ("\n");
327 return count;
328}
329
330/* Send a simple single-part message. */
331UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
332{
333 UInt count;
334 va_list vargs;
335 va_start(vargs,format);
336 count = VG_(vmessage) ( kind, format, vargs );
337 va_end(vargs);
338 return count;
339}
340
341/*--------------------------------------------------------------------*/
342/*--- end ---*/
343/*--------------------------------------------------------------------*/
344