Bug 444488 - Use glibc.pthread.stack_cache_size tunable
[valgrind.git] / coregrind / m_debuglog.c
blob355c3caf5b0aa568673fc815a531806fa0c92c28
1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- Debug (not-for-user) logging; also vprintf. m_debuglog.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2000-2017 Julian Seward
12 jseward@acm.org
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
31 /* Performs low-level debug logging that can safely run immediately
32 after startup. To minimise the dependencies on any other parts of
33 the system, the only place the debug output may go is file
34 descriptor 2 (stderr).
36 /* This is the first-initialised module in the entire system!
37 Therefore it is CRITICAL that it does not depend on any other code
38 running first. Hence only the following very limited includes. We
39 cannot depend (directly or indirectly) on any dynamic memory
40 allocation facilities, nor on the m_libc facilities, since the
41 latter depend on this module. DO NOT MESS WITH THESE INCLUDES
42 UNLESS YOU ARE 100% CERTAIN YOU UNDERSTAND THE CONSEQUENCES.
45 /* This module is also notable because it is linked into both
46 stage1 and stage2. */
48 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
49 of syscalls rather than the vanilla version, if a _nocancel version
50 is available. See docs/internals/Darwin-notes.txt for the reason
51 why. */
53 #include "pub_core_basics.h" /* basic types */
54 #include "pub_core_vkiscnums.h" /* for syscall numbers */
55 #include "pub_core_debuglog.h" /* our own iface */
56 #include "pub_core_clreq.h" /* for RUNNING_ON_VALGRIND */
57 #if defined(VGO_solaris)
58 #include "pub_core_vki.h" /* for EINTR and ERESTART */
59 #endif
61 static Bool clo_xml;
63 void VG_(debugLog_setXml)(Bool xml)
65 clo_xml = xml;
68 /*------------------------------------------------------------*/
69 /*--- Stuff to make us completely independent. ---*/
70 /*------------------------------------------------------------*/
72 /* ----- Platform-specifics ----- */
74 #if defined(VGP_x86_linux)
76 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
78 Int result;
80 __asm__ volatile (
81 "pushl %%ebx\n"
82 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */
83 "movl $2, %%ebx\n" /* %ebx = stderr */
84 "int $0x80\n" /* write(stderr, buf, n) */
85 "popl %%ebx\n"
86 : /*wr*/ "=a" (result)
87 : /*rd*/ "c" (buf), "d" (n)
88 : /*trash*/ "edi", "memory", "cc"
91 return result >= 0 ? result : -1;
94 static UInt local_sys_getpid ( void )
96 UInt __res;
97 __asm__ volatile (
98 "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n" /* %eax = __NR_getpid */
99 "int $0x80\n" /* getpid() */
100 "movl %%eax, %0\n" /* set __res = eax */
101 : "=mr" (__res)
103 : "eax" );
104 return __res;
107 #elif defined(VGP_amd64_linux)
109 __attribute__((noinline))
110 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
112 volatile Long block[2];
113 block[0] = (Long)buf;
114 block[1] = n;
115 __asm__ volatile (
116 "subq $256, %%rsp\n" /* don't trash the stack redzone */
117 "pushq %%r15\n" /* r15 is callee-save */
118 "movq %0, %%r15\n" /* r15 = &block */
119 "pushq %%r15\n" /* save &block */
120 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
121 "movq $2, %%rdi\n" /* rdi = stderr */
122 "movq 0(%%r15), %%rsi\n" /* rsi = buf */
123 "movq 8(%%r15), %%rdx\n" /* rdx = n */
124 "syscall\n" /* write(stderr, buf, n) */
125 "popq %%r15\n" /* reestablish &block */
126 "movq %%rax, 0(%%r15)\n" /* block[0] = result */
127 "popq %%r15\n" /* restore r15 */
128 "addq $256, %%rsp\n" /* restore stack ptr */
129 : /*wr*/
130 : /*rd*/ "r" (block)
131 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc", "rcx", "r11"
133 if (block[0] < 0)
134 block[0] = -1;
135 return (UInt)block[0];
138 static UInt local_sys_getpid ( void )
140 UInt __res;
141 __asm__ volatile (
142 "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n" /* %rax = __NR_getpid */
143 "syscall\n" /* getpid() */
144 "movl %%eax, %0\n" /* set __res = %eax */
145 : "=mr" (__res)
147 : "rax", "rcx", "r11"
149 return __res;
152 #elif defined(VGP_ppc32_linux)
154 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
156 volatile Int block[2];
157 block[0] = (Int)buf;
158 block[1] = n;
159 __asm__ volatile (
160 "addi 1,1,-256\n\t"
161 "mr 5,%0\n\t" /* r5 = &block[0] */
162 "stw 5,0(1)\n\t" /* stash on stack */
163 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* set %r0 = __NR_write */
164 "li 3,2\n\t" /* set %r3 = stderr */
165 "lwz 4,0(5)\n\t" /* set %r4 = buf */
166 "lwz 5,4(5)\n\t" /* set %r5 = n */
167 "sc\n\t" /* write(stderr, buf, n) */
168 "lwz 5,0(1)\n\t"
169 "addi 1,1,256\n\t"
170 "stw 3,0(5)\n" /* block[0] = result */
172 : "b" (block)
173 : "cc","memory","cr0","ctr",
174 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
176 if (block[0] < 0)
177 block[0] = -1;
178 return (UInt)block[0];
181 static UInt local_sys_getpid ( void )
183 register UInt __res __asm__ ("r3");
184 __asm__ volatile (
185 "li 0, %1\n\t"
186 "sc"
187 : "=&r" (__res)
188 : "i" (__NR_getpid)
189 : "cc","memory","cr0","ctr",
190 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
192 return __res;
195 #elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
197 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
199 volatile Long block[2];
200 block[0] = (Long)buf;
201 block[1] = (Long)n;
202 __asm__ volatile (
203 "addi 1,1,-256\n\t"
204 "mr 5,%0\n\t" /* r5 = &block[0] */
205 "std 5,0(1)\n\t" /* stash on stack */
206 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* %r0 = __NR_write */
207 "li 3,2\n\t" /* set %r3 = stderr */
208 "ld 4,0(5)\n\t" /* set %r4 = buf */
209 "ld 5,8(5)\n\t" /* set %r5 = n */
210 "sc\n\t" /* write(stderr, buf, n) */
211 "ld 5,0(1)\n\t"
212 "addi 1,1,256\n\t"
213 "std 3,0(5)\n" /* block[0] = result */
215 : "b" (block)
216 : "cc","memory","cr0","ctr",
217 "r0","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
219 if (block[0] < 0)
220 block[0] = -1;
221 return (UInt)(Int)block[0];
224 static UInt local_sys_getpid ( void )
226 register ULong __res __asm__ ("r3");
227 __asm__ volatile (
228 "li 0, %1\n\t"
229 "sc"
230 : "=&r" (__res)
231 : "i" (__NR_getpid)
232 : "cc","memory","cr0","ctr",
233 "r0","r4","r5","r6","r7","r8","r9","r10","r11","r12"
235 return (UInt)__res;
238 #elif defined(VGP_arm_linux)
240 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
242 volatile Int block[2];
243 block[0] = (Int)buf;
244 block[1] = n;
245 __asm__ volatile (
246 "mov r0, #2\n\t" /* stderr */
247 "ldr r1, [%0]\n\t" /* buf */
248 "ldr r2, [%0, #4]\n\t" /* n */
249 "push {r6,r7}\n\t"
250 "mov r7, #"VG_STRINGIFY(__NR_write)"\n\t"
251 "svc 0x0\n" /* write() */
252 "pop {r6,r7}\n\t"
253 "str r0, [%0]\n\t"
255 : "r" (block)
256 : "r0","r1","r2"
258 if (block[0] < 0)
259 block[0] = -1;
260 return (UInt)block[0];
263 static UInt local_sys_getpid ( void )
265 UInt __res;
266 __asm__ volatile (
267 "push {r6,r7}\n\t"
268 "mov r7, #"VG_STRINGIFY(__NR_getpid)"\n\t"
269 "svc 0x0\n\t" /* getpid() */
270 "pop {r6,r7}\n\t"
271 "mov %0, r0\n\t"
272 : "=r" (__res)
274 : "r0" );
275 return __res;
278 #elif defined(VGP_arm64_linux)
280 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
282 volatile ULong block[2];
283 block[0] = (ULong)buf;
284 block[1] = (ULong)n;
285 __asm__ volatile (
286 "mov x0, #2\n\t" /* stderr */
287 "ldr x1, [%0]\n\t" /* buf */
288 "ldr x2, [%0, #8]\n\t" /* n */
289 "mov x8, #"VG_STRINGIFY(__NR_write)"\n\t"
290 "svc 0x0\n" /* write() */
291 "str x0, [%0]\n\t"
293 : "r" (block)
294 : "x0","x1","x2","x7"
296 if (block[0] < 0)
297 block[0] = -1;
298 return (UInt)block[0];
301 static UInt local_sys_getpid ( void )
303 UInt __res;
304 __asm__ volatile (
305 "mov x8, #"VG_STRINGIFY(__NR_getpid)"\n"
306 "svc 0x0\n" /* getpid() */
307 "mov %0, x0\n"
308 : "=r" (__res)
310 : "x0", "x8" );
311 return (UInt)__res;
314 #elif defined(VGP_x86_darwin)
316 /* We would use VG_DARWIN_SYSNO_TO_KERNEL instead of VG_DARWIN_SYSNO_INDEX
317 except that the former has a C ternary ?: operator which isn't valid in
318 asm code. Both macros give the same results for Unix-class syscalls (which
319 these all are, as identified by the use of 'int 0x80'). */
320 __attribute__((noinline))
321 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
323 UInt __res;
324 __asm__ volatile (
325 "movl %2, %%eax\n" /* push n */
326 "pushl %%eax\n"
327 "movl %1, %%eax\n" /* push buf */
328 "pushl %%eax\n"
329 "movl $2, %%eax\n" /* push stderr */
330 "pushl %%eax\n"
331 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
332 ", %%eax\n"
333 "pushl %%eax\n" /* push fake return address */
334 "int $0x80\n" /* write(stderr, buf, n) */
335 "jnc 1f\n" /* jump if no error */
336 "movl $-1, %%eax\n" /* return -1 if error */
337 "1: "
338 "movl %%eax, %0\n" /* __res = eax */
339 "addl $16, %%esp\n" /* pop x4 */
340 : "=mr" (__res)
341 : "g" (buf), "g" (n)
342 : "eax", "edx", "cc"
344 return __res;
347 static UInt local_sys_getpid ( void )
349 UInt __res;
350 __asm__ volatile (
351 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
352 "int $0x80\n" /* getpid() */
353 "movl %%eax, %0\n" /* set __res = eax */
354 : "=mr" (__res)
356 : "eax", "cc" );
357 return __res;
360 #elif defined(VGP_amd64_darwin)
362 __attribute__((noinline))
363 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
365 UInt __res;
366 __asm__ volatile (
367 "movq $2, %%rdi\n" /* push stderr */
368 "movq %1, %%rsi\n" /* push buf */
369 "movl %2, %%edx\n" /* push n */
370 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_write_nocancel))
371 ", %%eax\n"
372 "syscall\n" /* write(stderr, buf, n) */
373 "jnc 1f\n" /* jump if no error */
374 "movq $-1, %%rax\n" /* return -1 if error */
375 "1: "
376 "movl %%eax, %0\n" /* __res = eax */
377 : "=mr" (__res)
378 : "g" (buf), "g" (n)
379 : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
380 return __res;
383 static UInt local_sys_getpid ( void )
385 UInt __res;
386 __asm__ volatile (
387 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_getpid))", %%eax\n"
388 "syscall\n" /* getpid() */
389 "movl %%eax, %0\n" /* set __res = eax */
390 : "=mr" (__res)
392 : "rax", "rcx", "cc" );
393 return __res;
396 #elif defined(VGP_s390x_linux)
398 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
400 register Int r2 asm("2") = 2; /* file descriptor STDERR */
401 register const HChar* r3 asm("3") = buf;
402 register ULong r4 asm("4") = n;
403 register ULong r2_res asm("2");
404 ULong __res;
406 __asm__ __volatile__ (
407 "svc %b1\n"
408 : "=d" (r2_res)
409 : "i" (__NR_write),
410 "0" (r2),
411 "d" (r3),
412 "d" (r4)
413 : "cc", "memory");
414 __res = r2_res;
416 if (__res >= (ULong)(-125))
417 __res = -1;
418 return (UInt)(__res);
421 static UInt local_sys_getpid ( void )
423 register ULong r2 asm("2");
424 ULong __res;
426 __asm__ __volatile__ (
427 "svc %b1\n"
428 : "=d" (r2)
429 : "i" (__NR_getpid)
430 : "cc", "memory");
431 __res = r2;
433 if (__res >= (ULong)(-125))
434 __res = -1;
435 return (UInt)(__res);
438 #elif defined(VGP_x86_freebsd)
439 static UInt local_sys_write_stderr (const HChar* buf, Int n )
441 Int result;
443 __asm__ volatile (
444 "movl %2, %%eax\n" /* push n */
445 "movl %1, %%edx\n" /* push buf */
446 "pushl %%eax\n"
447 "pushl %%edx\n"
448 "movl $2, %%eax\n" /* push stderr */
449 "pushl %%eax\n"
450 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n"
451 "pushl %%eax\n" /* push write syscall id */
452 "int $0x80\n" /* write(stderr, buf, n) */
453 "jnc 1f\n" /* jump if no error */
454 "movl $-1, %%eax\n" /* return -1 if error */
455 "1: "
456 "movl %%eax, %0\n" /* __res = eax */
457 "addl $16, %%esp\n" /* pop x4 */
458 : /*wr*/ "=mr" (result)
459 : /*rd*/ "g" (buf), "g" (n)
460 : /*trash*/ "eax", "edx", "cc"
462 return result >= 0 ? result : -1;
465 static UInt local_sys_getpid ( void )
467 UInt __res;
468 __asm__ volatile (
469 "movl $20, %%eax\n" /* set %eax = __NR_getpid */
470 "int $0x80\n" /* getpid() */
471 "movl %%eax, %0\n" /* set __res = eax */
472 : "=mr" (__res)
474 : "eax" );
475 return __res;
478 #elif defined(VGP_amd64_freebsd)
479 __attribute__((noinline))
480 static UInt local_sys_write_stderr (const HChar* buf, Int n )
482 volatile Long block[2];
483 block[0] = (Long)buf;
484 block[1] = n;
485 __asm__ volatile (
486 "subq $256, %%rsp\n" /* don't trash the stack redzone */
487 "pushq %%r15\n" /* r15 is callee-save */
488 "movq %0, %%r15\n" /* r15 = &block */
489 "pushq %%r15\n" /* save &block */
490 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
491 "movq $2, %%rdi\n" /* rdi = stderr */
492 "movq 0(%%r15), %%rsi\n" /* rsi = buf */
493 "movq 8(%%r15), %%rdx\n" /* rdx = n */
494 "syscall\n" /* write(stderr, buf, n) */
495 "popq %%r15\n" /* reestablish &block */
496 "movq %%rax, 0(%%r15)\n" /* block[0] = result */
497 "popq %%r15\n" /* restore r15 */
498 "addq $256, %%rsp\n" /* restore stack ptr */
499 : /*wr*/
500 : /*rd*/ "r" (block)
501 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc", "rcx", "r8", "r9", "r11"
503 if (block[0] < 0)
504 block[0] = -1;
505 return (UInt)block[0];
508 static UInt local_sys_getpid ( void )
510 UInt __res;
511 __asm__ volatile (
512 "movq $20, %%rax\n" /* set %rax = __NR_getpid */
513 "syscall\n" /* getpid() */
514 "movl %%eax, %0\n" /* set __res = %eax */
515 : "=mr" (__res)
517 : "rax", "rcx");//, "r11" );
518 return __res;
521 #elif defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
523 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
525 register RegWord v0 asm("2");
526 register RegWord a0 asm("4");
527 register RegWord a1 asm("5");
528 register RegWord a2 asm("6");
529 v0 = __NR_write;
530 a2 = n;
531 a1 = (RegWord)(Addr)buf;
532 a0 = 2; // stderr
533 __asm__ volatile (
534 "syscall \n\t"
535 "addiu $4, $0, -1 \n\t"
536 #if ((defined(__mips_isa_rev) && __mips_isa_rev >= 6))
537 "selnez $4, $4, $7 \n\t"
538 "seleqz $2, $2, $7 \n\t"
539 "or $2, $2, $4 \n\t"
540 #else
541 "movn $2, $4, $7 \n\t"
542 #endif
543 : "+d" (v0), "+d" (a0), "+d" (a1), "+d" (a2)
545 : "$1", "$3", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
546 "$24", "$25", "$31"
548 return v0;
551 static UInt local_sys_getpid ( void )
553 register RegWord v0 asm("2");
554 v0 = __NR_getpid;
555 __asm__ volatile (
556 "syscall \n\t"
557 : "+d" (v0)
559 : "$1", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12",
560 "$13", "$14", "$15", "$24", "$25", "$31"
562 return v0;
565 #elif defined(VGP_nanomips_linux)
567 __attribute__((noinline))
568 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
570 register RegWord t4 asm("2");
571 register RegWord a0 asm("4");
572 register RegWord a1 asm("5");
573 register RegWord a2 asm("6");
574 t4 = __NR_write;
575 a2 = n;
576 a1 = (RegWord)(Addr)buf;
577 a0 = 2; // stderr
578 __asm__ volatile (
579 "syscall[32] \n\t"
580 : "+d" (t4), "+d" (a0), "+d" (a1), "+d" (a2)
582 : "$at", "$t5", "$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2",
583 "$t3", "$t8", "$t9"
585 return a0;
588 __attribute__((noinline))
589 static UInt local_sys_getpid ( void )
591 register RegWord t4 asm("2");
592 register RegWord a0 asm("4");
593 t4 = __NR_getpid;
594 __asm__ volatile (
595 "syscall[32] \n\t"
596 : "+d" (t4), "=d" (a0)
598 : "$at", "$t5", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7", "$t0",
599 "$t1", "$t2", "$t3", "$t8", "$t9"
601 return a0;
604 #elif defined(VGP_x86_solaris)
605 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
607 UInt res, err;
608 Bool restart;
610 do {
611 /* The Solaris kernel does not restart syscalls automatically so it is
612 done here. */
613 __asm__ __volatile__ (
614 "movl %[n], %%eax\n" /* push n */
615 "pushl %%eax\n"
616 "movl %[buf], %%eax\n" /* push buf */
617 "pushl %%eax\n"
618 "movl $2, %%eax\n" /* push stderr */
619 "pushl %%eax\n"
620 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n"
621 "pushl %%eax\n" /* push fake return address */
622 "int $0x91\n" /* write(stderr, buf, n) */
623 "movl $0, %%edx\n" /* assume no error */
624 "jnc 1f\n" /* jump if no error */
625 "movl $1, %%edx\n" /* set error flag */
626 "1: "
627 "addl $16, %%esp\n" /* pop x4 */
628 : "=&a" (res), "=d" (err)
629 : [buf] "g" (buf), [n] "g" (n)
630 : "cc");
631 restart = err && (res == VKI_EINTR || res == VKI_ERESTART);
632 } while (restart);
634 return res;
637 static UInt local_sys_getpid ( void )
639 UInt res;
641 /* The getpid() syscall never returns EINTR or ERESTART so there is no need
642 for restarting it. */
643 __asm__ __volatile__ (
644 "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n"
645 "int $0x91\n" /* getpid() */
646 : "=a" (res)
648 : "edx", "cc");
650 return res;
653 #elif defined(VGP_amd64_solaris)
654 static UInt local_sys_write_stderr ( const HChar* buf, Int n )
656 ULong res, err;
657 Bool restart;
659 do {
660 /* The Solaris kernel does not restart syscalls automatically so it is
661 done here. */
662 __asm__ __volatile__ (
663 "movq $2, %%rdi\n" /* push stderr */
664 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n"
665 "syscall\n" /* write(stderr, buf, n) */
666 "movq $0, %%rdx\n" /* assume no error */
667 "jnc 1f\n" /* jump if no error */
668 "movq $1, %%rdx\n" /* set error flag */
669 "1: "
670 : "=a" (res), "=d" (err)
671 : "S" (buf), "d" (n)
672 : "cc");
673 restart = err && (res == VKI_EINTR || res == VKI_ERESTART);
674 } while (restart);
676 return res;
679 static UInt local_sys_getpid ( void )
681 UInt res;
683 /* The getpid() syscall never returns EINTR or ERESTART so there is no need
684 for restarting it. */
685 __asm__ __volatile__ (
686 "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n"
687 "syscall\n" /* getpid() */
688 : "=a" (res)
690 : "edx", "cc");
692 return res;
695 #else
696 # error Unknown platform
697 #endif
700 /* ----- generic ----- */
702 /* strlen, so we don't need m_libc */
703 static Int local_strlen ( const HChar* str )
705 Int i = 0;
706 while (str[i] != 0) i++;
707 return i;
710 static HChar local_toupper ( HChar c )
712 if (c >= 'a' && c <= 'z')
713 return c + ('A' - 'a');
714 else
715 return c;
718 /* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
720 static void emit ( const HChar* buf, Int n )
722 if (n >= 1)
723 (void)local_sys_write_stderr(buf, n);
727 /*------------------------------------------------------------*/
728 /*--- A simple, generic, vprintf implementation. ---*/
729 /*------------------------------------------------------------*/
731 /* -----------------------------------------------
732 Distantly derived from:
734 vprintf replacement for Checker.
735 Copyright 1993, 1994, 1995 Tristan Gingold
736 Written September 1993 Tristan Gingold
737 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
739 (Checker itself was GPL'd.)
740 ----------------------------------------------- */
742 /* Some flags. */
743 #define VG_MSG_SIGNED 1 /* The value is signed. */
744 #define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
745 #define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
746 #define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
747 #define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
748 #define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
750 /* Copy a string into the buffer. */
751 static
752 UInt myvprintf_str ( void(*send)(HChar,void*),
753 void* send_arg2,
754 Int flags,
755 Int width,
756 const HChar* str,
757 Bool capitalise )
759 # define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
760 UInt ret = 0;
761 Int i, extra;
762 Int len = local_strlen(str);
764 if (width == 0) {
765 ret += len;
766 for (i = 0; i < len; i++)
767 send(MAYBE_TOUPPER(str[i]), send_arg2);
768 return ret;
771 if (len > width) {
772 ret += width;
773 for (i = 0; i < width; i++)
774 send(MAYBE_TOUPPER(str[i]), send_arg2);
775 return ret;
778 extra = width - len;
779 if (! (flags & VG_MSG_LJUSTIFY)) {
780 ret += extra;
781 for (i = 0; i < extra; i++)
782 send(' ', send_arg2);
784 ret += len;
785 for (i = 0; i < len; i++)
786 send(MAYBE_TOUPPER(str[i]), send_arg2);
787 if (flags & VG_MSG_LJUSTIFY) {
788 ret += extra;
789 for (i = 0; i < extra; i++)
790 send(' ', send_arg2);
793 # undef MAYBE_TOUPPER
794 return ret;
798 /* Copy a string into the buffer, escaping bad XML chars. */
799 static
800 UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
801 void* send_arg2,
802 const HChar* str )
804 UInt ret = 0;
805 Int i;
806 Int len = local_strlen(str);
807 const HChar* alt;
809 for (i = 0; i < len; i++) {
810 switch (str[i]) {
811 case '&': alt = "&amp;"; break;
812 case '<': alt = "&lt;"; break;
813 case '>': alt = "&gt;"; break;
814 default: alt = NULL;
817 if (alt) {
818 while (*alt) {
819 send(*alt, send_arg2);
820 ret++;
821 alt++;
823 } else {
824 send(str[i], send_arg2);
825 ret++;
829 return ret;
833 /* Write P into the buffer according to these args:
834 * If SIGN is true, p is a signed.
835 * BASE is the base.
836 * If WITH_ZERO is true, '0' must be added.
837 * WIDTH is the width of the field.
839 static
840 UInt myvprintf_int64 ( void(*send)(HChar,void*),
841 void* send_arg2,
842 Int flags,
843 Int base,
844 Int width,
845 Bool capitalised,
846 ULong p )
848 /* To print an ULong base 2 needs 64 characters. If commas are requested,
849 add 21. Plus 1 for a possible sign plus 1 for \0. Makes 87 -- so let's
850 say 90. The size of BUF needs to be max(90, WIDTH + 1) */
851 HChar buf[width + 1 > 90 ? width + 1 : 90];
852 Int ind = 0;
853 Int i, nc = 0;
854 Bool neg = False;
855 const HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
856 UInt ret = 0;
858 if (base < 2 || base > 16)
859 return ret;
861 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
862 p = - (Long)p;
863 neg = True;
866 if (p == 0)
867 buf[ind++] = '0';
868 else {
869 while (p > 0) {
870 if (flags & VG_MSG_COMMA && 10 == base &&
871 0 == (ind-nc) % 3 && 0 != ind)
873 buf[ind++] = ',';
874 nc++;
876 buf[ind++] = digits[p % base];
877 p /= base;
881 if (neg)
882 buf[ind++] = '-';
884 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
885 for(; ind < width; ind++) {
886 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
890 /* Reverse copy to buffer. */
891 ret += ind;
892 for (i = ind -1; i >= 0; i--) {
893 send(buf[i], send_arg2);
895 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
896 for(; ind < width; ind++) {
897 ret++;
898 /* Never pad with zeroes on RHS -- changes the value! */
899 send(' ', send_arg2);
902 return ret;
906 /* A simple vprintf(). */
907 /* EXPORTED */
908 UInt
909 VG_(debugLog_vprintf) (
910 void(*send)(HChar,void*),
911 void* send_arg2,
912 const HChar* format,
913 va_list vargs
916 UInt ret = 0;
917 Int i;
918 Int flags;
919 Int width, precision;
920 Int n_ls = 0;
921 Bool is_long, is_sizet, caps;
923 /* We assume that vargs has already been initialised by the
924 caller, using va_start, and that the caller will similarly
925 clean up with va_end.
928 for (i = 0; format[i] != 0; i++) {
929 if (format[i] != '%') {
930 send(format[i], send_arg2);
931 ret++;
932 continue;
934 i++;
935 /* A '%' has been found. Ignore a trailing %. */
936 if (format[i] == 0)
937 break;
938 if (format[i] == '%') {
939 /* '%%' is replaced by '%'. */
940 send('%', send_arg2);
941 ret++;
942 continue;
944 flags = 0;
945 n_ls = 0;
946 width = 0; /* length of the field. */
947 precision = -1; /* unspecified precision */
948 while (1) {
949 switch (format[i]) {
950 case '(':
951 flags |= VG_MSG_PAREN;
952 break;
953 case ',':
954 case '\'':
955 /* If ',' or '\'' follows '%', commas will be inserted. */
956 flags |= VG_MSG_COMMA;
957 break;
958 case '-':
959 /* If '-' follows '%', justify on the left. */
960 flags |= VG_MSG_LJUSTIFY;
961 break;
962 case '0':
963 /* If '0' follows '%', pads will be inserted. */
964 flags |= VG_MSG_ZJUSTIFY;
965 break;
966 case '#':
967 /* If '#' follows '%', alternative format will be used. */
968 flags |= VG_MSG_ALTFORMAT;
969 break;
970 default:
971 goto parse_fieldwidth;
973 i++;
975 parse_fieldwidth:
976 /* Compute the field length. */
977 if (format[i] == '*') {
978 width = va_arg(vargs, Int);
979 ++i;
980 } else {
981 while (format[i] >= '0' && format[i] <= '9') {
982 width *= 10;
983 width += format[i++] - '0';
986 /* Parse precision, if any. Only meaningful for %f. For all other
987 format specifiers the precision will be silently ignored. */
988 if (format[i] == '.') {
989 ++i;
990 if (format[i] == '*') {
991 precision = va_arg(vargs, Int);
992 ++i;
993 } else {
994 precision = 0;
995 while (format[i] >= '0' && format[i] <= '9') {
996 precision *= 10;
997 precision += format[i++] - '0';
1002 is_sizet = False;
1003 if (format[i] == 'z') {
1004 is_sizet = True;
1005 ++i;
1006 } else {
1007 while (format[i] == 'l') {
1008 i++;
1009 n_ls++;
1013 // %d means print a 32-bit integer.
1014 // %ld means print a word-size integer.
1015 // %lld means print a 64-bit integer.
1016 if (0 == n_ls) { is_long = False; }
1017 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
1018 else { is_long = True; }
1020 switch (format[i]) {
1021 case 'o': /* %o */
1022 if (flags & VG_MSG_ALTFORMAT) {
1023 ret += 2;
1024 send('0',send_arg2);
1026 if (is_sizet)
1027 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
1028 (ULong)(va_arg (vargs, SizeT)));
1029 else if (is_long)
1030 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
1031 (ULong)(va_arg (vargs, ULong)));
1032 else
1033 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
1034 (ULong)(va_arg (vargs, UInt)));
1035 break;
1036 case 'd': /* %d */
1037 flags |= VG_MSG_SIGNED;
1038 if (is_long)
1039 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
1040 (ULong)(va_arg (vargs, Long)));
1041 else
1042 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
1043 (ULong)(va_arg (vargs, Int)));
1044 break;
1045 case 'u': /* %u */
1046 if (is_sizet)
1047 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
1048 (ULong)(va_arg (vargs, SizeT)));
1049 else if (is_long)
1050 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
1051 (ULong)(va_arg (vargs, ULong)));
1052 else
1053 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
1054 (ULong)(va_arg (vargs, UInt)));
1055 break;
1056 case 'p':
1057 if (format[i+1] == 'S') {
1058 i++;
1059 /* %pS, like %s but escaping chars for XML safety */
1060 /* Note: simplistic; ignores field width and flags */
1061 const HChar *str = va_arg (vargs, HChar *);
1062 if (str == NULL)
1063 str = "(null)";
1064 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
1065 } else if (format[i+1] == 's') {
1066 i++;
1067 /* %ps, synonym for %s with --xml=no / %pS with --xml=yes */
1068 const HChar *str = va_arg (vargs, HChar *);
1069 if (str == NULL)
1070 str = "(null)";
1071 if (clo_xml)
1072 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
1073 else
1074 ret += myvprintf_str(send, send_arg2, flags, width, str,
1075 False);
1076 } else {
1077 /* %p */
1078 ret += 2;
1079 send('0',send_arg2);
1080 send('x',send_arg2);
1081 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
1082 (ULong)((UWord)va_arg (vargs, void *)));
1084 break;
1085 case 'x': /* %x */
1086 case 'X': /* %X */
1087 caps = toBool(format[i] == 'X');
1088 if (flags & VG_MSG_ALTFORMAT) {
1089 ret += 2;
1090 send('0',send_arg2);
1091 send('x',send_arg2);
1093 if (is_sizet)
1094 ret += myvprintf_int64(send, send_arg2, flags, 16, width, False,
1095 (ULong)(va_arg (vargs, SizeT)));
1096 else if (is_long)
1097 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
1098 (ULong)(va_arg (vargs, ULong)));
1099 else
1100 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
1101 (ULong)(va_arg (vargs, UInt)));
1102 break;
1103 case 'c': /* %c */
1104 ret++;
1105 send(va_arg (vargs, int), send_arg2);
1106 break;
1107 case 's': case 'S': { /* %s */
1108 const HChar *str = va_arg (vargs, HChar *);
1109 if (str == NULL) str = "(null)";
1110 ret += myvprintf_str(send, send_arg2,
1111 flags, width, str, format[i]=='S');
1112 break;
1114 case 'f': {
1115 /* Print a floating point number in the format x.y without
1116 any exponent. Capabilities are extremely limited, basically
1117 a joke, but good enough for our needs. */
1118 Double val = va_arg (vargs, Double);
1119 Bool is_negative = False;
1120 Int cnt;
1122 if (val < 0.0) {
1123 is_negative = True;
1124 val = - val;
1126 /* If the integral part of the floating point number cannot be
1127 represented by an ULONG_MAX, print '*' characters */
1128 if (val > (Double)(~0ULL)) {
1129 if (width == 0) width = 6; // say
1130 for (cnt = 0; cnt < width; ++cnt)
1131 send('*', send_arg2);
1132 ret += width;
1133 break;
1135 /* The integral part of the floating point number is representable
1136 by an ULong. */
1137 ULong ipval = val;
1138 Double frac = val - ipval;
1140 if (precision == -1) precision = 6; // say
1142 /* Silently limit the precision to 10 digits. */
1143 if (precision > 10) precision = 10;
1145 /* Determine fractional part, possibly round up */
1146 ULong factor = 1;
1147 for (cnt = 0; cnt < precision; ++cnt)
1148 factor *= 10;
1149 ULong frval = frac * factor;
1150 if ((frac * factor - frval) > 0.5) // round up
1151 frval += 1;
1152 /* Check rounding. */
1153 if (frval == factor)
1154 ipval += 1;
1155 frval %= factor;
1157 /* Find out how many characters are needed to print the number */
1159 /* The integral part... */
1160 UInt ipwidth, num_digit = 1; // at least one digit
1161 ULong x, old_x = 0;
1162 for (x = 10; ; old_x = x, x *= 10, ++num_digit) {
1163 if (x <= old_x) break; // overflow occurred
1164 if (ipval < x) break;
1166 ipwidth = num_digit; // width of integral part.
1167 if (is_negative) ++num_digit;
1168 if (precision != 0)
1169 num_digit += 1 + precision;
1171 // Print the number
1173 // Fill in blanks on the left
1174 if (num_digit < width && (flags & VG_MSG_LJUSTIFY) == 0) {
1175 for (cnt = 0; cnt < width - num_digit; ++cnt)
1176 send(' ', send_arg2);
1177 ret += width - num_digit;
1179 // Sign, maybe
1180 if (is_negative) {
1181 send('-', send_arg2);
1182 ret += 1;
1184 // Integral part
1185 ret += myvprintf_int64(send, send_arg2, 0, 10, ipwidth, False,
1186 ipval);
1187 // Decimal point and fractional part
1188 if (precision != 0) {
1189 send('.', send_arg2);
1190 ret += 1;
1192 ret += myvprintf_int64(send, send_arg2, VG_MSG_ZJUSTIFY, 10,
1193 precision, False, frval);
1195 // Fill in blanks on the right
1196 if (num_digit < width && (flags & VG_MSG_LJUSTIFY) != 0) {
1197 for (cnt = 0; cnt < width - num_digit; ++cnt)
1198 send(' ', send_arg2);
1199 ret += width - num_digit;
1201 break;
1204 // case 'y': { /* %y - print symbol */
1205 // Addr a = va_arg(vargs, Addr);
1207 // HChar *name;
1208 // if (VG_(get_fnname_w_offset)(a, &name)) {
1209 // HChar buf[1 + VG_strlen(name) + 1 + 1];
1210 // if (flags & VG_MSG_PAREN) {
1211 // VG_(sprintf)(str, "(%s)", name):
1212 // } else {
1213 // VG_(sprintf)(str, "%s", name):
1214 // }
1215 // ret += myvprintf_str(send, flags, width, buf, 0);
1216 // }
1217 // break;
1218 // }
1219 default:
1220 break;
1223 return ret;
1227 /*------------------------------------------------------------*/
1228 /*--- Debuglog stuff. ---*/
1229 /*------------------------------------------------------------*/
1231 /* Only print messages whose stated level is less than or equal to
1232 this. By default, it makes this entire subsystem silent. */
1234 static Int loglevel = 0;
1236 /* Module startup. */
1237 /* EXPORTED */
1238 void VG_(debugLog_startup) ( Int level, const HChar* who )
1240 if (level < 0) level = 0;
1241 if (level > 10) level = 10;
1242 loglevel = level;
1243 VG_(debugLog)(1, "debuglog",
1244 "DebugLog system started by %s, "
1245 "level %d logging requested\n",
1246 who, loglevel);
1249 /* Get the logging threshold level, as set by the most recent call to
1250 VG_(debugLog_startup), or zero if there have been no such calls so
1251 far. */
1252 /* EXPORTED */
1253 Int VG_(debugLog_getLevel) ( void )
1255 return loglevel;
1259 /* ------------ */
1261 typedef
1262 struct {
1263 HChar buf[100];
1264 Int n;
1266 printf_buf;
1268 static void add_to_buf ( HChar c, void* p )
1270 printf_buf* buf = (printf_buf*)p;
1272 if (buf->n >= 100-10 /*paranoia*/ ) {
1273 emit( buf->buf, local_strlen(buf->buf) );
1274 buf->n = 0;
1275 buf->buf[buf->n] = 0;
1277 buf->buf[buf->n++] = c;
1278 buf->buf[buf->n] = 0;
1281 /* Send a logging message. Nothing is output unless 'level'
1282 is <= the current loglevel. */
1283 /* EXPORTED */
1284 void VG_(debugLog) ( Int level, const HChar* modulename,
1285 const HChar* format, ... )
1287 UInt pid;
1288 Int indent, depth, i;
1289 va_list vargs;
1290 printf_buf buf;
1292 if (level > loglevel)
1293 return;
1295 indent = 2*level - 1;
1296 if (indent < 1) indent = 1;
1298 buf.n = 0;
1299 buf.buf[0] = 0;
1300 pid = local_sys_getpid();
1302 // Print one '>' in front of the messages for each level of self-hosting
1303 // being performed.
1304 depth = RUNNING_ON_VALGRIND;
1305 for (i = 0; i < depth; i++) {
1306 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
1309 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
1310 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
1311 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
1312 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
1313 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
1314 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, modulename, False );
1315 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
1317 va_start(vargs,format);
1319 (void) VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
1321 if (buf.n > 0) {
1322 emit( buf.buf, local_strlen(buf.buf) );
1325 va_end(vargs);
1330 /*--------------------------------------------------------------------*/
1331 /*--- end m_debuglog.c ---*/
1332 /*--------------------------------------------------------------------*/