blob: 5838911f6b62be89e396cd088ff03480288b6a79 [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*/
sewardj1cf558c2005-04-25 01:36:56 +000045
njnc7561b92005-06-19 01:24:32 +000046/* This module is also notable because it is linked into both
47 stage1 and stage2. */
48
49#include "pub_core_basics.h" /* basic types */
50#include "pub_core_debuglog.h" /* our own iface */
sewardj45f4e7c2005-09-27 19:20:21 +000051#include "valgrind.h" /* for RUNNING_ON_VALGRIND */
sewardj1cf558c2005-04-25 01:36:56 +000052
53/*------------------------------------------------------------*/
54/*--- Stuff to make us completely independent. ---*/
55/*------------------------------------------------------------*/
56
sewardj2c48c7b2005-11-29 13:05:56 +000057/* ----- Platform-specifics ----- */
sewardj1cf558c2005-04-25 01:36:56 +000058
sewardj21c6d0f2005-05-02 10:33:44 +000059#if defined(VGP_x86_linux)
sewardj1cf558c2005-04-25 01:36:56 +000060
61static UInt local_sys_write_stderr ( HChar* buf, Int n )
62{
sewardj55c43762006-04-28 21:01:33 +000063 Int block[2];
64 block[0] = (Int)buf;
65 block[1] = n;
tom311400b2005-04-27 08:58:53 +000066 __asm__ volatile (
sewardj55c43762006-04-28 21:01:33 +000067 "pushl %%ebx\n" /* ebx is callee-save */
68 "movl %0, %%ebx\n" /* ebx = &block */
69 "pushl %%ebx\n" /* save &block */
70 "movl 0(%%ebx), %%ecx\n" /* %ecx = buf */
71 "movl 4(%%ebx), %%edx\n" /* %edx = n */
72 "movl $4, %%eax\n" /* %eax = __NR_write */
73 "movl $1, %%ebx\n" /* %ebx = stderr */
74 "int $0x80\n" /* write(stderr, buf, n) */
75 "popl %%ebx\n" /* reestablish &block */
76 "movl %%eax, 0(%%ebx)\n" /* block[0] = result */
77 "popl %%ebx\n" /* restore ebx */
78 : /*wr*/
79 : /*rd*/ "g" (block)
80 : /*trash*/ "eax", "edi", "ecx", "edx", "memory", "cc"
sewardjd4d203b2005-04-27 23:17:48 +000081 );
sewardj55c43762006-04-28 21:01:33 +000082 if (block[0] < 0)
83 block[0] = -1;
84 return block[0];
sewardj1cf558c2005-04-25 01:36:56 +000085}
86
87static UInt local_sys_getpid ( void )
88{
89 UInt __res;
tom311400b2005-04-27 08:58:53 +000090 __asm__ volatile (
91 "movl $20, %%eax\n" /* set %eax = __NR_getpid */
92 "int $0x80\n" /* getpid() */
93 "movl %%eax, %0\n" /* set __res = eax */
sewardjd4d203b2005-04-27 23:17:48 +000094 : "=mr" (__res)
95 :
96 : "eax" );
sewardj1cf558c2005-04-25 01:36:56 +000097 return __res;
98}
99
sewardj21c6d0f2005-05-02 10:33:44 +0000100#elif defined(VGP_amd64_linux)
sewardj7337f922006-05-26 11:31:15 +0000101__attribute__((noinline))
sewardj601371a2005-04-25 16:21:17 +0000102static UInt local_sys_write_stderr ( HChar* buf, Int n )
103{
sewardj7337f922006-05-26 11:31:15 +0000104 Long block[2];
105 block[0] = (Long)buf;
106 block[1] = n;
tomc6121862005-04-27 09:23:02 +0000107 __asm__ volatile (
sewardj7337f922006-05-26 11:31:15 +0000108 "subq $256, %%rsp\n" /* don't trash the stack redzone */
109 "pushq %%r15\n" /* r15 is callee-save */
110 "movq %0, %%r15\n" /* r15 = &block */
111 "pushq %%r15\n" /* save &block */
112 "movq $1, %%rax\n" /* rax = __NR_write */
113 "movq $2, %%rdi\n" /* rdi = stderr */
114 "movq 0(%%r15), %%rsi\n" /* rsi = buf */
115 "movq 8(%%r15), %%rdx\n" /* rdx = n */
116 "syscall\n" /* write(stderr, buf, n) */
117 "popq %%r15\n" /* reestablish &block */
118 "movq %%rax, 0(%%r15)\n" /* block[0] = result */
119 "popq %%r15\n" /* restore r15 */
120 "addq $256, %%rsp\n" /* restore stack ptr */
121 : /*wr*/
122 : /*rd*/ "g" (block)
123 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc"
124 );
125 if (block[0] < 0)
126 block[0] = -1;
127 return (UInt)block[0];
sewardj601371a2005-04-25 16:21:17 +0000128}
129
130static UInt local_sys_getpid ( void )
131{
tomc6121862005-04-27 09:23:02 +0000132 UInt __res;
133 __asm__ volatile (
134 "movq $39, %%rax\n" /* set %rax = __NR_getpid */
135 "syscall\n" /* getpid() */
136 "movl %%eax, %0\n" /* set __res = %eax */
137 : "=mr" (__res)
138 :
139 : "rax" );
140 return __res;
sewardj601371a2005-04-25 16:21:17 +0000141}
sewardj1cf558c2005-04-25 01:36:56 +0000142
cerion85665ca2005-06-20 15:51:07 +0000143#elif defined(VGP_ppc32_linux)
144
145static UInt local_sys_write_stderr ( HChar* buf, Int n )
146{
sewardja2699582006-05-22 13:04:42 +0000147 Int block[2];
148 block[0] = (Int)buf;
149 block[1] = n;
cerion85665ca2005-06-20 15:51:07 +0000150 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000151 "addi 1,1,-256\n\t"
152 "mr 5,%0\n\t" /* r5 = &block[0] */
153 "stw 5,0(1)\n\t" /* stash on stack */
154 "li 0,4\n\t" /* set %r0 = __NR_write (== 4) */
155 "li 3,2\n\t" /* set %r3 = stderr */
156 "lwz 4,0(5)\n\t" /* set %r4 = buf */
157 "lwz 5,4(5)\n\t" /* set %r5 = n */
158 "sc\n\t" /* write(stderr, buf, n) */
159 "lwz 5,0(1)\n\t"
160 "addi 1,1,256\n\t"
161 "stw 3,0(5)\n" /* block[0] = result */
162 :
163 : "b" (block)
164 : "cc","memory","cr0","ctr",
165 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
166 );
167 if (block[0] < 0)
168 block[0] = -1;
169 return (UInt)block[0];
cerion85665ca2005-06-20 15:51:07 +0000170}
171
172static UInt local_sys_getpid ( void )
173{
sewardja2699582006-05-22 13:04:42 +0000174 register UInt __res __asm__ ("r3");
175 __asm__ volatile (
176 "li 0, %1\n\t"
177 "sc"
178 : "=&r" (__res)
179 : "i" (20) /* == __NR_getpid */
180 : "cc","memory","cr0","ctr",
181 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
182 );
cerion85665ca2005-06-20 15:51:07 +0000183 return __res;
184}
185
sewardj2c48c7b2005-11-29 13:05:56 +0000186#elif defined(VGP_ppc64_linux)
187
188static UInt local_sys_write_stderr ( HChar* buf, Int n )
189{
sewardja2699582006-05-22 13:04:42 +0000190 Long block[2];
191 block[0] = (Long)buf;
192 block[1] = (Long)n;
sewardj2c48c7b2005-11-29 13:05:56 +0000193 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000194 "addi 1,1,-256\n\t"
195 "mr 5,%0\n\t" /* r5 = &block[0] */
196 "std 5,0(1)\n\t" /* stash on stack */
197 "li 0,4\n\t" /* set %r0 = __NR_write (== 4) */
198 "li 3,2\n\t" /* set %r3 = stderr */
199 "ld 4,0(5)\n\t" /* set %r4 = buf */
200 "ld 5,8(5)\n\t" /* set %r5 = n */
201 "sc\n\t" /* write(stderr, buf, n) */
202 "ld 5,0(1)\n\t"
203 "addi 1,1,256\n\t"
204 "std 3,0(5)\n" /* block[0] = result */
205 :
206 : "b" (block)
207 : "cc","memory","cr0","ctr",
208 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
209 );
210 if (block[0] < 0)
211 block[0] = -1;
212 return (UInt)(Int)block[0];
sewardj2c48c7b2005-11-29 13:05:56 +0000213}
214
215static UInt local_sys_getpid ( void )
216{
sewardja2699582006-05-22 13:04:42 +0000217 register ULong __res __asm__ ("r3");
218 __asm__ volatile (
219 "li 0, %1\n\t"
220 "sc"
221 : "=&r" (__res)
222 : "i" (20) /* == __NR_getpid */
223 : "cc","memory","cr0","ctr",
224 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
225 );
226 return (UInt)__res;
sewardj2c48c7b2005-11-29 13:05:56 +0000227}
228
sewardj1cf558c2005-04-25 01:36:56 +0000229#else
sewardj21c6d0f2005-05-02 10:33:44 +0000230# error Unknown platform
sewardj1cf558c2005-04-25 01:36:56 +0000231#endif
232
233
234/* ----- generic ----- */
235
236/* strlen, so we don't need m_libc */
237static Int local_strlen ( const HChar* str )
238{
239 Int i = 0;
240 while (str[i] != 0) i++;
241 return i;
242}
243
244static HChar local_toupper ( HChar c )
245{
246 if (c >= 'a' && c <= 'z')
247 return c + ('A' - 'a');
248 else
249 return c;
250}
251
252/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
253*/
254static void emit ( HChar* buf, Int n )
255{
256 if (n >= 1)
257 (void)local_sys_write_stderr(buf, n);
258}
259
260
261/*------------------------------------------------------------*/
262/*--- A simple, generic, vprintf implementation. ---*/
263/*------------------------------------------------------------*/
264
265/* -----------------------------------------------
266 Distantly derived from:
267
268 vprintf replacement for Checker.
269 Copyright 1993, 1994, 1995 Tristan Gingold
270 Written September 1993 Tristan Gingold
271 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
272
273 (Checker itself was GPL'd.)
274 ----------------------------------------------- */
275
276/* Some flags. */
277#define VG_MSG_SIGNED 1 /* The value is signed. */
278#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
279#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
280#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
281#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
282
283
284/* Copy a string into the buffer. */
285static
286UInt myvprintf_str ( void(*send)(HChar,void*),
287 void* send_arg2,
288 Int flags,
289 Int width,
290 HChar* str,
291 Bool capitalise )
292{
293# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
294 UInt ret = 0;
295 Int i, extra;
296 Int len = local_strlen(str);
297
298 if (width == 0) {
299 ret += len;
300 for (i = 0; i < len; i++)
301 send(MAYBE_TOUPPER(str[i]), send_arg2);
302 return ret;
303 }
304
305 if (len > width) {
306 ret += width;
307 for (i = 0; i < width; i++)
308 send(MAYBE_TOUPPER(str[i]), send_arg2);
309 return ret;
310 }
311
312 extra = width - len;
313 if (flags & VG_MSG_LJUSTIFY) {
314 ret += extra;
315 for (i = 0; i < extra; i++)
316 send(' ', send_arg2);
317 }
318 ret += len;
319 for (i = 0; i < len; i++)
320 send(MAYBE_TOUPPER(str[i]), send_arg2);
321 if (!(flags & VG_MSG_LJUSTIFY)) {
322 ret += extra;
323 for (i = 0; i < extra; i++)
324 send(' ', send_arg2);
325 }
326
327# undef MAYBE_TOUPPER
328 return ret;
329}
330
331
sewardjdaf77af2005-07-19 14:17:37 +0000332/* Copy a string into the buffer, escaping bad XML chars. */
333static
334UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
335 void* send_arg2,
336 HChar* str )
337{
338 UInt ret = 0;
339 Int i;
340 Int len = local_strlen(str);
341 HChar* alt;
342
343 for (i = 0; i < len; i++) {
344 switch (str[i]) {
345 case '&': alt = "&amp;"; break;
346 case '<': alt = "&lt;"; break;
347 case '>': alt = "&gt;"; break;
348 default: alt = NULL;
349 }
350
351 if (alt) {
352 while (*alt) {
353 send(*alt, send_arg2);
354 ret++;
355 alt++;
356 }
357 } else {
358 send(str[i], send_arg2);
359 ret++;
360 }
361 }
362
363 return ret;
364}
365
366
sewardj1cf558c2005-04-25 01:36:56 +0000367/* Write P into the buffer according to these args:
368 * If SIGN is true, p is a signed.
369 * BASE is the base.
370 * If WITH_ZERO is true, '0' must be added.
371 * WIDTH is the width of the field.
372 */
373static
374UInt myvprintf_int64 ( void(*send)(HChar,void*),
375 void* send_arg2,
376 Int flags,
377 Int base,
378 Int width,
379 ULong p )
380{
381 HChar buf[40];
382 Int ind = 0;
383 Int i, nc = 0;
384 Bool neg = False;
385 HChar* digits = "0123456789ABCDEF";
386 UInt ret = 0;
387
388 if (base < 2 || base > 16)
389 return ret;
390
391 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
392 p = - (Long)p;
393 neg = True;
394 }
395
396 if (p == 0)
397 buf[ind++] = '0';
398 else {
399 while (p > 0) {
400 if (flags & VG_MSG_COMMA && 10 == base &&
401 0 == (ind-nc) % 3 && 0 != ind)
402 {
403 buf[ind++] = ',';
404 nc++;
405 }
406 buf[ind++] = digits[p % base];
407 p /= base;
408 }
409 }
410
411 if (neg)
412 buf[ind++] = '-';
413
414 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
415 for(; ind < width; ind++) {
416 /* vg_assert(ind < 39); */
417 if (ind > 39) {
418 buf[39] = 0;
419 break;
420 }
421 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
422 }
423 }
424
425 /* Reverse copy to buffer. */
426 ret += ind;
427 for (i = ind -1; i >= 0; i--) {
428 send(buf[i], send_arg2);
429 }
430 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
431 for(; ind < width; ind++) {
432 ret++;
433 /* Never pad with zeroes on RHS -- changes the value! */
434 send(' ', send_arg2);
435 }
436 }
437 return ret;
438}
439
440
441/* A simple vprintf(). */
442/* EXPORTED */
443UInt
444VG_(debugLog_vprintf) (
445 void(*send)(HChar,void*),
446 void* send_arg2,
447 const HChar* format,
448 va_list vargs
449)
450{
451 UInt ret = 0;
452 Int i;
453 Int flags;
454 Int width;
njn68e46592005-08-26 19:42:27 +0000455 Int n_ls = 0;
sewardj1cf558c2005-04-25 01:36:56 +0000456 Bool is_long;
457
458 /* We assume that vargs has already been initialised by the
459 caller, using va_start, and that the caller will similarly
460 clean up with va_end.
461 */
462
463 for (i = 0; format[i] != 0; i++) {
464 if (format[i] != '%') {
465 send(format[i], send_arg2);
466 ret++;
467 continue;
468 }
469 i++;
470 /* A '%' has been found. Ignore a trailing %. */
471 if (format[i] == 0)
472 break;
473 if (format[i] == '%') {
njn02bc4b82005-05-15 17:28:26 +0000474 /* '%%' is replaced by '%'. */
sewardj1cf558c2005-04-25 01:36:56 +0000475 send('%', send_arg2);
476 ret++;
477 continue;
478 }
479 flags = 0;
njn68e46592005-08-26 19:42:27 +0000480 n_ls = 0;
sewardj1cf558c2005-04-25 01:36:56 +0000481 width = 0; /* length of the field. */
482 if (format[i] == '(') {
483 flags |= VG_MSG_PAREN;
484 i++;
485 }
486 /* If ',' follows '%', commas will be inserted. */
487 if (format[i] == ',') {
488 flags |= VG_MSG_COMMA;
489 i++;
490 }
491 /* If '-' follows '%', justify on the left. */
492 if (format[i] == '-') {
493 flags |= VG_MSG_LJUSTIFY;
494 i++;
495 }
496 /* If '0' follows '%', pads will be inserted. */
497 if (format[i] == '0') {
498 flags |= VG_MSG_ZJUSTIFY;
499 i++;
500 }
501 /* Compute the field length. */
502 while (format[i] >= '0' && format[i] <= '9') {
503 width *= 10;
504 width += format[i++] - '0';
505 }
506 while (format[i] == 'l') {
507 i++;
njn68e46592005-08-26 19:42:27 +0000508 n_ls++;
sewardj1cf558c2005-04-25 01:36:56 +0000509 }
510
njn68e46592005-08-26 19:42:27 +0000511 // %d means print a 32-bit integer.
512 // %ld means print a word-size integer.
513 // %lld means print a 64-bit integer.
514 if (0 == n_ls) { is_long = False; }
515 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
516 else { is_long = True; }
517
sewardj1cf558c2005-04-25 01:36:56 +0000518 switch (format[i]) {
519 case 'd': /* %d */
520 flags |= VG_MSG_SIGNED;
521 if (is_long)
522 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
523 (ULong)(va_arg (vargs, Long)));
524 else
525 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
526 (ULong)(va_arg (vargs, Int)));
527 break;
528 case 'u': /* %u */
529 if (is_long)
530 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
531 (ULong)(va_arg (vargs, ULong)));
532 else
533 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
534 (ULong)(va_arg (vargs, UInt)));
535 break;
536 case 'p': /* %p */
537 ret += 2;
538 send('0',send_arg2);
539 send('x',send_arg2);
540 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
541 (ULong)((UWord)va_arg (vargs, void *)));
542 break;
543 case 'x': /* %x */
544 if (is_long)
545 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
546 (ULong)(va_arg (vargs, ULong)));
547 else
548 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
549 (ULong)(va_arg (vargs, UInt)));
550 break;
551 case 'c': /* %c */
552 ret++;
553 send(va_arg (vargs, int), send_arg2);
554 break;
555 case 's': case 'S': { /* %s */
556 char *str = va_arg (vargs, char *);
557 if (str == (char*) 0) str = "(null)";
558 ret += myvprintf_str(send, send_arg2,
559 flags, width, str, format[i]=='S');
560 break;
561 }
sewardjdaf77af2005-07-19 14:17:37 +0000562 case 't': { /* %t, like %s but escaping chars for XML safety */
563 /* Note: simplistic; ignores field width and flags */
564 char *str = va_arg (vargs, char *);
565 if (str == (char*) 0) str = "(null)";
566 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
567 break;
568 }
569
sewardj1cf558c2005-04-25 01:36:56 +0000570// case 'y': { /* %y - print symbol */
571// Char buf[100];
572// Char *cp = buf;
573// Addr a = va_arg(vargs, Addr);
574//
575// if (flags & VG_MSG_PAREN)
576// *cp++ = '(';
577// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
578// if (flags & VG_MSG_PAREN) {
579// cp += VG_(strlen)(cp);
580// *cp++ = ')';
581// *cp = '\0';
582// }
583// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
584// }
585// break;
586// }
587 default:
588 break;
589 }
590 }
591 return ret;
592}
593
594
595/*------------------------------------------------------------*/
596/*--- Debuglog stuff. ---*/
597/*------------------------------------------------------------*/
598
599/* Only print messages whose stated level is less than or equal to
600 this. By default, it makes this entire subsystem silent. */
601
602static Int loglevel = 0;
603
sewardj1cf558c2005-04-25 01:36:56 +0000604/* Module startup. */
sewardj10759312005-05-30 23:52:47 +0000605/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000606void VG_(debugLog_startup) ( Int level, HChar* who )
607{
608 if (level < 0) level = 0;
609 if (level > 10) level = 10;
610 loglevel = level;
611 VG_(debugLog)(1, "debuglog",
612 "DebugLog system started by %s, "
613 "level %d logging requested\n",
614 who, loglevel);
615}
616
sewardj10759312005-05-30 23:52:47 +0000617/* Get the logging threshold level, as set by the most recent call to
618 VG_(debugLog_startup), or zero if there have been no such calls so
619 far. */
620/* EXPORTED */
621Int VG_(debugLog_getLevel) ( void )
622{
623 return loglevel;
624}
625
626
sewardj1cf558c2005-04-25 01:36:56 +0000627/* ------------ */
628
629typedef
630 struct {
631 HChar buf[100];
632 Int n;
633 }
634 printf_buf;
635
636static void add_to_buf ( HChar c, void* p )
637{
638 printf_buf* buf = (printf_buf*)p;
639
640 if (buf->n >= 100-10 /*paranoia*/ ) {
641 emit( buf->buf, local_strlen(buf->buf) );
642 buf->n = 0;
643 buf->buf[buf->n] = 0;
644 }
645 buf->buf[buf->n++] = c;
646 buf->buf[buf->n] = 0;
647}
648
649/* Send a logging message. Nothing is output unless 'level'
650 is <= the current loglevel. */
651/* EXPORTED */
652__attribute__((format(__printf__, 3, 4)))
653void VG_(debugLog) ( Int level, const HChar* modulename,
654 const HChar* format, ... )
655{
656 UInt ret, pid;
sewardj45f4e7c2005-09-27 19:20:21 +0000657 Int indent, depth, i;
sewardj1cf558c2005-04-25 01:36:56 +0000658 va_list vargs;
659 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000660
sewardj1cf558c2005-04-25 01:36:56 +0000661 if (level > loglevel)
662 return;
663
sewardjd85feff2005-04-25 02:37:56 +0000664 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000665 if (indent < 1) indent = 1;
666
sewardj1cf558c2005-04-25 01:36:56 +0000667 buf.n = 0;
668 buf.buf[0] = 0;
669 pid = local_sys_getpid();
sewardj45f4e7c2005-09-27 19:20:21 +0000670
671 // Print one '>' in front of the messages for each level of self-hosting
672 // being performed.
673 depth = RUNNING_ON_VALGRIND;
674 for (i = 0; i < depth; i++) {
675 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
676 }
677
sewardja5ebfa92005-04-25 02:04:54 +0000678 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
679 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)pid );
680 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000681 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000682 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000683 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000684 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000685
686 va_start(vargs,format);
687
688 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
689
690 if (buf.n > 0) {
691 emit( buf.buf, local_strlen(buf.buf) );
692 }
693
694 va_end(vargs);
695}
696
697
698
699/*--------------------------------------------------------------------*/
700/*--- end m_debuglog.c ---*/
701/*--------------------------------------------------------------------*/