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