Home | History | Annotate | Download | only in coregrind
      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 (at) 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 
     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 
     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 
     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))
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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))
    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 
    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))
    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 
    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)
    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 
    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)
    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 
    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 */
    439 static Int local_strlen ( const HChar* str )
    440 {
    441    Int i = 0;
    442    while (str[i] != 0) i++;
    443    return i;
    444 }
    445 
    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 */
    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
    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
    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
    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
    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 */
    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 */
    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 
    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 */
    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