1
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
10 Copyright (C) 2000-2011 Julian Seward
11 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 */
45
46 /* This module is also notable because it is linked into both
47 stage1 and stage2. */
48
49 /* 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
54 #include "pub_core_basics.h" /* basic types */
55 #include "pub_core_vkiscnums.h" /* for syscall numbers */
56 #include "pub_core_debuglog.h" /* our own iface */
57 #include "valgrind.h" /* for RUNNING_ON_VALGRIND */
58
59 static Bool clo_xml;
60
VG_(debugLog_setXml)61 void VG_(debugLog_setXml)(Bool xml)
62 {
63 clo_xml = xml;
64 }
65
66 /*------------------------------------------------------------*/
67 /*--- Stuff to make us completely independent. ---*/
68 /*------------------------------------------------------------*/
69
70 /* ----- Platform-specifics ----- */
71
72 #if defined(VGP_x86_linux)
73
local_sys_write_stderr(HChar * buf,Int n)74 static UInt local_sys_write_stderr ( HChar* buf, Int n )
75 {
76 volatile Int block[2];
77 block[0] = (Int)buf;
78 block[1] = n;
79 __asm__ volatile (
80 "pushl %%ebx\n" /* ebx is callee-save */
81 "movl %0, %%ebx\n" /* ebx = &block */
82 "pushl %%ebx\n" /* save &block */
83 "movl 0(%%ebx), %%ecx\n" /* %ecx = buf */
84 "movl 4(%%ebx), %%edx\n" /* %edx = n */
85 "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */
86 "movl $2, %%ebx\n" /* %ebx = stderr */
87 "int $0x80\n" /* write(stderr, buf, n) */
88 "popl %%ebx\n" /* reestablish &block */
89 "movl %%eax, 0(%%ebx)\n" /* block[0] = result */
90 "popl %%ebx\n" /* restore ebx */
91 : /*wr*/
92 : /*rd*/ "r" (block)
93 : /*trash*/ "eax", "edi", "ecx", "edx", "memory", "cc"
94 );
95 if (block[0] < 0)
96 block[0] = -1;
97 return block[0];
98 }
99
local_sys_getpid(void)100 static UInt local_sys_getpid ( void )
101 {
102 UInt __res;
103 __asm__ volatile (
104 "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n" /* %eax = __NR_getpid */
105 "int $0x80\n" /* getpid() */
106 "movl %%eax, %0\n" /* set __res = eax */
107 : "=mr" (__res)
108 :
109 : "eax" );
110 return __res;
111 }
112
113 #elif defined(VGP_amd64_linux)
114 __attribute__((noinline))
local_sys_write_stderr(HChar * buf,Int n)115 static UInt local_sys_write_stderr ( HChar* buf, Int n )
116 {
117 volatile Long block[2];
118 block[0] = (Long)buf;
119 block[1] = n;
120 __asm__ volatile (
121 "subq $256, %%rsp\n" /* don't trash the stack redzone */
122 "pushq %%r15\n" /* r15 is callee-save */
123 "movq %0, %%r15\n" /* r15 = &block */
124 "pushq %%r15\n" /* save &block */
125 "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */
126 "movq $2, %%rdi\n" /* rdi = stderr */
127 "movq 0(%%r15), %%rsi\n" /* rsi = buf */
128 "movq 8(%%r15), %%rdx\n" /* rdx = n */
129 "syscall\n" /* write(stderr, buf, n) */
130 "popq %%r15\n" /* reestablish &block */
131 "movq %%rax, 0(%%r15)\n" /* block[0] = result */
132 "popq %%r15\n" /* restore r15 */
133 "addq $256, %%rsp\n" /* restore stack ptr */
134 : /*wr*/
135 : /*rd*/ "r" (block)
136 : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc"
137 );
138 if (block[0] < 0)
139 block[0] = -1;
140 return (UInt)block[0];
141 }
142
local_sys_getpid(void)143 static UInt local_sys_getpid ( void )
144 {
145 UInt __res;
146 __asm__ volatile (
147 "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n" /* %rax = __NR_getpid */
148 "syscall\n" /* getpid() */
149 "movl %%eax, %0\n" /* set __res = %eax */
150 : "=mr" (__res)
151 :
152 : "rax" );
153 return __res;
154 }
155
156 #elif defined(VGP_ppc32_linux)
157
local_sys_write_stderr(HChar * buf,Int n)158 static UInt local_sys_write_stderr ( HChar* buf, Int n )
159 {
160 volatile Int block[2];
161 block[0] = (Int)buf;
162 block[1] = n;
163 __asm__ volatile (
164 "addi 1,1,-256\n\t"
165 "mr 5,%0\n\t" /* r5 = &block[0] */
166 "stw 5,0(1)\n\t" /* stash on stack */
167 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* set %r0 = __NR_write */
168 "li 3,2\n\t" /* set %r3 = stderr */
169 "lwz 4,0(5)\n\t" /* set %r4 = buf */
170 "lwz 5,4(5)\n\t" /* set %r5 = n */
171 "sc\n\t" /* write(stderr, buf, n) */
172 "lwz 5,0(1)\n\t"
173 "addi 1,1,256\n\t"
174 "stw 3,0(5)\n" /* block[0] = result */
175 :
176 : "b" (block)
177 : "cc","memory","cr0","ctr",
178 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
179 );
180 if (block[0] < 0)
181 block[0] = -1;
182 return (UInt)block[0];
183 }
184
local_sys_getpid(void)185 static UInt local_sys_getpid ( void )
186 {
187 register UInt __res __asm__ ("r3");
188 __asm__ volatile (
189 "li 0, %1\n\t"
190 "sc"
191 : "=&r" (__res)
192 : "i" (__NR_getpid)
193 : "cc","memory","cr0","ctr",
194 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
195 );
196 return __res;
197 }
198
199 #elif defined(VGP_ppc64_linux)
200
local_sys_write_stderr(HChar * buf,Int n)201 static UInt local_sys_write_stderr ( HChar* buf, Int n )
202 {
203 volatile Long block[2];
204 block[0] = (Long)buf;
205 block[1] = (Long)n;
206 __asm__ volatile (
207 "addi 1,1,-256\n\t"
208 "mr 5,%0\n\t" /* r5 = &block[0] */
209 "std 5,0(1)\n\t" /* stash on stack */
210 "li 0,"VG_STRINGIFY(__NR_write)"\n\t" /* %r0 = __NR_write */
211 "li 3,2\n\t" /* set %r3 = stderr */
212 "ld 4,0(5)\n\t" /* set %r4 = buf */
213 "ld 5,8(5)\n\t" /* set %r5 = n */
214 "sc\n\t" /* write(stderr, buf, n) */
215 "ld 5,0(1)\n\t"
216 "addi 1,1,256\n\t"
217 "std 3,0(5)\n" /* block[0] = result */
218 :
219 : "b" (block)
220 : "cc","memory","cr0","ctr",
221 "r0","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12"
222 );
223 if (block[0] < 0)
224 block[0] = -1;
225 return (UInt)(Int)block[0];
226 }
227
local_sys_getpid(void)228 static UInt local_sys_getpid ( void )
229 {
230 register ULong __res __asm__ ("r3");
231 __asm__ volatile (
232 "li 0, %1\n\t"
233 "sc"
234 : "=&r" (__res)
235 : "i" (__NR_getpid)
236 : "cc","memory","cr0","ctr",
237 "r0","r2","r4","r5","r6","r7","r8","r9","r10","r11","r12"
238 );
239 return (UInt)__res;
240 }
241
242 #elif defined(VGP_arm_linux)
243
local_sys_write_stderr(HChar * buf,Int n)244 static UInt local_sys_write_stderr ( HChar* buf, Int n )
245 {
246 volatile Int block[2];
247 block[0] = (Int)buf;
248 block[1] = n;
249 __asm__ volatile (
250 "mov r0, #2\n\t" /* stderr */
251 "ldr r1, [%0]\n\t" /* buf */
252 "ldr r2, [%0, #4]\n\t" /* n */
253 "mov r7, #"VG_STRINGIFY(__NR_write)"\n\t"
254 "svc 0x0\n" /* write() */
255 "str r0, [%0]\n\t"
256 :
257 : "r" (block)
258 : "r0","r1","r2","r7"
259 );
260 if (block[0] < 0)
261 block[0] = -1;
262 return (UInt)block[0];
263 }
264
local_sys_getpid(void)265 static UInt local_sys_getpid ( void )
266 {
267 UInt __res;
268 __asm__ volatile (
269 "mov r7, #"VG_STRINGIFY(__NR_getpid)"\n"
270 "svc 0x0\n" /* getpid() */
271 "mov %0, r0\n"
272 : "=r" (__res)
273 :
274 : "r0", "r7" );
275 return __res;
276 }
277
278 #elif defined(VGP_x86_darwin)
279
280 /* We would use VG_DARWIN_SYSNO_TO_KERNEL instead of VG_DARWIN_SYSNO_INDEX
281 except that the former has a C ternary ?: operator which isn't valid in
282 asm code. Both macros give the same results for Unix-class syscalls (which
283 these all are, as identified by the use of 'int 0x80'). */
284 __attribute__((noinline))
local_sys_write_stderr(HChar * buf,Int n)285 static UInt local_sys_write_stderr ( HChar* buf, Int n )
286 {
287 UInt __res;
288 __asm__ volatile (
289 "movl %2, %%eax\n" /* push n */
290 "pushl %%eax\n"
291 "movl %1, %%eax\n" /* push buf */
292 "pushl %%eax\n"
293 "movl $2, %%eax\n" /* push stderr */
294 "pushl %%eax\n"
295 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
296 ", %%eax\n"
297 "pushl %%eax\n" /* push fake return address */
298 "int $0x80\n" /* write(stderr, buf, n) */
299 "jnc 1f\n" /* jump if no error */
300 "movl $-1, %%eax\n" /* return -1 if error */
301 "1: "
302 "movl %%eax, %0\n" /* __res = eax */
303 "addl $16, %%esp\n" /* pop x4 */
304 : "=mr" (__res)
305 : "g" (buf), "g" (n)
306 : "eax", "edx", "cc"
307 );
308 return __res;
309 }
310
local_sys_getpid(void)311 static UInt local_sys_getpid ( void )
312 {
313 UInt __res;
314 __asm__ volatile (
315 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
316 "int $0x80\n" /* getpid() */
317 "movl %%eax, %0\n" /* set __res = eax */
318 : "=mr" (__res)
319 :
320 : "eax", "cc" );
321 return __res;
322 }
323
324 #elif defined(VGP_amd64_darwin)
325
326 __attribute__((noinline))
local_sys_write_stderr(HChar * buf,Int n)327 static UInt local_sys_write_stderr ( HChar* buf, Int n )
328 {
329 UInt __res;
330 __asm__ volatile (
331 "movq $2, %%rdi\n" /* push stderr */
332 "movq %1, %%rsi\n" /* push buf */
333 "movl %2, %%edx\n" /* push n */
334 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_write_nocancel))
335 ", %%eax\n"
336 "syscall\n" /* write(stderr, buf, n) */
337 "jnc 1f\n" /* jump if no error */
338 "movq $-1, %%rax\n" /* return -1 if error */
339 "1: "
340 "movl %%eax, %0\n" /* __res = eax */
341 : "=mr" (__res)
342 : "g" (buf), "g" (n)
343 : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
344 return __res;
345 }
346
local_sys_getpid(void)347 static UInt local_sys_getpid ( void )
348 {
349 UInt __res;
350 __asm__ volatile (
351 "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_FOR_KERNEL(__NR_getpid))", %%eax\n"
352 "syscall\n" /* getpid() */
353 "movl %%eax, %0\n" /* set __res = eax */
354 : "=mr" (__res)
355 :
356 : "rax", "rcx", "cc" );
357 return __res;
358 }
359
360 #elif defined(VGP_s390x_linux)
local_sys_write_stderr(HChar * buf,Int n)361 static UInt local_sys_write_stderr ( HChar* buf, Int n )
362 {
363 register Int r2 asm("2") = 2; /* file descriptor STDERR */
364 register HChar* r3 asm("3") = buf;
365 register ULong r4 asm("4") = n;
366 register ULong r2_res asm("2");
367 ULong __res;
368
369 __asm__ __volatile__ (
370 "svc %b1\n"
371 : "=d" (r2_res)
372 : "i" (__NR_write),
373 "0" (r2),
374 "d" (r3),
375 "d" (r4)
376 : "cc", "memory");
377 __res = r2_res;
378
379 if (__res >= (ULong)(-125))
380 __res = -1;
381 return (UInt)(__res);
382 }
383
local_sys_getpid(void)384 static UInt local_sys_getpid ( void )
385 {
386 register ULong r2 asm("2");
387 ULong __res;
388
389 __asm__ __volatile__ (
390 "svc %b1\n"
391 : "=d" (r2)
392 : "i" (__NR_getpid)
393 : "cc", "memory");
394 __res = r2;
395
396 if (__res >= (ULong)(-125))
397 __res = -1;
398 return (UInt)(__res);
399 }
400
401
402 #else
403 # error Unknown platform
404 #endif
405
406
407 /* ----- generic ----- */
408
409 /* strlen, so we don't need m_libc */
local_strlen(const HChar * str)410 static Int local_strlen ( const HChar* str )
411 {
412 Int i = 0;
413 while (str[i] != 0) i++;
414 return i;
415 }
416
local_toupper(HChar c)417 static HChar local_toupper ( HChar c )
418 {
419 if (c >= 'a' && c <= 'z')
420 return c + ('A' - 'a');
421 else
422 return c;
423 }
424
425 /* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
426 */
emit(HChar * buf,Int n)427 static void emit ( HChar* buf, Int n )
428 {
429 if (n >= 1)
430 (void)local_sys_write_stderr(buf, n);
431 }
432
433
434 /*------------------------------------------------------------*/
435 /*--- A simple, generic, vprintf implementation. ---*/
436 /*------------------------------------------------------------*/
437
438 /* -----------------------------------------------
439 Distantly derived from:
440
441 vprintf replacement for Checker.
442 Copyright 1993, 1994, 1995 Tristan Gingold
443 Written September 1993 Tristan Gingold
444 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
445
446 (Checker itself was GPL'd.)
447 ----------------------------------------------- */
448
449 /* Some flags. */
450 #define VG_MSG_SIGNED 1 /* The value is signed. */
451 #define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
452 #define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
453 #define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
454 #define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
455 #define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
456
457 /* Copy a string into the buffer. */
458 static
myvprintf_str(void (* send)(HChar,void *),void * send_arg2,Int flags,Int width,HChar * str,Bool capitalise)459 UInt myvprintf_str ( void(*send)(HChar,void*),
460 void* send_arg2,
461 Int flags,
462 Int width,
463 HChar* str,
464 Bool capitalise )
465 {
466 # define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
467 UInt ret = 0;
468 Int i, extra;
469 Int len = local_strlen(str);
470
471 if (width == 0) {
472 ret += len;
473 for (i = 0; i < len; i++)
474 send(MAYBE_TOUPPER(str[i]), send_arg2);
475 return ret;
476 }
477
478 if (len > width) {
479 ret += width;
480 for (i = 0; i < width; i++)
481 send(MAYBE_TOUPPER(str[i]), send_arg2);
482 return ret;
483 }
484
485 extra = width - len;
486 if (flags & VG_MSG_LJUSTIFY) {
487 ret += extra;
488 for (i = 0; i < extra; i++)
489 send(' ', send_arg2);
490 }
491 ret += len;
492 for (i = 0; i < len; i++)
493 send(MAYBE_TOUPPER(str[i]), send_arg2);
494 if (!(flags & VG_MSG_LJUSTIFY)) {
495 ret += extra;
496 for (i = 0; i < extra; i++)
497 send(' ', send_arg2);
498 }
499
500 # undef MAYBE_TOUPPER
501 return ret;
502 }
503
504
505 /* Copy a string into the buffer, escaping bad XML chars. */
506 static
myvprintf_str_XML_simplistic(void (* send)(HChar,void *),void * send_arg2,HChar * str)507 UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
508 void* send_arg2,
509 HChar* str )
510 {
511 UInt ret = 0;
512 Int i;
513 Int len = local_strlen(str);
514 HChar* alt;
515
516 for (i = 0; i < len; i++) {
517 switch (str[i]) {
518 case '&': alt = "&"; break;
519 case '<': alt = "<"; break;
520 case '>': alt = ">"; break;
521 default: alt = NULL;
522 }
523
524 if (alt) {
525 while (*alt) {
526 send(*alt, send_arg2);
527 ret++;
528 alt++;
529 }
530 } else {
531 send(str[i], send_arg2);
532 ret++;
533 }
534 }
535
536 return ret;
537 }
538
539
540 /* Write P into the buffer according to these args:
541 * If SIGN is true, p is a signed.
542 * BASE is the base.
543 * If WITH_ZERO is true, '0' must be added.
544 * WIDTH is the width of the field.
545 */
546 static
myvprintf_int64(void (* send)(HChar,void *),void * send_arg2,Int flags,Int base,Int width,Bool capitalised,ULong p)547 UInt myvprintf_int64 ( void(*send)(HChar,void*),
548 void* send_arg2,
549 Int flags,
550 Int base,
551 Int width,
552 Bool capitalised,
553 ULong p )
554 {
555 HChar buf[40];
556 Int ind = 0;
557 Int i, nc = 0;
558 Bool neg = False;
559 HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
560 UInt ret = 0;
561
562 if (base < 2 || base > 16)
563 return ret;
564
565 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
566 p = - (Long)p;
567 neg = True;
568 }
569
570 if (p == 0)
571 buf[ind++] = '0';
572 else {
573 while (p > 0) {
574 if (flags & VG_MSG_COMMA && 10 == base &&
575 0 == (ind-nc) % 3 && 0 != ind)
576 {
577 buf[ind++] = ',';
578 nc++;
579 }
580 buf[ind++] = digits[p % base];
581 p /= base;
582 }
583 }
584
585 if (neg)
586 buf[ind++] = '-';
587
588 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
589 for(; ind < width; ind++) {
590 /* vg_assert(ind < 39); */
591 if (ind > 39) {
592 buf[39] = 0;
593 break;
594 }
595 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
596 }
597 }
598
599 /* Reverse copy to buffer. */
600 ret += ind;
601 for (i = ind -1; i >= 0; i--) {
602 send(buf[i], send_arg2);
603 }
604 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
605 for(; ind < width; ind++) {
606 ret++;
607 /* Never pad with zeroes on RHS -- changes the value! */
608 send(' ', send_arg2);
609 }
610 }
611 return ret;
612 }
613
614
615 /* A simple vprintf(). */
616 /* EXPORTED */
617 UInt
VG_(debugLog_vprintf)618 VG_(debugLog_vprintf) (
619 void(*send)(HChar,void*),
620 void* send_arg2,
621 const HChar* format,
622 va_list vargs
623 )
624 {
625 UInt ret = 0;
626 Int i;
627 Int flags;
628 Int width;
629 Int n_ls = 0;
630 Bool is_long, caps;
631
632 /* We assume that vargs has already been initialised by the
633 caller, using va_start, and that the caller will similarly
634 clean up with va_end.
635 */
636
637 for (i = 0; format[i] != 0; i++) {
638 if (format[i] != '%') {
639 send(format[i], send_arg2);
640 ret++;
641 continue;
642 }
643 i++;
644 /* A '%' has been found. Ignore a trailing %. */
645 if (format[i] == 0)
646 break;
647 if (format[i] == '%') {
648 /* '%%' is replaced by '%'. */
649 send('%', send_arg2);
650 ret++;
651 continue;
652 }
653 flags = 0;
654 n_ls = 0;
655 width = 0; /* length of the field. */
656 while (1) {
657 switch (format[i]) {
658 case '(':
659 flags |= VG_MSG_PAREN;
660 break;
661 case ',':
662 case '\'':
663 /* If ',' or '\'' follows '%', commas will be inserted. */
664 flags |= VG_MSG_COMMA;
665 break;
666 case '-':
667 /* If '-' follows '%', justify on the left. */
668 flags |= VG_MSG_LJUSTIFY;
669 break;
670 case '0':
671 /* If '0' follows '%', pads will be inserted. */
672 flags |= VG_MSG_ZJUSTIFY;
673 break;
674 case '#':
675 /* If '#' follows '%', alternative format will be used. */
676 flags |= VG_MSG_ALTFORMAT;
677 break;
678 default:
679 goto parse_fieldwidth;
680 }
681 i++;
682 }
683 parse_fieldwidth:
684 /* Compute the field length. */
685 while (format[i] >= '0' && format[i] <= '9') {
686 width *= 10;
687 width += format[i++] - '0';
688 }
689 while (format[i] == 'l') {
690 i++;
691 n_ls++;
692 }
693
694 // %d means print a 32-bit integer.
695 // %ld means print a word-size integer.
696 // %lld means print a 64-bit integer.
697 if (0 == n_ls) { is_long = False; }
698 else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
699 else { is_long = True; }
700
701 switch (format[i]) {
702 case 'o': /* %o */
703 if (flags & VG_MSG_ALTFORMAT) {
704 ret += 2;
705 send('0',send_arg2);
706 }
707 if (is_long)
708 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
709 (ULong)(va_arg (vargs, ULong)));
710 else
711 ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
712 (ULong)(va_arg (vargs, UInt)));
713 break;
714 case 'd': /* %d */
715 flags |= VG_MSG_SIGNED;
716 if (is_long)
717 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
718 (ULong)(va_arg (vargs, Long)));
719 else
720 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
721 (ULong)(va_arg (vargs, Int)));
722 break;
723 case 'u': /* %u */
724 if (is_long)
725 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
726 (ULong)(va_arg (vargs, ULong)));
727 else
728 ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
729 (ULong)(va_arg (vargs, UInt)));
730 break;
731 case 'p':
732 if (format[i+1] == 'S') {
733 i++;
734 /* %pS, like %s but escaping chars for XML safety */
735 /* Note: simplistic; ignores field width and flags */
736 char *str = va_arg (vargs, char *);
737 if (str == (char*) 0)
738 str = "(null)";
739 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
740 } else if (format[i+1] == 's') {
741 i++;
742 /* %ps, synonym for %s with --xml=no / %pS with --xml=yes */
743 char *str = va_arg (vargs, char *);
744 if (str == (char*) 0)
745 str = "(null)";
746 if (clo_xml)
747 ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
748 else
749 ret += myvprintf_str(send, send_arg2, flags, width, str,
750 False);
751 } else {
752 /* %p */
753 ret += 2;
754 send('0',send_arg2);
755 send('x',send_arg2);
756 ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
757 (ULong)((UWord)va_arg (vargs, void *)));
758 }
759 break;
760 case 'x': /* %x */
761 case 'X': /* %X */
762 caps = toBool(format[i] == 'X');
763 if (flags & VG_MSG_ALTFORMAT) {
764 ret += 2;
765 send('0',send_arg2);
766 send('x',send_arg2);
767 }
768 if (is_long)
769 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
770 (ULong)(va_arg (vargs, ULong)));
771 else
772 ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
773 (ULong)(va_arg (vargs, UInt)));
774 break;
775 case 'c': /* %c */
776 ret++;
777 send(va_arg (vargs, int), send_arg2);
778 break;
779 case 's': case 'S': { /* %s */
780 char *str = va_arg (vargs, char *);
781 if (str == (char*) 0) str = "(null)";
782 ret += myvprintf_str(send, send_arg2,
783 flags, width, str, format[i]=='S');
784 break;
785 }
786
787 // case 'y': { /* %y - print symbol */
788 // Char buf[100];
789 // Char *cp = buf;
790 // Addr a = va_arg(vargs, Addr);
791 //
792 // if (flags & VG_MSG_PAREN)
793 // *cp++ = '(';
794 // if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
795 // if (flags & VG_MSG_PAREN) {
796 // cp += VG_(strlen)(cp);
797 // *cp++ = ')';
798 // *cp = '\0';
799 // }
800 // ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
801 // }
802 // break;
803 // }
804 default:
805 break;
806 }
807 }
808 return ret;
809 }
810
811
812 /*------------------------------------------------------------*/
813 /*--- Debuglog stuff. ---*/
814 /*------------------------------------------------------------*/
815
816 /* Only print messages whose stated level is less than or equal to
817 this. By default, it makes this entire subsystem silent. */
818
819 static Int loglevel = 0;
820
821 /* Module startup. */
822 /* EXPORTED */
VG_(debugLog_startup)823 void VG_(debugLog_startup) ( Int level, HChar* who )
824 {
825 if (level < 0) level = 0;
826 if (level > 10) level = 10;
827 loglevel = level;
828 VG_(debugLog)(1, "debuglog",
829 "DebugLog system started by %s, "
830 "level %d logging requested\n",
831 who, loglevel);
832 }
833
834 /* Get the logging threshold level, as set by the most recent call to
835 VG_(debugLog_startup), or zero if there have been no such calls so
836 far. */
837 /* EXPORTED */
VG_(debugLog_getLevel)838 Int VG_(debugLog_getLevel) ( void )
839 {
840 return loglevel;
841 }
842
843
844 /* ------------ */
845
846 typedef
847 struct {
848 HChar buf[100];
849 Int n;
850 }
851 printf_buf;
852
add_to_buf(HChar c,void * p)853 static void add_to_buf ( HChar c, void* p )
854 {
855 printf_buf* buf = (printf_buf*)p;
856
857 if (buf->n >= 100-10 /*paranoia*/ ) {
858 emit( buf->buf, local_strlen(buf->buf) );
859 buf->n = 0;
860 buf->buf[buf->n] = 0;
861 }
862 buf->buf[buf->n++] = c;
863 buf->buf[buf->n] = 0;
864 }
865
866 /* Send a logging message. Nothing is output unless 'level'
867 is <= the current loglevel. */
868 /* EXPORTED */
VG_(debugLog)869 void VG_(debugLog) ( Int level, const HChar* modulename,
870 const HChar* format, ... )
871 {
872 UInt pid;
873 Int indent, depth, i;
874 va_list vargs;
875 printf_buf buf;
876
877 if (level > loglevel)
878 return;
879
880 indent = 2*level - 1;
881 if (indent < 1) indent = 1;
882
883 buf.n = 0;
884 buf.buf[0] = 0;
885 pid = local_sys_getpid();
886
887 // Print one '>' in front of the messages for each level of self-hosting
888 // being performed.
889 depth = RUNNING_ON_VALGRIND;
890 for (i = 0; i < depth; i++) {
891 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
892 }
893
894 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
895 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)pid );
896 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
897 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, False, (ULong)level );
898 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
899 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
900 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
901
902 va_start(vargs,format);
903
904 (void) VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
905
906 if (buf.n > 0) {
907 emit( buf.buf, local_strlen(buf.buf) );
908 }
909
910 va_end(vargs);
911 }
912
913
914
915 /*--------------------------------------------------------------------*/
916 /*--- end m_debuglog.c ---*/
917 /*--------------------------------------------------------------------*/
918