blob: cc3e2ea617a9b5f8407ece0faece27ab1f912b24 [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
10 Copyright (C) 2000-2005 Julian Seward
11 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"
njnc44a6c22005-06-03 13:21:18 +000032#include "pub_core_debuglog.h"
33#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000034#include "pub_core_libcassert.h"
sewardj592ae092005-11-08 19:01:44 +000035#include "pub_core_libcfile.h" // VG_(write)(), VG_(write_socket)()
njnc44a6c22005-06-03 13:21:18 +000036#include "pub_core_libcprint.h"
sewardj592ae092005-11-08 19:01:44 +000037#include "pub_core_libcproc.h" // VG_(getpid)(), VG_(read_millisecond_timer()
njnc44a6c22005-06-03 13:21:18 +000038#include "pub_core_options.h"
njn24a6efb2005-06-20 03:36:51 +000039#include "valgrind.h" // For RUNNING_ON_VALGRIND
njnc44a6c22005-06-03 13:21:18 +000040
njnc44a6c22005-06-03 13:21:18 +000041
sewardja11553a2005-07-19 12:17:05 +000042
njnc44a6c22005-06-03 13:21:18 +000043/* ---------------------------------------------------------------------
44 Writing to file or a socket
45 ------------------------------------------------------------------ */
46
47/* Tell the logging mechanism whether we are logging to a file
48 descriptor or a socket descriptor. */
49Bool VG_(logging_to_socket) = False;
50
51/* Do the low-level send of a message to the logging sink. */
52static void send_bytes_to_logging_sink ( Char* msg, Int nbytes )
53{
54 if (!VG_(logging_to_socket)) {
55 VG_(write)( VG_(clo_log_fd), msg, nbytes );
56 } else {
57 Int rc = VG_(write_socket)( VG_(clo_log_fd), msg, nbytes );
58 if (rc == -1) {
59 // For example, the listener process died. Switch back to stderr.
60 VG_(logging_to_socket) = False;
61 VG_(clo_log_fd) = 2;
62 VG_(write)( VG_(clo_log_fd), msg, nbytes );
63 }
64 }
65}
66
67/* ---------------------------------------------------------------------
68 printf() and friends
69 ------------------------------------------------------------------ */
70
sewardj45f4e7c2005-09-27 19:20:21 +000071typedef
72 struct {
73 HChar buf[100];
74 Int n;
75 }
76 printf_buf;
njnc44a6c22005-06-03 13:21:18 +000077
78// Adds a single char to the buffer. When the buffer gets sufficiently
79// full, we write its contents to the logging sink.
80static void add_to_myprintf_buf ( HChar c, void *p )
81{
82 printf_buf *myprintf_buf = (printf_buf *)p;
83
84 if (myprintf_buf->n >= 100-10 /*paranoia*/ ) {
85 send_bytes_to_logging_sink( myprintf_buf->buf, myprintf_buf->n );
86 myprintf_buf->n = 0;
87 }
88 myprintf_buf->buf[myprintf_buf->n++] = c;
89 myprintf_buf->buf[myprintf_buf->n] = 0;
90}
91
92UInt VG_(vprintf) ( const HChar *format, va_list vargs )
93{
94 UInt ret = 0;
95 printf_buf myprintf_buf = {"",0};
96
97 if (VG_(clo_log_fd) >= 0) {
98 ret = VG_(debugLog_vprintf)
99 ( add_to_myprintf_buf, &myprintf_buf, format, vargs );
100
101 // Write out any chars left in the buffer.
102 if (myprintf_buf.n > 0) {
103 send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
104 }
105 }
106 return ret;
107}
108
109UInt VG_(printf) ( const HChar *format, ... )
110{
111 UInt ret;
112 va_list vargs;
113
114 va_start(vargs, format);
115 ret = VG_(vprintf)(format, vargs);
116 va_end(vargs);
117
118 return ret;
119}
120
121/* A general replacement for sprintf(). */
122static void add_to_vg_sprintf_buf ( HChar c, void *p )
123{
124 char **vg_sprintf_ptr = p;
125 *(*vg_sprintf_ptr)++ = c;
126}
127
128UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
129{
130 Int ret;
131 Char *vg_sprintf_ptr = buf;
132
133 ret = VG_(debugLog_vprintf)
134 ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
135 add_to_vg_sprintf_buf('\0', &vg_sprintf_ptr);
136
137 vg_assert(VG_(strlen)(buf) == ret);
138
139 return ret;
140}
141
142UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
143{
144 UInt ret;
145 va_list vargs;
146
147 va_start(vargs,format);
148 ret = VG_(vsprintf)(buf, format, vargs);
149 va_end(vargs);
150
151 return ret;
152}
153
sewardj45f4e7c2005-09-27 19:20:21 +0000154
155/* A replacement for snprintf. */
156typedef
157 struct {
158 HChar* buf;
159 Int buf_size;
160 Int buf_used;
161 }
162 snprintf_buf;
163
164static void add_to_vg_snprintf_buf ( HChar c, void* p )
165{
166 snprintf_buf* b = p;
167 if (b->buf_size > 0 && b->buf_used < b->buf_size) {
168 b->buf[b->buf_used++] = c;
169 if (b->buf_used < b->buf_size)
170 b->buf[b->buf_used] = 0;
171 }
172}
173
174UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
175{
176 Int ret;
177 snprintf_buf b;
178 b.buf = buf;
179 b.buf_size = size < 0 ? 0 : size;
180 b.buf_used = 0;
181
182 ret = VG_(debugLog_vprintf)
183 ( add_to_vg_snprintf_buf, &b, format, vargs );
184
185 return b.buf_used;
186}
187
188UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
189{
190 UInt ret;
191 va_list vargs;
192
193 va_start(vargs,format);
194 ret = VG_(vsnprintf)(buf, size, format, vargs);
195 va_end(vargs);
196
197 return ret;
198}
199
200
njnc44a6c22005-06-03 13:21:18 +0000201/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000202 percentify()
203 ------------------------------------------------------------------ */
204
njn7a5915e2005-07-17 16:12:59 +0000205// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000206// Right justifies in 'buf'.
207void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000208{
209 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000210 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000211 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000212
njn641e6162005-07-17 16:16:41 +0000213 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000214 // Have to generate the format string in order to be flexible about
215 // the width of the field.
216 VG_(sprintf)(fmt, "%%-%lds", n_buf);
217 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
218 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000219 return;
220 }
221
222 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000223
224 if (d == 0) {
225 VG_(sprintf)(buf, "%lld%%", p1);
226 } else {
227 ULong p2;
228 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000229 switch (d) {
230 case 1: ex = 10; break;
231 case 2: ex = 100; break;
232 case 3: ex = 1000; break;
233 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
234 }
235 p2 = ((100*n*ex) / m) % ex;
236 // Have to generate the format string in order to be flexible about
237 // the width of the post-decimal-point part.
238 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
239 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
240 VG_(sprintf)(buf, fmt, p1, p2);
241 }
242
243 len = VG_(strlen)(buf);
244 space = n_buf - len;
245 if (space < 0) space = 0; /* Allow for v. small field_width */
246 i = len;
247
248 /* Right justify in field */
249 for ( ; i >= 0; i--) buf[i + space] = buf[i];
250 for (i = 0; i < space; i++) buf[i] = ' ';
251}
252
sewardja11553a2005-07-19 12:17:05 +0000253
254/* ---------------------------------------------------------------------
sewardj592ae092005-11-08 19:01:44 +0000255 elapsed_wallclock_time()
sewardja11553a2005-07-19 12:17:05 +0000256 ------------------------------------------------------------------ */
257
sewardj592ae092005-11-08 19:01:44 +0000258/* Get the elapsed wallclock time since startup into buf, which must
259 16 chars long. This is unchecked. It also relies on the
260 millisecond timer having been set to zero by an initial read in
261 m_main during startup. */
sewardja11553a2005-07-19 12:17:05 +0000262
sewardj592ae092005-11-08 19:01:44 +0000263void VG_(elapsed_wallclock_time) ( /*OUT*/HChar* buf )
sewardja11553a2005-07-19 12:17:05 +0000264{
sewardj592ae092005-11-08 19:01:44 +0000265 UInt t, ms, s, mins, hours, days;
266
267 t = VG_(read_millisecond_timer)(); /* milliseconds */
268
269 ms = t % 1000;
270 t /= 1000; /* now in seconds */
271
272 s = t % 60;
273 t /= 60; /* now in minutes */
274
275 mins = t % 60;
276 t /= 60; /* now in hours */
277
278 hours = t % 24;
279 t /= 24; /* now in days */
280
281 days = t;
282
283 VG_(sprintf)(buf, "%02u:%02u:%02u:%02u.%03u", days, hours, mins, s, ms);
sewardja11553a2005-07-19 12:17:05 +0000284}
285
286
njn856c54e2005-06-26 18:43:40 +0000287/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000288 message()
289 ------------------------------------------------------------------ */
290
291UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
292{
sewardj45f4e7c2005-09-27 19:20:21 +0000293 UInt count = 0;
294 Char c;
295 Int i, depth;
njnc44a6c22005-06-03 13:21:18 +0000296
297 switch (kind) {
298 case Vg_UserMsg: c = '='; break;
299 case Vg_DebugMsg: c = '-'; break;
300 case Vg_DebugExtraMsg: c = '+'; break;
301 case Vg_ClientMsg: c = '*'; break;
302 default: c = '?'; break;
303 }
304
sewardj45f4e7c2005-09-27 19:20:21 +0000305 // Print one '>' in front of the messages for each level of self-hosting
306 // being performed.
307 depth = RUNNING_ON_VALGRIND;
308 for (i = 0; i < depth; i++) {
309 count += VG_(printf) (">");
310 }
311
njnc44a6c22005-06-03 13:21:18 +0000312 if (!VG_(clo_xml))
sewardj45f4e7c2005-09-27 19:20:21 +0000313 count += VG_(printf) ("%c%c", c,c);
njnc44a6c22005-06-03 13:21:18 +0000314
315 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000316 HChar buf[50];
sewardj592ae092005-11-08 19:01:44 +0000317 VG_(elapsed_wallclock_time)(buf);
sewardja11553a2005-07-19 12:17:05 +0000318 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000319 }
320
321 if (!VG_(clo_xml))
322 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
323
324 count += VG_(vprintf)(format, vargs);
325 count += VG_(printf) ("\n");
326 return count;
327}
328
329/* Send a simple single-part message. */
330UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
331{
332 UInt count;
333 va_list vargs;
334 va_start(vargs,format);
335 count = VG_(vmessage) ( kind, format, vargs );
336 va_end(vargs);
337 return count;
338}
339
340/*--------------------------------------------------------------------*/
341/*--- end ---*/
342/*--------------------------------------------------------------------*/
343