]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_debuglog.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_debuglog.c
1
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-2010 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
46 /* This module is also notable because it is linked into both 
47    stage1 and stage2. */
48
49 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
50    of syscalls rather than the vanilla version, if a _nocancel version
51    is available.  See docs/internals/Darwin-notes.txt for the reason
52    why. */
53
54 #include "pub_core_basics.h"     /* basic types */
55 #include "pub_core_vkiscnums.h"  /* for syscall numbers */
56 #include "pub_core_debuglog.h"   /* our own iface */
57 #include "valgrind.h"            /* for RUNNING_ON_VALGRIND */
58
59 #if defined(VGO_l4re)
60 #include <l4/sys/utcb.h>
61 #include <unistd.h>
62 #endif
63
64 /*------------------------------------------------------------*/
65 /*--- Stuff to make us completely independent.             ---*/
66 /*------------------------------------------------------------*/
67
68 /* ----- Platform-specifics ----- */
69
70 #if defined(VGP_x86_linux)
71
72 static UInt local_sys_write_stderr ( HChar* buf, Int n )
73 {
74    volatile Int block[2];
75    block[0] = (Int)buf;
76    block[1] = n;
77    __asm__ volatile (
78       "pushl %%ebx\n"           /* ebx is callee-save */
79       "movl  %0, %%ebx\n"       /* ebx = &block */
80       "pushl %%ebx\n"           /* save &block */
81       "movl  0(%%ebx), %%ecx\n" /* %ecx = buf */
82       "movl  4(%%ebx), %%edx\n" /* %edx = n */
83       "movl  $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */
84       "movl  $2, %%ebx\n"       /* %ebx = stderr */
85       "int   $0x80\n"           /* write(stderr, buf, n) */
86       "popl  %%ebx\n"           /* reestablish &block */
87       "movl  %%eax, 0(%%ebx)\n" /* block[0] = result */
88       "popl  %%ebx\n"           /* restore ebx */
89       : /*wr*/
90       : /*rd*/    "r" (block)
91       : /*trash*/ "eax", "edi", "ecx", "edx", "memory", "cc"
92    );
93    if (block[0] < 0) 
94       block[0] = -1;
95    return block[0];
96 }
97
98 static UInt local_sys_getpid ( void )
99 {
100    UInt __res;
101    __asm__ volatile (
102       "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n" /* %eax = __NR_getpid */
103       "int  $0x80\n"       /* getpid() */
104       "movl %%eax, %0\n"   /* set __res = eax */
105       : "=mr" (__res)
106       :
107       : "eax" );
108    return __res;
109 }
110
111 #elif defined(VGP_amd64_linux)
112 __attribute__((noinline))
113 static UInt local_sys_write_stderr ( HChar* buf, Int n )
114 {
115    volatile Long block[2];
116    block[0] = (Long)buf;
117    block[1] = n;
118    __asm__ volatile (
119       "subq  $256, %%rsp\n"     /* don't trash the stack redzone */
120       "pushq %%r15\n"           /* r15 is callee-save */
121       "movq  %0, %%r15\n"       /* r15 = &block */
122       "pushq %%r15\n"           /* save &block */
123       "movq  $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
124       "movq  $2, %%rdi\n"       /* rdi = stderr */
125       "movq  0(%%r15), %%rsi\n" /* rsi = buf */
126       "movq  8(%%r15), %%rdx\n" /* rdx = n */
127       "syscall\n"               /* write(stderr, buf, n) */
128       "popq  %%r15\n"           /* reestablish &block */
129       "movq  %%rax, 0(%%r15)\n" /* block[0] = result */
130       "popq  %%r15\n"           /* restore r15 */
131       "addq  $256, %%rsp\n"     /* restore stack ptr */
132       : /*wr*/
133       : /*rd*/    "r" (block)
134       : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc"
135    );
136    if (block[0] < 0) 
137       block[0] = -1;
138    return (UInt)block[0];
139 }
140
141 static UInt local_sys_getpid ( void )
142 {
143    UInt __res;
144    __asm__ volatile (
145       "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n" /* %rax = __NR_getpid */
146       "syscall\n"          /* getpid() */
147       "movl %%eax, %0\n"   /* set __res = %eax */
148       : "=mr" (__res)
149       :
150       : "rax" );
151    return __res;
152 }
153
154 #elif defined(VGP_ppc32_linux)
155
156 static UInt local_sys_write_stderr ( HChar* buf, Int n )
157 {
158    volatile Int block[2];
159    block[0] = (Int)buf;
160    block[1] = n;
161    __asm__ volatile (
162       "addi 1,1,-256\n\t"
163       "mr   5,%0\n\t"     /* r5 = &block[0] */
164       "stw  5,0(1)\n\t"   /* stash on stack */
165       "li   0,"VG_STRINGIFY(__NR_write)"\n\t" /* set %r0 = __NR_write */
166       "li   3,2\n\t"      /* set %r3 = stderr */
167       "lwz  4,0(5)\n\t"   /* set %r4 = buf */
168       "lwz  5,4(5)\n\t"   /* set %r5 = n */
169       "sc\n\t"            /* write(stderr, buf, n) */
170       "lwz  5,0(1)\n\t"
171       "addi 1,1,256\n\t"
172       "stw  3,0(5)\n"     /* block[0] = result */
173       :
174       : "b" (block)
175       : "cc","memory","cr0","ctr",
176         "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
177    );
178    if (block[0] < 0)
179       block[0] = -1;
180    return (UInt)block[0];
181 }
182
183 static UInt local_sys_getpid ( void )
184 {
185    register UInt __res __asm__ ("r3");
186    __asm__ volatile ( 
187       "li 0, %1\n\t"
188       "sc"
189       : "=&r" (__res)
190       : "i" (__NR_getpid)
191       : "cc","memory","cr0","ctr",
192         "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
193    );
194    return __res;
195 }
196
197 #elif defined(VGP_ppc64_linux)
198
199 static UInt local_sys_write_stderr ( HChar* buf, Int n )
200 {
201    volatile Long block[2];
202    block[0] = (Long)buf;
203    block[1] = (Long)n;
204    __asm__ volatile (
205       "addi 1,1,-256\n\t"
206       "mr   5,%0\n\t"     /* r5 = &block[0] */
207       "std  5,0(1)\n\t"   /* stash on stack */
208       "li   0,"VG_STRINGIFY(__NR_write)"\n\t" /* %r0 = __NR_write */
209       "li   3,2\n\t"      /* set %r3 = stderr */
210       "ld   4,0(5)\n\t"   /* set %r4 = buf */
211       "ld   5,8(5)\n\t"   /* set %r5 = n */
212       "sc\n\t"            /* write(stderr, buf, n) */
213       "ld   5,0(1)\n\t"
214       "addi 1,1,256\n\t"
215       "std  3,0(5)\n"     /* block[0] = result */
216       :
217       : "b" (block)
218       : "cc","memory","cr0","ctr",
219         "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
220    );
221    if (block[0] < 0)
222       block[0] = -1;
223    return (UInt)(Int)block[0];
224 }
225
226 static UInt local_sys_getpid ( void )
227 {
228    register ULong __res __asm__ ("r3");
229    __asm__ volatile ( 
230       "li 0, %1\n\t"
231       "sc"
232       : "=&r" (__res)
233       : "i" (__NR_getpid)
234       : "cc","memory","cr0","ctr",
235         "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
236    );
237    return (UInt)__res;
238 }
239
240 #elif defined(VGP_arm_linux)
241
242 static UInt local_sys_write_stderr ( HChar* buf, Int n )
243 {
244    volatile Int block[2];
245    block[0] = (Int)buf;
246    block[1] = n;
247    __asm__ volatile (
248       "mov  r0, #2\n\t"        /* stderr */
249       "ldr  r1, [%0]\n\t"      /* buf */
250       "ldr  r2, [%0, #4]\n\t"  /* n */
251       "mov  r7, #"VG_STRINGIFY(__NR_write)"\n\t"
252       "svc  0x0\n"          /* write() */
253       "str  r0, [%0]\n\t"
254       :
255       : "r" (block)
256       : "r0","r1","r2","r7"
257    );
258    if (block[0] < 0)
259       block[0] = -1;
260    return (UInt)block[0];
261 }
262
263 static UInt local_sys_getpid ( void )
264 {
265    UInt __res;
266    __asm__ volatile (
267       "mov  r7, #"VG_STRINGIFY(__NR_getpid)"\n"
268       "svc  0x0\n"      /* getpid() */
269       "mov  %0, r0\n"
270       : "=r" (__res)
271       :
272       : "r0", "r7" );
273    return __res;
274 }
275
276 #elif defined(VGP_ppc32_aix5)
277
278 static UInt local_sys_write_stderr ( HChar* buf, Int n )
279 {
280    /* For some reason gcc-3.3.2 doesn't preserve r31 across the asm
281       even though we state it to be trashed.  So use r27 instead. */
282    volatile UInt block[3];
283    block[0] = (UInt)buf;
284    block[1] = n;
285    block[2] = __NR_write;
286    __asm__ __volatile__ (
287       "mr    28,%0\n\t"      /* establish base ptr */
288       "mr    27,2\n\t"       /* save r2 in r27 */
289       "mflr  30\n\t"         /* save lr in r30 */
290
291       "lwz 2,8(28)\n\t"      /* set %r2 = __NR_write */
292       "li  3,2\n\t"          /* set %r3 = stderr */
293       "lwz 4,0(28)\n\t"      /* set %r4 = buf */
294       "lwz 5,4(28)\n\t"      /* set %r5 = n */
295
296       "crorc 6,6,6\n\t"
297       ".long 0x48000005\n\t" /* bl .+4 */
298       "mflr  29\n\t"
299       "addi  29,29,16\n\t"
300       "mtlr  29\n\t"
301       "sc\n\t"               /* write() */
302
303       "stw 3,0(28)\n\t"      /* result */
304       "stw 4,4(28)\n\t"      /* error? */
305
306       "mr   2,27\n\t"        /* restore r2 */
307       "mtlr 30"              /* restore lr */
308
309       : /*out*/
310       : /*in*/  "b" (&block[0])
311       : /*trash*/
312            /*temps*/    "r31","r30","r29","r28","r27",
313            /*args*/     "r3","r4","r5","r6","r7","r8","r9","r10",
314            /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
315                         "xer","ctr","cr0","cr1","cr2","cr3",
316                         "cr4","cr5","cr6","cr7"
317    );
318    if (block[1] != 0)
319       return -1;
320    else
321       return block[0];
322 }
323
324 static UInt local_sys_getpid ( void )
325 {
326    /* For some reason gcc-3.3.2 doesn't preserve r31 across the asm
327       even though we state it to be trashed.  So use r27 instead. */
328    volatile UInt block[1];
329    block[0] = __NR_getpid;
330    __asm__ __volatile__ (
331       "mr    28,%0\n\t"      /* establish base ptr */
332       "mr    27,2\n\t"       /* save r2 in r27 */
333       "mflr  30\n\t"         /* save lr in r30 */
334
335       "lwz   2,0(28)\n\t"    /* set %r2 = __NR_getpid */
336
337       "crorc 6,6,6\n\t"
338       ".long 0x48000005\n\t" /* bl .+4 */
339       "mflr  29\n\t"
340       "addi  29,29,16\n\t"
341       "mtlr  29\n\t"
342       "sc\n\t"               /* getpid() */
343
344       "stw   3,0(28)\n\t"    /* result -> block[0] */
345
346       "mr   2,27\n\t"        /* restore r2 */
347       "mtlr 30"              /* restore lr */
348
349       : /*out*/
350       : /*in*/  "b" (&block[0])
351       : /*trash*/
352            /*temps*/    "r31","r30","r29","r28","r27",
353            /*args*/     "r3","r4","r5","r6","r7","r8","r9","r10",
354            /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
355                         "xer","ctr","cr0","cr1","cr2","cr3",
356                         "cr4","cr5","cr6","cr7"
357    );
358    return block[0];
359 }
360
361 #elif defined(VGP_ppc64_aix5)
362
363 static UInt local_sys_write_stderr ( HChar* buf, Int n )
364 {
365    volatile ULong block[3];
366    block[0] = (ULong)buf;
367    block[1] = n;
368    block[2] = (ULong)__NR_write;
369    __asm__ __volatile__ (
370       "mr    28,%0\n\t"      /* establish base ptr */
371       "mr    27,2\n\t"       /* save r2 in r27 */
372       "mflr  30\n\t"         /* save lr in r30 */
373
374       "ld  2,16(28)\n\t"     /* set %r2 = __NR_write */
375       "li  3,2\n\t"          /* set %r3 = stderr */
376       "ld  4,0(28)\n\t"      /* set %r4 = buf */
377       "ld  5,8(28)\n\t"      /* set %r5 = n */
378
379       "crorc 6,6,6\n\t"
380       ".long 0x48000005\n\t" /* bl .+4 */
381       "mflr  29\n\t"
382       "addi  29,29,16\n\t"
383       "mtlr  29\n\t"
384       "sc\n\t"               /* write() */
385
386       "std 3,0(28)\n\t"      /* result */
387       "std 4,8(28)\n\t"      /* error? */
388
389       "mr   2,27\n\t"        /* restore r2 */
390       "mtlr 30"              /* restore lr */
391
392       : /*out*/
393       : /*in*/  "b" (&block[0])
394       : /*trash*/
395            /*temps*/    "r31","r30","r29","r28","r27",
396            /*args*/     "r3","r4","r5","r6","r7","r8","r9","r10",
397            /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
398                         "xer","ctr","cr0","cr1","cr2","cr3",
399                         "cr4","cr5","cr6","cr7"
400    );
401    if (block[1] != 0)
402       return (UInt)-1;
403    else
404       return (UInt)block[0];
405 }
406
407 static UInt local_sys_getpid ( void )
408 {
409    volatile ULong block[1];
410    block[0] = __NR_getpid;
411    __asm__ __volatile__ (
412       "mr    28,%0\n\t"      /* establish base ptr */
413       "mr    27,2\n\t"       /* save r2 in r27 */
414       "mflr  30\n\t"         /* save lr in r30 */
415
416       "ld    2,0(28)\n\t"    /* set %r2 = __NR_getpid */
417
418       "crorc 6,6,6\n\t"
419       ".long 0x48000005\n\t" /* bl .+4 */
420       "mflr  29\n\t"
421       "addi  29,29,16\n\t"
422       "mtlr  29\n\t"
423       "sc\n\t"               /* getpid() */
424
425       "std  3,0(28)\n\t"     /* result -> block[0] */
426
427       "mr   2,27\n\t"        /* restore r2 */
428       "mtlr 30"              /* restore lr */
429
430       : /*out*/
431       : /*in*/  "b" (&block[0])
432       : /*trash*/
433            /*temps*/    "r31","r30","r29","r28","r27",
434            /*args*/     "r3","r4","r5","r6","r7","r8","r9","r10",
435            /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
436                         "xer","ctr","cr0","cr1","cr2","cr3",
437                         "cr4","cr5","cr6","cr7"
438    );
439    return (UInt)block[0];
440 }
441
442 #elif defined(VGP_x86_darwin)
443
444 /* We would use VG_DARWIN_SYSNO_TO_KERNEL instead of VG_DARWIN_SYSNO_INDEX
445    except that the former has a C ternary ?: operator which isn't valid in
446    asm code.  Both macros give the same results for Unix-class syscalls (which
447    these all are, as identified by the use of 'int 0x80'). */
448 __attribute__((noinline))
449 static UInt local_sys_write_stderr ( HChar* buf, Int n )
450 {
451    UInt __res;
452    __asm__ volatile (
453       "movl  %2, %%eax\n"    /* push n */
454       "pushl %%eax\n"
455       "movl  %1, %%eax\n"    /* push buf */
456       "pushl %%eax\n"
457       "movl  $2, %%eax\n"    /* push stderr */
458       "pushl %%eax\n"
459       "movl  $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
460              ", %%eax\n"
461       "pushl %%eax\n"        /* push fake return address */
462       "int   $0x80\n"        /* write(stderr, buf, n) */
463       "jnc   1f\n"           /* jump if no error */
464       "movl  $-1, %%eax\n"   /* return -1 if error */
465       "1: "
466       "movl  %%eax, %0\n"    /* __res = eax */
467       "addl  $16, %%esp\n"   /* pop x4 */
468       : "=mr" (__res)
469       : "g" (buf), "g" (n)
470       : "eax", "edx", "cc"
471    );
472    return __res;
473 }
474
475 static UInt local_sys_getpid ( void )
476 {
477    UInt __res;
478    __asm__ volatile (
479       "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
480       "int  $0x80\n"       /* getpid() */
481       "movl %%eax, %0\n"   /* set __res = eax */
482       : "=mr" (__res)
483       :
484       : "eax", "cc" );
485    return __res;
486 }
487
488 #elif defined(VGP_amd64_darwin)
489
490 __attribute__((noinline))
491 static UInt local_sys_write_stderr ( HChar* buf, Int n )
492 {
493    UInt __res;
494    __asm__ volatile (
495       "movq  $2, %%rdi\n"    /* push stderr */
496       "movq  %1, %%rsi\n"    /* push buf */
497       "movl  %2, %%edx\n"    /* push n */
498       "movl  $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_write_nocancel))
499              ", %%eax\n"
500       "syscall\n"            /* write(stderr, buf, n) */
501       "jnc   1f\n"           /* jump if no error */
502       "movq  $-1, %%rax\n"   /* return -1 if error */
503       "1: "
504       "movl  %%eax, %0\n"    /* __res = eax */
505       : "=mr" (__res)
506       : "g" (buf), "g" (n)
507       : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
508    return __res;
509 }
510
511 static UInt local_sys_getpid ( void )
512 {
513    UInt __res;
514    __asm__ volatile (
515       "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_getpid))", %%eax\n"
516       "syscall\n"          /* getpid() */
517       "movl %%eax, %0\n"   /* set __res = eax */
518       : "=mr" (__res)
519       :
520       : "rax", "rcx", "cc" );
521    return __res;
522 }
523
524 #elif defined(VGP_x86_l4re)
525
526 static UInt local_sys_write_stderr ( HChar* buf, Int n )
527 {
528   write(1, buf, n);
529   return n;
530 }
531
532 static UInt local_sys_getpid ( void )
533 {
534   return (UInt)l4_utcb_tcr()->user[2];
535 }
536
537 #elif defined(VGP_s390x_linux)
538 static UInt local_sys_write_stderr ( HChar* buf, Int n )
539 {
540    register Int    r2     asm("2") = 2;      /* file descriptor STDERR */
541    register HChar* r3     asm("3") = buf;
542    register ULong  r4     asm("4") = n;
543    register ULong  r2_res asm("2");
544    ULong __res;
545
546    __asm__ __volatile__ (
547       "svc %b1\n"
548       : "=d" (r2_res)
549       : "i" (__NR_write),
550         "0" (r2),
551         "d" (r3),
552         "d" (r4)
553       : "cc", "memory");
554    __res = r2_res;
555
556    if (__res >= (ULong)(-125))
557       __res = -1;
558    return (UInt)(__res);
559 }
560
561 static UInt local_sys_getpid ( void )
562 {
563    register ULong r2 asm("2");
564    ULong __res;
565
566    __asm__ __volatile__ (
567       "svc %b1\n"
568       : "=d" (r2)
569       : "i" (__NR_getpid)
570       : "cc", "memory");
571    __res = r2;
572
573    if (__res >= (ULong)(-125))
574       __res = -1;
575    return (UInt)(__res);
576 }
577
578
579 #else
580 # error Unknown platform
581 #endif
582
583
584 /* ----- generic ----- */
585
586 /* strlen, so we don't need m_libc */
587 static Int local_strlen ( const HChar* str )
588 {
589    Int i = 0;
590    while (str[i] != 0) i++;
591    return i;
592 }
593
594 static HChar local_toupper ( HChar c )
595 {
596    if (c >= 'a' && c <= 'z')
597       return c + ('A' - 'a'); 
598    else
599       return c;
600 }
601
602 /* Emit buf[0 .. n-1] to stderr.  Unfortunately platform-specific. 
603 */
604 static void emit ( HChar* buf, Int n )
605 {
606    if (n >= 1)
607       (void)local_sys_write_stderr(buf, n);
608 }
609
610
611 /*------------------------------------------------------------*/
612 /*--- A simple, generic, vprintf implementation.           ---*/
613 /*------------------------------------------------------------*/
614
615 /* -----------------------------------------------
616    Distantly derived from:
617
618       vprintf replacement for Checker.
619       Copyright 1993, 1994, 1995 Tristan Gingold
620       Written September 1993 Tristan Gingold
621       Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
622
623    (Checker itself was GPL'd.)
624    ----------------------------------------------- */
625
626 /* Some flags.  */
627 #define VG_MSG_SIGNED    1 /* The value is signed. */
628 #define VG_MSG_ZJUSTIFY  2 /* Must justify with '0'. */
629 #define VG_MSG_LJUSTIFY  4 /* Must justify on the left. */
630 #define VG_MSG_PAREN     8 /* Parenthesize if present (for %y) */
631 #define VG_MSG_COMMA    16 /* Add commas to numbers (for %d, %u) */
632 #define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
633
634 /* Copy a string into the buffer. */
635 static 
636 UInt myvprintf_str ( void(*send)(HChar,void*),
637                      void* send_arg2,
638                      Int flags, 
639                      Int width, 
640                      HChar* str, 
641                      Bool capitalise )
642 {
643 #  define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
644    UInt ret = 0;
645    Int i, extra;
646    Int len = local_strlen(str);
647
648    if (width == 0) {
649       ret += len;
650       for (i = 0; i < len; i++)
651           send(MAYBE_TOUPPER(str[i]), send_arg2);
652       return ret;
653    }
654
655    if (len > width) {
656       ret += width;
657       for (i = 0; i < width; i++)
658          send(MAYBE_TOUPPER(str[i]), send_arg2);
659       return ret;
660    }
661
662    extra = width - len;
663    if (flags & VG_MSG_LJUSTIFY) {
664       ret += extra;
665       for (i = 0; i < extra; i++)
666          send(' ', send_arg2);
667    }
668    ret += len;
669    for (i = 0; i < len; i++)
670       send(MAYBE_TOUPPER(str[i]), send_arg2);
671    if (!(flags & VG_MSG_LJUSTIFY)) {
672       ret += extra;
673       for (i = 0; i < extra; i++)
674          send(' ', send_arg2);
675    }
676
677 #  undef MAYBE_TOUPPER
678    return ret;
679 }
680
681
682 /* Copy a string into the buffer, escaping bad XML chars. */
683 static 
684 UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
685                                     void* send_arg2,
686                                     HChar* str )
687 {
688    UInt   ret = 0;
689    Int    i;
690    Int    len = local_strlen(str);
691    HChar* alt;
692
693    for (i = 0; i < len; i++) {
694       switch (str[i]) {
695          case '&': alt = "&amp;"; break;
696          case '<': alt = "&lt;"; break;
697          case '>': alt = "&gt;"; break;
698          default:  alt = NULL;
699       }
700
701       if (alt) {
702          while (*alt) {
703             send(*alt, send_arg2);
704             ret++;
705             alt++;
706          }
707       } else {
708          send(str[i], send_arg2);
709          ret++;
710       }
711    }
712
713    return ret;
714 }
715
716
717 /* Write P into the buffer according to these args:
718  *  If SIGN is true, p is a signed.
719  *  BASE is the base.
720  *  If WITH_ZERO is true, '0' must be added.
721  *  WIDTH is the width of the field.
722  */
723 static 
724 UInt myvprintf_int64 ( void(*send)(HChar,void*), 
725                        void* send_arg2,
726                        Int flags, 
727                        Int base, 
728                        Int width, 
729                        Bool capitalised,
730                        ULong p )
731 {
732    HChar  buf[40];
733    Int    ind = 0;
734    Int    i, nc = 0;
735    Bool   neg = False;
736    HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
737    UInt   ret = 0;
738
739    if (base < 2 || base > 16)
740       return ret;
741  
742    if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
743       p   = - (Long)p;
744       neg = True;
745    }
746
747    if (p == 0)
748       buf[ind++] = '0';
749    else {
750       while (p > 0) {
751          if (flags & VG_MSG_COMMA && 10 == base &&
752              0 == (ind-nc) % 3 && 0 != ind) 
753          {
754             buf[ind++] = ',';
755             nc++;
756          }
757          buf[ind++] = digits[p % base];
758          p /= base;
759       }
760    }
761
762    if (neg)
763       buf[ind++] = '-';
764
765    if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
766       for(; ind < width; ind++) {
767          /* vg_assert(ind < 39); */
768          if (ind > 39) {
769             buf[39] = 0;
770             break;
771          }
772          buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
773       }
774    }
775
776    /* Reverse copy to buffer.  */
777    ret += ind;
778    for (i = ind -1; i >= 0; i--) {
779       send(buf[i], send_arg2);
780    }
781    if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
782       for(; ind < width; ind++) {
783          ret++;
784          /* Never pad with zeroes on RHS -- changes the value! */
785          send(' ', send_arg2);
786       }
787    }
788    return ret;
789 }
790
791
792 /* A simple vprintf().  */
793 /* EXPORTED */
794 UInt
795 VG_(debugLog_vprintf) ( 
796    void(*send)(HChar,void*), 
797    void* send_arg2,
798    const HChar* format, 
799    va_list vargs
800 )
801 {
802    UInt ret = 0;
803    Int  i;
804    Int  flags;
805    Int  width;
806    Int  n_ls = 0;
807    Bool is_long, caps;
808
809    /* We assume that vargs has already been initialised by the 
810       caller, using va_start, and that the caller will similarly
811       clean up with va_end.
812    */
813
814    for (i = 0; format[i] != 0; i++) {
815       if (format[i] != '%') {
816          send(format[i], send_arg2);
817          ret++;
818          continue;
819       }
820       i++;
821       /* A '%' has been found.  Ignore a trailing %. */
822       if (format[i] == 0)
823          break;
824       if (format[i] == '%') {
825          /* '%%' is replaced by '%'. */
826          send('%', send_arg2);
827          ret++;
828          continue;
829       }
830       flags = 0;
831       n_ls  = 0;
832       width = 0; /* length of the field. */
833       while (1) {
834          switch (format[i]) {
835          case '(':
836             flags |= VG_MSG_PAREN;
837             break;
838          case ',':
839          case '\'':
840             /* If ',' or '\'' follows '%', commas will be inserted. */
841             flags |= VG_MSG_COMMA;
842             break;
843          case '-':
844             /* If '-' follows '%', justify on the left. */
845             flags |= VG_MSG_LJUSTIFY;
846             break;
847          case '0':
848             /* If '0' follows '%', pads will be inserted. */
849             flags |= VG_MSG_ZJUSTIFY;
850             break;
851          case '#':
852             /* If '#' follows '%', alternative format will be used. */
853             flags |= VG_MSG_ALTFORMAT;
854             break;
855          default:
856             goto parse_fieldwidth;
857          }
858          i++;
859       }
860      parse_fieldwidth:
861       /* Compute the field length. */
862       while (format[i] >= '0' && format[i] <= '9') {
863          width *= 10;
864          width += format[i++] - '0';
865       }
866       while (format[i] == 'l') {
867          i++;
868          n_ls++;
869       }
870
871       //   %d means print a 32-bit integer.
872       //  %ld means print a word-size integer.
873       // %lld means print a 64-bit integer.
874       if      (0 == n_ls) { is_long = False; }
875       else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
876       else                { is_long = True; }
877
878       switch (format[i]) {
879          case 'o': /* %o */
880             if (flags & VG_MSG_ALTFORMAT) {
881                ret += 2;
882                send('0',send_arg2);
883             }
884             if (is_long)
885                ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
886                                       (ULong)(va_arg (vargs, ULong)));
887             else
888                ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
889                                       (ULong)(va_arg (vargs, UInt)));
890             break;
891          case 'd': /* %d */
892             flags |= VG_MSG_SIGNED;
893             if (is_long)
894                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
895                                       (ULong)(va_arg (vargs, Long)));
896             else
897                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
898                                       (ULong)(va_arg (vargs, Int)));
899             break;
900          case 'u': /* %u */
901             if (is_long)
902                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
903                                       (ULong)(va_arg (vargs, ULong)));
904             else
905                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
906                                       (ULong)(va_arg (vargs, UInt)));
907             break;
908          case 'p': /* %p */
909             ret += 2;
910             send('0',send_arg2);
911             send('x',send_arg2);
912             ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
913                                    (ULong)((UWord)va_arg (vargs, void *)));
914             break;
915          case 'x': /* %x */
916          case 'X': /* %X */
917             caps = toBool(format[i] == 'X');
918             if (flags & VG_MSG_ALTFORMAT) {
919                ret += 2;
920                send('0',send_arg2);
921                send('x',send_arg2);
922             }
923             if (is_long)
924                ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
925                                       (ULong)(va_arg (vargs, ULong)));
926             else
927                ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
928                                       (ULong)(va_arg (vargs, UInt)));
929             break;
930          case 'c': /* %c */
931             ret++;
932             send(va_arg (vargs, int), send_arg2);
933             break;
934          case 's': case 'S': { /* %s */
935             char *str = va_arg (vargs, char *);
936             if (str == (char*) 0) str = "(null)";
937             ret += myvprintf_str(send, send_arg2, 
938                                  flags, width, str, format[i]=='S');
939             break;
940          }
941          case 't': { /* %t, like %s but escaping chars for XML safety */
942             /* Note: simplistic; ignores field width and flags */
943             char *str = va_arg (vargs, char *);
944             if (str == (char*) 0) str = "(null)";
945             ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
946             break;
947          }
948
949 //         case 'y': { /* %y - print symbol */
950 //            Char buf[100];
951 //            Char *cp = buf;
952 //            Addr a = va_arg(vargs, Addr);
953 //
954 //            if (flags & VG_MSG_PAREN)
955 //               *cp++ = '(';
956 //            if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
957 //               if (flags & VG_MSG_PAREN) {
958 //                  cp += VG_(strlen)(cp);
959 //                  *cp++ = ')';
960 //                  *cp = '\0';
961 //               }
962 //               ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
963 //            }
964 //            break;
965 //         }
966          default:
967             break;
968       }
969    }
970    return ret;
971 }
972
973
974 /*------------------------------------------------------------*/
975 /*--- Debuglog stuff.                                      ---*/
976 /*------------------------------------------------------------*/
977
978 /* Only print messages whose stated level is less than or equal to
979    this.  By default, it makes this entire subsystem silent. */
980
981 static Int loglevel = 0;
982
983 /* Module startup. */
984 /* EXPORTED */
985 void VG_(debugLog_startup) ( Int level, HChar* who )
986 {
987    if (level < 0)  level = 0;
988    if (level > 10) level = 10;
989    loglevel = level;
990    VG_(debugLog)(1, "debuglog", 
991                  "DebugLog system started by %s, "
992                  "level %d logging requested\n", 
993                  who, loglevel);
994 }
995
996 /* Get the logging threshold level, as set by the most recent call to
997    VG_(debugLog_startup), or zero if there have been no such calls so
998    far. */
999 /* EXPORTED */
1000 Int VG_(debugLog_getLevel) ( void )
1001 {
1002    return loglevel;
1003 }
1004
1005
1006 /* ------------ */
1007
1008 typedef 
1009    struct {
1010       HChar buf[100];
1011       Int   n;
1012    } 
1013    printf_buf;
1014
1015 static void add_to_buf ( HChar c, void* p )
1016 {
1017    printf_buf* buf = (printf_buf*)p;
1018
1019    if (buf->n >= 100-10 /*paranoia*/ ) {
1020       emit( buf->buf, local_strlen(buf->buf) );
1021       buf->n = 0;
1022       buf->buf[buf->n] = 0;      
1023    }
1024    buf->buf[buf->n++] = c;
1025    buf->buf[buf->n] = 0;
1026 }
1027
1028 /* Send a logging message.  Nothing is output unless 'level'
1029    is <= the current loglevel. */
1030 /* EXPORTED */
1031 void VG_(debugLog) ( Int level, const HChar* modulename,
1032                                 const HChar* format, ... )
1033 {
1034    UInt pid;
1035    Int indent, depth, i;
1036    va_list vargs;
1037    printf_buf buf;
1038
1039    if (level > loglevel)
1040       return;
1041
1042    indent = 2*level - 1;
1043    if (indent < 1) indent = 1;
1044
1045    buf.n = 0;
1046    buf.buf[0] = 0;
1047    pid = local_sys_getpid();
1048
1049    // Print one '>' in front of the messages for each level of self-hosting
1050    // being performed.
1051    depth = RUNNING_ON_VALGRIND;
1052    for (i = 0; i < depth; i++) {
1053       (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
1054    }
1055    
1056    (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
1057    (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
1058    (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
1059    (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
1060    (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
1061    (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
1062    (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
1063
1064    va_start(vargs,format);
1065    
1066    (void) VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
1067
1068    if (buf.n > 0) {
1069       emit( buf.buf, local_strlen(buf.buf) );
1070    }
1071
1072    va_end(vargs);
1073 }
1074
1075
1076
1077 /*--------------------------------------------------------------------*/
1078 /*--- end                                           m_debuglog.c ---*/
1079 /*--------------------------------------------------------------------*/