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