blob: 7ad3f8c76b0110353e799fa01d5bf458a0b15b60 [file] [log] [blame]
sewardj1cf558c2005-04-25 01:36:56 +00001
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
sewardj9eecbbb2010-05-03 21:37:12 +000010 Copyright (C) 2000-2010 Julian Seward
sewardj1cf558c2005-04-25 01:36:56 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31
32/* Performs low-level debug logging that can safely run immediately
33 after startup. To minimise the dependencies on any other parts of
34 the system, the only place the debug output may go is file
35 descriptor 2 (stderr).
36*/
37/* This is the first-initialised module in the entire system!
38 Therefore it is CRITICAL that it does not depend on any other code
39 running first. Hence only the following very limited includes. We
40 cannot depend (directly or indirectly) on any dynamic memory
41 allocation facilities, nor on the m_libc facilities, since the
42 latter depend on this module. DO NOT MESS WITH THESE INCLUDES
43 UNLESS YOU ARE 100% CERTAIN YOU UNDERSTAND THE CONSEQUENCES.
44*/
sewardj1cf558c2005-04-25 01:36:56 +000045
njnc7561b92005-06-19 01:24:32 +000046/* This module is also notable because it is linked into both
47 stage1 and stage2. */
48
njnf76d27a2009-05-28 01:53:07 +000049/* 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
njnc7561b92005-06-19 01:24:32 +000054#include "pub_core_basics.h" /* basic types */
sewardj17edf032006-10-17 01:53:34 +000055#include "pub_core_vkiscnums.h" /* for syscall numbers */
njnc7561b92005-06-19 01:24:32 +000056#include "pub_core_debuglog.h" /* our own iface */
sewardj45f4e7c2005-09-27 19:20:21 +000057#include "valgrind.h" /* for RUNNING_ON_VALGRIND */
sewardj1cf558c2005-04-25 01:36:56 +000058
59/*------------------------------------------------------------*/
60/*--- Stuff to make us completely independent. ---*/
61/*------------------------------------------------------------*/
62
sewardj2c48c7b2005-11-29 13:05:56 +000063/* ----- Platform-specifics ----- */
sewardj1cf558c2005-04-25 01:36:56 +000064
sewardj21c6d0f2005-05-02 10:33:44 +000065#if defined(VGP_x86_linux)
sewardj1cf558c2005-04-25 01:36:56 +000066
67static UInt local_sys_write_stderr ( HChar* buf, Int n )
68{
sewardj17edf032006-10-17 01:53:34 +000069 volatile Int block[2];
sewardj55c43762006-04-28 21:01:33 +000070 block[0] = (Int)buf;
71 block[1] = n;
tom311400b2005-04-27 08:58:53 +000072 __asm__ volatile (
sewardj55c43762006-04-28 21:01:33 +000073 "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 */
sewardj17edf032006-10-17 01:53:34 +000078 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */
njn5ed05a52009-05-20 06:59:19 +000079 "movl $2, %%ebx\n" /* %ebx = stderr */
sewardj55c43762006-04-28 21:01:33 +000080 "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*/
sewardjf068f192011-04-26 07:52:44 +000085 : /*rd*/ "r" (block)
sewardj55c43762006-04-28 21:01:33 +000086 : /*trash*/ "eax", "edi", "ecx", "edx", "memory", "cc"
sewardjd4d203b2005-04-27 23:17:48 +000087 );
sewardj55c43762006-04-28 21:01:33 +000088 if (block[0] < 0)
89 block[0] = -1;
90 return block[0];
sewardj1cf558c2005-04-25 01:36:56 +000091}
92
93static UInt local_sys_getpid ( void )
94{
95 UInt __res;
tom311400b2005-04-27 08:58:53 +000096 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +000097 "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n" /* %eax = __NR_getpid */
tom311400b2005-04-27 08:58:53 +000098 "int $0x80\n" /* getpid() */
99 "movl %%eax, %0\n" /* set __res = eax */
sewardjd4d203b2005-04-27 23:17:48 +0000100 : "=mr" (__res)
101 :
102 : "eax" );
sewardj1cf558c2005-04-25 01:36:56 +0000103 return __res;
104}
105
sewardj21c6d0f2005-05-02 10:33:44 +0000106#elif defined(VGP_amd64_linux)
sewardj7337f922006-05-26 11:31:15 +0000107__attribute__((noinline))
sewardj601371a2005-04-25 16:21:17 +0000108static UInt local_sys_write_stderr ( HChar* buf, Int n )
109{
sewardj17edf032006-10-17 01:53:34 +0000110 volatile Long block[2];
sewardj7337f922006-05-26 11:31:15 +0000111 block[0] = (Long)buf;
112 block[1] = n;
tomc6121862005-04-27 09:23:02 +0000113 __asm__ volatile (
sewardj7337f922006-05-26 11:31:15 +0000114 "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 */
sewardj17edf032006-10-17 01:53:34 +0000118 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
sewardj7337f922006-05-26 11:31:15 +0000119 "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*/
sewardjf068f192011-04-26 07:52:44 +0000128 : /*rd*/ "r" (block)
sewardj7337f922006-05-26 11:31:15 +0000129 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc"
130 );
131 if (block[0] < 0)
132 block[0] = -1;
133 return (UInt)block[0];
sewardj601371a2005-04-25 16:21:17 +0000134}
135
136static UInt local_sys_getpid ( void )
137{
tomc6121862005-04-27 09:23:02 +0000138 UInt __res;
139 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +0000140 "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n" /* %rax = __NR_getpid */
tomc6121862005-04-27 09:23:02 +0000141 "syscall\n" /* getpid() */
142 "movl %%eax, %0\n" /* set __res = %eax */
143 : "=mr" (__res)
144 :
145 : "rax" );
146 return __res;
sewardj601371a2005-04-25 16:21:17 +0000147}
sewardj1cf558c2005-04-25 01:36:56 +0000148
cerion85665ca2005-06-20 15:51:07 +0000149#elif defined(VGP_ppc32_linux)
150
151static UInt local_sys_write_stderr ( HChar* buf, Int n )
152{
sewardj17edf032006-10-17 01:53:34 +0000153 volatile Int block[2];
sewardja2699582006-05-22 13:04:42 +0000154 block[0] = (Int)buf;
155 block[1] = n;
cerion85665ca2005-06-20 15:51:07 +0000156 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000157 "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 */
sewardj17edf032006-10-17 01:53:34 +0000160 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* set %r0 = __NR_write */
sewardja2699582006-05-22 13:04:42 +0000161 "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];
cerion85665ca2005-06-20 15:51:07 +0000176}
177
178static UInt local_sys_getpid ( void )
179{
sewardja2699582006-05-22 13:04:42 +0000180 register UInt __res __asm__ ("r3");
181 __asm__ volatile (
182 "li 0, %1\n\t"
183 "sc"
184 : "=&r" (__res)
sewardj17edf032006-10-17 01:53:34 +0000185 : "i" (__NR_getpid)
sewardja2699582006-05-22 13:04:42 +0000186 : "cc","memory","cr0","ctr",
187 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
188 );
cerion85665ca2005-06-20 15:51:07 +0000189 return __res;
190}
191
sewardj2c48c7b2005-11-29 13:05:56 +0000192#elif defined(VGP_ppc64_linux)
193
194static UInt local_sys_write_stderr ( HChar* buf, Int n )
195{
sewardj17edf032006-10-17 01:53:34 +0000196 volatile Long block[2];
sewardja2699582006-05-22 13:04:42 +0000197 block[0] = (Long)buf;
198 block[1] = (Long)n;
sewardj2c48c7b2005-11-29 13:05:56 +0000199 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000200 "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 */
sewardj17edf032006-10-17 01:53:34 +0000203 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* %r0 = __NR_write */
sewardja2699582006-05-22 13:04:42 +0000204 "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];
sewardj2c48c7b2005-11-29 13:05:56 +0000219}
220
221static UInt local_sys_getpid ( void )
222{
sewardja2699582006-05-22 13:04:42 +0000223 register ULong __res __asm__ ("r3");
224 __asm__ volatile (
225 "li 0, %1\n\t"
226 "sc"
227 : "=&r" (__res)
sewardj17edf032006-10-17 01:53:34 +0000228 : "i" (__NR_getpid)
sewardja2699582006-05-22 13:04:42 +0000229 : "cc","memory","cr0","ctr",
230 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
231 );
232 return (UInt)__res;
sewardj2c48c7b2005-11-29 13:05:56 +0000233}
234
sewardj59570ff2010-01-01 11:59:33 +0000235#elif defined(VGP_arm_linux)
236
237static 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 (
sewardj188a6d72010-08-26 09:40:37 +0000243 "mov r0, #2\n\t" /* stderr */
244 "ldr r1, [%0]\n\t" /* buf */
245 "ldr r2, [%0, #4]\n\t" /* n */
sewardj59570ff2010-01-01 11:59:33 +0000246 "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
258static 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
njnf76d27a2009-05-28 01:53:07 +0000271#elif defined(VGP_x86_darwin)
272
njn1a1e95c2009-06-03 06:50:06 +0000273/* We would use VG_DARWIN_SYSNO_TO_KERNEL instead of VG_DARWIN_SYSNO_INDEX
274 except that the former has a C ternary ?: operator which isn't valid in
275 asm code. Both macros give the same results for Unix-class syscalls (which
276 these all are, as identified by the use of 'int 0x80'). */
njnf76d27a2009-05-28 01:53:07 +0000277__attribute__((noinline))
278static UInt local_sys_write_stderr ( HChar* buf, Int n )
279{
280 UInt __res;
281 __asm__ volatile (
282 "movl %2, %%eax\n" /* push n */
283 "pushl %%eax\n"
284 "movl %1, %%eax\n" /* push buf */
285 "pushl %%eax\n"
286 "movl $2, %%eax\n" /* push stderr */
287 "pushl %%eax\n"
288 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
289 ", %%eax\n"
290 "pushl %%eax\n" /* push fake return address */
291 "int $0x80\n" /* write(stderr, buf, n) */
292 "jnc 1f\n" /* jump if no error */
293 "movl $-1, %%eax\n" /* return -1 if error */
294 "1: "
295 "movl %%eax, %0\n" /* __res = eax */
296 "addl $16, %%esp\n" /* pop x4 */
297 : "=mr" (__res)
298 : "g" (buf), "g" (n)
299 : "eax", "edx", "cc"
300 );
301 return __res;
302}
303
304static UInt local_sys_getpid ( void )
305{
306 UInt __res;
307 __asm__ volatile (
308 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
309 "int $0x80\n" /* getpid() */
310 "movl %%eax, %0\n" /* set __res = eax */
311 : "=mr" (__res)
312 :
313 : "eax", "cc" );
314 return __res;
315}
316
317#elif defined(VGP_amd64_darwin)
318
319__attribute__((noinline))
320static UInt local_sys_write_stderr ( HChar* buf, Int n )
321{
322 UInt __res;
323 __asm__ volatile (
324 "movq $2, %%rdi\n" /* push stderr */
325 "movq %1, %%rsi\n" /* push buf */
326 "movl %2, %%edx\n" /* push n */
njn1a1e95c2009-06-03 06:50:06 +0000327 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_write_nocancel))
njnf76d27a2009-05-28 01:53:07 +0000328 ", %%eax\n"
329 "syscall\n" /* write(stderr, buf, n) */
330 "jnc 1f\n" /* jump if no error */
331 "movq $-1, %%rax\n" /* return -1 if error */
332 "1: "
333 "movl %%eax, %0\n" /* __res = eax */
334 : "=mr" (__res)
335 : "g" (buf), "g" (n)
336 : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
337 return __res;
338}
339
340static UInt local_sys_getpid ( void )
341{
342 UInt __res;
343 __asm__ volatile (
njn1a1e95c2009-06-03 06:50:06 +0000344 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_getpid))", %%eax\n"
njnf76d27a2009-05-28 01:53:07 +0000345 "syscall\n" /* getpid() */
346 "movl %%eax, %0\n" /* set __res = eax */
347 : "=mr" (__res)
348 :
349 : "rax", "rcx", "cc" );
350 return __res;
351}
352
sewardjb5b87402011-03-07 16:05:35 +0000353#elif defined(VGP_s390x_linux)
354static UInt local_sys_write_stderr ( HChar* buf, Int n )
355{
356 register Int r2 asm("2") = 2; /* file descriptor STDERR */
357 register HChar* r3 asm("3") = buf;
358 register ULong r4 asm("4") = n;
359 register ULong r2_res asm("2");
360 ULong __res;
361
362 __asm__ __volatile__ (
363 "svc %b1\n"
364 : "=d" (r2_res)
365 : "i" (__NR_write),
366 "0" (r2),
367 "d" (r3),
368 "d" (r4)
369 : "cc", "memory");
370 __res = r2_res;
371
372 if (__res >= (ULong)(-125))
373 __res = -1;
374 return (UInt)(__res);
375}
376
377static UInt local_sys_getpid ( void )
378{
379 register ULong r2 asm("2");
380 ULong __res;
381
382 __asm__ __volatile__ (
383 "svc %b1\n"
384 : "=d" (r2)
385 : "i" (__NR_getpid)
386 : "cc", "memory");
387 __res = r2;
388
389 if (__res >= (ULong)(-125))
390 __res = -1;
391 return (UInt)(__res);
392}
393
394
sewardj1cf558c2005-04-25 01:36:56 +0000395#else
sewardj21c6d0f2005-05-02 10:33:44 +0000396# error Unknown platform
sewardj1cf558c2005-04-25 01:36:56 +0000397#endif
398
399
400/* ----- generic ----- */
401
402/* strlen, so we don't need m_libc */
403static Int local_strlen ( const HChar* str )
404{
405 Int i = 0;
406 while (str[i] != 0) i++;
407 return i;
408}
409
410static HChar local_toupper ( HChar c )
411{
412 if (c >= 'a' && c <= 'z')
413 return c + ('A' - 'a');
414 else
415 return c;
416}
417
418/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
419*/
420static void emit ( HChar* buf, Int n )
421{
422 if (n >= 1)
423 (void)local_sys_write_stderr(buf, n);
424}
425
426
427/*------------------------------------------------------------*/
428/*--- A simple, generic, vprintf implementation. ---*/
429/*------------------------------------------------------------*/
430
431/* -----------------------------------------------
432 Distantly derived from:
433
434 vprintf replacement for Checker.
435 Copyright 1993, 1994, 1995 Tristan Gingold
436 Written September 1993 Tristan Gingold
437 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
438
439 (Checker itself was GPL'd.)
440 ----------------------------------------------- */
441
442/* Some flags. */
443#define VG_MSG_SIGNED 1 /* The value is signed. */
444#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
445#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
446#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
447#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
barta0b6b2c2008-07-07 06:49:24 +0000448#define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
sewardj1cf558c2005-04-25 01:36:56 +0000449
450/* Copy a string into the buffer. */
451static
452UInt myvprintf_str ( void(*send)(HChar,void*),
453 void* send_arg2,
454 Int flags,
455 Int width,
456 HChar* str,
457 Bool capitalise )
458{
459# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
460 UInt ret = 0;
461 Int i, extra;
462 Int len = local_strlen(str);
463
464 if (width == 0) {
465 ret += len;
466 for (i = 0; i < len; i++)
467 send(MAYBE_TOUPPER(str[i]), send_arg2);
468 return ret;
469 }
470
471 if (len > width) {
472 ret += width;
473 for (i = 0; i < width; i++)
474 send(MAYBE_TOUPPER(str[i]), send_arg2);
475 return ret;
476 }
477
478 extra = width - len;
479 if (flags & VG_MSG_LJUSTIFY) {
480 ret += extra;
481 for (i = 0; i < extra; i++)
482 send(' ', send_arg2);
483 }
484 ret += len;
485 for (i = 0; i < len; i++)
486 send(MAYBE_TOUPPER(str[i]), send_arg2);
487 if (!(flags & VG_MSG_LJUSTIFY)) {
488 ret += extra;
489 for (i = 0; i < extra; i++)
490 send(' ', send_arg2);
491 }
492
493# undef MAYBE_TOUPPER
494 return ret;
495}
496
497
sewardjdaf77af2005-07-19 14:17:37 +0000498/* Copy a string into the buffer, escaping bad XML chars. */
499static
500UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
501 void* send_arg2,
502 HChar* str )
503{
504 UInt ret = 0;
505 Int i;
506 Int len = local_strlen(str);
507 HChar* alt;
508
509 for (i = 0; i < len; i++) {
510 switch (str[i]) {
511 case '&': alt = "&amp;"; break;
512 case '<': alt = "&lt;"; break;
513 case '>': alt = "&gt;"; break;
514 default: alt = NULL;
515 }
516
517 if (alt) {
518 while (*alt) {
519 send(*alt, send_arg2);
520 ret++;
521 alt++;
522 }
523 } else {
524 send(str[i], send_arg2);
525 ret++;
526 }
527 }
528
529 return ret;
530}
531
532
sewardj1cf558c2005-04-25 01:36:56 +0000533/* Write P into the buffer according to these args:
534 * If SIGN is true, p is a signed.
535 * BASE is the base.
536 * If WITH_ZERO is true, '0' must be added.
537 * WIDTH is the width of the field.
538 */
539static
540UInt myvprintf_int64 ( void(*send)(HChar,void*),
541 void* send_arg2,
542 Int flags,
543 Int base,
544 Int width,
sewardja44b15f2007-02-16 14:10:24 +0000545 Bool capitalised,
sewardj1cf558c2005-04-25 01:36:56 +0000546 ULong p )
547{
548 HChar buf[40];
549 Int ind = 0;
550 Int i, nc = 0;
551 Bool neg = False;
sewardja44b15f2007-02-16 14:10:24 +0000552 HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
sewardj1cf558c2005-04-25 01:36:56 +0000553 UInt ret = 0;
554
555 if (base < 2 || base > 16)
556 return ret;
557
558 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
559 p = - (Long)p;
560 neg = True;
561 }
562
563 if (p == 0)
564 buf[ind++] = '0';
565 else {
566 while (p > 0) {
567 if (flags & VG_MSG_COMMA && 10 == base &&
568 0 == (ind-nc) % 3 && 0 != ind)
569 {
570 buf[ind++] = ',';
571 nc++;
572 }
573 buf[ind++] = digits[p % base];
574 p /= base;
575 }
576 }
577
578 if (neg)
579 buf[ind++] = '-';
580
581 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
582 for(; ind < width; ind++) {
583 /* vg_assert(ind < 39); */
584 if (ind > 39) {
585 buf[39] = 0;
586 break;
587 }
588 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
589 }
590 }
591
592 /* Reverse copy to buffer. */
593 ret += ind;
594 for (i = ind -1; i >= 0; i--) {
595 send(buf[i], send_arg2);
596 }
597 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
598 for(; ind < width; ind++) {
599 ret++;
600 /* Never pad with zeroes on RHS -- changes the value! */
601 send(' ', send_arg2);
602 }
603 }
604 return ret;
605}
606
607
608/* A simple vprintf(). */
609/* EXPORTED */
610UInt
611VG_(debugLog_vprintf) (
612 void(*send)(HChar,void*),
613 void* send_arg2,
614 const HChar* format,
615 va_list vargs
616)
617{
618 UInt ret = 0;
619 Int i;
620 Int flags;
621 Int width;
njn68e46592005-08-26 19:42:27 +0000622 Int n_ls = 0;
sewardja44b15f2007-02-16 14:10:24 +0000623 Bool is_long, caps;
sewardj1cf558c2005-04-25 01:36:56 +0000624
625 /* We assume that vargs has already been initialised by the
626 caller, using va_start, and that the caller will similarly
627 clean up with va_end.
628 */
629
630 for (i = 0; format[i] != 0; i++) {
631 if (format[i] != '%') {
632 send(format[i], send_arg2);
633 ret++;
634 continue;
635 }
636 i++;
637 /* A '%' has been found. Ignore a trailing %. */
638 if (format[i] == 0)
639 break;
640 if (format[i] == '%') {
njn02bc4b82005-05-15 17:28:26 +0000641 /* '%%' is replaced by '%'. */
sewardj1cf558c2005-04-25 01:36:56 +0000642 send('%', send_arg2);
643 ret++;
644 continue;
645 }
646 flags = 0;
njn68e46592005-08-26 19:42:27 +0000647 n_ls = 0;
sewardj1cf558c2005-04-25 01:36:56 +0000648 width = 0; /* length of the field. */
barta0b6b2c2008-07-07 06:49:24 +0000649 while (1) {
650 switch (format[i]) {
651 case '(':
652 flags |= VG_MSG_PAREN;
653 break;
654 case ',':
655 case '\'':
656 /* If ',' or '\'' follows '%', commas will be inserted. */
657 flags |= VG_MSG_COMMA;
658 break;
659 case '-':
660 /* If '-' follows '%', justify on the left. */
661 flags |= VG_MSG_LJUSTIFY;
662 break;
663 case '0':
664 /* If '0' follows '%', pads will be inserted. */
665 flags |= VG_MSG_ZJUSTIFY;
666 break;
667 case '#':
668 /* If '#' follows '%', alternative format will be used. */
669 flags |= VG_MSG_ALTFORMAT;
670 break;
671 default:
672 goto parse_fieldwidth;
673 }
sewardj1cf558c2005-04-25 01:36:56 +0000674 i++;
675 }
barta0b6b2c2008-07-07 06:49:24 +0000676 parse_fieldwidth:
sewardj1cf558c2005-04-25 01:36:56 +0000677 /* Compute the field length. */
678 while (format[i] >= '0' && format[i] <= '9') {
679 width *= 10;
680 width += format[i++] - '0';
681 }
682 while (format[i] == 'l') {
683 i++;
njn68e46592005-08-26 19:42:27 +0000684 n_ls++;
sewardj1cf558c2005-04-25 01:36:56 +0000685 }
686
njn68e46592005-08-26 19:42:27 +0000687 // %d means print a 32-bit integer.
688 // %ld means print a word-size integer.
689 // %lld means print a 64-bit integer.
690 if (0 == n_ls) { is_long = False; }
691 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
692 else { is_long = True; }
693
sewardj1cf558c2005-04-25 01:36:56 +0000694 switch (format[i]) {
bart042257f2009-07-26 08:40:17 +0000695 case 'o': /* %o */
696 if (flags & VG_MSG_ALTFORMAT) {
697 ret += 2;
698 send('0',send_arg2);
699 }
700 if (is_long)
701 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
702 (ULong)(va_arg (vargs, ULong)));
703 else
704 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
705 (ULong)(va_arg (vargs, UInt)));
706 break;
sewardj1cf558c2005-04-25 01:36:56 +0000707 case 'd': /* %d */
708 flags |= VG_MSG_SIGNED;
709 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000710 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000711 (ULong)(va_arg (vargs, Long)));
712 else
sewardja44b15f2007-02-16 14:10:24 +0000713 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000714 (ULong)(va_arg (vargs, Int)));
715 break;
716 case 'u': /* %u */
717 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000718 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000719 (ULong)(va_arg (vargs, ULong)));
720 else
sewardja44b15f2007-02-16 14:10:24 +0000721 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000722 (ULong)(va_arg (vargs, UInt)));
723 break;
bartb3af9cf2011-10-06 19:08:37 +0000724 case 'p':
725 if (format[i+1] == 'S') {
726 i++;
727 /* %pS, like %s but escaping chars for XML safety */
728 /* Note: simplistic; ignores field width and flags */
729 char *str = va_arg (vargs, char *);
730 if (str == (char*) 0)
731 str = "(null)";
732 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
733 } else {
734 /* %p */
735 ret += 2;
736 send('0',send_arg2);
737 send('x',send_arg2);
738 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
739 (ULong)((UWord)va_arg (vargs, void *)));
740 }
sewardj1cf558c2005-04-25 01:36:56 +0000741 break;
742 case 'x': /* %x */
sewardja44b15f2007-02-16 14:10:24 +0000743 case 'X': /* %X */
744 caps = toBool(format[i] == 'X');
barta0b6b2c2008-07-07 06:49:24 +0000745 if (flags & VG_MSG_ALTFORMAT) {
746 ret += 2;
747 send('0',send_arg2);
748 send('x',send_arg2);
749 }
sewardj1cf558c2005-04-25 01:36:56 +0000750 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000751 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000752 (ULong)(va_arg (vargs, ULong)));
753 else
sewardja44b15f2007-02-16 14:10:24 +0000754 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000755 (ULong)(va_arg (vargs, UInt)));
756 break;
757 case 'c': /* %c */
758 ret++;
759 send(va_arg (vargs, int), send_arg2);
760 break;
761 case 's': case 'S': { /* %s */
762 char *str = va_arg (vargs, char *);
763 if (str == (char*) 0) str = "(null)";
764 ret += myvprintf_str(send, send_arg2,
765 flags, width, str, format[i]=='S');
766 break;
767 }
sewardjdaf77af2005-07-19 14:17:37 +0000768
sewardj1cf558c2005-04-25 01:36:56 +0000769// case 'y': { /* %y - print symbol */
770// Char buf[100];
771// Char *cp = buf;
772// Addr a = va_arg(vargs, Addr);
773//
774// if (flags & VG_MSG_PAREN)
775// *cp++ = '(';
776// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
777// if (flags & VG_MSG_PAREN) {
778// cp += VG_(strlen)(cp);
779// *cp++ = ')';
780// *cp = '\0';
781// }
782// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
783// }
784// break;
785// }
786 default:
787 break;
788 }
789 }
790 return ret;
791}
792
793
794/*------------------------------------------------------------*/
795/*--- Debuglog stuff. ---*/
796/*------------------------------------------------------------*/
797
798/* Only print messages whose stated level is less than or equal to
799 this. By default, it makes this entire subsystem silent. */
800
801static Int loglevel = 0;
802
sewardj1cf558c2005-04-25 01:36:56 +0000803/* Module startup. */
sewardj10759312005-05-30 23:52:47 +0000804/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000805void VG_(debugLog_startup) ( Int level, HChar* who )
806{
807 if (level < 0) level = 0;
808 if (level > 10) level = 10;
809 loglevel = level;
810 VG_(debugLog)(1, "debuglog",
811 "DebugLog system started by %s, "
812 "level %d logging requested\n",
813 who, loglevel);
814}
815
sewardj10759312005-05-30 23:52:47 +0000816/* Get the logging threshold level, as set by the most recent call to
817 VG_(debugLog_startup), or zero if there have been no such calls so
818 far. */
819/* EXPORTED */
820Int VG_(debugLog_getLevel) ( void )
821{
822 return loglevel;
823}
824
825
sewardj1cf558c2005-04-25 01:36:56 +0000826/* ------------ */
827
828typedef
829 struct {
830 HChar buf[100];
831 Int n;
832 }
833 printf_buf;
834
835static void add_to_buf ( HChar c, void* p )
836{
837 printf_buf* buf = (printf_buf*)p;
838
839 if (buf->n >= 100-10 /*paranoia*/ ) {
840 emit( buf->buf, local_strlen(buf->buf) );
841 buf->n = 0;
842 buf->buf[buf->n] = 0;
843 }
844 buf->buf[buf->n++] = c;
845 buf->buf[buf->n] = 0;
846}
847
848/* Send a logging message. Nothing is output unless 'level'
849 is <= the current loglevel. */
850/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000851void VG_(debugLog) ( Int level, const HChar* modulename,
852 const HChar* format, ... )
853{
sewardjc7ffc942011-03-28 16:26:42 +0000854 UInt pid;
sewardj45f4e7c2005-09-27 19:20:21 +0000855 Int indent, depth, i;
sewardj1cf558c2005-04-25 01:36:56 +0000856 va_list vargs;
857 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000858
sewardj1cf558c2005-04-25 01:36:56 +0000859 if (level > loglevel)
860 return;
861
sewardjd85feff2005-04-25 02:37:56 +0000862 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000863 if (indent < 1) indent = 1;
864
sewardj1cf558c2005-04-25 01:36:56 +0000865 buf.n = 0;
866 buf.buf[0] = 0;
867 pid = local_sys_getpid();
sewardj45f4e7c2005-09-27 19:20:21 +0000868
869 // Print one '>' in front of the messages for each level of self-hosting
870 // being performed.
871 depth = RUNNING_ON_VALGRIND;
872 for (i = 0; i < depth; i++) {
873 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
874 }
875
sewardja5ebfa92005-04-25 02:04:54 +0000876 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
sewardja44b15f2007-02-16 14:10:24 +0000877 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
sewardja5ebfa92005-04-25 02:04:54 +0000878 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardja44b15f2007-02-16 14:10:24 +0000879 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000880 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000881 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000882 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000883
884 va_start(vargs,format);
885
sewardjc7ffc942011-03-28 16:26:42 +0000886 (void) VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
sewardj1cf558c2005-04-25 01:36:56 +0000887
888 if (buf.n > 0) {
889 emit( buf.buf, local_strlen(buf.buf) );
890 }
891
892 va_end(vargs);
893}
894
895
896
897/*--------------------------------------------------------------------*/
898/*--- end m_debuglog.c ---*/
899/*--------------------------------------------------------------------*/