blob: 44f7376f7a742372c4fb98101b222b84728ece7b [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
391
sewardj1cf558c2005-04-25 01:36:56 +0000392#else
sewardj21c6d0f2005-05-02 10:33:44 +0000393# error Unknown platform
sewardj1cf558c2005-04-25 01:36:56 +0000394#endif
395
396
397/* ----- generic ----- */
398
399/* strlen, so we don't need m_libc */
400static Int local_strlen ( const HChar* str )
401{
402 Int i = 0;
403 while (str[i] != 0) i++;
404 return i;
405}
406
407static HChar local_toupper ( HChar c )
408{
409 if (c >= 'a' && c <= 'z')
410 return c + ('A' - 'a');
411 else
412 return c;
413}
414
415/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
416*/
417static void emit ( HChar* buf, Int n )
418{
419 if (n >= 1)
420 (void)local_sys_write_stderr(buf, n);
421}
422
423
424/*------------------------------------------------------------*/
425/*--- A simple, generic, vprintf implementation. ---*/
426/*------------------------------------------------------------*/
427
428/* -----------------------------------------------
429 Distantly derived from:
430
431 vprintf replacement for Checker.
432 Copyright 1993, 1994, 1995 Tristan Gingold
433 Written September 1993 Tristan Gingold
434 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
435
436 (Checker itself was GPL'd.)
437 ----------------------------------------------- */
438
439/* Some flags. */
440#define VG_MSG_SIGNED 1 /* The value is signed. */
441#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
442#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
443#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
444#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
barta0b6b2c2008-07-07 06:49:24 +0000445#define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
sewardj1cf558c2005-04-25 01:36:56 +0000446
447/* Copy a string into the buffer. */
448static
449UInt myvprintf_str ( void(*send)(HChar,void*),
450 void* send_arg2,
451 Int flags,
452 Int width,
453 HChar* str,
454 Bool capitalise )
455{
456# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
457 UInt ret = 0;
458 Int i, extra;
459 Int len = local_strlen(str);
460
461 if (width == 0) {
462 ret += len;
463 for (i = 0; i < len; i++)
464 send(MAYBE_TOUPPER(str[i]), send_arg2);
465 return ret;
466 }
467
468 if (len > width) {
469 ret += width;
470 for (i = 0; i < width; i++)
471 send(MAYBE_TOUPPER(str[i]), send_arg2);
472 return ret;
473 }
474
475 extra = width - len;
476 if (flags & VG_MSG_LJUSTIFY) {
477 ret += extra;
478 for (i = 0; i < extra; i++)
479 send(' ', send_arg2);
480 }
481 ret += len;
482 for (i = 0; i < len; i++)
483 send(MAYBE_TOUPPER(str[i]), send_arg2);
484 if (!(flags & VG_MSG_LJUSTIFY)) {
485 ret += extra;
486 for (i = 0; i < extra; i++)
487 send(' ', send_arg2);
488 }
489
490# undef MAYBE_TOUPPER
491 return ret;
492}
493
494
sewardjdaf77af2005-07-19 14:17:37 +0000495/* Copy a string into the buffer, escaping bad XML chars. */
496static
497UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
498 void* send_arg2,
499 HChar* str )
500{
501 UInt ret = 0;
502 Int i;
503 Int len = local_strlen(str);
504 HChar* alt;
505
506 for (i = 0; i < len; i++) {
507 switch (str[i]) {
508 case '&': alt = "&amp;"; break;
509 case '<': alt = "&lt;"; break;
510 case '>': alt = "&gt;"; break;
511 default: alt = NULL;
512 }
513
514 if (alt) {
515 while (*alt) {
516 send(*alt, send_arg2);
517 ret++;
518 alt++;
519 }
520 } else {
521 send(str[i], send_arg2);
522 ret++;
523 }
524 }
525
526 return ret;
527}
528
529
sewardj1cf558c2005-04-25 01:36:56 +0000530/* Write P into the buffer according to these args:
531 * If SIGN is true, p is a signed.
532 * BASE is the base.
533 * If WITH_ZERO is true, '0' must be added.
534 * WIDTH is the width of the field.
535 */
536static
537UInt myvprintf_int64 ( void(*send)(HChar,void*),
538 void* send_arg2,
539 Int flags,
540 Int base,
541 Int width,
sewardja44b15f2007-02-16 14:10:24 +0000542 Bool capitalised,
sewardj1cf558c2005-04-25 01:36:56 +0000543 ULong p )
544{
545 HChar buf[40];
546 Int ind = 0;
547 Int i, nc = 0;
548 Bool neg = False;
sewardja44b15f2007-02-16 14:10:24 +0000549 HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
sewardj1cf558c2005-04-25 01:36:56 +0000550 UInt ret = 0;
551
552 if (base < 2 || base > 16)
553 return ret;
554
555 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
556 p = - (Long)p;
557 neg = True;
558 }
559
560 if (p == 0)
561 buf[ind++] = '0';
562 else {
563 while (p > 0) {
564 if (flags & VG_MSG_COMMA && 10 == base &&
565 0 == (ind-nc) % 3 && 0 != ind)
566 {
567 buf[ind++] = ',';
568 nc++;
569 }
570 buf[ind++] = digits[p % base];
571 p /= base;
572 }
573 }
574
575 if (neg)
576 buf[ind++] = '-';
577
578 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
579 for(; ind < width; ind++) {
580 /* vg_assert(ind < 39); */
581 if (ind > 39) {
582 buf[39] = 0;
583 break;
584 }
585 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
586 }
587 }
588
589 /* Reverse copy to buffer. */
590 ret += ind;
591 for (i = ind -1; i >= 0; i--) {
592 send(buf[i], send_arg2);
593 }
594 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
595 for(; ind < width; ind++) {
596 ret++;
597 /* Never pad with zeroes on RHS -- changes the value! */
598 send(' ', send_arg2);
599 }
600 }
601 return ret;
602}
603
604
605/* A simple vprintf(). */
606/* EXPORTED */
607UInt
608VG_(debugLog_vprintf) (
609 void(*send)(HChar,void*),
610 void* send_arg2,
611 const HChar* format,
612 va_list vargs
613)
614{
615 UInt ret = 0;
616 Int i;
617 Int flags;
618 Int width;
njn68e46592005-08-26 19:42:27 +0000619 Int n_ls = 0;
sewardja44b15f2007-02-16 14:10:24 +0000620 Bool is_long, caps;
sewardj1cf558c2005-04-25 01:36:56 +0000621
622 /* We assume that vargs has already been initialised by the
623 caller, using va_start, and that the caller will similarly
624 clean up with va_end.
625 */
626
627 for (i = 0; format[i] != 0; i++) {
628 if (format[i] != '%') {
629 send(format[i], send_arg2);
630 ret++;
631 continue;
632 }
633 i++;
634 /* A '%' has been found. Ignore a trailing %. */
635 if (format[i] == 0)
636 break;
637 if (format[i] == '%') {
njn02bc4b82005-05-15 17:28:26 +0000638 /* '%%' is replaced by '%'. */
sewardj1cf558c2005-04-25 01:36:56 +0000639 send('%', send_arg2);
640 ret++;
641 continue;
642 }
643 flags = 0;
njn68e46592005-08-26 19:42:27 +0000644 n_ls = 0;
sewardj1cf558c2005-04-25 01:36:56 +0000645 width = 0; /* length of the field. */
barta0b6b2c2008-07-07 06:49:24 +0000646 while (1) {
647 switch (format[i]) {
648 case '(':
649 flags |= VG_MSG_PAREN;
650 break;
651 case ',':
652 case '\'':
653 /* If ',' or '\'' follows '%', commas will be inserted. */
654 flags |= VG_MSG_COMMA;
655 break;
656 case '-':
657 /* If '-' follows '%', justify on the left. */
658 flags |= VG_MSG_LJUSTIFY;
659 break;
660 case '0':
661 /* If '0' follows '%', pads will be inserted. */
662 flags |= VG_MSG_ZJUSTIFY;
663 break;
664 case '#':
665 /* If '#' follows '%', alternative format will be used. */
666 flags |= VG_MSG_ALTFORMAT;
667 break;
668 default:
669 goto parse_fieldwidth;
670 }
sewardj1cf558c2005-04-25 01:36:56 +0000671 i++;
672 }
barta0b6b2c2008-07-07 06:49:24 +0000673 parse_fieldwidth:
sewardj1cf558c2005-04-25 01:36:56 +0000674 /* Compute the field length. */
675 while (format[i] >= '0' && format[i] <= '9') {
676 width *= 10;
677 width += format[i++] - '0';
678 }
679 while (format[i] == 'l') {
680 i++;
njn68e46592005-08-26 19:42:27 +0000681 n_ls++;
sewardj1cf558c2005-04-25 01:36:56 +0000682 }
683
njn68e46592005-08-26 19:42:27 +0000684 // %d means print a 32-bit integer.
685 // %ld means print a word-size integer.
686 // %lld means print a 64-bit integer.
687 if (0 == n_ls) { is_long = False; }
688 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
689 else { is_long = True; }
690
sewardj1cf558c2005-04-25 01:36:56 +0000691 switch (format[i]) {
bart042257f2009-07-26 08:40:17 +0000692 case 'o': /* %o */
693 if (flags & VG_MSG_ALTFORMAT) {
694 ret += 2;
695 send('0',send_arg2);
696 }
697 if (is_long)
698 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
699 (ULong)(va_arg (vargs, ULong)));
700 else
701 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
702 (ULong)(va_arg (vargs, UInt)));
703 break;
sewardj1cf558c2005-04-25 01:36:56 +0000704 case 'd': /* %d */
705 flags |= VG_MSG_SIGNED;
706 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000707 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000708 (ULong)(va_arg (vargs, Long)));
709 else
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, Int)));
712 break;
713 case 'u': /* %u */
714 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000715 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000716 (ULong)(va_arg (vargs, ULong)));
717 else
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, UInt)));
720 break;
bartb3af9cf2011-10-06 19:08:37 +0000721 case 'p':
722 if (format[i+1] == 'S') {
723 i++;
724 /* %pS, like %s but escaping chars for XML safety */
725 /* Note: simplistic; ignores field width and flags */
726 char *str = va_arg (vargs, char *);
727 if (str == (char*) 0)
728 str = "(null)";
729 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
bartdb4384e2011-10-11 18:49:35 +0000730 } else if (format[i+1] == 's') {
731 i++;
732 /* %ps, synonym for %s with --xml=no / %pS with --xml=yes */
733 char *str = va_arg (vargs, char *);
734 if (str == (char*) 0)
735 str = "(null)";
736 if (clo_xml)
737 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
738 else
739 ret += myvprintf_str(send, send_arg2, flags, width, str,
740 False);
bartb3af9cf2011-10-06 19:08:37 +0000741 } else {
742 /* %p */
743 ret += 2;
744 send('0',send_arg2);
745 send('x',send_arg2);
746 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
747 (ULong)((UWord)va_arg (vargs, void *)));
748 }
sewardj1cf558c2005-04-25 01:36:56 +0000749 break;
750 case 'x': /* %x */
sewardja44b15f2007-02-16 14:10:24 +0000751 case 'X': /* %X */
752 caps = toBool(format[i] == 'X');
barta0b6b2c2008-07-07 06:49:24 +0000753 if (flags & VG_MSG_ALTFORMAT) {
754 ret += 2;
755 send('0',send_arg2);
756 send('x',send_arg2);
757 }
sewardj1cf558c2005-04-25 01:36:56 +0000758 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000759 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000760 (ULong)(va_arg (vargs, ULong)));
761 else
sewardja44b15f2007-02-16 14:10:24 +0000762 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000763 (ULong)(va_arg (vargs, UInt)));
764 break;
765 case 'c': /* %c */
766 ret++;
767 send(va_arg (vargs, int), send_arg2);
768 break;
769 case 's': case 'S': { /* %s */
770 char *str = va_arg (vargs, char *);
771 if (str == (char*) 0) str = "(null)";
772 ret += myvprintf_str(send, send_arg2,
773 flags, width, str, format[i]=='S');
774 break;
775 }
sewardjdaf77af2005-07-19 14:17:37 +0000776
sewardj1cf558c2005-04-25 01:36:56 +0000777// case 'y': { /* %y - print symbol */
778// Char buf[100];
779// Char *cp = buf;
780// Addr a = va_arg(vargs, Addr);
781//
782// if (flags & VG_MSG_PAREN)
783// *cp++ = '(';
784// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
785// if (flags & VG_MSG_PAREN) {
786// cp += VG_(strlen)(cp);
787// *cp++ = ')';
788// *cp = '\0';
789// }
790// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
791// }
792// break;
793// }
794 default:
795 break;
796 }
797 }
798 return ret;
799}
800
801
802/*------------------------------------------------------------*/
803/*--- Debuglog stuff. ---*/
804/*------------------------------------------------------------*/
805
806/* Only print messages whose stated level is less than or equal to
807 this. By default, it makes this entire subsystem silent. */
808
809static Int loglevel = 0;
810
sewardj1cf558c2005-04-25 01:36:56 +0000811/* Module startup. */
sewardj10759312005-05-30 23:52:47 +0000812/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000813void VG_(debugLog_startup) ( Int level, HChar* who )
814{
815 if (level < 0) level = 0;
816 if (level > 10) level = 10;
817 loglevel = level;
818 VG_(debugLog)(1, "debuglog",
819 "DebugLog system started by %s, "
820 "level %d logging requested\n",
821 who, loglevel);
822}
823
sewardj10759312005-05-30 23:52:47 +0000824/* Get the logging threshold level, as set by the most recent call to
825 VG_(debugLog_startup), or zero if there have been no such calls so
826 far. */
827/* EXPORTED */
828Int VG_(debugLog_getLevel) ( void )
829{
830 return loglevel;
831}
832
833
sewardj1cf558c2005-04-25 01:36:56 +0000834/* ------------ */
835
836typedef
837 struct {
838 HChar buf[100];
839 Int n;
840 }
841 printf_buf;
842
843static void add_to_buf ( HChar c, void* p )
844{
845 printf_buf* buf = (printf_buf*)p;
846
847 if (buf->n >= 100-10 /*paranoia*/ ) {
848 emit( buf->buf, local_strlen(buf->buf) );
849 buf->n = 0;
850 buf->buf[buf->n] = 0;
851 }
852 buf->buf[buf->n++] = c;
853 buf->buf[buf->n] = 0;
854}
855
856/* Send a logging message. Nothing is output unless 'level'
857 is <= the current loglevel. */
858/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000859void VG_(debugLog) ( Int level, const HChar* modulename,
860 const HChar* format, ... )
861{
sewardjc7ffc942011-03-28 16:26:42 +0000862 UInt pid;
sewardj45f4e7c2005-09-27 19:20:21 +0000863 Int indent, depth, i;
sewardj1cf558c2005-04-25 01:36:56 +0000864 va_list vargs;
865 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000866
sewardj1cf558c2005-04-25 01:36:56 +0000867 if (level > loglevel)
868 return;
869
sewardjd85feff2005-04-25 02:37:56 +0000870 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000871 if (indent < 1) indent = 1;
872
sewardj1cf558c2005-04-25 01:36:56 +0000873 buf.n = 0;
874 buf.buf[0] = 0;
875 pid = local_sys_getpid();
sewardj45f4e7c2005-09-27 19:20:21 +0000876
877 // Print one '>' in front of the messages for each level of self-hosting
878 // being performed.
879 depth = RUNNING_ON_VALGRIND;
880 for (i = 0; i < depth; i++) {
881 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
882 }
883
sewardja5ebfa92005-04-25 02:04:54 +0000884 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
sewardja44b15f2007-02-16 14:10:24 +0000885 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
sewardja5ebfa92005-04-25 02:04:54 +0000886 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardja44b15f2007-02-16 14:10:24 +0000887 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000888 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000889 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000890 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000891
892 va_start(vargs,format);
893
sewardjc7ffc942011-03-28 16:26:42 +0000894 (void) VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
sewardj1cf558c2005-04-25 01:36:56 +0000895
896 if (buf.n > 0) {
897 emit( buf.buf, local_strlen(buf.buf) );
898 }
899
900 va_end(vargs);
901}
902
903
904
905/*--------------------------------------------------------------------*/
906/*--- end m_debuglog.c ---*/
907/*--------------------------------------------------------------------*/