blob: f782c48841a76e73700d15cf6220521e5c8b0d9b [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
31#include "core.h"
32#include "pub_core_debuglog.h"
33#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000034#include "pub_core_libcassert.h"
njnc44a6c22005-06-03 13:21:18 +000035#include "pub_core_libcprint.h"
36#include "pub_core_options.h"
37#include "valgrind.h" // for RUNNING_ON_VALGRIND
38
39#include <time.h>
40#include <sys/time.h>
41
42/* ---------------------------------------------------------------------
43 Writing to file or a socket
44 ------------------------------------------------------------------ */
45
46/* Tell the logging mechanism whether we are logging to a file
47 descriptor or a socket descriptor. */
48Bool VG_(logging_to_socket) = False;
49
50/* Do the low-level send of a message to the logging sink. */
51static void send_bytes_to_logging_sink ( Char* msg, Int nbytes )
52{
53 if (!VG_(logging_to_socket)) {
54 VG_(write)( VG_(clo_log_fd), msg, nbytes );
55 } else {
56 Int rc = VG_(write_socket)( VG_(clo_log_fd), msg, nbytes );
57 if (rc == -1) {
58 // For example, the listener process died. Switch back to stderr.
59 VG_(logging_to_socket) = False;
60 VG_(clo_log_fd) = 2;
61 VG_(write)( VG_(clo_log_fd), msg, nbytes );
62 }
63 }
64}
65
66/* ---------------------------------------------------------------------
67 printf() and friends
68 ------------------------------------------------------------------ */
69
70typedef struct {
71 char buf[100];
72 int n;
73} printf_buf;
74
75// Adds a single char to the buffer. When the buffer gets sufficiently
76// full, we write its contents to the logging sink.
77static void add_to_myprintf_buf ( HChar c, void *p )
78{
79 printf_buf *myprintf_buf = (printf_buf *)p;
80
81 if (myprintf_buf->n >= 100-10 /*paranoia*/ ) {
82 send_bytes_to_logging_sink( myprintf_buf->buf, myprintf_buf->n );
83 myprintf_buf->n = 0;
84 }
85 myprintf_buf->buf[myprintf_buf->n++] = c;
86 myprintf_buf->buf[myprintf_buf->n] = 0;
87}
88
89UInt VG_(vprintf) ( const HChar *format, va_list vargs )
90{
91 UInt ret = 0;
92 printf_buf myprintf_buf = {"",0};
93
94 if (VG_(clo_log_fd) >= 0) {
95 ret = VG_(debugLog_vprintf)
96 ( add_to_myprintf_buf, &myprintf_buf, format, vargs );
97
98 // Write out any chars left in the buffer.
99 if (myprintf_buf.n > 0) {
100 send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
101 }
102 }
103 return ret;
104}
105
106UInt VG_(printf) ( const HChar *format, ... )
107{
108 UInt ret;
109 va_list vargs;
110
111 va_start(vargs, format);
112 ret = VG_(vprintf)(format, vargs);
113 va_end(vargs);
114
115 return ret;
116}
117
118/* A general replacement for sprintf(). */
119static void add_to_vg_sprintf_buf ( HChar c, void *p )
120{
121 char **vg_sprintf_ptr = p;
122 *(*vg_sprintf_ptr)++ = c;
123}
124
125UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
126{
127 Int ret;
128 Char *vg_sprintf_ptr = buf;
129
130 ret = VG_(debugLog_vprintf)
131 ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
132 add_to_vg_sprintf_buf('\0', &vg_sprintf_ptr);
133
134 vg_assert(VG_(strlen)(buf) == ret);
135
136 return ret;
137}
138
139UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
140{
141 UInt ret;
142 va_list vargs;
143
144 va_start(vargs,format);
145 ret = VG_(vsprintf)(buf, format, vargs);
146 va_end(vargs);
147
148 return ret;
149}
150
151/* ---------------------------------------------------------------------
152 message()
153 ------------------------------------------------------------------ */
154
155UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
156{
157 UInt count = 0;
158 Char c;
159 const Char* pfx_s;
160 static const Char pfx[] = ">>>>>>>>>>>>>>>>";
161
162 switch (kind) {
163 case Vg_UserMsg: c = '='; break;
164 case Vg_DebugMsg: c = '-'; break;
165 case Vg_DebugExtraMsg: c = '+'; break;
166 case Vg_ClientMsg: c = '*'; break;
167 default: c = '?'; break;
168 }
169
170 // The pfx trick prints one or more '>' characters in front of the
171 // messages when running Valgrind under Valgrind, one per level of
172 // self-hosting.
173 pfx_s = &pfx[sizeof(pfx)-1-RUNNING_ON_VALGRIND],
174
175 // Print the message
176 count = 0;
177
178 if (!VG_(clo_xml))
179 count += VG_(printf) ("%s%c%c", pfx_s, c,c);
180
181 if (VG_(clo_time_stamp)) {
182 struct timeval tv;
183 struct tm tm;
184
185 if ( gettimeofday( &tv, NULL ) == 0 &&
186 localtime_r( &tv.tv_sec, &tm ) == &tm )
187 {
188 count +=
189 VG_(printf)( "%04d-%02d-%02d %02d:%02d:%02d.%03d ",
190 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
191 tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000 );
192 }
193 }
194
195 if (!VG_(clo_xml))
196 count += VG_(printf) ("%d%c%c ", VG_(getpid)(), c,c);
197
198 count += VG_(vprintf)(format, vargs);
199 count += VG_(printf) ("\n");
200 return count;
201}
202
203/* Send a simple single-part message. */
204UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
205{
206 UInt count;
207 va_list vargs;
208 va_start(vargs,format);
209 count = VG_(vmessage) ( kind, format, vargs );
210 va_end(vargs);
211 return count;
212}
213
214/*--------------------------------------------------------------------*/
215/*--- end ---*/
216/*--------------------------------------------------------------------*/
217