AM_CPPFLAGS += -DVG_LIBDIR="\"$(valdir)"\" -I$(srcdir)/demangle \
-DKICKSTART_BASE=@KICKSTART_BASE@ \
- -DVG_PLATFORM="\"$(VG_PLATFORM)"\"
+ -DVG_PLATFORM="$(VG_PLATFORM)"
AM_CFLAGS = $(WERROR) -Wmissing-prototypes -Winline -Wall -Wshadow -O -g @ARCH_CORE_AM_CFLAGS@
AM_CFLAGS += -fno-omit-frame-pointer
pub_core_errormgr.h \
pub_core_execontext.h \
pub_core_stacktrace.h \
+ pub_core_sigframe.h \
+ pub_core_debuglog.h \
ume.h \
vg_symtab2.h \
vg_symtypes.h \
ume.c \
\
stage1.c \
+ m_debuglog.c \
${VG_ARCH}/jmp_with_stack.c
valgrind_DEPENDENCIES =
valgrind_LDFLAGS=-static -g
m_errormgr.c \
m_execontext.c \
m_stacktrace.c \
+ m_debuglog.c \
ume.c \
\
vg_scheduler.c \
$(PERL) $(srcdir)/gen_toolint.pl proto < $(srcdir)/toolfuncs.def > $@ || rm -f $@
$(PERL) $(srcdir)/gen_toolint.pl struct < $(srcdir)/toolfuncs.def >> $@ || rm -f $@
+
vg_inject_so_SOURCES = vg_intercept.c
vg_inject_so_CFLAGS = $(AM_CFLAGS) -fpic
vg_inject_so_LDADD = -ldl
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- Debug (not-for-user) logging; also vprintf. m_debuglog.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2005 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+
+/* Performs low-level debug logging that can safely run immediately
+ after startup. To minimise the dependencies on any other parts of
+ the system, the only place the debug output may go is file
+ descriptor 2 (stderr).
+*/
+/* This is the first-initialised module in the entire system!
+ Therefore it is CRITICAL that it does not depend on any other code
+ running first. Hence only the following very limited includes. We
+ cannot depend (directly or indirectly) on any dynamic memory
+ allocation facilities, nor on the m_libc facilities, since the
+ latter depend on this module. DO NOT MESS WITH THESE INCLUDES
+ UNLESS YOU ARE 100% CERTAIN YOU UNDERSTAND THE CONSEQUENCES.
+*/
+/* This module is also different from all others in the sense that it
+ is linked into both stage1 and stage2.
+*/
+#include "basic_types.h" /* basic types */
+#include "pub_core_debuglog.h" /* our own iface */
+
+
+/*------------------------------------------------------------*/
+/*--- Stuff to make us completely independent. ---*/
+/*------------------------------------------------------------*/
+
+/* ----- x86-linux specifics ----- */
+
+#if VG_PLATFORM == x86-linux
+
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+ UInt __res;
+ __asm__ volatile ("int $0x80"
+ : "=a" (__res)
+ : "0" (4), /* __NR_write */
+ "b" (2), /* stderr */
+ "c" (buf),
+ "d" (n) );
+ if (__res < 0)
+ __res = -1;
+ return __res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+ UInt __res;
+ __asm__ volatile ("int $0x80"
+ : "=a" (__res)
+ : "0" (20) /* __NR_getpid */);
+ return __res;
+}
+
+
+#else
+#error Unknown VG_PLATFORM
+#endif
+
+
+/* ----- generic ----- */
+
+/* strlen, so we don't need m_libc */
+static Int local_strlen ( const HChar* str )
+{
+ Int i = 0;
+ while (str[i] != 0) i++;
+ return i;
+}
+
+static HChar local_toupper ( HChar c )
+{
+ if (c >= 'a' && c <= 'z')
+ return c + ('A' - 'a');
+ else
+ return c;
+}
+
+/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
+*/
+static void emit ( HChar* buf, Int n )
+{
+ if (n >= 1)
+ (void)local_sys_write_stderr(buf, n);
+}
+
+
+/*------------------------------------------------------------*/
+/*--- A simple, generic, vprintf implementation. ---*/
+/*------------------------------------------------------------*/
+
+/* -----------------------------------------------
+ Distantly derived from:
+
+ vprintf replacement for Checker.
+ Copyright 1993, 1994, 1995 Tristan Gingold
+ Written September 1993 Tristan Gingold
+ Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
+
+ (Checker itself was GPL'd.)
+ ----------------------------------------------- */
+
+/* Some flags. */
+#define VG_MSG_SIGNED 1 /* The value is signed. */
+#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
+#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
+#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
+#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
+
+
+/* Copy a string into the buffer. */
+static
+UInt myvprintf_str ( void(*send)(HChar,void*),
+ void* send_arg2,
+ Int flags,
+ Int width,
+ HChar* str,
+ Bool capitalise )
+{
+# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
+ UInt ret = 0;
+ Int i, extra;
+ Int len = local_strlen(str);
+
+ if (width == 0) {
+ ret += len;
+ for (i = 0; i < len; i++)
+ send(MAYBE_TOUPPER(str[i]), send_arg2);
+ return ret;
+ }
+
+ if (len > width) {
+ ret += width;
+ for (i = 0; i < width; i++)
+ send(MAYBE_TOUPPER(str[i]), send_arg2);
+ return ret;
+ }
+
+ extra = width - len;
+ if (flags & VG_MSG_LJUSTIFY) {
+ ret += extra;
+ for (i = 0; i < extra; i++)
+ send(' ', send_arg2);
+ }
+ ret += len;
+ for (i = 0; i < len; i++)
+ send(MAYBE_TOUPPER(str[i]), send_arg2);
+ if (!(flags & VG_MSG_LJUSTIFY)) {
+ ret += extra;
+ for (i = 0; i < extra; i++)
+ send(' ', send_arg2);
+ }
+
+# undef MAYBE_TOUPPER
+ return ret;
+}
+
+
+/* Write P into the buffer according to these args:
+ * If SIGN is true, p is a signed.
+ * BASE is the base.
+ * If WITH_ZERO is true, '0' must be added.
+ * WIDTH is the width of the field.
+ */
+static
+UInt myvprintf_int64 ( void(*send)(HChar,void*),
+ void* send_arg2,
+ Int flags,
+ Int base,
+ Int width,
+ ULong p )
+{
+ HChar buf[40];
+ Int ind = 0;
+ Int i, nc = 0;
+ Bool neg = False;
+ HChar* digits = "0123456789ABCDEF";
+ UInt ret = 0;
+
+ if (base < 2 || base > 16)
+ return ret;
+
+ if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
+ p = - (Long)p;
+ neg = True;
+ }
+
+ if (p == 0)
+ buf[ind++] = '0';
+ else {
+ while (p > 0) {
+ if (flags & VG_MSG_COMMA && 10 == base &&
+ 0 == (ind-nc) % 3 && 0 != ind)
+ {
+ buf[ind++] = ',';
+ nc++;
+ }
+ buf[ind++] = digits[p % base];
+ p /= base;
+ }
+ }
+
+ if (neg)
+ buf[ind++] = '-';
+
+ if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
+ for(; ind < width; ind++) {
+ /* vg_assert(ind < 39); */
+ if (ind > 39) {
+ buf[39] = 0;
+ break;
+ }
+ buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
+ }
+ }
+
+ /* Reverse copy to buffer. */
+ ret += ind;
+ for (i = ind -1; i >= 0; i--) {
+ send(buf[i], send_arg2);
+ }
+ if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
+ for(; ind < width; ind++) {
+ ret++;
+ /* Never pad with zeroes on RHS -- changes the value! */
+ send(' ', send_arg2);
+ }
+ }
+ return ret;
+}
+
+
+/* A simple vprintf(). */
+/* EXPORTED */
+UInt
+VG_(debugLog_vprintf) (
+ void(*send)(HChar,void*),
+ void* send_arg2,
+ const HChar* format,
+ va_list vargs
+)
+{
+ UInt ret = 0;
+ Int i;
+ Int flags;
+ Int width;
+ Bool is_long;
+
+ /* We assume that vargs has already been initialised by the
+ caller, using va_start, and that the caller will similarly
+ clean up with va_end.
+ */
+
+ for (i = 0; format[i] != 0; i++) {
+ if (format[i] != '%') {
+ send(format[i], send_arg2);
+ ret++;
+ continue;
+ }
+ i++;
+ /* A '%' has been found. Ignore a trailing %. */
+ if (format[i] == 0)
+ break;
+ if (format[i] == '%') {
+ /* `%%' is replaced by `%'. */
+ send('%', send_arg2);
+ ret++;
+ continue;
+ }
+ flags = 0;
+ is_long = False;
+ width = 0; /* length of the field. */
+ if (format[i] == '(') {
+ flags |= VG_MSG_PAREN;
+ i++;
+ }
+ /* If ',' follows '%', commas will be inserted. */
+ if (format[i] == ',') {
+ flags |= VG_MSG_COMMA;
+ i++;
+ }
+ /* If '-' follows '%', justify on the left. */
+ if (format[i] == '-') {
+ flags |= VG_MSG_LJUSTIFY;
+ i++;
+ }
+ /* If '0' follows '%', pads will be inserted. */
+ if (format[i] == '0') {
+ flags |= VG_MSG_ZJUSTIFY;
+ i++;
+ }
+ /* Compute the field length. */
+ while (format[i] >= '0' && format[i] <= '9') {
+ width *= 10;
+ width += format[i++] - '0';
+ }
+ while (format[i] == 'l') {
+ i++;
+ is_long = True;
+ }
+
+ switch (format[i]) {
+ case 'd': /* %d */
+ flags |= VG_MSG_SIGNED;
+ if (is_long)
+ ret += myvprintf_int64(send, send_arg2, flags, 10, width,
+ (ULong)(va_arg (vargs, Long)));
+ else
+ ret += myvprintf_int64(send, send_arg2, flags, 10, width,
+ (ULong)(va_arg (vargs, Int)));
+ break;
+ case 'u': /* %u */
+ if (is_long)
+ ret += myvprintf_int64(send, send_arg2, flags, 10, width,
+ (ULong)(va_arg (vargs, ULong)));
+ else
+ ret += myvprintf_int64(send, send_arg2, flags, 10, width,
+ (ULong)(va_arg (vargs, UInt)));
+ break;
+ case 'p': /* %p */
+ ret += 2;
+ send('0',send_arg2);
+ send('x',send_arg2);
+ ret += myvprintf_int64(send, send_arg2, flags, 16, width,
+ (ULong)((UWord)va_arg (vargs, void *)));
+ break;
+ case 'x': /* %x */
+ if (is_long)
+ ret += myvprintf_int64(send, send_arg2, flags, 16, width,
+ (ULong)(va_arg (vargs, ULong)));
+ else
+ ret += myvprintf_int64(send, send_arg2, flags, 16, width,
+ (ULong)(va_arg (vargs, UInt)));
+ break;
+ case 'c': /* %c */
+ ret++;
+ send(va_arg (vargs, int), send_arg2);
+ break;
+ case 's': case 'S': { /* %s */
+ char *str = va_arg (vargs, char *);
+ if (str == (char*) 0) str = "(null)";
+ ret += myvprintf_str(send, send_arg2,
+ flags, width, str, format[i]=='S');
+ break;
+ }
+// case 'y': { /* %y - print symbol */
+// Char buf[100];
+// Char *cp = buf;
+// Addr a = va_arg(vargs, Addr);
+//
+// if (flags & VG_MSG_PAREN)
+// *cp++ = '(';
+// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
+// if (flags & VG_MSG_PAREN) {
+// cp += VG_(strlen)(cp);
+// *cp++ = ')';
+// *cp = '\0';
+// }
+// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
+// }
+// break;
+// }
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Debuglog stuff. ---*/
+/*------------------------------------------------------------*/
+
+/* Only print messages whose stated level is less than or equal to
+ this. By default, it makes this entire subsystem silent. */
+
+static Int loglevel = 0;
+
+/* EXPORTED */
+/* Module startup. */
+void VG_(debugLog_startup) ( Int level, HChar* who )
+{
+ if (level < 0) level = 0;
+ if (level > 10) level = 10;
+ loglevel = level;
+ VG_(debugLog)(1, "debuglog",
+ "DebugLog system started by %s, "
+ "level %d logging requested\n",
+ who, loglevel);
+}
+
+/* ------------ */
+
+typedef
+ struct {
+ HChar buf[100];
+ Int n;
+ }
+ printf_buf;
+
+static void add_to_buf ( HChar c, void* p )
+{
+ printf_buf* buf = (printf_buf*)p;
+
+ if (buf->n >= 100-10 /*paranoia*/ ) {
+ emit( buf->buf, local_strlen(buf->buf) );
+ buf->n = 0;
+ buf->buf[buf->n] = 0;
+ }
+ buf->buf[buf->n++] = c;
+ buf->buf[buf->n] = 0;
+}
+
+/* Send a logging message. Nothing is output unless 'level'
+ is <= the current loglevel. */
+/* EXPORTED */
+__attribute__((format(__printf__, 3, 4)))
+void VG_(debugLog) ( Int level, const HChar* modulename,
+ const HChar* format, ... )
+{
+ UInt ret, pid;
+ va_list vargs;
+ printf_buf buf;
+
+ if (level > loglevel)
+ return;
+
+ buf.n = 0;
+ buf.buf[0] = 0;
+ pid = local_sys_getpid();
+ (void)myvprintf_str ( add_to_buf, &buf, 0, 1, "<", False );
+ (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 5, (ULong)pid );
+ (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ",", False );
+ (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)level );
+ (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ",", False );
+ (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
+ (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "> ", False );
+
+ va_start(vargs,format);
+
+ ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
+
+ if (buf.n > 0) {
+ emit( buf.buf, local_strlen(buf.buf) );
+ }
+
+ va_end(vargs);
+}
+
+
+
+/*--------------------------------------------------------------------*/
+/*--- end m_debuglog.c ---*/
+/*--------------------------------------------------------------------*/
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- Debug (not-for-user) logging. pub_core_debuglog.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2005 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_DEBUGLOG_H
+#define __PUB_CORE_DEBUGLOG_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module provides a low-level debug logging facility
+// that works through all the twists and turns of program startup. Is
+// is completely independent of everything, including all memory
+// facilities, and emits the debug log on file descriptor 2 (stderr).
+// This module is the first to be initialised at system startup.
+//
+// Because VG_(debugLog) does printf-style formatting, and because
+// this module depends on NO OTHERS, this module contains Valgrind's
+// vfprintf implementation too.
+//--------------------------------------------------------------------
+
+/* Gaaah! We don't want glibc dependencies, but there is no easy,
+ portable way to avoid using stdarg.h. */
+#include <stdarg.h>
+
+#include "core_asm.h" /* For definition of VG_ macro */
+
+/* There are no tool-visible exports from m_debuglog, hence no header
+ file for it. */
+/* #include "pub_tool_debuglog.h" */
+
+
+/* Module startup. */
+extern
+void VG_(debugLog_startup) ( Int level, HChar* who );
+
+/* Send debugging output. Nothing happens unless 'level'
+ does not exceed the logging threshold level. */
+extern
+__attribute__((format(__printf__, 3, 4)))
+void VG_(debugLog) ( Int level, const HChar* modulename,
+ const HChar* format, ... );
+
+/* A simple vprintf(). For each emitted byte, (*send) is called with
+ that byte, and 'send_arg2' as its second param. */
+extern
+UInt VG_(debugLog_vprintf) (
+ void (*send)(HChar,void*), /* byte sink */
+ void* send_arg2, /* 2nd arg for byte sink */
+ const HChar *format,
+ va_list vargs
+ );
+
+
+#endif // __PUB_CORE_DEBUGLOG_H
+
+/*--------------------------------------------------------------------*/
+/*--- end pub_core_debuglog.h ---*/
+/*--------------------------------------------------------------------*/
#include "core.h"
#include "ume.h"
#include "memcheck/memcheck.h"
+#include "pub_core_debuglog.h"
+
static int stack[SIGSTKSZ*4];
foreach_map(prmap, /*dummy*/NULL);
}
+ VG_(debugLog)(1, "stage1", "main2(): starting stage2\n");
jump_and_switch_stacks(
(Addr) esp, /* stack */
(Addr) info.init_eip /* where to */
{
struct rlimit rlim;
const char *cp;
+ int i, loglevel;
+
+ /* Start the debugging-log system ASAP. First find out how many
+ "-d"s were specified. This is a pre-scan of the command line. */
+ loglevel = 0;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-')
+ break;
+ if (0 == strcmp(argv[i], "--"))
+ break;
+ if (0 == strcmp(argv[i], "-d"))
+ loglevel++;
+ }
+
+ /* ... and start the debug logger. Now we can safely emit logging
+ messages all through startup. */
+ VG_(debugLog_startup)(loglevel, "Stage 1");
// Initial stack pointer is to argc, which is immediately before argv[0]
// on the stack. Nb: Assumes argc is word-aligned.
setrlimit(RLIMIT_AS, &rlim);
/* move onto another stack so we can play with the main one */
+ VG_(debugLog)(1, "stage1", "main(): running main2() on new stack\n");
jump_and_switch_stacks(
(Addr) stack + sizeof(stack), /* stack */
(Addr) main2 /* where to */
#include "ume.h"
#include "pub_core_execontext.h"
#include "pub_core_errormgr.h"
+#include "pub_core_debuglog.h"
#include <dirent.h>
#include <dlfcn.h>
VG_CLO_STREQ(arg, "--quiet"))
VG_(clo_verbosity)--;
+ else if (VG_CLO_STREQ(arg, "-d")) {
+ /* do nothing */
+ }
+
else VG_BOOL_CLO(arg, "--branchpred", VG_(clo_branchpred))
else VG_BOOL_CLO(arg, "--db-attach", VG_(clo_db_attach))
else VG_BOOL_CLO(arg, "--demangle", VG_(clo_demangle))
return True;
}
+/* This may be needed before m_mylibc is OK to run. */
+static Int local_strcmp ( const HChar* s1, const HChar* s2 )
+{
+ while (True) {
+ if (*s1 == 0 && *s2 == 0) return 0;
+ if (*s1 == 0) return -1;
+ if (*s2 == 0) return 1;
+
+ if (*(UChar*)s1 < *(UChar*)s2) return -1;
+ if (*(UChar*)s1 > *(UChar*)s2) return 1;
+
+ s1++; s2++;
+ }
+}
+
+
int main(int argc, char **argv, char **envp)
{
char **cl_argv;
Addr sp_at_startup; /* client's SP at the point we gained control. */
UInt * client_auxv;
struct vki_rlimit zero = { 0, 0 };
- Int padfile;
+ Int padfile, loglevel, i;
//============================================================
// Nb: startup is complex. Prerequisites are shown at every step.
// *** Be very careful when messing with the order ***
//============================================================
+ //--------------------------------------------------------------
+ // Start up the logging mechanism
+ // p: none
+ //--------------------------------------------------------------
+ /* Start the debugging-log system ASAP. First find out how many
+ "-d"s were specified. This is a pre-scan of the command line. */
+ loglevel = 0;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-')
+ break;
+ if (0 == local_strcmp(argv[i], "--"))
+ break;
+ if (0 == local_strcmp(argv[i], "-d"))
+ loglevel++;
+ }
+
+ /* ... and start the debug logger. Now we can safely emit logging
+ messages all through startup. */
+ VG_(debugLog_startup)(loglevel, "Stage 2");
+
//============================================================
// Command line argument handling order:
// * If --help/--help-debug are present, show usage message
#include "core.h"
+#include "pub_core_debuglog.h" /* VG_(debugLog_vprintf) */
#include <time.h>
#include <sys/time.h>
static char mbuf[M_MSGBUF];
static int n_mbuf;
-static void add_to_buf ( Char c, void *p )
+static void add_to_buf ( HChar c, void *p )
{
if (n_mbuf >= (M_MSGBUF-1)) return;
mbuf[n_mbuf++] = c;
int count;
va_list vargs;
va_start(vargs,format);
- count = VG_(vprintf) ( add_to_buf, format, vargs, 0 );
+ count = VG_(debugLog_vprintf) ( add_to_buf, NULL, format, vargs );
va_end(vargs);
return count;
}
{
int count;
count = start_msg ( kind );
- count += VG_(vprintf) ( add_to_buf, format, vargs, 0 );
+ count += VG_(debugLog_vprintf) ( add_to_buf, NULL, format, vargs );
count += end_msg();
return count;
}
#include "core.h"
#include "pub_core_stacktrace.h"
+#include "pub_core_debuglog.h" /* VG_(debugLog_vprintf) */
+
/* ---------------------------------------------------------------------
Wrappers around system calls, and other stuff, to do with signals.
}
-/* ---------------------------------------------------------------------
- printf implementation. The key function, vg_vprintf(), emits chars
- into a caller-supplied function. Distantly derived from:
-
- vprintf replacement for Checker.
- Copyright 1993, 1994, 1995 Tristan Gingold
- Written September 1993 Tristan Gingold
- Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
-
- (Checker itself was GPL'd.)
- ------------------------------------------------------------------ */
-
-
-/* Some flags. */
-#define VG_MSG_SIGNED 1 /* The value is signed. */
-#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
-#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
-#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
-#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
-
-/* Copy a string into the buffer. */
-static UInt
-myvprintf_str ( void(*send)(Char, void*), Int flags, Int width, Char* str,
- Bool capitalise, void *send_arg )
-{
-# define MAYBE_TOUPPER(ch) (capitalise ? VG_(toupper)(ch) : (ch))
- UInt ret = 0;
- Int i, extra;
- Int len = VG_(strlen)(str);
-
- if (width == 0) {
- ret += len;
- for (i = 0; i < len; i++)
- send(MAYBE_TOUPPER(str[i]), send_arg);
- return ret;
- }
-
- if (len > width) {
- ret += width;
- for (i = 0; i < width; i++)
- send(MAYBE_TOUPPER(str[i]), send_arg);
- return ret;
- }
-
- extra = width - len;
- if (flags & VG_MSG_LJUSTIFY) {
- ret += extra;
- for (i = 0; i < extra; i++)
- send(' ', send_arg);
- }
- ret += len;
- for (i = 0; i < len; i++)
- send(MAYBE_TOUPPER(str[i]), send_arg);
- if (!(flags & VG_MSG_LJUSTIFY)) {
- ret += extra;
- for (i = 0; i < extra; i++)
- send(' ', send_arg);
- }
-
-# undef MAYBE_TOUPPER
-
- return ret;
-}
-
-/* Write P into the buffer according to these args:
- * If SIGN is true, p is a signed.
- * BASE is the base.
- * If WITH_ZERO is true, '0' must be added.
- * WIDTH is the width of the field.
- */
-static UInt
-myvprintf_int64 ( void(*send)(Char,void*), Int flags, Int base, Int width, ULong p, void *send_arg)
-{
- Char buf[40];
- Int ind = 0;
- Int i, nc = 0;
- Bool neg = False;
- Char *digits = "0123456789ABCDEF";
- UInt ret = 0;
-
- if (base < 2 || base > 16)
- return ret;
-
- if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
- p = - (Long)p;
- neg = True;
- }
-
- if (p == 0)
- buf[ind++] = '0';
- else {
- while (p > 0) {
- if (flags & VG_MSG_COMMA && 10 == base &&
- 0 == (ind-nc) % 3 && 0 != ind)
- {
- buf[ind++] = ',';
- nc++;
- }
- buf[ind++] = digits[p % base];
- p /= base;
- }
- }
-
- if (neg)
- buf[ind++] = '-';
-
- if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
- for(; ind < width; ind++) {
- vg_assert(ind < 39);
- buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
- }
- }
-
- /* Reverse copy to buffer. */
- ret += ind;
- for (i = ind -1; i >= 0; i--) {
- send(buf[i], send_arg);
- }
- if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
- for(; ind < width; ind++) {
- ret++;
- send(' ', send_arg); // Never pad with zeroes on RHS -- changes the value!
- }
- }
- return ret;
-}
-
-
-/* A simple vprintf(). */
-UInt
-VG_(vprintf) ( void(*send)(Char,void*), const Char *format, va_list vargs, void *send_arg )
-{
- UInt ret = 0;
- int i;
- int flags;
- int width;
- Bool is_long;
-
- /* We assume that vargs has already been initialised by the
- caller, using va_start, and that the caller will similarly
- clean up with va_end.
- */
-
- for (i = 0; format[i] != 0; i++) {
- if (format[i] != '%') {
- send(format[i], send_arg);
- ret++;
- continue;
- }
- i++;
- /* A '%' has been found. Ignore a trailing %. */
- if (format[i] == 0)
- break;
- if (format[i] == '%') {
- /* `%%' is replaced by `%'. */
- send('%', send_arg);
- ret++;
- continue;
- }
- flags = 0;
- is_long = False;
- width = 0; /* length of the field. */
- if (format[i] == '(') {
- flags |= VG_MSG_PAREN;
- i++;
- }
- /* If ',' follows '%', commas will be inserted. */
- if (format[i] == ',') {
- flags |= VG_MSG_COMMA;
- i++;
- }
- /* If '-' follows '%', justify on the left. */
- if (format[i] == '-') {
- flags |= VG_MSG_LJUSTIFY;
- i++;
- }
- /* If '0' follows '%', pads will be inserted. */
- if (format[i] == '0') {
- flags |= VG_MSG_ZJUSTIFY;
- i++;
- }
- /* Compute the field length. */
- while (format[i] >= '0' && format[i] <= '9') {
- width *= 10;
- width += format[i++] - '0';
- }
- while (format[i] == 'l') {
- i++;
- is_long = True;
- }
-
- switch (format[i]) {
- case 'd': /* %d */
- flags |= VG_MSG_SIGNED;
- if (is_long)
- ret += myvprintf_int64(send, flags, 10, width,
- (ULong)(va_arg (vargs, Long)), send_arg);
- else
- ret += myvprintf_int64(send, flags, 10, width,
- (ULong)(va_arg (vargs, Int)), send_arg);
- break;
- case 'u': /* %u */
- if (is_long)
- ret += myvprintf_int64(send, flags, 10, width,
- (ULong)(va_arg (vargs, ULong)), send_arg);
- else
- ret += myvprintf_int64(send, flags, 10, width,
- (ULong)(va_arg (vargs, UInt)), send_arg);
- break;
- case 'p': /* %p */
- ret += 2;
- send('0',send_arg);
- send('x',send_arg);
- ret += myvprintf_int64(send, flags, 16, width,
- (ULong)((UWord)va_arg (vargs, void *)), send_arg);
- break;
- case 'x': /* %x */
- if (is_long)
- ret += myvprintf_int64(send, flags, 16, width,
- (ULong)(va_arg (vargs, ULong)), send_arg);
- else
- ret += myvprintf_int64(send, flags, 16, width,
- (ULong)(va_arg (vargs, UInt)), send_arg);
- break;
- case 'c': /* %c */
- ret++;
- send(va_arg (vargs, int), send_arg);
- break;
- case 's': case 'S': { /* %s */
- char *str = va_arg (vargs, char *);
- if (str == (char*) 0) str = "(null)";
- ret += myvprintf_str(send, flags, width, str, format[i]=='S', send_arg);
- break;
- }
- case 'y': { /* %y - print symbol */
- Char buf[100];
- Char *cp = buf;
- Addr a = va_arg(vargs, Addr);
-
- if (flags & VG_MSG_PAREN)
- *cp++ = '(';
- if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
- if (flags & VG_MSG_PAREN) {
- cp += VG_(strlen)(cp);
- *cp++ = ')';
- *cp = '\0';
- }
- ret += myvprintf_str(send, flags, width, buf, 0, send_arg);
- }
-
- break;
- }
- default:
- break;
- }
- }
- return ret;
-}
-
-
/* A general replacement for printf(). Note that only low-level
debugging info should be sent via here. The official route is to
to use vg_message(). This interface is deprecated.
int n;
} printf_buf;
-static void add_to_myprintf_buf ( Char c, void *p )
+static void add_to_myprintf_buf ( HChar c, void *p )
{
printf_buf *myprintf_buf = (printf_buf *)p;
printf_buf myprintf_buf = {"",0};
va_start(vargs,format);
- ret = VG_(vprintf) ( add_to_myprintf_buf, format, vargs, &myprintf_buf );
+ ret = VG_(debugLog_vprintf)
+ ( add_to_myprintf_buf, &myprintf_buf, format, vargs );
if (myprintf_buf.n > 0 && VG_(clo_log_fd) >= 0) {
VG_(send_bytes_to_logging_sink)( myprintf_buf.buf, myprintf_buf.n );
}
/* A general replacement for sprintf(). */
-static void add_to_vg_sprintf_buf ( Char c, void *p )
+static void add_to_vg_sprintf_buf ( HChar c, void *p )
{
char **vg_sprintf_ptr = p;
*(*vg_sprintf_ptr)++ = c;
va_start(vargs,format);
- ret = VG_(vprintf) ( add_to_vg_sprintf_buf, format, vargs, &vg_sprintf_ptr );
+ ret = VG_(debugLog_vprintf)
+ ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
add_to_vg_sprintf_buf(0,&vg_sprintf_ptr);
va_end(vargs);
entered = True;
va_start(vargs,format);
- VG_(vprintf) ( add_to_vg_sprintf_buf, format, vargs, &bufptr );
+ VG_(debugLog_vprintf) ( add_to_vg_sprintf_buf, &bufptr, format, vargs );
add_to_vg_sprintf_buf('\0', &bufptr);
va_end(vargs);
#include "core.h"
#include "vg_symtypes.h"
+#include "pub_core_debuglog.h" /* VG_(debugLog_vprintf) */
typedef enum {
TyUnknown, /* unknown type */
}
}
-static void bprintf(void (*send)(Char, void*), void *send_arg, const Char *fmt, ...)
+static
+void bprintf(void (*send)(HChar, void*), void *send_arg, const Char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
- VG_(vprintf)(send, fmt, vargs, send_arg);
+ VG_(debugLog_vprintf)(send, send_arg, fmt, vargs);
va_end(vargs);
}
static UInt describe_addr_bufsz;
/* Add a character to the result buffer */
-static void describe_addr_addbuf(Char c,void *p) {
+static void describe_addr_addbuf(HChar c,void *p) {
if ((describe_addr_bufidx+1) >= describe_addr_bufsz) {
Char *n;
extern UInt VG_(printf) ( const char *format, ... );
/* too noisy ... __attribute__ ((format (printf, 1, 2))) ; */
extern UInt VG_(sprintf) ( Char* buf, Char *format, ... );
-extern UInt VG_(vprintf) ( void(*send)(Char, void *),
- const Char *format, va_list vargs, void *send_arg );
extern Int VG_(rename) ( Char* old_name, Char* new_name );