blob: 9a81c56f6755d3c88da572baec8a35b27f53b7d0 [file] [log] [blame]
sewardj1cf558c2005-04-25 01:36:56 +00001
2/*--------------------------------------------------------------------*/
3/*--- Debug (not-for-user) logging; also vprintf. m_debuglog.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
32/* Performs low-level debug logging that can safely run immediately
33 after startup. To minimise the dependencies on any other parts of
34 the system, the only place the debug output may go is file
35 descriptor 2 (stderr).
36*/
37/* This is the first-initialised module in the entire system!
38 Therefore it is CRITICAL that it does not depend on any other code
39 running first. Hence only the following very limited includes. We
40 cannot depend (directly or indirectly) on any dynamic memory
41 allocation facilities, nor on the m_libc facilities, since the
42 latter depend on this module. DO NOT MESS WITH THESE INCLUDES
43 UNLESS YOU ARE 100% CERTAIN YOU UNDERSTAND THE CONSEQUENCES.
44*/
45/* This module is also different from all others in the sense that it
46 is linked into both stage1 and stage2.
47*/
48#include "basic_types.h" /* basic types */
49#include "pub_core_debuglog.h" /* our own iface */
50
51
52/*------------------------------------------------------------*/
53/*--- Stuff to make us completely independent. ---*/
54/*------------------------------------------------------------*/
55
56/* ----- x86-linux specifics ----- */
57
sewardj601371a2005-04-25 16:21:17 +000058/* Arse! Really I want to test VG_PLATFORM, but this does not
59 seem to be possible. */
60#if defined(__i386__) && defined(__linux__)
sewardj1cf558c2005-04-25 01:36:56 +000061
62static UInt local_sys_write_stderr ( HChar* buf, Int n )
63{
64 UInt __res;
65 __asm__ volatile ("int $0x80"
66 : "=a" (__res)
67 : "0" (4), /* __NR_write */
68 "b" (2), /* stderr */
69 "c" (buf),
70 "d" (n) );
71 if (__res < 0)
72 __res = -1;
73 return __res;
74}
75
76static UInt local_sys_getpid ( void )
77{
78 UInt __res;
79 __asm__ volatile ("int $0x80"
80 : "=a" (__res)
81 : "0" (20) /* __NR_getpid */);
82 return __res;
83}
84
sewardj601371a2005-04-25 16:21:17 +000085#elif defined(__x86_64__) && defined(__linux__)
86
87static UInt local_sys_write_stderr ( HChar* buf, Int n )
88{
89 return 0;
90}
91
92static UInt local_sys_getpid ( void )
93{
94 return 0;
95}
sewardj1cf558c2005-04-25 01:36:56 +000096
97#else
98#error Unknown VG_PLATFORM
99#endif
100
101
102/* ----- generic ----- */
103
104/* strlen, so we don't need m_libc */
105static Int local_strlen ( const HChar* str )
106{
107 Int i = 0;
108 while (str[i] != 0) i++;
109 return i;
110}
111
112static HChar local_toupper ( HChar c )
113{
114 if (c >= 'a' && c <= 'z')
115 return c + ('A' - 'a');
116 else
117 return c;
118}
119
120/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
121*/
122static void emit ( HChar* buf, Int n )
123{
124 if (n >= 1)
125 (void)local_sys_write_stderr(buf, n);
126}
127
128
129/*------------------------------------------------------------*/
130/*--- A simple, generic, vprintf implementation. ---*/
131/*------------------------------------------------------------*/
132
133/* -----------------------------------------------
134 Distantly derived from:
135
136 vprintf replacement for Checker.
137 Copyright 1993, 1994, 1995 Tristan Gingold
138 Written September 1993 Tristan Gingold
139 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
140
141 (Checker itself was GPL'd.)
142 ----------------------------------------------- */
143
144/* Some flags. */
145#define VG_MSG_SIGNED 1 /* The value is signed. */
146#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
147#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
148#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
149#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
150
151
152/* Copy a string into the buffer. */
153static
154UInt myvprintf_str ( void(*send)(HChar,void*),
155 void* send_arg2,
156 Int flags,
157 Int width,
158 HChar* str,
159 Bool capitalise )
160{
161# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
162 UInt ret = 0;
163 Int i, extra;
164 Int len = local_strlen(str);
165
166 if (width == 0) {
167 ret += len;
168 for (i = 0; i < len; i++)
169 send(MAYBE_TOUPPER(str[i]), send_arg2);
170 return ret;
171 }
172
173 if (len > width) {
174 ret += width;
175 for (i = 0; i < width; i++)
176 send(MAYBE_TOUPPER(str[i]), send_arg2);
177 return ret;
178 }
179
180 extra = width - len;
181 if (flags & VG_MSG_LJUSTIFY) {
182 ret += extra;
183 for (i = 0; i < extra; i++)
184 send(' ', send_arg2);
185 }
186 ret += len;
187 for (i = 0; i < len; i++)
188 send(MAYBE_TOUPPER(str[i]), send_arg2);
189 if (!(flags & VG_MSG_LJUSTIFY)) {
190 ret += extra;
191 for (i = 0; i < extra; i++)
192 send(' ', send_arg2);
193 }
194
195# undef MAYBE_TOUPPER
196 return ret;
197}
198
199
200/* Write P into the buffer according to these args:
201 * If SIGN is true, p is a signed.
202 * BASE is the base.
203 * If WITH_ZERO is true, '0' must be added.
204 * WIDTH is the width of the field.
205 */
206static
207UInt myvprintf_int64 ( void(*send)(HChar,void*),
208 void* send_arg2,
209 Int flags,
210 Int base,
211 Int width,
212 ULong p )
213{
214 HChar buf[40];
215 Int ind = 0;
216 Int i, nc = 0;
217 Bool neg = False;
218 HChar* digits = "0123456789ABCDEF";
219 UInt ret = 0;
220
221 if (base < 2 || base > 16)
222 return ret;
223
224 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
225 p = - (Long)p;
226 neg = True;
227 }
228
229 if (p == 0)
230 buf[ind++] = '0';
231 else {
232 while (p > 0) {
233 if (flags & VG_MSG_COMMA && 10 == base &&
234 0 == (ind-nc) % 3 && 0 != ind)
235 {
236 buf[ind++] = ',';
237 nc++;
238 }
239 buf[ind++] = digits[p % base];
240 p /= base;
241 }
242 }
243
244 if (neg)
245 buf[ind++] = '-';
246
247 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
248 for(; ind < width; ind++) {
249 /* vg_assert(ind < 39); */
250 if (ind > 39) {
251 buf[39] = 0;
252 break;
253 }
254 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
255 }
256 }
257
258 /* Reverse copy to buffer. */
259 ret += ind;
260 for (i = ind -1; i >= 0; i--) {
261 send(buf[i], send_arg2);
262 }
263 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
264 for(; ind < width; ind++) {
265 ret++;
266 /* Never pad with zeroes on RHS -- changes the value! */
267 send(' ', send_arg2);
268 }
269 }
270 return ret;
271}
272
273
274/* A simple vprintf(). */
275/* EXPORTED */
276UInt
277VG_(debugLog_vprintf) (
278 void(*send)(HChar,void*),
279 void* send_arg2,
280 const HChar* format,
281 va_list vargs
282)
283{
284 UInt ret = 0;
285 Int i;
286 Int flags;
287 Int width;
288 Bool is_long;
289
290 /* We assume that vargs has already been initialised by the
291 caller, using va_start, and that the caller will similarly
292 clean up with va_end.
293 */
294
295 for (i = 0; format[i] != 0; i++) {
296 if (format[i] != '%') {
297 send(format[i], send_arg2);
298 ret++;
299 continue;
300 }
301 i++;
302 /* A '%' has been found. Ignore a trailing %. */
303 if (format[i] == 0)
304 break;
305 if (format[i] == '%') {
306 /* `%%' is replaced by `%'. */
307 send('%', send_arg2);
308 ret++;
309 continue;
310 }
311 flags = 0;
312 is_long = False;
313 width = 0; /* length of the field. */
314 if (format[i] == '(') {
315 flags |= VG_MSG_PAREN;
316 i++;
317 }
318 /* If ',' follows '%', commas will be inserted. */
319 if (format[i] == ',') {
320 flags |= VG_MSG_COMMA;
321 i++;
322 }
323 /* If '-' follows '%', justify on the left. */
324 if (format[i] == '-') {
325 flags |= VG_MSG_LJUSTIFY;
326 i++;
327 }
328 /* If '0' follows '%', pads will be inserted. */
329 if (format[i] == '0') {
330 flags |= VG_MSG_ZJUSTIFY;
331 i++;
332 }
333 /* Compute the field length. */
334 while (format[i] >= '0' && format[i] <= '9') {
335 width *= 10;
336 width += format[i++] - '0';
337 }
338 while (format[i] == 'l') {
339 i++;
340 is_long = True;
341 }
342
343 switch (format[i]) {
344 case 'd': /* %d */
345 flags |= VG_MSG_SIGNED;
346 if (is_long)
347 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
348 (ULong)(va_arg (vargs, Long)));
349 else
350 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
351 (ULong)(va_arg (vargs, Int)));
352 break;
353 case 'u': /* %u */
354 if (is_long)
355 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
356 (ULong)(va_arg (vargs, ULong)));
357 else
358 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
359 (ULong)(va_arg (vargs, UInt)));
360 break;
361 case 'p': /* %p */
362 ret += 2;
363 send('0',send_arg2);
364 send('x',send_arg2);
365 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
366 (ULong)((UWord)va_arg (vargs, void *)));
367 break;
368 case 'x': /* %x */
369 if (is_long)
370 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
371 (ULong)(va_arg (vargs, ULong)));
372 else
373 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
374 (ULong)(va_arg (vargs, UInt)));
375 break;
376 case 'c': /* %c */
377 ret++;
378 send(va_arg (vargs, int), send_arg2);
379 break;
380 case 's': case 'S': { /* %s */
381 char *str = va_arg (vargs, char *);
382 if (str == (char*) 0) str = "(null)";
383 ret += myvprintf_str(send, send_arg2,
384 flags, width, str, format[i]=='S');
385 break;
386 }
387// case 'y': { /* %y - print symbol */
388// Char buf[100];
389// Char *cp = buf;
390// Addr a = va_arg(vargs, Addr);
391//
392// if (flags & VG_MSG_PAREN)
393// *cp++ = '(';
394// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
395// if (flags & VG_MSG_PAREN) {
396// cp += VG_(strlen)(cp);
397// *cp++ = ')';
398// *cp = '\0';
399// }
400// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
401// }
402// break;
403// }
404 default:
405 break;
406 }
407 }
408 return ret;
409}
410
411
412/*------------------------------------------------------------*/
413/*--- Debuglog stuff. ---*/
414/*------------------------------------------------------------*/
415
416/* Only print messages whose stated level is less than or equal to
417 this. By default, it makes this entire subsystem silent. */
418
419static Int loglevel = 0;
420
421/* EXPORTED */
422/* Module startup. */
423void VG_(debugLog_startup) ( Int level, HChar* who )
424{
425 if (level < 0) level = 0;
426 if (level > 10) level = 10;
427 loglevel = level;
428 VG_(debugLog)(1, "debuglog",
429 "DebugLog system started by %s, "
430 "level %d logging requested\n",
431 who, loglevel);
432}
433
434/* ------------ */
435
436typedef
437 struct {
438 HChar buf[100];
439 Int n;
440 }
441 printf_buf;
442
443static void add_to_buf ( HChar c, void* p )
444{
445 printf_buf* buf = (printf_buf*)p;
446
447 if (buf->n >= 100-10 /*paranoia*/ ) {
448 emit( buf->buf, local_strlen(buf->buf) );
449 buf->n = 0;
450 buf->buf[buf->n] = 0;
451 }
452 buf->buf[buf->n++] = c;
453 buf->buf[buf->n] = 0;
454}
455
456/* Send a logging message. Nothing is output unless 'level'
457 is <= the current loglevel. */
458/* EXPORTED */
459__attribute__((format(__printf__, 3, 4)))
460void VG_(debugLog) ( Int level, const HChar* modulename,
461 const HChar* format, ... )
462{
463 UInt ret, pid;
sewardja5ebfa92005-04-25 02:04:54 +0000464 Int indent;
sewardj1cf558c2005-04-25 01:36:56 +0000465 va_list vargs;
466 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000467
sewardj1cf558c2005-04-25 01:36:56 +0000468
469 if (level > loglevel)
470 return;
471
sewardjd85feff2005-04-25 02:37:56 +0000472 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000473 if (indent < 1) indent = 1;
474
sewardj1cf558c2005-04-25 01:36:56 +0000475 buf.n = 0;
476 buf.buf[0] = 0;
477 pid = local_sys_getpid();
sewardja5ebfa92005-04-25 02:04:54 +0000478 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
479 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)pid );
480 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000481 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000482 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000483 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000484 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000485
486 va_start(vargs,format);
487
488 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
489
490 if (buf.n > 0) {
491 emit( buf.buf, local_strlen(buf.buf) );
492 }
493
494 va_end(vargs);
495}
496
497
498
499/*--------------------------------------------------------------------*/
500/*--- end m_debuglog.c ---*/
501/*--------------------------------------------------------------------*/