blob: 8e1c032742db0ff4919aeab1a927fed60f878bd3 [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
sewardjec062e82011-10-23 07:32:08 +000010 Copyright (C) 2000-2011 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
bartdb4384e2011-10-11 18:49:35 +000059static Bool clo_xml;
60
61void VG_(debugLog_setXml)(Bool xml)
62{
63 clo_xml = xml;
64}
65
sewardj1cf558c2005-04-25 01:36:56 +000066/*------------------------------------------------------------*/
67/*--- Stuff to make us completely independent. ---*/
68/*------------------------------------------------------------*/
69
sewardj2c48c7b2005-11-29 13:05:56 +000070/* ----- Platform-specifics ----- */
sewardj1cf558c2005-04-25 01:36:56 +000071
sewardj21c6d0f2005-05-02 10:33:44 +000072#if defined(VGP_x86_linux)
sewardj1cf558c2005-04-25 01:36:56 +000073
74static UInt local_sys_write_stderr ( HChar* buf, Int n )
75{
bartdf0c09e2012-01-30 15:07:20 +000076 Int result;
77
tom311400b2005-04-27 08:58:53 +000078 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +000079 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */
njn5ed05a52009-05-20 06:59:19 +000080 "movl $2, %%ebx\n" /* %ebx = stderr */
sewardj55c43762006-04-28 21:01:33 +000081 "int $0x80\n" /* write(stderr, buf, n) */
bartdf0c09e2012-01-30 15:07:20 +000082 : /*wr*/ "=a" (result)
83 : /*rd*/ "c" (buf), "d" (n)
84 : /*trash*/ "ebx", "edi", "memory", "cc"
sewardjd4d203b2005-04-27 23:17:48 +000085 );
bartdf0c09e2012-01-30 15:07:20 +000086
87 return result >= 0 ? result : -1;
sewardj1cf558c2005-04-25 01:36:56 +000088}
89
90static UInt local_sys_getpid ( void )
91{
92 UInt __res;
tom311400b2005-04-27 08:58:53 +000093 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +000094 "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n" /* %eax = __NR_getpid */
tom311400b2005-04-27 08:58:53 +000095 "int $0x80\n" /* getpid() */
96 "movl %%eax, %0\n" /* set __res = eax */
sewardjd4d203b2005-04-27 23:17:48 +000097 : "=mr" (__res)
98 :
99 : "eax" );
sewardj1cf558c2005-04-25 01:36:56 +0000100 return __res;
101}
102
sewardj21c6d0f2005-05-02 10:33:44 +0000103#elif defined(VGP_amd64_linux)
sewardj7337f922006-05-26 11:31:15 +0000104__attribute__((noinline))
sewardj601371a2005-04-25 16:21:17 +0000105static UInt local_sys_write_stderr ( HChar* buf, Int n )
106{
sewardj17edf032006-10-17 01:53:34 +0000107 volatile Long block[2];
sewardj7337f922006-05-26 11:31:15 +0000108 block[0] = (Long)buf;
109 block[1] = n;
tomc6121862005-04-27 09:23:02 +0000110 __asm__ volatile (
sewardj7337f922006-05-26 11:31:15 +0000111 "subq $256, %%rsp\n" /* don't trash the stack redzone */
112 "pushq %%r15\n" /* r15 is callee-save */
113 "movq %0, %%r15\n" /* r15 = &block */
114 "pushq %%r15\n" /* save &block */
sewardj17edf032006-10-17 01:53:34 +0000115 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
sewardj7337f922006-05-26 11:31:15 +0000116 "movq $2, %%rdi\n" /* rdi = stderr */
117 "movq 0(%%r15), %%rsi\n" /* rsi = buf */
118 "movq 8(%%r15), %%rdx\n" /* rdx = n */
119 "syscall\n" /* write(stderr, buf, n) */
120 "popq %%r15\n" /* reestablish &block */
121 "movq %%rax, 0(%%r15)\n" /* block[0] = result */
122 "popq %%r15\n" /* restore r15 */
123 "addq $256, %%rsp\n" /* restore stack ptr */
124 : /*wr*/
sewardjf068f192011-04-26 07:52:44 +0000125 : /*rd*/ "r" (block)
sewardj7337f922006-05-26 11:31:15 +0000126 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc"
127 );
128 if (block[0] < 0)
129 block[0] = -1;
130 return (UInt)block[0];
sewardj601371a2005-04-25 16:21:17 +0000131}
132
133static UInt local_sys_getpid ( void )
134{
tomc6121862005-04-27 09:23:02 +0000135 UInt __res;
136 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +0000137 "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n" /* %rax = __NR_getpid */
tomc6121862005-04-27 09:23:02 +0000138 "syscall\n" /* getpid() */
139 "movl %%eax, %0\n" /* set __res = %eax */
140 : "=mr" (__res)
141 :
142 : "rax" );
143 return __res;
sewardj601371a2005-04-25 16:21:17 +0000144}
sewardj1cf558c2005-04-25 01:36:56 +0000145
cerion85665ca2005-06-20 15:51:07 +0000146#elif defined(VGP_ppc32_linux)
147
148static UInt local_sys_write_stderr ( HChar* buf, Int n )
149{
sewardj17edf032006-10-17 01:53:34 +0000150 volatile Int block[2];
sewardja2699582006-05-22 13:04:42 +0000151 block[0] = (Int)buf;
152 block[1] = n;
cerion85665ca2005-06-20 15:51:07 +0000153 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000154 "addi 1,1,-256\n\t"
155 "mr 5,%0\n\t" /* r5 = &block[0] */
156 "stw 5,0(1)\n\t" /* stash on stack */
sewardj17edf032006-10-17 01:53:34 +0000157 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* set %r0 = __NR_write */
sewardja2699582006-05-22 13:04:42 +0000158 "li 3,2\n\t" /* set %r3 = stderr */
159 "lwz 4,0(5)\n\t" /* set %r4 = buf */
160 "lwz 5,4(5)\n\t" /* set %r5 = n */
161 "sc\n\t" /* write(stderr, buf, n) */
162 "lwz 5,0(1)\n\t"
163 "addi 1,1,256\n\t"
164 "stw 3,0(5)\n" /* block[0] = result */
165 :
166 : "b" (block)
167 : "cc","memory","cr0","ctr",
168 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
169 );
170 if (block[0] < 0)
171 block[0] = -1;
172 return (UInt)block[0];
cerion85665ca2005-06-20 15:51:07 +0000173}
174
175static UInt local_sys_getpid ( void )
176{
sewardja2699582006-05-22 13:04:42 +0000177 register UInt __res __asm__ ("r3");
178 __asm__ volatile (
179 "li 0, %1\n\t"
180 "sc"
181 : "=&r" (__res)
sewardj17edf032006-10-17 01:53:34 +0000182 : "i" (__NR_getpid)
sewardja2699582006-05-22 13:04:42 +0000183 : "cc","memory","cr0","ctr",
184 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
185 );
cerion85665ca2005-06-20 15:51:07 +0000186 return __res;
187}
188
sewardj2c48c7b2005-11-29 13:05:56 +0000189#elif defined(VGP_ppc64_linux)
190
191static UInt local_sys_write_stderr ( HChar* buf, Int n )
192{
sewardj17edf032006-10-17 01:53:34 +0000193 volatile Long block[2];
sewardja2699582006-05-22 13:04:42 +0000194 block[0] = (Long)buf;
195 block[1] = (Long)n;
sewardj2c48c7b2005-11-29 13:05:56 +0000196 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000197 "addi 1,1,-256\n\t"
198 "mr 5,%0\n\t" /* r5 = &block[0] */
199 "std 5,0(1)\n\t" /* stash on stack */
sewardj17edf032006-10-17 01:53:34 +0000200 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* %r0 = __NR_write */
sewardja2699582006-05-22 13:04:42 +0000201 "li 3,2\n\t" /* set %r3 = stderr */
202 "ld 4,0(5)\n\t" /* set %r4 = buf */
203 "ld 5,8(5)\n\t" /* set %r5 = n */
204 "sc\n\t" /* write(stderr, buf, n) */
205 "ld 5,0(1)\n\t"
206 "addi 1,1,256\n\t"
207 "std 3,0(5)\n" /* block[0] = result */
208 :
209 : "b" (block)
210 : "cc","memory","cr0","ctr",
211 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
212 );
213 if (block[0] < 0)
214 block[0] = -1;
215 return (UInt)(Int)block[0];
sewardj2c48c7b2005-11-29 13:05:56 +0000216}
217
218static UInt local_sys_getpid ( void )
219{
sewardja2699582006-05-22 13:04:42 +0000220 register ULong __res __asm__ ("r3");
221 __asm__ volatile (
222 "li 0, %1\n\t"
223 "sc"
224 : "=&r" (__res)
sewardj17edf032006-10-17 01:53:34 +0000225 : "i" (__NR_getpid)
sewardja2699582006-05-22 13:04:42 +0000226 : "cc","memory","cr0","ctr",
227 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
228 );
229 return (UInt)__res;
sewardj2c48c7b2005-11-29 13:05:56 +0000230}
231
sewardj59570ff2010-01-01 11:59:33 +0000232#elif defined(VGP_arm_linux)
233
234static UInt local_sys_write_stderr ( HChar* buf, Int n )
235{
236 volatile Int block[2];
237 block[0] = (Int)buf;
238 block[1] = n;
239 __asm__ volatile (
sewardj188a6d72010-08-26 09:40:37 +0000240 "mov r0, #2\n\t" /* stderr */
241 "ldr r1, [%0]\n\t" /* buf */
242 "ldr r2, [%0, #4]\n\t" /* n */
sewardj59570ff2010-01-01 11:59:33 +0000243 "mov r7, #"VG_STRINGIFY(__NR_write)"\n\t"
244 "svc 0x0\n" /* write() */
245 "str r0, [%0]\n\t"
246 :
247 : "r" (block)
248 : "r0","r1","r2","r7"
249 );
250 if (block[0] < 0)
251 block[0] = -1;
252 return (UInt)block[0];
253}
254
255static UInt local_sys_getpid ( void )
256{
257 UInt __res;
258 __asm__ volatile (
259 "mov r7, #"VG_STRINGIFY(__NR_getpid)"\n"
260 "svc 0x0\n" /* getpid() */
261 "mov %0, r0\n"
262 : "=r" (__res)
263 :
264 : "r0", "r7" );
265 return __res;
266}
267
njnf76d27a2009-05-28 01:53:07 +0000268#elif defined(VGP_x86_darwin)
269
njn1a1e95c2009-06-03 06:50:06 +0000270/* We would use VG_DARWIN_SYSNO_TO_KERNEL instead of VG_DARWIN_SYSNO_INDEX
271 except that the former has a C ternary ?: operator which isn't valid in
272 asm code. Both macros give the same results for Unix-class syscalls (which
273 these all are, as identified by the use of 'int 0x80'). */
njnf76d27a2009-05-28 01:53:07 +0000274__attribute__((noinline))
275static UInt local_sys_write_stderr ( HChar* buf, Int n )
276{
277 UInt __res;
278 __asm__ volatile (
279 "movl %2, %%eax\n" /* push n */
280 "pushl %%eax\n"
281 "movl %1, %%eax\n" /* push buf */
282 "pushl %%eax\n"
283 "movl $2, %%eax\n" /* push stderr */
284 "pushl %%eax\n"
285 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
286 ", %%eax\n"
287 "pushl %%eax\n" /* push fake return address */
288 "int $0x80\n" /* write(stderr, buf, n) */
289 "jnc 1f\n" /* jump if no error */
290 "movl $-1, %%eax\n" /* return -1 if error */
291 "1: "
292 "movl %%eax, %0\n" /* __res = eax */
293 "addl $16, %%esp\n" /* pop x4 */
294 : "=mr" (__res)
295 : "g" (buf), "g" (n)
296 : "eax", "edx", "cc"
297 );
298 return __res;
299}
300
301static UInt local_sys_getpid ( void )
302{
303 UInt __res;
304 __asm__ volatile (
305 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
306 "int $0x80\n" /* getpid() */
307 "movl %%eax, %0\n" /* set __res = eax */
308 : "=mr" (__res)
309 :
310 : "eax", "cc" );
311 return __res;
312}
313
314#elif defined(VGP_amd64_darwin)
315
316__attribute__((noinline))
317static UInt local_sys_write_stderr ( HChar* buf, Int n )
318{
319 UInt __res;
320 __asm__ volatile (
321 "movq $2, %%rdi\n" /* push stderr */
322 "movq %1, %%rsi\n" /* push buf */
323 "movl %2, %%edx\n" /* push n */
njn1a1e95c2009-06-03 06:50:06 +0000324 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_write_nocancel))
njnf76d27a2009-05-28 01:53:07 +0000325 ", %%eax\n"
326 "syscall\n" /* write(stderr, buf, n) */
327 "jnc 1f\n" /* jump if no error */
328 "movq $-1, %%rax\n" /* return -1 if error */
329 "1: "
330 "movl %%eax, %0\n" /* __res = eax */
331 : "=mr" (__res)
332 : "g" (buf), "g" (n)
333 : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
334 return __res;
335}
336
337static UInt local_sys_getpid ( void )
338{
339 UInt __res;
340 __asm__ volatile (
njn1a1e95c2009-06-03 06:50:06 +0000341 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_getpid))", %%eax\n"
njnf76d27a2009-05-28 01:53:07 +0000342 "syscall\n" /* getpid() */
343 "movl %%eax, %0\n" /* set __res = eax */
344 : "=mr" (__res)
345 :
346 : "rax", "rcx", "cc" );
347 return __res;
348}
349
sewardjb5b87402011-03-07 16:05:35 +0000350#elif defined(VGP_s390x_linux)
351static UInt local_sys_write_stderr ( HChar* buf, Int n )
352{
353 register Int r2 asm("2") = 2; /* file descriptor STDERR */
354 register HChar* r3 asm("3") = buf;
355 register ULong r4 asm("4") = n;
356 register ULong r2_res asm("2");
357 ULong __res;
358
359 __asm__ __volatile__ (
360 "svc %b1\n"
361 : "=d" (r2_res)
362 : "i" (__NR_write),
363 "0" (r2),
364 "d" (r3),
365 "d" (r4)
366 : "cc", "memory");
367 __res = r2_res;
368
369 if (__res >= (ULong)(-125))
370 __res = -1;
371 return (UInt)(__res);
372}
373
374static UInt local_sys_getpid ( void )
375{
376 register ULong r2 asm("2");
377 ULong __res;
378
379 __asm__ __volatile__ (
380 "svc %b1\n"
381 : "=d" (r2)
382 : "i" (__NR_getpid)
383 : "cc", "memory");
384 __res = r2;
385
386 if (__res >= (ULong)(-125))
387 __res = -1;
388 return (UInt)(__res);
389}
390
sewardj5db15402012-06-07 09:13:21 +0000391#elif defined(VGP_mips32_linux)
392static UInt local_sys_write_stderr ( HChar* buf, Int n )
393{
394 volatile Int block[2];
395 block[0] = (Int)buf;
396 block[1] = n;
397 __asm__ volatile (
398 "li $4, 2\n\t" /* stderr */
399 "lw $5, 0(%0)\n\t" /* buf */
400 "lw $6, 4(%0)\n\t" /* n */
401 "move $7, $0\n\t"
402 "li $2, %1\n\t" /* set v0 = __NR_write */
403 "syscall\n\t" /* write() */
404 "nop\n\t"
405 :
406 : "r" (block), "n" (__NR_write)
407 : "2", "4", "5", "6", "7"
408 );
409 if (block[0] < 0)
410 block[0] = -1;
411 return (UInt)block[0];
412}
413
414static UInt local_sys_getpid ( void )
415{
416 UInt __res;
417 __asm__ volatile (
418 "li $2, %1\n\t" /* set v0 = __NR_getpid */
419 "syscall\n\t" /* getpid() */
420 "nop\n\t"
421 "move %0, $2\n"
422 : "=r" (__res)
423 : "n" (__NR_getpid)
424 : "$2" );
425 return __res;
426}
427
sewardjb5b87402011-03-07 16:05:35 +0000428
sewardj1cf558c2005-04-25 01:36:56 +0000429#else
sewardj21c6d0f2005-05-02 10:33:44 +0000430# error Unknown platform
sewardj1cf558c2005-04-25 01:36:56 +0000431#endif
432
433
434/* ----- generic ----- */
435
436/* strlen, so we don't need m_libc */
437static Int local_strlen ( const HChar* str )
438{
439 Int i = 0;
440 while (str[i] != 0) i++;
441 return i;
442}
443
444static HChar local_toupper ( HChar c )
445{
446 if (c >= 'a' && c <= 'z')
447 return c + ('A' - 'a');
448 else
449 return c;
450}
451
452/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
453*/
454static void emit ( HChar* buf, Int n )
455{
456 if (n >= 1)
457 (void)local_sys_write_stderr(buf, n);
458}
459
460
461/*------------------------------------------------------------*/
462/*--- A simple, generic, vprintf implementation. ---*/
463/*------------------------------------------------------------*/
464
465/* -----------------------------------------------
466 Distantly derived from:
467
468 vprintf replacement for Checker.
469 Copyright 1993, 1994, 1995 Tristan Gingold
470 Written September 1993 Tristan Gingold
471 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
472
473 (Checker itself was GPL'd.)
474 ----------------------------------------------- */
475
476/* Some flags. */
477#define VG_MSG_SIGNED 1 /* The value is signed. */
478#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
479#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
480#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
481#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
barta0b6b2c2008-07-07 06:49:24 +0000482#define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
sewardj1cf558c2005-04-25 01:36:56 +0000483
484/* Copy a string into the buffer. */
485static
486UInt myvprintf_str ( void(*send)(HChar,void*),
487 void* send_arg2,
488 Int flags,
489 Int width,
490 HChar* str,
491 Bool capitalise )
492{
493# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
494 UInt ret = 0;
495 Int i, extra;
496 Int len = local_strlen(str);
497
498 if (width == 0) {
499 ret += len;
500 for (i = 0; i < len; i++)
501 send(MAYBE_TOUPPER(str[i]), send_arg2);
502 return ret;
503 }
504
505 if (len > width) {
506 ret += width;
507 for (i = 0; i < width; i++)
508 send(MAYBE_TOUPPER(str[i]), send_arg2);
509 return ret;
510 }
511
512 extra = width - len;
513 if (flags & VG_MSG_LJUSTIFY) {
514 ret += extra;
515 for (i = 0; i < extra; i++)
516 send(' ', send_arg2);
517 }
518 ret += len;
519 for (i = 0; i < len; i++)
520 send(MAYBE_TOUPPER(str[i]), send_arg2);
521 if (!(flags & VG_MSG_LJUSTIFY)) {
522 ret += extra;
523 for (i = 0; i < extra; i++)
524 send(' ', send_arg2);
525 }
526
527# undef MAYBE_TOUPPER
528 return ret;
529}
530
531
sewardjdaf77af2005-07-19 14:17:37 +0000532/* Copy a string into the buffer, escaping bad XML chars. */
533static
534UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
535 void* send_arg2,
536 HChar* str )
537{
538 UInt ret = 0;
539 Int i;
540 Int len = local_strlen(str);
541 HChar* alt;
542
543 for (i = 0; i < len; i++) {
544 switch (str[i]) {
545 case '&': alt = "&amp;"; break;
546 case '<': alt = "&lt;"; break;
547 case '>': alt = "&gt;"; break;
548 default: alt = NULL;
549 }
550
551 if (alt) {
552 while (*alt) {
553 send(*alt, send_arg2);
554 ret++;
555 alt++;
556 }
557 } else {
558 send(str[i], send_arg2);
559 ret++;
560 }
561 }
562
563 return ret;
564}
565
566
sewardj1cf558c2005-04-25 01:36:56 +0000567/* Write P into the buffer according to these args:
568 * If SIGN is true, p is a signed.
569 * BASE is the base.
570 * If WITH_ZERO is true, '0' must be added.
571 * WIDTH is the width of the field.
572 */
573static
574UInt myvprintf_int64 ( void(*send)(HChar,void*),
575 void* send_arg2,
576 Int flags,
577 Int base,
578 Int width,
sewardja44b15f2007-02-16 14:10:24 +0000579 Bool capitalised,
sewardj1cf558c2005-04-25 01:36:56 +0000580 ULong p )
581{
582 HChar buf[40];
583 Int ind = 0;
584 Int i, nc = 0;
585 Bool neg = False;
sewardja44b15f2007-02-16 14:10:24 +0000586 HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
sewardj1cf558c2005-04-25 01:36:56 +0000587 UInt ret = 0;
588
589 if (base < 2 || base > 16)
590 return ret;
591
592 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
593 p = - (Long)p;
594 neg = True;
595 }
596
597 if (p == 0)
598 buf[ind++] = '0';
599 else {
600 while (p > 0) {
601 if (flags & VG_MSG_COMMA && 10 == base &&
602 0 == (ind-nc) % 3 && 0 != ind)
603 {
604 buf[ind++] = ',';
605 nc++;
606 }
607 buf[ind++] = digits[p % base];
608 p /= base;
609 }
610 }
611
612 if (neg)
613 buf[ind++] = '-';
614
615 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
616 for(; ind < width; ind++) {
617 /* vg_assert(ind < 39); */
618 if (ind > 39) {
619 buf[39] = 0;
620 break;
621 }
622 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
623 }
624 }
625
626 /* Reverse copy to buffer. */
627 ret += ind;
628 for (i = ind -1; i >= 0; i--) {
629 send(buf[i], send_arg2);
630 }
631 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
632 for(; ind < width; ind++) {
633 ret++;
634 /* Never pad with zeroes on RHS -- changes the value! */
635 send(' ', send_arg2);
636 }
637 }
638 return ret;
639}
640
641
642/* A simple vprintf(). */
643/* EXPORTED */
644UInt
645VG_(debugLog_vprintf) (
646 void(*send)(HChar,void*),
647 void* send_arg2,
648 const HChar* format,
649 va_list vargs
650)
651{
652 UInt ret = 0;
653 Int i;
654 Int flags;
655 Int width;
njn68e46592005-08-26 19:42:27 +0000656 Int n_ls = 0;
sewardja44b15f2007-02-16 14:10:24 +0000657 Bool is_long, caps;
sewardj1cf558c2005-04-25 01:36:56 +0000658
659 /* We assume that vargs has already been initialised by the
660 caller, using va_start, and that the caller will similarly
661 clean up with va_end.
662 */
663
664 for (i = 0; format[i] != 0; i++) {
665 if (format[i] != '%') {
666 send(format[i], send_arg2);
667 ret++;
668 continue;
669 }
670 i++;
671 /* A '%' has been found. Ignore a trailing %. */
672 if (format[i] == 0)
673 break;
674 if (format[i] == '%') {
njn02bc4b82005-05-15 17:28:26 +0000675 /* '%%' is replaced by '%'. */
sewardj1cf558c2005-04-25 01:36:56 +0000676 send('%', send_arg2);
677 ret++;
678 continue;
679 }
680 flags = 0;
njn68e46592005-08-26 19:42:27 +0000681 n_ls = 0;
sewardj1cf558c2005-04-25 01:36:56 +0000682 width = 0; /* length of the field. */
barta0b6b2c2008-07-07 06:49:24 +0000683 while (1) {
684 switch (format[i]) {
685 case '(':
686 flags |= VG_MSG_PAREN;
687 break;
688 case ',':
689 case '\'':
690 /* If ',' or '\'' follows '%', commas will be inserted. */
691 flags |= VG_MSG_COMMA;
692 break;
693 case '-':
694 /* If '-' follows '%', justify on the left. */
695 flags |= VG_MSG_LJUSTIFY;
696 break;
697 case '0':
698 /* If '0' follows '%', pads will be inserted. */
699 flags |= VG_MSG_ZJUSTIFY;
700 break;
701 case '#':
702 /* If '#' follows '%', alternative format will be used. */
703 flags |= VG_MSG_ALTFORMAT;
704 break;
705 default:
706 goto parse_fieldwidth;
707 }
sewardj1cf558c2005-04-25 01:36:56 +0000708 i++;
709 }
barta0b6b2c2008-07-07 06:49:24 +0000710 parse_fieldwidth:
sewardj1cf558c2005-04-25 01:36:56 +0000711 /* Compute the field length. */
712 while (format[i] >= '0' && format[i] <= '9') {
713 width *= 10;
714 width += format[i++] - '0';
715 }
716 while (format[i] == 'l') {
717 i++;
njn68e46592005-08-26 19:42:27 +0000718 n_ls++;
sewardj1cf558c2005-04-25 01:36:56 +0000719 }
720
njn68e46592005-08-26 19:42:27 +0000721 // %d means print a 32-bit integer.
722 // %ld means print a word-size integer.
723 // %lld means print a 64-bit integer.
724 if (0 == n_ls) { is_long = False; }
725 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
726 else { is_long = True; }
727
sewardj1cf558c2005-04-25 01:36:56 +0000728 switch (format[i]) {
bart042257f2009-07-26 08:40:17 +0000729 case 'o': /* %o */
730 if (flags & VG_MSG_ALTFORMAT) {
731 ret += 2;
732 send('0',send_arg2);
733 }
734 if (is_long)
735 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
736 (ULong)(va_arg (vargs, ULong)));
737 else
738 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
739 (ULong)(va_arg (vargs, UInt)));
740 break;
sewardj1cf558c2005-04-25 01:36:56 +0000741 case 'd': /* %d */
742 flags |= VG_MSG_SIGNED;
743 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000744 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000745 (ULong)(va_arg (vargs, Long)));
746 else
sewardja44b15f2007-02-16 14:10:24 +0000747 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000748 (ULong)(va_arg (vargs, Int)));
749 break;
750 case 'u': /* %u */
751 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000752 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000753 (ULong)(va_arg (vargs, ULong)));
754 else
sewardja44b15f2007-02-16 14:10:24 +0000755 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000756 (ULong)(va_arg (vargs, UInt)));
757 break;
bartb3af9cf2011-10-06 19:08:37 +0000758 case 'p':
759 if (format[i+1] == 'S') {
760 i++;
761 /* %pS, like %s but escaping chars for XML safety */
762 /* Note: simplistic; ignores field width and flags */
763 char *str = va_arg (vargs, char *);
764 if (str == (char*) 0)
765 str = "(null)";
766 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
bartdb4384e2011-10-11 18:49:35 +0000767 } else if (format[i+1] == 's') {
768 i++;
769 /* %ps, synonym for %s with --xml=no / %pS with --xml=yes */
770 char *str = va_arg (vargs, char *);
771 if (str == (char*) 0)
772 str = "(null)";
773 if (clo_xml)
774 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
775 else
776 ret += myvprintf_str(send, send_arg2, flags, width, str,
777 False);
bartb3af9cf2011-10-06 19:08:37 +0000778 } else {
779 /* %p */
780 ret += 2;
781 send('0',send_arg2);
782 send('x',send_arg2);
783 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
784 (ULong)((UWord)va_arg (vargs, void *)));
785 }
sewardj1cf558c2005-04-25 01:36:56 +0000786 break;
787 case 'x': /* %x */
sewardja44b15f2007-02-16 14:10:24 +0000788 case 'X': /* %X */
789 caps = toBool(format[i] == 'X');
barta0b6b2c2008-07-07 06:49:24 +0000790 if (flags & VG_MSG_ALTFORMAT) {
791 ret += 2;
792 send('0',send_arg2);
793 send('x',send_arg2);
794 }
sewardj1cf558c2005-04-25 01:36:56 +0000795 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000796 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000797 (ULong)(va_arg (vargs, ULong)));
798 else
sewardja44b15f2007-02-16 14:10:24 +0000799 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000800 (ULong)(va_arg (vargs, UInt)));
801 break;
802 case 'c': /* %c */
803 ret++;
804 send(va_arg (vargs, int), send_arg2);
805 break;
806 case 's': case 'S': { /* %s */
807 char *str = va_arg (vargs, char *);
808 if (str == (char*) 0) str = "(null)";
809 ret += myvprintf_str(send, send_arg2,
810 flags, width, str, format[i]=='S');
811 break;
812 }
sewardjdaf77af2005-07-19 14:17:37 +0000813
sewardj1cf558c2005-04-25 01:36:56 +0000814// case 'y': { /* %y - print symbol */
815// Char buf[100];
816// Char *cp = buf;
817// Addr a = va_arg(vargs, Addr);
818//
819// if (flags & VG_MSG_PAREN)
820// *cp++ = '(';
821// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
822// if (flags & VG_MSG_PAREN) {
823// cp += VG_(strlen)(cp);
824// *cp++ = ')';
825// *cp = '\0';
826// }
827// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
828// }
829// break;
830// }
831 default:
832 break;
833 }
834 }
835 return ret;
836}
837
838
839/*------------------------------------------------------------*/
840/*--- Debuglog stuff. ---*/
841/*------------------------------------------------------------*/
842
843/* Only print messages whose stated level is less than or equal to
844 this. By default, it makes this entire subsystem silent. */
845
846static Int loglevel = 0;
847
sewardj1cf558c2005-04-25 01:36:56 +0000848/* Module startup. */
sewardj10759312005-05-30 23:52:47 +0000849/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000850void VG_(debugLog_startup) ( Int level, HChar* who )
851{
852 if (level < 0) level = 0;
853 if (level > 10) level = 10;
854 loglevel = level;
855 VG_(debugLog)(1, "debuglog",
856 "DebugLog system started by %s, "
857 "level %d logging requested\n",
858 who, loglevel);
859}
860
sewardj10759312005-05-30 23:52:47 +0000861/* Get the logging threshold level, as set by the most recent call to
862 VG_(debugLog_startup), or zero if there have been no such calls so
863 far. */
864/* EXPORTED */
865Int VG_(debugLog_getLevel) ( void )
866{
867 return loglevel;
868}
869
870
sewardj1cf558c2005-04-25 01:36:56 +0000871/* ------------ */
872
873typedef
874 struct {
875 HChar buf[100];
876 Int n;
877 }
878 printf_buf;
879
880static void add_to_buf ( HChar c, void* p )
881{
882 printf_buf* buf = (printf_buf*)p;
883
884 if (buf->n >= 100-10 /*paranoia*/ ) {
885 emit( buf->buf, local_strlen(buf->buf) );
886 buf->n = 0;
887 buf->buf[buf->n] = 0;
888 }
889 buf->buf[buf->n++] = c;
890 buf->buf[buf->n] = 0;
891}
892
893/* Send a logging message. Nothing is output unless 'level'
894 is <= the current loglevel. */
895/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000896void VG_(debugLog) ( Int level, const HChar* modulename,
897 const HChar* format, ... )
898{
sewardjc7ffc942011-03-28 16:26:42 +0000899 UInt pid;
sewardj45f4e7c2005-09-27 19:20:21 +0000900 Int indent, depth, i;
sewardj1cf558c2005-04-25 01:36:56 +0000901 va_list vargs;
902 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000903
sewardj1cf558c2005-04-25 01:36:56 +0000904 if (level > loglevel)
905 return;
906
sewardjd85feff2005-04-25 02:37:56 +0000907 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000908 if (indent < 1) indent = 1;
909
sewardj1cf558c2005-04-25 01:36:56 +0000910 buf.n = 0;
911 buf.buf[0] = 0;
912 pid = local_sys_getpid();
sewardj45f4e7c2005-09-27 19:20:21 +0000913
914 // Print one '>' in front of the messages for each level of self-hosting
915 // being performed.
916 depth = RUNNING_ON_VALGRIND;
917 for (i = 0; i < depth; i++) {
918 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
919 }
920
sewardja5ebfa92005-04-25 02:04:54 +0000921 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
sewardja44b15f2007-02-16 14:10:24 +0000922 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
sewardja5ebfa92005-04-25 02:04:54 +0000923 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardja44b15f2007-02-16 14:10:24 +0000924 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000925 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000926 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000927 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000928
929 va_start(vargs,format);
930
sewardjc7ffc942011-03-28 16:26:42 +0000931 (void) VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
sewardj1cf558c2005-04-25 01:36:56 +0000932
933 if (buf.n > 0) {
934 emit( buf.buf, local_strlen(buf.buf) );
935 }
936
937 va_end(vargs);
938}
939
940
941
942/*--------------------------------------------------------------------*/
943/*--- end m_debuglog.c ---*/
944/*--------------------------------------------------------------------*/