blob: 431e04e0990ebf6546212b6090295b1a1a392ff4 [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
njn9f207462009-03-10 22:02:09 +000010 Copyright (C) 2000-2009 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
49#include "pub_core_basics.h" /* basic types */
sewardj17edf032006-10-17 01:53:34 +000050#include "pub_core_vkiscnums.h" /* for syscall numbers */
njnc7561b92005-06-19 01:24:32 +000051#include "pub_core_debuglog.h" /* our own iface */
sewardj45f4e7c2005-09-27 19:20:21 +000052#include "valgrind.h" /* for RUNNING_ON_VALGRIND */
sewardj1cf558c2005-04-25 01:36:56 +000053
54/*------------------------------------------------------------*/
55/*--- Stuff to make us completely independent. ---*/
56/*------------------------------------------------------------*/
57
sewardj2c48c7b2005-11-29 13:05:56 +000058/* ----- Platform-specifics ----- */
sewardj1cf558c2005-04-25 01:36:56 +000059
sewardj21c6d0f2005-05-02 10:33:44 +000060#if defined(VGP_x86_linux)
sewardj1cf558c2005-04-25 01:36:56 +000061
62static UInt local_sys_write_stderr ( HChar* buf, Int n )
63{
sewardj17edf032006-10-17 01:53:34 +000064 volatile Int block[2];
sewardj55c43762006-04-28 21:01:33 +000065 block[0] = (Int)buf;
66 block[1] = n;
tom311400b2005-04-27 08:58:53 +000067 __asm__ volatile (
sewardj55c43762006-04-28 21:01:33 +000068 "pushl %%ebx\n" /* ebx is callee-save */
69 "movl %0, %%ebx\n" /* ebx = &block */
70 "pushl %%ebx\n" /* save &block */
71 "movl 0(%%ebx), %%ecx\n" /* %ecx = buf */
72 "movl 4(%%ebx), %%edx\n" /* %edx = n */
sewardj17edf032006-10-17 01:53:34 +000073 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */
njn5ed05a52009-05-20 06:59:19 +000074 "movl $2, %%ebx\n" /* %ebx = stderr */
sewardj55c43762006-04-28 21:01:33 +000075 "int $0x80\n" /* write(stderr, buf, n) */
76 "popl %%ebx\n" /* reestablish &block */
77 "movl %%eax, 0(%%ebx)\n" /* block[0] = result */
78 "popl %%ebx\n" /* restore ebx */
79 : /*wr*/
80 : /*rd*/ "g" (block)
81 : /*trash*/ "eax", "edi", "ecx", "edx", "memory", "cc"
sewardjd4d203b2005-04-27 23:17:48 +000082 );
sewardj55c43762006-04-28 21:01:33 +000083 if (block[0] < 0)
84 block[0] = -1;
85 return block[0];
sewardj1cf558c2005-04-25 01:36:56 +000086}
87
88static UInt local_sys_getpid ( void )
89{
90 UInt __res;
tom311400b2005-04-27 08:58:53 +000091 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +000092 "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n" /* %eax = __NR_getpid */
tom311400b2005-04-27 08:58:53 +000093 "int $0x80\n" /* getpid() */
94 "movl %%eax, %0\n" /* set __res = eax */
sewardjd4d203b2005-04-27 23:17:48 +000095 : "=mr" (__res)
96 :
97 : "eax" );
sewardj1cf558c2005-04-25 01:36:56 +000098 return __res;
99}
100
sewardj21c6d0f2005-05-02 10:33:44 +0000101#elif defined(VGP_amd64_linux)
sewardj7337f922006-05-26 11:31:15 +0000102__attribute__((noinline))
sewardj601371a2005-04-25 16:21:17 +0000103static UInt local_sys_write_stderr ( HChar* buf, Int n )
104{
sewardj17edf032006-10-17 01:53:34 +0000105 volatile Long block[2];
sewardj7337f922006-05-26 11:31:15 +0000106 block[0] = (Long)buf;
107 block[1] = n;
tomc6121862005-04-27 09:23:02 +0000108 __asm__ volatile (
sewardj7337f922006-05-26 11:31:15 +0000109 "subq $256, %%rsp\n" /* don't trash the stack redzone */
110 "pushq %%r15\n" /* r15 is callee-save */
111 "movq %0, %%r15\n" /* r15 = &block */
112 "pushq %%r15\n" /* save &block */
sewardj17edf032006-10-17 01:53:34 +0000113 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
sewardj7337f922006-05-26 11:31:15 +0000114 "movq $2, %%rdi\n" /* rdi = stderr */
115 "movq 0(%%r15), %%rsi\n" /* rsi = buf */
116 "movq 8(%%r15), %%rdx\n" /* rdx = n */
117 "syscall\n" /* write(stderr, buf, n) */
118 "popq %%r15\n" /* reestablish &block */
119 "movq %%rax, 0(%%r15)\n" /* block[0] = result */
120 "popq %%r15\n" /* restore r15 */
121 "addq $256, %%rsp\n" /* restore stack ptr */
122 : /*wr*/
123 : /*rd*/ "g" (block)
124 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc"
125 );
126 if (block[0] < 0)
127 block[0] = -1;
128 return (UInt)block[0];
sewardj601371a2005-04-25 16:21:17 +0000129}
130
131static UInt local_sys_getpid ( void )
132{
tomc6121862005-04-27 09:23:02 +0000133 UInt __res;
134 __asm__ volatile (
sewardj17edf032006-10-17 01:53:34 +0000135 "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n" /* %rax = __NR_getpid */
tomc6121862005-04-27 09:23:02 +0000136 "syscall\n" /* getpid() */
137 "movl %%eax, %0\n" /* set __res = %eax */
138 : "=mr" (__res)
139 :
140 : "rax" );
141 return __res;
sewardj601371a2005-04-25 16:21:17 +0000142}
sewardj1cf558c2005-04-25 01:36:56 +0000143
cerion85665ca2005-06-20 15:51:07 +0000144#elif defined(VGP_ppc32_linux)
145
146static UInt local_sys_write_stderr ( HChar* buf, Int n )
147{
sewardj17edf032006-10-17 01:53:34 +0000148 volatile Int block[2];
sewardja2699582006-05-22 13:04:42 +0000149 block[0] = (Int)buf;
150 block[1] = n;
cerion85665ca2005-06-20 15:51:07 +0000151 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000152 "addi 1,1,-256\n\t"
153 "mr 5,%0\n\t" /* r5 = &block[0] */
154 "stw 5,0(1)\n\t" /* stash on stack */
sewardj17edf032006-10-17 01:53:34 +0000155 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* set %r0 = __NR_write */
sewardja2699582006-05-22 13:04:42 +0000156 "li 3,2\n\t" /* set %r3 = stderr */
157 "lwz 4,0(5)\n\t" /* set %r4 = buf */
158 "lwz 5,4(5)\n\t" /* set %r5 = n */
159 "sc\n\t" /* write(stderr, buf, n) */
160 "lwz 5,0(1)\n\t"
161 "addi 1,1,256\n\t"
162 "stw 3,0(5)\n" /* block[0] = result */
163 :
164 : "b" (block)
165 : "cc","memory","cr0","ctr",
166 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
167 );
168 if (block[0] < 0)
169 block[0] = -1;
170 return (UInt)block[0];
cerion85665ca2005-06-20 15:51:07 +0000171}
172
173static UInt local_sys_getpid ( void )
174{
sewardja2699582006-05-22 13:04:42 +0000175 register UInt __res __asm__ ("r3");
176 __asm__ volatile (
177 "li 0, %1\n\t"
178 "sc"
179 : "=&r" (__res)
sewardj17edf032006-10-17 01:53:34 +0000180 : "i" (__NR_getpid)
sewardja2699582006-05-22 13:04:42 +0000181 : "cc","memory","cr0","ctr",
182 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
183 );
cerion85665ca2005-06-20 15:51:07 +0000184 return __res;
185}
186
sewardj2c48c7b2005-11-29 13:05:56 +0000187#elif defined(VGP_ppc64_linux)
188
189static UInt local_sys_write_stderr ( HChar* buf, Int n )
190{
sewardj17edf032006-10-17 01:53:34 +0000191 volatile Long block[2];
sewardja2699582006-05-22 13:04:42 +0000192 block[0] = (Long)buf;
193 block[1] = (Long)n;
sewardj2c48c7b2005-11-29 13:05:56 +0000194 __asm__ volatile (
sewardja2699582006-05-22 13:04:42 +0000195 "addi 1,1,-256\n\t"
196 "mr 5,%0\n\t" /* r5 = &block[0] */
197 "std 5,0(1)\n\t" /* stash on stack */
sewardj17edf032006-10-17 01:53:34 +0000198 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* %r0 = __NR_write */
sewardja2699582006-05-22 13:04:42 +0000199 "li 3,2\n\t" /* set %r3 = stderr */
200 "ld 4,0(5)\n\t" /* set %r4 = buf */
201 "ld 5,8(5)\n\t" /* set %r5 = n */
202 "sc\n\t" /* write(stderr, buf, n) */
203 "ld 5,0(1)\n\t"
204 "addi 1,1,256\n\t"
205 "std 3,0(5)\n" /* block[0] = result */
206 :
207 : "b" (block)
208 : "cc","memory","cr0","ctr",
209 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
210 );
211 if (block[0] < 0)
212 block[0] = -1;
213 return (UInt)(Int)block[0];
sewardj2c48c7b2005-11-29 13:05:56 +0000214}
215
216static UInt local_sys_getpid ( void )
217{
sewardja2699582006-05-22 13:04:42 +0000218 register ULong __res __asm__ ("r3");
219 __asm__ volatile (
220 "li 0, %1\n\t"
221 "sc"
222 : "=&r" (__res)
sewardj17edf032006-10-17 01:53:34 +0000223 : "i" (__NR_getpid)
sewardja2699582006-05-22 13:04:42 +0000224 : "cc","memory","cr0","ctr",
225 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
226 );
227 return (UInt)__res;
sewardj2c48c7b2005-11-29 13:05:56 +0000228}
229
sewardj17edf032006-10-17 01:53:34 +0000230#elif defined(VGP_ppc32_aix5)
231
232static UInt local_sys_write_stderr ( HChar* buf, Int n )
233{
234 /* For some reason gcc-3.3.2 doesn't preserve r31 across the asm
235 even though we state it to be trashed. So use r27 instead. */
236 volatile UInt block[3];
237 block[0] = (UInt)buf;
238 block[1] = n;
239 block[2] = __NR_write;
240 __asm__ __volatile__ (
241 "mr 28,%0\n\t" /* establish base ptr */
242 "mr 27,2\n\t" /* save r2 in r27 */
243 "mflr 30\n\t" /* save lr in r30 */
244
245 "lwz 2,8(28)\n\t" /* set %r2 = __NR_write */
246 "li 3,2\n\t" /* set %r3 = stderr */
247 "lwz 4,0(28)\n\t" /* set %r4 = buf */
248 "lwz 5,4(28)\n\t" /* set %r5 = n */
249
sewardj13552642006-11-10 22:47:27 +0000250 "crorc 6,6,6\n\t"
sewardj17edf032006-10-17 01:53:34 +0000251 ".long 0x48000005\n\t" /* bl .+4 */
252 "mflr 29\n\t"
sewardj13552642006-11-10 22:47:27 +0000253 "addi 29,29,16\n\t"
sewardj17edf032006-10-17 01:53:34 +0000254 "mtlr 29\n\t"
sewardj17edf032006-10-17 01:53:34 +0000255 "sc\n\t" /* write() */
256
257 "stw 3,0(28)\n\t" /* result */
258 "stw 4,4(28)\n\t" /* error? */
259
260 "mr 2,27\n\t" /* restore r2 */
261 "mtlr 30" /* restore lr */
262
263 : /*out*/
264 : /*in*/ "b" (&block[0])
265 : /*trash*/
266 /*temps*/ "r31","r30","r29","r28","r27",
267 /*args*/ "r3","r4","r5","r6","r7","r8","r9","r10",
268 /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
269 "xer","ctr","cr0","cr1","cr2","cr3",
270 "cr4","cr5","cr6","cr7"
271 );
272 if (block[1] != 0)
273 return -1;
274 else
275 return block[0];
276}
277
278static UInt local_sys_getpid ( void )
279{
280 /* For some reason gcc-3.3.2 doesn't preserve r31 across the asm
281 even though we state it to be trashed. So use r27 instead. */
282 volatile UInt block[1];
283 block[0] = __NR_getpid;
284 __asm__ __volatile__ (
285 "mr 28,%0\n\t" /* establish base ptr */
286 "mr 27,2\n\t" /* save r2 in r27 */
287 "mflr 30\n\t" /* save lr in r30 */
288
289 "lwz 2,0(28)\n\t" /* set %r2 = __NR_getpid */
290
sewardj13552642006-11-10 22:47:27 +0000291 "crorc 6,6,6\n\t"
sewardj17edf032006-10-17 01:53:34 +0000292 ".long 0x48000005\n\t" /* bl .+4 */
293 "mflr 29\n\t"
sewardj13552642006-11-10 22:47:27 +0000294 "addi 29,29,16\n\t"
sewardj17edf032006-10-17 01:53:34 +0000295 "mtlr 29\n\t"
sewardj17edf032006-10-17 01:53:34 +0000296 "sc\n\t" /* getpid() */
297
298 "stw 3,0(28)\n\t" /* result -> block[0] */
299
300 "mr 2,27\n\t" /* restore r2 */
301 "mtlr 30" /* restore lr */
302
303 : /*out*/
304 : /*in*/ "b" (&block[0])
305 : /*trash*/
306 /*temps*/ "r31","r30","r29","r28","r27",
307 /*args*/ "r3","r4","r5","r6","r7","r8","r9","r10",
308 /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
309 "xer","ctr","cr0","cr1","cr2","cr3",
310 "cr4","cr5","cr6","cr7"
311 );
312 return block[0];
313}
314
315#elif defined(VGP_ppc64_aix5)
316
317static UInt local_sys_write_stderr ( HChar* buf, Int n )
318{
319 volatile ULong block[3];
320 block[0] = (ULong)buf;
321 block[1] = n;
322 block[2] = (ULong)__NR_write;
323 __asm__ __volatile__ (
324 "mr 28,%0\n\t" /* establish base ptr */
325 "mr 27,2\n\t" /* save r2 in r27 */
326 "mflr 30\n\t" /* save lr in r30 */
327
328 "ld 2,16(28)\n\t" /* set %r2 = __NR_write */
329 "li 3,2\n\t" /* set %r3 = stderr */
330 "ld 4,0(28)\n\t" /* set %r4 = buf */
331 "ld 5,8(28)\n\t" /* set %r5 = n */
332
sewardj13552642006-11-10 22:47:27 +0000333 "crorc 6,6,6\n\t"
sewardj17edf032006-10-17 01:53:34 +0000334 ".long 0x48000005\n\t" /* bl .+4 */
335 "mflr 29\n\t"
sewardj13552642006-11-10 22:47:27 +0000336 "addi 29,29,16\n\t"
sewardj17edf032006-10-17 01:53:34 +0000337 "mtlr 29\n\t"
sewardj17edf032006-10-17 01:53:34 +0000338 "sc\n\t" /* write() */
339
340 "std 3,0(28)\n\t" /* result */
341 "std 4,8(28)\n\t" /* error? */
342
343 "mr 2,27\n\t" /* restore r2 */
344 "mtlr 30" /* restore lr */
345
346 : /*out*/
347 : /*in*/ "b" (&block[0])
348 : /*trash*/
349 /*temps*/ "r31","r30","r29","r28","r27",
350 /*args*/ "r3","r4","r5","r6","r7","r8","r9","r10",
351 /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
352 "xer","ctr","cr0","cr1","cr2","cr3",
353 "cr4","cr5","cr6","cr7"
354 );
355 if (block[1] != 0)
356 return (UInt)-1;
357 else
358 return (UInt)block[0];
359}
360
361static UInt local_sys_getpid ( void )
362{
363 volatile ULong block[1];
364 block[0] = __NR_getpid;
365 __asm__ __volatile__ (
366 "mr 28,%0\n\t" /* establish base ptr */
367 "mr 27,2\n\t" /* save r2 in r27 */
368 "mflr 30\n\t" /* save lr in r30 */
369
370 "ld 2,0(28)\n\t" /* set %r2 = __NR_getpid */
371
sewardj13552642006-11-10 22:47:27 +0000372 "crorc 6,6,6\n\t"
sewardj17edf032006-10-17 01:53:34 +0000373 ".long 0x48000005\n\t" /* bl .+4 */
374 "mflr 29\n\t"
sewardj13552642006-11-10 22:47:27 +0000375 "addi 29,29,16\n\t"
sewardj17edf032006-10-17 01:53:34 +0000376 "mtlr 29\n\t"
sewardj17edf032006-10-17 01:53:34 +0000377 "sc\n\t" /* getpid() */
378
379 "std 3,0(28)\n\t" /* result -> block[0] */
380
381 "mr 2,27\n\t" /* restore r2 */
382 "mtlr 30" /* restore lr */
383
384 : /*out*/
385 : /*in*/ "b" (&block[0])
386 : /*trash*/
387 /*temps*/ "r31","r30","r29","r28","r27",
388 /*args*/ "r3","r4","r5","r6","r7","r8","r9","r10",
389 /*paranoia*/ "memory","cc","r0","r1","r11","r12","r13",
390 "xer","ctr","cr0","cr1","cr2","cr3",
391 "cr4","cr5","cr6","cr7"
392 );
393 return (UInt)block[0];
394}
395
sewardj1cf558c2005-04-25 01:36:56 +0000396#else
sewardj21c6d0f2005-05-02 10:33:44 +0000397# error Unknown platform
sewardj1cf558c2005-04-25 01:36:56 +0000398#endif
399
400
401/* ----- generic ----- */
402
403/* strlen, so we don't need m_libc */
404static Int local_strlen ( const HChar* str )
405{
406 Int i = 0;
407 while (str[i] != 0) i++;
408 return i;
409}
410
411static HChar local_toupper ( HChar c )
412{
413 if (c >= 'a' && c <= 'z')
414 return c + ('A' - 'a');
415 else
416 return c;
417}
418
419/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
420*/
421static void emit ( HChar* buf, Int n )
422{
423 if (n >= 1)
424 (void)local_sys_write_stderr(buf, n);
425}
426
427
428/*------------------------------------------------------------*/
429/*--- A simple, generic, vprintf implementation. ---*/
430/*------------------------------------------------------------*/
431
432/* -----------------------------------------------
433 Distantly derived from:
434
435 vprintf replacement for Checker.
436 Copyright 1993, 1994, 1995 Tristan Gingold
437 Written September 1993 Tristan Gingold
438 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
439
440 (Checker itself was GPL'd.)
441 ----------------------------------------------- */
442
443/* Some flags. */
444#define VG_MSG_SIGNED 1 /* The value is signed. */
445#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
446#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
447#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
448#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
barta0b6b2c2008-07-07 06:49:24 +0000449#define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
sewardj1cf558c2005-04-25 01:36:56 +0000450
451/* Copy a string into the buffer. */
452static
453UInt myvprintf_str ( void(*send)(HChar,void*),
454 void* send_arg2,
455 Int flags,
456 Int width,
457 HChar* str,
458 Bool capitalise )
459{
460# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
461 UInt ret = 0;
462 Int i, extra;
463 Int len = local_strlen(str);
464
465 if (width == 0) {
466 ret += len;
467 for (i = 0; i < len; i++)
468 send(MAYBE_TOUPPER(str[i]), send_arg2);
469 return ret;
470 }
471
472 if (len > width) {
473 ret += width;
474 for (i = 0; i < width; i++)
475 send(MAYBE_TOUPPER(str[i]), send_arg2);
476 return ret;
477 }
478
479 extra = width - len;
480 if (flags & VG_MSG_LJUSTIFY) {
481 ret += extra;
482 for (i = 0; i < extra; i++)
483 send(' ', send_arg2);
484 }
485 ret += len;
486 for (i = 0; i < len; i++)
487 send(MAYBE_TOUPPER(str[i]), send_arg2);
488 if (!(flags & VG_MSG_LJUSTIFY)) {
489 ret += extra;
490 for (i = 0; i < extra; i++)
491 send(' ', send_arg2);
492 }
493
494# undef MAYBE_TOUPPER
495 return ret;
496}
497
498
sewardjdaf77af2005-07-19 14:17:37 +0000499/* Copy a string into the buffer, escaping bad XML chars. */
500static
501UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
502 void* send_arg2,
503 HChar* str )
504{
505 UInt ret = 0;
506 Int i;
507 Int len = local_strlen(str);
508 HChar* alt;
509
510 for (i = 0; i < len; i++) {
511 switch (str[i]) {
512 case '&': alt = "&amp;"; break;
513 case '<': alt = "&lt;"; break;
514 case '>': alt = "&gt;"; break;
515 default: alt = NULL;
516 }
517
518 if (alt) {
519 while (*alt) {
520 send(*alt, send_arg2);
521 ret++;
522 alt++;
523 }
524 } else {
525 send(str[i], send_arg2);
526 ret++;
527 }
528 }
529
530 return ret;
531}
532
533
sewardj1cf558c2005-04-25 01:36:56 +0000534/* Write P into the buffer according to these args:
535 * If SIGN is true, p is a signed.
536 * BASE is the base.
537 * If WITH_ZERO is true, '0' must be added.
538 * WIDTH is the width of the field.
539 */
540static
541UInt myvprintf_int64 ( void(*send)(HChar,void*),
542 void* send_arg2,
543 Int flags,
544 Int base,
545 Int width,
sewardja44b15f2007-02-16 14:10:24 +0000546 Bool capitalised,
sewardj1cf558c2005-04-25 01:36:56 +0000547 ULong p )
548{
549 HChar buf[40];
550 Int ind = 0;
551 Int i, nc = 0;
552 Bool neg = False;
sewardja44b15f2007-02-16 14:10:24 +0000553 HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
sewardj1cf558c2005-04-25 01:36:56 +0000554 UInt ret = 0;
555
556 if (base < 2 || base > 16)
557 return ret;
558
559 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
560 p = - (Long)p;
561 neg = True;
562 }
563
564 if (p == 0)
565 buf[ind++] = '0';
566 else {
567 while (p > 0) {
568 if (flags & VG_MSG_COMMA && 10 == base &&
569 0 == (ind-nc) % 3 && 0 != ind)
570 {
571 buf[ind++] = ',';
572 nc++;
573 }
574 buf[ind++] = digits[p % base];
575 p /= base;
576 }
577 }
578
579 if (neg)
580 buf[ind++] = '-';
581
582 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
583 for(; ind < width; ind++) {
584 /* vg_assert(ind < 39); */
585 if (ind > 39) {
586 buf[39] = 0;
587 break;
588 }
589 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
590 }
591 }
592
593 /* Reverse copy to buffer. */
594 ret += ind;
595 for (i = ind -1; i >= 0; i--) {
596 send(buf[i], send_arg2);
597 }
598 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
599 for(; ind < width; ind++) {
600 ret++;
601 /* Never pad with zeroes on RHS -- changes the value! */
602 send(' ', send_arg2);
603 }
604 }
605 return ret;
606}
607
608
609/* A simple vprintf(). */
610/* EXPORTED */
611UInt
612VG_(debugLog_vprintf) (
613 void(*send)(HChar,void*),
614 void* send_arg2,
615 const HChar* format,
616 va_list vargs
617)
618{
619 UInt ret = 0;
620 Int i;
621 Int flags;
622 Int width;
njn68e46592005-08-26 19:42:27 +0000623 Int n_ls = 0;
sewardja44b15f2007-02-16 14:10:24 +0000624 Bool is_long, caps;
sewardj1cf558c2005-04-25 01:36:56 +0000625
626 /* We assume that vargs has already been initialised by the
627 caller, using va_start, and that the caller will similarly
628 clean up with va_end.
629 */
630
631 for (i = 0; format[i] != 0; i++) {
632 if (format[i] != '%') {
633 send(format[i], send_arg2);
634 ret++;
635 continue;
636 }
637 i++;
638 /* A '%' has been found. Ignore a trailing %. */
639 if (format[i] == 0)
640 break;
641 if (format[i] == '%') {
njn02bc4b82005-05-15 17:28:26 +0000642 /* '%%' is replaced by '%'. */
sewardj1cf558c2005-04-25 01:36:56 +0000643 send('%', send_arg2);
644 ret++;
645 continue;
646 }
647 flags = 0;
njn68e46592005-08-26 19:42:27 +0000648 n_ls = 0;
sewardj1cf558c2005-04-25 01:36:56 +0000649 width = 0; /* length of the field. */
barta0b6b2c2008-07-07 06:49:24 +0000650 while (1) {
651 switch (format[i]) {
652 case '(':
653 flags |= VG_MSG_PAREN;
654 break;
655 case ',':
656 case '\'':
657 /* If ',' or '\'' follows '%', commas will be inserted. */
658 flags |= VG_MSG_COMMA;
659 break;
660 case '-':
661 /* If '-' follows '%', justify on the left. */
662 flags |= VG_MSG_LJUSTIFY;
663 break;
664 case '0':
665 /* If '0' follows '%', pads will be inserted. */
666 flags |= VG_MSG_ZJUSTIFY;
667 break;
668 case '#':
669 /* If '#' follows '%', alternative format will be used. */
670 flags |= VG_MSG_ALTFORMAT;
671 break;
672 default:
673 goto parse_fieldwidth;
674 }
sewardj1cf558c2005-04-25 01:36:56 +0000675 i++;
676 }
barta0b6b2c2008-07-07 06:49:24 +0000677 parse_fieldwidth:
sewardj1cf558c2005-04-25 01:36:56 +0000678 /* Compute the field length. */
679 while (format[i] >= '0' && format[i] <= '9') {
680 width *= 10;
681 width += format[i++] - '0';
682 }
683 while (format[i] == 'l') {
684 i++;
njn68e46592005-08-26 19:42:27 +0000685 n_ls++;
sewardj1cf558c2005-04-25 01:36:56 +0000686 }
687
njn68e46592005-08-26 19:42:27 +0000688 // %d means print a 32-bit integer.
689 // %ld means print a word-size integer.
690 // %lld means print a 64-bit integer.
691 if (0 == n_ls) { is_long = False; }
692 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
693 else { is_long = True; }
694
sewardj1cf558c2005-04-25 01:36:56 +0000695 switch (format[i]) {
696 case 'd': /* %d */
697 flags |= VG_MSG_SIGNED;
698 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000699 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000700 (ULong)(va_arg (vargs, Long)));
701 else
sewardja44b15f2007-02-16 14:10:24 +0000702 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000703 (ULong)(va_arg (vargs, Int)));
704 break;
705 case 'u': /* %u */
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, ULong)));
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, UInt)));
712 break;
713 case 'p': /* %p */
714 ret += 2;
715 send('0',send_arg2);
716 send('x',send_arg2);
sewardja44b15f2007-02-16 14:10:24 +0000717 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
sewardj1cf558c2005-04-25 01:36:56 +0000718 (ULong)((UWord)va_arg (vargs, void *)));
719 break;
720 case 'x': /* %x */
sewardja44b15f2007-02-16 14:10:24 +0000721 case 'X': /* %X */
722 caps = toBool(format[i] == 'X');
barta0b6b2c2008-07-07 06:49:24 +0000723 if (flags & VG_MSG_ALTFORMAT) {
724 ret += 2;
725 send('0',send_arg2);
726 send('x',send_arg2);
727 }
sewardj1cf558c2005-04-25 01:36:56 +0000728 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000729 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000730 (ULong)(va_arg (vargs, ULong)));
731 else
sewardja44b15f2007-02-16 14:10:24 +0000732 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000733 (ULong)(va_arg (vargs, UInt)));
734 break;
735 case 'c': /* %c */
736 ret++;
737 send(va_arg (vargs, int), send_arg2);
738 break;
739 case 's': case 'S': { /* %s */
740 char *str = va_arg (vargs, char *);
741 if (str == (char*) 0) str = "(null)";
742 ret += myvprintf_str(send, send_arg2,
743 flags, width, str, format[i]=='S');
744 break;
745 }
sewardjdaf77af2005-07-19 14:17:37 +0000746 case 't': { /* %t, like %s but escaping chars for XML safety */
747 /* Note: simplistic; ignores field width and flags */
748 char *str = va_arg (vargs, char *);
749 if (str == (char*) 0) str = "(null)";
750 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
751 break;
752 }
753
sewardj1cf558c2005-04-25 01:36:56 +0000754// case 'y': { /* %y - print symbol */
755// Char buf[100];
756// Char *cp = buf;
757// Addr a = va_arg(vargs, Addr);
758//
759// if (flags & VG_MSG_PAREN)
760// *cp++ = '(';
761// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
762// if (flags & VG_MSG_PAREN) {
763// cp += VG_(strlen)(cp);
764// *cp++ = ')';
765// *cp = '\0';
766// }
767// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
768// }
769// break;
770// }
771 default:
772 break;
773 }
774 }
775 return ret;
776}
777
778
779/*------------------------------------------------------------*/
780/*--- Debuglog stuff. ---*/
781/*------------------------------------------------------------*/
782
783/* Only print messages whose stated level is less than or equal to
784 this. By default, it makes this entire subsystem silent. */
785
786static Int loglevel = 0;
787
sewardj1cf558c2005-04-25 01:36:56 +0000788/* Module startup. */
sewardj10759312005-05-30 23:52:47 +0000789/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000790void VG_(debugLog_startup) ( Int level, HChar* who )
791{
792 if (level < 0) level = 0;
793 if (level > 10) level = 10;
794 loglevel = level;
795 VG_(debugLog)(1, "debuglog",
796 "DebugLog system started by %s, "
797 "level %d logging requested\n",
798 who, loglevel);
799}
800
sewardj10759312005-05-30 23:52:47 +0000801/* Get the logging threshold level, as set by the most recent call to
802 VG_(debugLog_startup), or zero if there have been no such calls so
803 far. */
804/* EXPORTED */
805Int VG_(debugLog_getLevel) ( void )
806{
807 return loglevel;
808}
809
810
sewardj1cf558c2005-04-25 01:36:56 +0000811/* ------------ */
812
813typedef
814 struct {
815 HChar buf[100];
816 Int n;
817 }
818 printf_buf;
819
820static void add_to_buf ( HChar c, void* p )
821{
822 printf_buf* buf = (printf_buf*)p;
823
824 if (buf->n >= 100-10 /*paranoia*/ ) {
825 emit( buf->buf, local_strlen(buf->buf) );
826 buf->n = 0;
827 buf->buf[buf->n] = 0;
828 }
829 buf->buf[buf->n++] = c;
830 buf->buf[buf->n] = 0;
831}
832
833/* Send a logging message. Nothing is output unless 'level'
834 is <= the current loglevel. */
835/* EXPORTED */
836__attribute__((format(__printf__, 3, 4)))
837void VG_(debugLog) ( Int level, const HChar* modulename,
838 const HChar* format, ... )
839{
840 UInt ret, pid;
sewardj45f4e7c2005-09-27 19:20:21 +0000841 Int indent, depth, i;
sewardj1cf558c2005-04-25 01:36:56 +0000842 va_list vargs;
843 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000844
sewardj1cf558c2005-04-25 01:36:56 +0000845 if (level > loglevel)
846 return;
847
sewardjd85feff2005-04-25 02:37:56 +0000848 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000849 if (indent < 1) indent = 1;
850
sewardj1cf558c2005-04-25 01:36:56 +0000851 buf.n = 0;
852 buf.buf[0] = 0;
853 pid = local_sys_getpid();
sewardj45f4e7c2005-09-27 19:20:21 +0000854
855 // Print one '>' in front of the messages for each level of self-hosting
856 // being performed.
857 depth = RUNNING_ON_VALGRIND;
858 for (i = 0; i < depth; i++) {
859 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
860 }
861
sewardja5ebfa92005-04-25 02:04:54 +0000862 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
sewardja44b15f2007-02-16 14:10:24 +0000863 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
sewardja5ebfa92005-04-25 02:04:54 +0000864 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardja44b15f2007-02-16 14:10:24 +0000865 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000866 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000867 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000868 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000869
870 va_start(vargs,format);
871
872 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
873
874 if (buf.n > 0) {
875 emit( buf.buf, local_strlen(buf.buf) );
876 }
877
878 va_end(vargs);
879}
880
881
882
883/*--------------------------------------------------------------------*/
884/*--- end m_debuglog.c ---*/
885/*--------------------------------------------------------------------*/