blob: c2aeb090fb5e44bff60c5265e69d76f4f643f9c8 [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"
njn24a6efb2005-06-20 03:36:51 +000035#include "pub_core_libcfile.h" // For VG_(write)(), VG_(write_socket)()
njnc44a6c22005-06-03 13:21:18 +000036#include "pub_core_libcprint.h"
njn24a6efb2005-06-20 03:36:51 +000037#include "pub_core_libcproc.h" // For VG_(getpid)()
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/* ---------------------------------------------------------------------
255 ctime()
256 ------------------------------------------------------------------ */
257
258/* BUF must be at least 25 characters long. This is unchecked. */
259
260void VG_(ctime) ( /*OUT*/HChar* buf )
261{
sewardj45f4e7c2005-09-27 19:20:21 +0000262#if 0
sewardja11553a2005-07-19 12:17:05 +0000263 struct timeval tv;
264 struct tm tm;
sewardj45f4e7c2005-09-27 19:20:21 +0000265 buf[0] = 0;
sewardja11553a2005-07-19 12:17:05 +0000266 if ( gettimeofday( &tv, NULL ) == 0
267 && localtime_r( &tv.tv_sec, &tm ) == &tm )
268 {
269 VG_(sprintf)( buf,
270 "%04d-%02d-%02d %02d:%02d:%02d.%03d",
271 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
272 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000 );
273 }
sewardj45f4e7c2005-09-27 19:20:21 +0000274#else
275 VG_(strcpy)(buf, "VG_(ctime) HACK!");
276#endif
sewardja11553a2005-07-19 12:17:05 +0000277}
278
279
njn856c54e2005-06-26 18:43:40 +0000280/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000281 message()
282 ------------------------------------------------------------------ */
283
284UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
285{
sewardj45f4e7c2005-09-27 19:20:21 +0000286 UInt count = 0;
287 Char c;
288 Int i, depth;
njnc44a6c22005-06-03 13:21:18 +0000289
290 switch (kind) {
291 case Vg_UserMsg: c = '='; break;
292 case Vg_DebugMsg: c = '-'; break;
293 case Vg_DebugExtraMsg: c = '+'; break;
294 case Vg_ClientMsg: c = '*'; break;
295 default: c = '?'; break;
296 }
297
sewardj45f4e7c2005-09-27 19:20:21 +0000298 // Print one '>' in front of the messages for each level of self-hosting
299 // being performed.
300 depth = RUNNING_ON_VALGRIND;
301 for (i = 0; i < depth; i++) {
302 count += VG_(printf) (">");
303 }
304
njnc44a6c22005-06-03 13:21:18 +0000305 if (!VG_(clo_xml))
sewardj45f4e7c2005-09-27 19:20:21 +0000306 count += VG_(printf) ("%c%c", c,c);
njnc44a6c22005-06-03 13:21:18 +0000307
308 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000309 HChar buf[50];
310 VG_(ctime)(buf);
311 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000312 }
313
314 if (!VG_(clo_xml))
315 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
316
317 count += VG_(vprintf)(format, vargs);
318 count += VG_(printf) ("\n");
319 return count;
320}
321
322/* Send a simple single-part message. */
323UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
324{
325 UInt count;
326 va_list vargs;
327 va_start(vargs,format);
328 count = VG_(vmessage) ( kind, format, vargs );
329 va_end(vargs);
330 return count;
331}
332
333/*--------------------------------------------------------------------*/
334/*--- end ---*/
335/*--------------------------------------------------------------------*/
336