blob: 14743890125fe54d495f7b86e1d2490e7d260e69 [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
sewardj9ebd6e02007-01-08 06:01:59 +000010 Copyright (C) 2000-2007 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 */
sewardj55c43762006-04-28 21:01:33 +000074 "movl $1, %%ebx\n" /* %ebx = stderr */
75 "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) */
449
450
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. */
650 if (format[i] == '(') {
651 flags |= VG_MSG_PAREN;
652 i++;
653 }
654 /* If ',' follows '%', commas will be inserted. */
655 if (format[i] == ',') {
656 flags |= VG_MSG_COMMA;
657 i++;
658 }
659 /* If '-' follows '%', justify on the left. */
660 if (format[i] == '-') {
661 flags |= VG_MSG_LJUSTIFY;
662 i++;
663 }
664 /* If '0' follows '%', pads will be inserted. */
665 if (format[i] == '0') {
666 flags |= VG_MSG_ZJUSTIFY;
667 i++;
668 }
669 /* Compute the field length. */
670 while (format[i] >= '0' && format[i] <= '9') {
671 width *= 10;
672 width += format[i++] - '0';
673 }
674 while (format[i] == 'l') {
675 i++;
njn68e46592005-08-26 19:42:27 +0000676 n_ls++;
sewardj1cf558c2005-04-25 01:36:56 +0000677 }
678
njn68e46592005-08-26 19:42:27 +0000679 // %d means print a 32-bit integer.
680 // %ld means print a word-size integer.
681 // %lld means print a 64-bit integer.
682 if (0 == n_ls) { is_long = False; }
683 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
684 else { is_long = True; }
685
sewardj1cf558c2005-04-25 01:36:56 +0000686 switch (format[i]) {
687 case 'd': /* %d */
688 flags |= VG_MSG_SIGNED;
689 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000690 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000691 (ULong)(va_arg (vargs, Long)));
692 else
sewardja44b15f2007-02-16 14:10:24 +0000693 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000694 (ULong)(va_arg (vargs, Int)));
695 break;
696 case 'u': /* %u */
697 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000698 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000699 (ULong)(va_arg (vargs, ULong)));
700 else
sewardja44b15f2007-02-16 14:10:24 +0000701 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
sewardj1cf558c2005-04-25 01:36:56 +0000702 (ULong)(va_arg (vargs, UInt)));
703 break;
704 case 'p': /* %p */
705 ret += 2;
706 send('0',send_arg2);
707 send('x',send_arg2);
sewardja44b15f2007-02-16 14:10:24 +0000708 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
sewardj1cf558c2005-04-25 01:36:56 +0000709 (ULong)((UWord)va_arg (vargs, void *)));
710 break;
711 case 'x': /* %x */
sewardja44b15f2007-02-16 14:10:24 +0000712 case 'X': /* %X */
713 caps = toBool(format[i] == 'X');
sewardj1cf558c2005-04-25 01:36:56 +0000714 if (is_long)
sewardja44b15f2007-02-16 14:10:24 +0000715 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
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, 16, width, caps,
sewardj1cf558c2005-04-25 01:36:56 +0000719 (ULong)(va_arg (vargs, UInt)));
720 break;
721 case 'c': /* %c */
722 ret++;
723 send(va_arg (vargs, int), send_arg2);
724 break;
725 case 's': case 'S': { /* %s */
726 char *str = va_arg (vargs, char *);
727 if (str == (char*) 0) str = "(null)";
728 ret += myvprintf_str(send, send_arg2,
729 flags, width, str, format[i]=='S');
730 break;
731 }
sewardjdaf77af2005-07-19 14:17:37 +0000732 case 't': { /* %t, like %s but escaping chars for XML safety */
733 /* Note: simplistic; ignores field width and flags */
734 char *str = va_arg (vargs, char *);
735 if (str == (char*) 0) str = "(null)";
736 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
737 break;
738 }
739
sewardj1cf558c2005-04-25 01:36:56 +0000740// case 'y': { /* %y - print symbol */
741// Char buf[100];
742// Char *cp = buf;
743// Addr a = va_arg(vargs, Addr);
744//
745// if (flags & VG_MSG_PAREN)
746// *cp++ = '(';
747// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
748// if (flags & VG_MSG_PAREN) {
749// cp += VG_(strlen)(cp);
750// *cp++ = ')';
751// *cp = '\0';
752// }
753// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
754// }
755// break;
756// }
757 default:
758 break;
759 }
760 }
761 return ret;
762}
763
764
765/*------------------------------------------------------------*/
766/*--- Debuglog stuff. ---*/
767/*------------------------------------------------------------*/
768
769/* Only print messages whose stated level is less than or equal to
770 this. By default, it makes this entire subsystem silent. */
771
772static Int loglevel = 0;
773
sewardj1cf558c2005-04-25 01:36:56 +0000774/* Module startup. */
sewardj10759312005-05-30 23:52:47 +0000775/* EXPORTED */
sewardj1cf558c2005-04-25 01:36:56 +0000776void VG_(debugLog_startup) ( Int level, HChar* who )
777{
778 if (level < 0) level = 0;
779 if (level > 10) level = 10;
780 loglevel = level;
781 VG_(debugLog)(1, "debuglog",
782 "DebugLog system started by %s, "
783 "level %d logging requested\n",
784 who, loglevel);
785}
786
sewardj10759312005-05-30 23:52:47 +0000787/* Get the logging threshold level, as set by the most recent call to
788 VG_(debugLog_startup), or zero if there have been no such calls so
789 far. */
790/* EXPORTED */
791Int VG_(debugLog_getLevel) ( void )
792{
793 return loglevel;
794}
795
796
sewardj1cf558c2005-04-25 01:36:56 +0000797/* ------------ */
798
799typedef
800 struct {
801 HChar buf[100];
802 Int n;
803 }
804 printf_buf;
805
806static void add_to_buf ( HChar c, void* p )
807{
808 printf_buf* buf = (printf_buf*)p;
809
810 if (buf->n >= 100-10 /*paranoia*/ ) {
811 emit( buf->buf, local_strlen(buf->buf) );
812 buf->n = 0;
813 buf->buf[buf->n] = 0;
814 }
815 buf->buf[buf->n++] = c;
816 buf->buf[buf->n] = 0;
817}
818
819/* Send a logging message. Nothing is output unless 'level'
820 is <= the current loglevel. */
821/* EXPORTED */
822__attribute__((format(__printf__, 3, 4)))
823void VG_(debugLog) ( Int level, const HChar* modulename,
824 const HChar* format, ... )
825{
826 UInt ret, pid;
sewardj45f4e7c2005-09-27 19:20:21 +0000827 Int indent, depth, i;
sewardj1cf558c2005-04-25 01:36:56 +0000828 va_list vargs;
829 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000830
sewardj1cf558c2005-04-25 01:36:56 +0000831 if (level > loglevel)
832 return;
833
sewardjd85feff2005-04-25 02:37:56 +0000834 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000835 if (indent < 1) indent = 1;
836
sewardj1cf558c2005-04-25 01:36:56 +0000837 buf.n = 0;
838 buf.buf[0] = 0;
839 pid = local_sys_getpid();
sewardj45f4e7c2005-09-27 19:20:21 +0000840
841 // Print one '>' in front of the messages for each level of self-hosting
842 // being performed.
843 depth = RUNNING_ON_VALGRIND;
844 for (i = 0; i < depth; i++) {
845 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
846 }
847
sewardja5ebfa92005-04-25 02:04:54 +0000848 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
sewardja44b15f2007-02-16 14:10:24 +0000849 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
sewardja5ebfa92005-04-25 02:04:54 +0000850 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardja44b15f2007-02-16 14:10:24 +0000851 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000852 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000853 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000854 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000855
856 va_start(vargs,format);
857
858 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
859
860 if (buf.n > 0) {
861 emit( buf.buf, local_strlen(buf.buf) );
862 }
863
864 va_end(vargs);
865}
866
867
868
869/*--------------------------------------------------------------------*/
870/*--- end m_debuglog.c ---*/
871/*--------------------------------------------------------------------*/