blob: 9b79f3768ea69a6067347257097e5a38246f5795 [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;
tom311400b2005-04-27 08:58:53 +000065 __asm__ volatile (
66 "movl $4, %%eax\n" /* set %eax = __NR_write */
67 "movl $2, %%ebx\n" /* set %ebx = stderr */
68 "movl %1, %%ecx\n" /* set %ecx = buf */
69 "movl %2, %%edx\n" /* set %ecx = n */
70 "int $0x80\n" /* write(stderr, buf, n) */
71 "movl %%eax, %0\n" /* set __res = eax */
72 : "=mr" (__res)
73 : "g" (buf), "g" (n) );
sewardj1cf558c2005-04-25 01:36:56 +000074 if (__res < 0)
75 __res = -1;
76 return __res;
77}
78
79static UInt local_sys_getpid ( void )
80{
81 UInt __res;
tom311400b2005-04-27 08:58:53 +000082 __asm__ volatile (
83 "movl $20, %%eax\n" /* set %eax = __NR_getpid */
84 "int $0x80\n" /* getpid() */
85 "movl %%eax, %0\n" /* set __res = eax */
86 : "=mr" (__res) );
sewardj1cf558c2005-04-25 01:36:56 +000087 return __res;
88}
89
sewardj601371a2005-04-25 16:21:17 +000090#elif defined(__x86_64__) && defined(__linux__)
91
92static UInt local_sys_write_stderr ( HChar* buf, Int n )
93{
94 return 0;
95}
96
97static UInt local_sys_getpid ( void )
98{
99 return 0;
100}
sewardj1cf558c2005-04-25 01:36:56 +0000101
102#else
103#error Unknown VG_PLATFORM
104#endif
105
106
107/* ----- generic ----- */
108
109/* strlen, so we don't need m_libc */
110static Int local_strlen ( const HChar* str )
111{
112 Int i = 0;
113 while (str[i] != 0) i++;
114 return i;
115}
116
117static HChar local_toupper ( HChar c )
118{
119 if (c >= 'a' && c <= 'z')
120 return c + ('A' - 'a');
121 else
122 return c;
123}
124
125/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
126*/
127static void emit ( HChar* buf, Int n )
128{
129 if (n >= 1)
130 (void)local_sys_write_stderr(buf, n);
131}
132
133
134/*------------------------------------------------------------*/
135/*--- A simple, generic, vprintf implementation. ---*/
136/*------------------------------------------------------------*/
137
138/* -----------------------------------------------
139 Distantly derived from:
140
141 vprintf replacement for Checker.
142 Copyright 1993, 1994, 1995 Tristan Gingold
143 Written September 1993 Tristan Gingold
144 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
145
146 (Checker itself was GPL'd.)
147 ----------------------------------------------- */
148
149/* Some flags. */
150#define VG_MSG_SIGNED 1 /* The value is signed. */
151#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
152#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
153#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
154#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
155
156
157/* Copy a string into the buffer. */
158static
159UInt myvprintf_str ( void(*send)(HChar,void*),
160 void* send_arg2,
161 Int flags,
162 Int width,
163 HChar* str,
164 Bool capitalise )
165{
166# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
167 UInt ret = 0;
168 Int i, extra;
169 Int len = local_strlen(str);
170
171 if (width == 0) {
172 ret += len;
173 for (i = 0; i < len; i++)
174 send(MAYBE_TOUPPER(str[i]), send_arg2);
175 return ret;
176 }
177
178 if (len > width) {
179 ret += width;
180 for (i = 0; i < width; i++)
181 send(MAYBE_TOUPPER(str[i]), send_arg2);
182 return ret;
183 }
184
185 extra = width - len;
186 if (flags & VG_MSG_LJUSTIFY) {
187 ret += extra;
188 for (i = 0; i < extra; i++)
189 send(' ', send_arg2);
190 }
191 ret += len;
192 for (i = 0; i < len; i++)
193 send(MAYBE_TOUPPER(str[i]), send_arg2);
194 if (!(flags & VG_MSG_LJUSTIFY)) {
195 ret += extra;
196 for (i = 0; i < extra; i++)
197 send(' ', send_arg2);
198 }
199
200# undef MAYBE_TOUPPER
201 return ret;
202}
203
204
205/* Write P into the buffer according to these args:
206 * If SIGN is true, p is a signed.
207 * BASE is the base.
208 * If WITH_ZERO is true, '0' must be added.
209 * WIDTH is the width of the field.
210 */
211static
212UInt myvprintf_int64 ( void(*send)(HChar,void*),
213 void* send_arg2,
214 Int flags,
215 Int base,
216 Int width,
217 ULong p )
218{
219 HChar buf[40];
220 Int ind = 0;
221 Int i, nc = 0;
222 Bool neg = False;
223 HChar* digits = "0123456789ABCDEF";
224 UInt ret = 0;
225
226 if (base < 2 || base > 16)
227 return ret;
228
229 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
230 p = - (Long)p;
231 neg = True;
232 }
233
234 if (p == 0)
235 buf[ind++] = '0';
236 else {
237 while (p > 0) {
238 if (flags & VG_MSG_COMMA && 10 == base &&
239 0 == (ind-nc) % 3 && 0 != ind)
240 {
241 buf[ind++] = ',';
242 nc++;
243 }
244 buf[ind++] = digits[p % base];
245 p /= base;
246 }
247 }
248
249 if (neg)
250 buf[ind++] = '-';
251
252 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
253 for(; ind < width; ind++) {
254 /* vg_assert(ind < 39); */
255 if (ind > 39) {
256 buf[39] = 0;
257 break;
258 }
259 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
260 }
261 }
262
263 /* Reverse copy to buffer. */
264 ret += ind;
265 for (i = ind -1; i >= 0; i--) {
266 send(buf[i], send_arg2);
267 }
268 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
269 for(; ind < width; ind++) {
270 ret++;
271 /* Never pad with zeroes on RHS -- changes the value! */
272 send(' ', send_arg2);
273 }
274 }
275 return ret;
276}
277
278
279/* A simple vprintf(). */
280/* EXPORTED */
281UInt
282VG_(debugLog_vprintf) (
283 void(*send)(HChar,void*),
284 void* send_arg2,
285 const HChar* format,
286 va_list vargs
287)
288{
289 UInt ret = 0;
290 Int i;
291 Int flags;
292 Int width;
293 Bool is_long;
294
295 /* We assume that vargs has already been initialised by the
296 caller, using va_start, and that the caller will similarly
297 clean up with va_end.
298 */
299
300 for (i = 0; format[i] != 0; i++) {
301 if (format[i] != '%') {
302 send(format[i], send_arg2);
303 ret++;
304 continue;
305 }
306 i++;
307 /* A '%' has been found. Ignore a trailing %. */
308 if (format[i] == 0)
309 break;
310 if (format[i] == '%') {
311 /* `%%' is replaced by `%'. */
312 send('%', send_arg2);
313 ret++;
314 continue;
315 }
316 flags = 0;
317 is_long = False;
318 width = 0; /* length of the field. */
319 if (format[i] == '(') {
320 flags |= VG_MSG_PAREN;
321 i++;
322 }
323 /* If ',' follows '%', commas will be inserted. */
324 if (format[i] == ',') {
325 flags |= VG_MSG_COMMA;
326 i++;
327 }
328 /* If '-' follows '%', justify on the left. */
329 if (format[i] == '-') {
330 flags |= VG_MSG_LJUSTIFY;
331 i++;
332 }
333 /* If '0' follows '%', pads will be inserted. */
334 if (format[i] == '0') {
335 flags |= VG_MSG_ZJUSTIFY;
336 i++;
337 }
338 /* Compute the field length. */
339 while (format[i] >= '0' && format[i] <= '9') {
340 width *= 10;
341 width += format[i++] - '0';
342 }
343 while (format[i] == 'l') {
344 i++;
345 is_long = True;
346 }
347
348 switch (format[i]) {
349 case 'd': /* %d */
350 flags |= VG_MSG_SIGNED;
351 if (is_long)
352 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
353 (ULong)(va_arg (vargs, Long)));
354 else
355 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
356 (ULong)(va_arg (vargs, Int)));
357 break;
358 case 'u': /* %u */
359 if (is_long)
360 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
361 (ULong)(va_arg (vargs, ULong)));
362 else
363 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
364 (ULong)(va_arg (vargs, UInt)));
365 break;
366 case 'p': /* %p */
367 ret += 2;
368 send('0',send_arg2);
369 send('x',send_arg2);
370 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
371 (ULong)((UWord)va_arg (vargs, void *)));
372 break;
373 case 'x': /* %x */
374 if (is_long)
375 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
376 (ULong)(va_arg (vargs, ULong)));
377 else
378 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
379 (ULong)(va_arg (vargs, UInt)));
380 break;
381 case 'c': /* %c */
382 ret++;
383 send(va_arg (vargs, int), send_arg2);
384 break;
385 case 's': case 'S': { /* %s */
386 char *str = va_arg (vargs, char *);
387 if (str == (char*) 0) str = "(null)";
388 ret += myvprintf_str(send, send_arg2,
389 flags, width, str, format[i]=='S');
390 break;
391 }
392// case 'y': { /* %y - print symbol */
393// Char buf[100];
394// Char *cp = buf;
395// Addr a = va_arg(vargs, Addr);
396//
397// if (flags & VG_MSG_PAREN)
398// *cp++ = '(';
399// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
400// if (flags & VG_MSG_PAREN) {
401// cp += VG_(strlen)(cp);
402// *cp++ = ')';
403// *cp = '\0';
404// }
405// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
406// }
407// break;
408// }
409 default:
410 break;
411 }
412 }
413 return ret;
414}
415
416
417/*------------------------------------------------------------*/
418/*--- Debuglog stuff. ---*/
419/*------------------------------------------------------------*/
420
421/* Only print messages whose stated level is less than or equal to
422 this. By default, it makes this entire subsystem silent. */
423
424static Int loglevel = 0;
425
426/* EXPORTED */
427/* Module startup. */
428void VG_(debugLog_startup) ( Int level, HChar* who )
429{
430 if (level < 0) level = 0;
431 if (level > 10) level = 10;
432 loglevel = level;
433 VG_(debugLog)(1, "debuglog",
434 "DebugLog system started by %s, "
435 "level %d logging requested\n",
436 who, loglevel);
437}
438
439/* ------------ */
440
441typedef
442 struct {
443 HChar buf[100];
444 Int n;
445 }
446 printf_buf;
447
448static void add_to_buf ( HChar c, void* p )
449{
450 printf_buf* buf = (printf_buf*)p;
451
452 if (buf->n >= 100-10 /*paranoia*/ ) {
453 emit( buf->buf, local_strlen(buf->buf) );
454 buf->n = 0;
455 buf->buf[buf->n] = 0;
456 }
457 buf->buf[buf->n++] = c;
458 buf->buf[buf->n] = 0;
459}
460
461/* Send a logging message. Nothing is output unless 'level'
462 is <= the current loglevel. */
463/* EXPORTED */
464__attribute__((format(__printf__, 3, 4)))
465void VG_(debugLog) ( Int level, const HChar* modulename,
466 const HChar* format, ... )
467{
468 UInt ret, pid;
sewardja5ebfa92005-04-25 02:04:54 +0000469 Int indent;
sewardj1cf558c2005-04-25 01:36:56 +0000470 va_list vargs;
471 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000472
sewardj1cf558c2005-04-25 01:36:56 +0000473
474 if (level > loglevel)
475 return;
476
sewardjd85feff2005-04-25 02:37:56 +0000477 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000478 if (indent < 1) indent = 1;
479
sewardj1cf558c2005-04-25 01:36:56 +0000480 buf.n = 0;
481 buf.buf[0] = 0;
482 pid = local_sys_getpid();
sewardja5ebfa92005-04-25 02:04:54 +0000483 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
484 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)pid );
485 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000486 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000487 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000488 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000489 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000490
491 va_start(vargs,format);
492
493 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
494
495 if (buf.n > 0) {
496 emit( buf.buf, local_strlen(buf.buf) );
497 }
498
499 va_end(vargs);
500}
501
502
503
504/*--------------------------------------------------------------------*/
505/*--- end m_debuglog.c ---*/
506/*--------------------------------------------------------------------*/