• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
59 static Bool clo_xml;
60 
VG_(debugLog_setXml)61 void 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 
local_sys_write_stderr(HChar * buf,Int n)74 static 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 
local_sys_getpid(void)92 static 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))
local_sys_write_stderr(HChar * buf,Int n)107 static 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 
local_sys_getpid(void)135 static 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 
local_sys_write_stderr(HChar * buf,Int n)150 static 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 
local_sys_getpid(void)177 static 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 
local_sys_write_stderr(HChar * buf,Int n)193 static 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 
local_sys_getpid(void)220 static 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 
local_sys_write_stderr(HChar * buf,Int n)236 static 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 
local_sys_getpid(void)257 static 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))
local_sys_write_stderr(HChar * buf,Int n)277 static 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 
local_sys_getpid(void)303 static 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))
local_sys_write_stderr(HChar * buf,Int n)319 static 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 
local_sys_getpid(void)339 static 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)
local_sys_write_stderr(HChar * buf,Int n)353 static 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 
local_sys_getpid(void)376 static 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)
local_sys_write_stderr(HChar * buf,Int n)394 static 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 
local_sys_getpid(void)416 static 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 */
local_strlen(const HChar * str)439 static Int local_strlen ( const HChar* str )
440 {
441    Int i = 0;
442    while (str[i] != 0) i++;
443    return i;
444 }
445 
local_toupper(HChar c)446 static 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 */
emit(HChar * buf,Int n)456 static 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. */
487 static
myvprintf_str(void (* send)(HChar,void *),void * send_arg2,Int flags,Int width,HChar * str,Bool capitalise)488 UInt 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. */
535 static
myvprintf_str_XML_simplistic(void (* send)(HChar,void *),void * send_arg2,HChar * str)536 UInt 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  */
575 static
myvprintf_int64(void (* send)(HChar,void *),void * send_arg2,Int flags,Int base,Int width,Bool capitalised,ULong p)576 UInt 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 */
646 UInt
VG_(debugLog_vprintf)647 VG_(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 
848 static Int loglevel = 0;
849 
850 /* Module startup. */
851 /* EXPORTED */
VG_(debugLog_startup)852 void 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 */
VG_(debugLog_getLevel)867 Int VG_(debugLog_getLevel) ( void )
868 {
869    return loglevel;
870 }
871 
872 
873 /* ------------ */
874 
875 typedef
876    struct {
877       HChar buf[100];
878       Int   n;
879    }
880    printf_buf;
881 
add_to_buf(HChar c,void * p)882 static 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 */
VG_(debugLog)898 void 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