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