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