blob: 5d435e328abd3ead54bc2129529a61ac70f01deb [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
41#include <time.h>
42#include <sys/time.h>
43
sewardja11553a2005-07-19 12:17:05 +000044
njnc44a6c22005-06-03 13:21:18 +000045/* ---------------------------------------------------------------------
46 Writing to file or a socket
47 ------------------------------------------------------------------ */
48
49/* Tell the logging mechanism whether we are logging to a file
50 descriptor or a socket descriptor. */
51Bool VG_(logging_to_socket) = False;
52
53/* Do the low-level send of a message to the logging sink. */
54static void send_bytes_to_logging_sink ( Char* msg, Int nbytes )
55{
56 if (!VG_(logging_to_socket)) {
57 VG_(write)( VG_(clo_log_fd), msg, nbytes );
58 } else {
59 Int rc = VG_(write_socket)( VG_(clo_log_fd), msg, nbytes );
60 if (rc == -1) {
61 // For example, the listener process died. Switch back to stderr.
62 VG_(logging_to_socket) = False;
63 VG_(clo_log_fd) = 2;
64 VG_(write)( VG_(clo_log_fd), msg, nbytes );
65 }
66 }
67}
68
69/* ---------------------------------------------------------------------
70 printf() and friends
71 ------------------------------------------------------------------ */
72
73typedef struct {
74 char buf[100];
75 int n;
76} printf_buf;
77
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
154/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000155 percentify()
156 ------------------------------------------------------------------ */
157
njn7a5915e2005-07-17 16:12:59 +0000158// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000159// Right justifies in 'buf'.
160void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000161{
162 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000163 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000164 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000165
njn641e6162005-07-17 16:16:41 +0000166 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000167 // Have to generate the format string in order to be flexible about
168 // the width of the field.
169 VG_(sprintf)(fmt, "%%-%lds", n_buf);
170 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
171 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000172 return;
173 }
174
175 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000176
177 if (d == 0) {
178 VG_(sprintf)(buf, "%lld%%", p1);
179 } else {
180 ULong p2;
181 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000182 switch (d) {
183 case 1: ex = 10; break;
184 case 2: ex = 100; break;
185 case 3: ex = 1000; break;
186 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
187 }
188 p2 = ((100*n*ex) / m) % ex;
189 // Have to generate the format string in order to be flexible about
190 // the width of the post-decimal-point part.
191 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
192 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
193 VG_(sprintf)(buf, fmt, p1, p2);
194 }
195
196 len = VG_(strlen)(buf);
197 space = n_buf - len;
198 if (space < 0) space = 0; /* Allow for v. small field_width */
199 i = len;
200
201 /* Right justify in field */
202 for ( ; i >= 0; i--) buf[i + space] = buf[i];
203 for (i = 0; i < space; i++) buf[i] = ' ';
204}
205
sewardja11553a2005-07-19 12:17:05 +0000206
207/* ---------------------------------------------------------------------
208 ctime()
209 ------------------------------------------------------------------ */
210
211/* BUF must be at least 25 characters long. This is unchecked. */
212
213void VG_(ctime) ( /*OUT*/HChar* buf )
214{
215 struct timeval tv;
216 struct tm tm;
217 buf[0] = 0;
218 if ( gettimeofday( &tv, NULL ) == 0
219 && localtime_r( &tv.tv_sec, &tm ) == &tm )
220 {
221 VG_(sprintf)( buf,
222 "%04d-%02d-%02d %02d:%02d:%02d.%03d",
223 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
224 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000 );
225 }
226}
227
228
njn856c54e2005-06-26 18:43:40 +0000229/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000230 message()
231 ------------------------------------------------------------------ */
232
233UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
234{
235 UInt count = 0;
236 Char c;
237 const Char* pfx_s;
238 static const Char pfx[] = ">>>>>>>>>>>>>>>>";
239
240 switch (kind) {
241 case Vg_UserMsg: c = '='; break;
242 case Vg_DebugMsg: c = '-'; break;
243 case Vg_DebugExtraMsg: c = '+'; break;
244 case Vg_ClientMsg: c = '*'; break;
245 default: c = '?'; break;
246 }
247
248 // The pfx trick prints one or more '>' characters in front of the
249 // messages when running Valgrind under Valgrind, one per level of
250 // self-hosting.
251 pfx_s = &pfx[sizeof(pfx)-1-RUNNING_ON_VALGRIND],
252
253 // Print the message
254 count = 0;
255
256 if (!VG_(clo_xml))
257 count += VG_(printf) ("%s%c%c", pfx_s, c,c);
258
259 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000260 HChar buf[50];
261 VG_(ctime)(buf);
262 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000263 }
264
265 if (!VG_(clo_xml))
266 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
267
268 count += VG_(vprintf)(format, vargs);
269 count += VG_(printf) ("\n");
270 return count;
271}
272
273/* Send a simple single-part message. */
274UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
275{
276 UInt count;
277 va_list vargs;
278 va_start(vargs,format);
279 count = VG_(vmessage) ( kind, format, vargs );
280 va_end(vargs);
281 return count;
282}
283
284/*--------------------------------------------------------------------*/
285/*--- end ---*/
286/*--------------------------------------------------------------------*/
287