blob: 9adb6618e1d8c7e26afaf9939a915da33575adb2 [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.
njn856c54e2005-06-26 18:43:40 +0000159void VG_(percentify)(UInt n, UInt m, UInt d, Int n_buf, char buf[])
160{
161 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000162 ULong p1;
njn856c54e2005-06-26 18:43:40 +0000163
njn641e6162005-07-17 16:16:41 +0000164 if (m == 0) {
165 VG_(sprintf)(buf, "--%%");
166 return;
167 }
168
169 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000170
171 if (d == 0) {
172 VG_(sprintf)(buf, "%lld%%", p1);
173 } else {
174 ULong p2;
175 UInt ex;
176 Char fmt[32];
177 switch (d) {
178 case 1: ex = 10; break;
179 case 2: ex = 100; break;
180 case 3: ex = 1000; break;
181 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
182 }
183 p2 = ((100*n*ex) / m) % ex;
184 // Have to generate the format string in order to be flexible about
185 // the width of the post-decimal-point part.
186 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
187 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
188 VG_(sprintf)(buf, fmt, p1, p2);
189 }
190
191 len = VG_(strlen)(buf);
192 space = n_buf - len;
193 if (space < 0) space = 0; /* Allow for v. small field_width */
194 i = len;
195
196 /* Right justify in field */
197 for ( ; i >= 0; i--) buf[i + space] = buf[i];
198 for (i = 0; i < space; i++) buf[i] = ' ';
199}
200
sewardja11553a2005-07-19 12:17:05 +0000201
202/* ---------------------------------------------------------------------
203 ctime()
204 ------------------------------------------------------------------ */
205
206/* BUF must be at least 25 characters long. This is unchecked. */
207
208void VG_(ctime) ( /*OUT*/HChar* buf )
209{
210 struct timeval tv;
211 struct tm tm;
212 buf[0] = 0;
213 if ( gettimeofday( &tv, NULL ) == 0
214 && localtime_r( &tv.tv_sec, &tm ) == &tm )
215 {
216 VG_(sprintf)( buf,
217 "%04d-%02d-%02d %02d:%02d:%02d.%03d",
218 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
219 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000 );
220 }
221}
222
223
njn856c54e2005-06-26 18:43:40 +0000224/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000225 message()
226 ------------------------------------------------------------------ */
227
228UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
229{
230 UInt count = 0;
231 Char c;
232 const Char* pfx_s;
233 static const Char pfx[] = ">>>>>>>>>>>>>>>>";
234
235 switch (kind) {
236 case Vg_UserMsg: c = '='; break;
237 case Vg_DebugMsg: c = '-'; break;
238 case Vg_DebugExtraMsg: c = '+'; break;
239 case Vg_ClientMsg: c = '*'; break;
240 default: c = '?'; break;
241 }
242
243 // The pfx trick prints one or more '>' characters in front of the
244 // messages when running Valgrind under Valgrind, one per level of
245 // self-hosting.
246 pfx_s = &pfx[sizeof(pfx)-1-RUNNING_ON_VALGRIND],
247
248 // Print the message
249 count = 0;
250
251 if (!VG_(clo_xml))
252 count += VG_(printf) ("%s%c%c", pfx_s, c,c);
253
254 if (VG_(clo_time_stamp)) {
sewardja11553a2005-07-19 12:17:05 +0000255 HChar buf[50];
256 VG_(ctime)(buf);
257 count += VG_(printf)( "%s ", buf);
njnc44a6c22005-06-03 13:21:18 +0000258 }
259
260 if (!VG_(clo_xml))
261 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
262
263 count += VG_(vprintf)(format, vargs);
264 count += VG_(printf) ("\n");
265 return count;
266}
267
268/* Send a simple single-part message. */
269UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
270{
271 UInt count;
272 va_list vargs;
273 va_start(vargs,format);
274 count = VG_(vmessage) ( kind, format, vargs );
275 va_end(vargs);
276 return count;
277}
278
279/*--------------------------------------------------------------------*/
280/*--- end ---*/
281/*--------------------------------------------------------------------*/
282