rtld: Make thread-safe by replacing libc printf functions
authorJohn Marino <draco@marino.st>
Sat, 21 Jan 2012 15:07:30 +0000 (16:07 +0100)
committerJohn Marino <draco@marino.st>
Mon, 23 Jan 2012 16:13:17 +0000 (17:13 +0100)
The dynamic linker is linked with the specially built static pic libc to
get some C runtime services such as printf().  Unfortunately, the
multithread-safeness measures in libc do now work in the rtld environment.

The dynlinker now uses FreeBSD's kernel printf() implementation instead of
libc's version.  This printf does not require any shared global data and
thus is mt-safe.  This commit replaces printf() and related functions with
rtld_ versions, and also removes calls to err(3).

Currently stdio is still pulled from libc within the libmap implementation
that uses fopen().  This is safe, yet not optimal, and is a candidate for
future change.

The makefile was cleaned up to remove the unused bits to building an
executable dynlinker and also require gnu99.

Taken-from: FreeBSD SVN 225152

libexec/rtld-elf/Makefile
libexec/rtld-elf/debug.c
libexec/rtld-elf/malloc.c
libexec/rtld-elf/rtld.c
libexec/rtld-elf/rtld.h
libexec/rtld-elf/rtld_lock.c
libexec/rtld-elf/rtld_printf.c [new file with mode: 0644]
libexec/rtld-elf/rtld_printf.h [copied from libexec/rtld-elf/xmalloc.c with 67% similarity]
libexec/rtld-elf/xmalloc.c

index 347aff1..3527ad1 100644 (file)
@@ -1,9 +1,11 @@
-# $FreeBSD: src/libexec/rtld-elf/Makefile,v 1.10.2.6 2002/06/22 17:03:13 jdp Exp $
+# $FreeBSD$
 
 PROG=          ld-elf.so.2
-SRCS=          rtld_start.S rtld.c rtld_lock.c map_object.c malloc.c \
-               xmalloc.c debug.c reloc.c libmap.c
+SRCS=          rtld_start.S \
+               reloc.c rtld.c rtld_lock.c rtld_printf.c map_object.c \
+               malloc.c xmalloc.c debug.c libmap.c
 MAN=           rtld.1
+CSTD?=         gnu99
 WARNS?=                2
 
 # To activate LD_DEBUG functionality, define ENABLE_DEBUG
@@ -24,25 +26,15 @@ MLINKS+=    rtld.1 _rtld_functrace.3
 .include "${.CURDIR}/${MACHINE_ARCH}/Makefile.inc"
 .endif
 
-.ifdef LDSCRIPT
-OBJS+=         dyn_hack.so
-LDFLAGS+=      -Wl,-T,${LDSCRIPT} -Wl,-E -Wl,-Bstatic
-DPADD=         ${.OBJDIR}/../../lib/libc_rtld/libc_rtld.a
-LDADD=         -L${.OBJDIR}/../../lib/libc_rtld -lc_rtld
-.else
 CFLAGS+=       -fpic -DPIC
 LDFLAGS+=      -shared -Wl,-Bsymbolic
 DPADD=         ${.OBJDIR}/../../lib/libc_rtld/libc_rtld_pic.a
 LDADD=         -L${.OBJDIR}/../../lib/libc_rtld -lc_rtld_pic
-.endif
 
 .ifdef ENABLE_DEBUG
 CFLAGS+=       -DDEBUG
 .endif
 
-dyn_hack.so:
-       ${CC} -shared -nostdlib -o dyn_hack.so -x c /dev/null
-
 .PATH: ${.CURDIR}/${MACHINE_ARCH}
 
 .include <bsd.prog.mk>
index 3b7611c..8f8311c 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "debug.h"
 #include "rtld.h"
+#include "rtld_printf.h"
 
 static const char rel_header[] =
     " symbol name               r_info r_offset st_value st_size    address    value\n"
@@ -49,9 +50,8 @@ debug_printf(const char *format, ...)
        va_list ap;
        va_start(ap, format);
 
-       fflush(stdout);
-       vfprintf(stderr, format, ap);
-       putc('\n', stderr);
+       rtld_vfdprintf(STDERR_FILENO, format, ap);
+       rtld_fdputchar(STDERR_FILENO, '\n');
 
        va_end(ap);
     }
@@ -71,28 +71,28 @@ void
 dump_obj_relocations (Obj_Entry *obj)
 {
 
-    printf("Object \"%s\", relocbase %p\n", obj->path, obj->relocbase);
+    rtld_printf("Object \"%s\", relocbase %p\n", obj->path, obj->relocbase);
 
     if (obj->relsize) {
-        printf("Non-PLT Relocations: %ld\n",
+        rtld_printf("Non-PLT Relocations: %ld\n",
             (obj->relsize / sizeof(Elf_Rel)));
         dump_Elf_Rel(obj, obj->rel, obj->relsize);
     }
 
     if (obj->relasize) {
-        printf("Non-PLT Relocations with Addend: %ld\n",
+        rtld_printf("Non-PLT Relocations with Addend: %ld\n",
             (obj->relasize / sizeof(Elf_Rela)));
         dump_Elf_Rela(obj, obj->rela, obj->relasize);
     }
 
     if (obj->pltrelsize) {
-        printf("PLT Relocations: %ld\n",
+        rtld_printf("PLT Relocations: %ld\n",
             (obj->pltrelsize / sizeof(Elf_Rel)));
         dump_Elf_Rel(obj, obj->pltrel, obj->pltrelsize);
     }
 
     if (obj->pltrelasize) {
-        printf("PLT Relocations with Addend: %ld\n",
+        rtld_printf("PLT Relocations with Addend: %ld\n",
             (obj->pltrelasize / sizeof(Elf_Rela)));
         dump_Elf_Rela(obj, obj->pltrela, obj->pltrelasize);
     }
@@ -106,12 +106,12 @@ dump_Elf_Rel (Obj_Entry *obj, const Elf_Rel *rel0, u_long relsize)
     const Elf_Sym *sym;
     Elf_Addr *dstaddr;
 
-    printf("%s", rel_header);
+    rtld_putstr(rel_header);
     rellim = (const Elf_Rel *)((const char *)rel0 + relsize);
     for (rel = rel0; rel < rellim; rel++) {
        dstaddr = (Elf_Addr *)(obj->relocbase + rel->r_offset);
         sym = obj->symtab + ELF_R_SYM(rel->r_info);
-        printf(rel_format,
+        rtld_printf(rel_format,
                obj->strtab + sym->st_name,
                (u_long)rel->r_info, (u_long)rel->r_offset,
                (u_long)sym->st_value, (int)sym->st_size,
@@ -128,12 +128,12 @@ dump_Elf_Rela (Obj_Entry *obj, const Elf_Rela *rela0, u_long relasize)
     const Elf_Sym *sym;
     Elf_Addr *dstaddr;
 
-    printf("%s", rel_header);
+    rtld_putstr(rel_header);
     relalim = (const Elf_Rela *)((const char *)rela0 + relasize);
     for (rela = rela0; rela < relalim; rela++) {
        dstaddr = (Elf_Addr *)(obj->relocbase + rela->r_offset);
         sym = obj->symtab + ELF_R_SYM(rela->r_info);
-        printf(rel_format,
+        rtld_printf(rel_format,
                obj->strtab + sym->st_name,
                (u_long)rela->r_info, (u_long)rela->r_offset,
                (u_long)sym->st_value, (int)sym->st_size,
index 7d31c95..413bbb9 100644 (file)
@@ -43,7 +43,6 @@
  */
 
 #include <sys/types.h>
-#include <err.h>
 #include <paths.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -52,6 +51,7 @@
 #include <unistd.h>
 #include <sys/param.h>
 #include <sys/mman.h>
+#include "rtld_printf.h"
 #ifndef BSD
 #define MAP_COPY       MAP_PRIVATE
 #define MAP_FILE       0
@@ -64,7 +64,6 @@
 
 static void morecore();
 static int findbucket();
-static void xprintf(const char *, ...) __printflike(1, 2);
 
 /*
  * Pre-allocate mmap'ed pages
@@ -144,8 +143,7 @@ botch(s)
 #endif
 
 /* Debugging stuff */
-static void xprintf(const char *, ...);
-#define TRACE()        xprintf("TRACE %s:%d\n", __FILE__, __LINE__)
+#define TRACE()        rtld_printf("TRACE %s:%d\n", __FILE__, __LINE__)
 
 void *
 malloc(nbytes)
@@ -476,7 +474,8 @@ int n;
                caddr_t addr = (caddr_t)
                        (((long)pagepool_start + pagesz - 1) & ~(pagesz - 1));
                if (munmap(addr, pagepool_end - addr) != 0)
-                       warn("morepages: munmap %p", addr);
+                       rtld_fdprintf(STDERR_FILENO, "morepages: munmap %p",
+                           addr);
        }
 
        offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1));
@@ -484,7 +483,7 @@ int n;
        if ((pagepool_start = mmap(0, n * pagesz,
                        PROT_READ|PROT_WRITE,
                        MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) {
-               xprintf("Cannot map anonymous memory");
+               rtld_printf("Cannot map anonymous memory\n");
                return 0;
        }
        pagepool_end = pagepool_start + n * pagesz;
@@ -495,18 +494,3 @@ int        n;
 #endif
        return n;
 }
-
-/*
- * Non-mallocing printf, for use by malloc itself.
- */
-static void
-xprintf(const char *fmt, ...)
-{
-    char buf[256];
-    va_list ap;
-
-    va_start(ap, fmt);
-    vsprintf(buf, fmt, ap);
-    (void)write(STDOUT_FILENO, buf, strlen(buf));
-    va_end(ap);
-}
index c41e684..ce457e3 100644 (file)
@@ -63,6 +63,7 @@
 #include "debug.h"
 #include "rtld.h"
 #include "libmap.h"
+#include "rtld_printf.h"
 
 #define PATH_RTLD      "/usr/libexec/ld-elf.so.2"
 #define LD_ARY_CACHE   16
@@ -743,7 +744,7 @@ _rtld_error(const char *fmt, ...)
     va_list ap;
 
     va_start(ap, fmt);
-    vsnprintf(buf, sizeof buf, fmt, ap);
+    rtld_vsnprintf(buf, sizeof buf, fmt, ap);
     error_message = buf;
     va_end(ap);
 }
@@ -863,7 +864,8 @@ die(void)
 
     if (msg == NULL)
        msg = "Fatal error";
-    errx(1, "%s", msg);
+    rtld_fdputstr(STDERR_FILENO, msg);
+    _exit(1);
 }
 
 /*
@@ -3164,7 +3166,7 @@ trace_loaded_objects(Obj_Entry *obj)
        bool                    is_lib;
 
        if (list_containers && obj->needed != NULL)
-           printf("%s:\n", obj->path);
+           rtld_printf("%s:\n", obj->path);
        for (needed = obj->needed; needed; needed = needed->next) {
            if (needed->obj != NULL) {
                if (needed->obj->traced && !list_containers)
@@ -3181,17 +3183,17 @@ trace_loaded_objects(Obj_Entry *obj)
            while ((c = *fmt++) != '\0') {
                switch (c) {
                default:
-                   putchar(c);
+                   rtld_putchar(c);
                    continue;
                case '\\':
                    switch (c = *fmt) {
                    case '\0':
                        continue;
                    case 'n':
-                       putchar('\n');
+                       rtld_putchar('\n');
                        break;
                    case 't':
-                       putchar('\t');
+                       rtld_putchar('\t');
                        break;
                    }
                    break;
@@ -3201,22 +3203,23 @@ trace_loaded_objects(Obj_Entry *obj)
                        continue;
                    case '%':
                    default:
-                       putchar(c);
+                       rtld_putchar(c);
                        break;
                    case 'A':
-                       printf("%s", main_local);
+                       rtld_putstr(main_local);
                        break;
                    case 'a':
-                       printf("%s", obj_main->path);
+                       rtld_putstr(obj_main->path);
                        break;
                    case 'o':
-                       printf("%s", name);
+                       rtld_putstr(name);
                        break;
                    case 'p':
-                       printf("%s", path);
+                       rtld_putstr(path);
                        break;
                    case 'x':
-                       printf("%p", needed->obj ? needed->obj->mapbase : 0);
+                       rtld_printf("%p", needed->obj ? needed->obj->mapbase :
+                         0);
                        break;
                    }
                    break;
index b8b887b..9b4eea8 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <elf-hints.h>
 #include <link.h>
+#include <stdarg.h>
 #include <setjmp.h>
 #include <stddef.h>
 
index 9eed0de..7f018fc 100644 (file)
@@ -182,8 +182,6 @@ rtld_lock_t rtld_bind_lock = &rtld_locks[0];
 rtld_lock_t    rtld_libc_lock = &rtld_locks[1];
 rtld_lock_t    rtld_phdr_lock = &rtld_locks[2];
 
-#define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0)
-
 void
 rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
 {
diff --git a/libexec/rtld-elf/rtld_printf.c b/libexec/rtld-elf/rtld_printf.c
new file mode 100644 (file)
index 0000000..b9aadc3
--- /dev/null
@@ -0,0 +1,487 @@
+/*-
+ * Copyright (c) 1986, 1988, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include "rtld_printf.h"
+
+#define MAXNBUF        (sizeof(intmax_t) * NBBY + 1)
+
+#define        PRINT_METHOD_SNPRINTF   1
+#define        PRINT_METHOD_WRITE      2
+
+struct snprintf_arg {
+       int     method;
+       char    *str;
+       char    *buf;
+       size_t  remain;
+       size_t  buf_total;
+       int     fd;
+};
+
+static void
+printf_out(struct snprintf_arg *info)
+{
+
+       if (info->remain == info->buf_total)
+               return;
+       write(info->fd, info->buf, info->buf_total - info->remain);
+       info->str = info->buf;
+       info->remain = info->buf_total;
+}
+
+static void
+snprintf_func(int ch, struct snprintf_arg *const info)
+{
+
+       switch (info->method) {
+       case PRINT_METHOD_SNPRINTF:
+               if (info->remain >= 2) {
+                       *info->str++ = ch;
+                       info->remain--;
+               }
+               break;
+       case PRINT_METHOD_WRITE:
+               if (info->remain > 0) {
+                       *info->str++ = ch;
+                       info->remain--;
+               } else
+                       printf_out(info);
+               break;
+       }
+}
+
+static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+#define        hex2ascii(hex)  (hex2ascii_data[hex])
+
+static __inline int
+imax(int a, int b)
+{
+
+       return (a > b ? a : b);
+}
+
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
+{
+       char *p, c;
+
+       p = nbuf;
+       *p = '\0';
+       do {
+               c = hex2ascii(num % base);
+               *++p = upper ? toupper(c) : c;
+       } while (num /= base);
+       if (lenp)
+               *lenp = p - nbuf;
+       return (p);
+}
+
+static int
+kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap)
+{
+#define PCHAR(c) snprintf_func((c), arg)
+       char nbuf[MAXNBUF];
+       const char *p, *percent, *q;
+       u_char *up;
+       int ch, n;
+       uintmax_t num;
+       int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
+       int cflag, hflag, jflag, tflag, zflag;
+       int dwidth, upper;
+       char padc;
+       int stop = 0, retval = 0;
+
+       num = 0;
+
+       if (fmt == NULL)
+               fmt = "(fmt null)\n";
+
+       if (radix < 2 || radix > 36)
+               radix = 10;
+
+       for (;;) {
+               padc = ' ';
+               width = 0;
+               while ((ch = (u_char)*fmt++) != '%' || stop) {
+                       if (ch == '\0')
+                               return (retval);
+                       PCHAR(ch);
+               }
+               percent = fmt - 1;
+               qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
+               sign = 0; dot = 0; dwidth = 0; upper = 0;
+               cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
+reswitch:      switch (ch = (u_char)*fmt++) {
+               case '.':
+                       dot = 1;
+                       goto reswitch;
+               case '#':
+                       sharpflag = 1;
+                       goto reswitch;
+               case '+':
+                       sign = 1;
+                       goto reswitch;
+               case '-':
+                       ladjust = 1;
+                       goto reswitch;
+               case '%':
+                       PCHAR(ch);
+                       break;
+               case '*':
+                       if (!dot) {
+                               width = va_arg(ap, int);
+                               if (width < 0) {
+                                       ladjust = !ladjust;
+                                       width = -width;
+                               }
+                       } else {
+                               dwidth = va_arg(ap, int);
+                       }
+                       goto reswitch;
+               case '0':
+                       if (!dot) {
+                               padc = '0';
+                               goto reswitch;
+                       }
+               case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                               for (n = 0;; ++fmt) {
+                                       n = n * 10 + ch - '0';
+                                       ch = *fmt;
+                                       if (ch < '0' || ch > '9')
+                                               break;
+                               }
+                       if (dot)
+                               dwidth = n;
+                       else
+                               width = n;
+                       goto reswitch;
+               case 'b':
+                       num = (u_int)va_arg(ap, int);
+                       p = va_arg(ap, char *);
+                       for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
+                               PCHAR(*q--);
+
+                       if (num == 0)
+                               break;
+
+                       for (tmp = 0; *p;) {
+                               n = *p++;
+                               if (num & (1 << (n - 1))) {
+                                       PCHAR(tmp ? ',' : '<');
+                                       for (; (n = *p) > ' '; ++p)
+                                               PCHAR(n);
+                                       tmp = 1;
+                               } else
+                                       for (; *p > ' '; ++p)
+                                               continue;
+                       }
+                       if (tmp)
+                               PCHAR('>');
+                       break;
+               case 'c':
+                       PCHAR(va_arg(ap, int));
+                       break;
+               case 'D':
+                       up = va_arg(ap, u_char *);
+                       p = va_arg(ap, char *);
+                       if (!width)
+                               width = 16;
+                       while(width--) {
+                               PCHAR(hex2ascii(*up >> 4));
+                               PCHAR(hex2ascii(*up & 0x0f));
+                               up++;
+                               if (width)
+                                       for (q=p;*q;q++)
+                                               PCHAR(*q);
+                       }
+                       break;
+               case 'd':
+               case 'i':
+                       base = 10;
+                       sign = 1;
+                       goto handle_sign;
+               case 'h':
+                       if (hflag) {
+                               hflag = 0;
+                               cflag = 1;
+                       } else
+                               hflag = 1;
+                       goto reswitch;
+               case 'j':
+                       jflag = 1;
+                       goto reswitch;
+               case 'l':
+                       if (lflag) {
+                               lflag = 0;
+                               qflag = 1;
+                       } else
+                               lflag = 1;
+                       goto reswitch;
+               case 'n':
+                       if (jflag)
+                               *(va_arg(ap, intmax_t *)) = retval;
+                       else if (qflag)
+                               *(va_arg(ap, quad_t *)) = retval;
+                       else if (lflag)
+                               *(va_arg(ap, long *)) = retval;
+                       else if (zflag)
+                               *(va_arg(ap, size_t *)) = retval;
+                       else if (hflag)
+                               *(va_arg(ap, short *)) = retval;
+                       else if (cflag)
+                               *(va_arg(ap, char *)) = retval;
+                       else
+                               *(va_arg(ap, int *)) = retval;
+                       break;
+               case 'o':
+                       base = 8;
+                       goto handle_nosign;
+               case 'p':
+                       base = 16;
+                       sharpflag = (width == 0);
+                       sign = 0;
+                       num = (uintptr_t)va_arg(ap, void *);
+                       goto number;
+               case 'q':
+                       qflag = 1;
+                       goto reswitch;
+               case 'r':
+                       base = radix;
+                       if (sign)
+                               goto handle_sign;
+                       goto handle_nosign;
+               case 's':
+                       p = va_arg(ap, char *);
+                       if (p == NULL)
+                               p = "(null)";
+                       if (!dot)
+                               n = strlen (p);
+                       else
+                               for (n = 0; n < dwidth && p[n]; n++)
+                                       continue;
+
+                       width -= n;
+
+                       if (!ladjust && width > 0)
+                               while (width--)
+                                       PCHAR(padc);
+                       while (n--)
+                               PCHAR(*p++);
+                       if (ladjust && width > 0)
+                               while (width--)
+                                       PCHAR(padc);
+                       break;
+               case 't':
+                       tflag = 1;
+                       goto reswitch;
+               case 'u':
+                       base = 10;
+                       goto handle_nosign;
+               case 'X':
+                       upper = 1;
+               case 'x':
+                       base = 16;
+                       goto handle_nosign;
+               case 'y':
+                       base = 16;
+                       sign = 1;
+                       goto handle_sign;
+               case 'z':
+                       zflag = 1;
+                       goto reswitch;
+handle_nosign:
+                       sign = 0;
+                       if (jflag)
+                               num = va_arg(ap, uintmax_t);
+                       else if (qflag)
+                               num = va_arg(ap, u_quad_t);
+                       else if (tflag)
+                               num = va_arg(ap, ptrdiff_t);
+                       else if (lflag)
+                               num = va_arg(ap, u_long);
+                       else if (zflag)
+                               num = va_arg(ap, size_t);
+                       else if (hflag)
+                               num = (u_short)va_arg(ap, int);
+                       else if (cflag)
+                               num = (u_char)va_arg(ap, int);
+                       else
+                               num = va_arg(ap, u_int);
+                       goto number;
+handle_sign:
+                       if (jflag)
+                               num = va_arg(ap, intmax_t);
+                       else if (qflag)
+                               num = va_arg(ap, quad_t);
+                       else if (tflag)
+                               num = va_arg(ap, ptrdiff_t);
+                       else if (lflag)
+                               num = va_arg(ap, long);
+                       else if (zflag)
+                               num = va_arg(ap, ssize_t);
+                       else if (hflag)
+                               num = (short)va_arg(ap, int);
+                       else if (cflag)
+                               num = (char)va_arg(ap, int);
+                       else
+                               num = va_arg(ap, int);
+number:
+                       if (sign && (intmax_t)num < 0) {
+                               neg = 1;
+                               num = -(intmax_t)num;
+                       }
+                       p = ksprintn(nbuf, num, base, &n, upper);
+                       tmp = 0;
+                       if (sharpflag && num != 0) {
+                               if (base == 8)
+                                       tmp++;
+                               else if (base == 16)
+                                       tmp += 2;
+                       }
+                       if (neg)
+                               tmp++;
+
+                       if (!ladjust && padc == '0')
+                               dwidth = width - tmp;
+                       width -= tmp + imax(dwidth, n);
+                       dwidth -= n;
+                       if (!ladjust)
+                               while (width-- > 0)
+                                       PCHAR(' ');
+                       if (neg)
+                               PCHAR('-');
+                       if (sharpflag && num != 0) {
+                               if (base == 8) {
+                                       PCHAR('0');
+                               } else if (base == 16) {
+                                       PCHAR('0');
+                                       PCHAR('x');
+                               }
+                       }
+                       while (dwidth-- > 0)
+                               PCHAR('0');
+
+                       while (*p)
+                               PCHAR(*p--);
+
+                       if (ladjust)
+                               while (width-- > 0)
+                                       PCHAR(' ');
+
+                       break;
+               default:
+                       while (percent < fmt)
+                               PCHAR(*percent++);
+                       /*
+                        * Since we ignore an formatting argument it is no
+                        * longer safe to obey the remaining formatting
+                        * arguments as the arguments will no longer match
+                        * the format specs.
+                        */
+                       stop = 1;
+                       break;
+               }
+       }
+#undef PCHAR
+}
+
+int
+rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap)
+{
+       struct snprintf_arg info;
+       int retval;
+
+       info.method = PRINT_METHOD_SNPRINTF;
+       info.buf = info.str = buf;
+       info.buf_total = info.remain = bufsize;
+       info.fd = -1;
+       retval = kvprintf(fmt, &info, 10, ap);
+       if (info.remain >= 1)
+               *info.str++ = '\0';
+       return (retval);
+}
+
+int
+rtld_vfdprintf(int fd, const char *fmt, va_list ap)
+{
+       char buf[512];
+       struct snprintf_arg info;
+       int retval;
+
+       info.method = PRINT_METHOD_WRITE;
+       info.buf = info.str = buf;
+       info.buf_total = info.remain = sizeof(buf);
+       info.fd = fd;
+       retval = kvprintf(fmt, &info, 10, ap);
+       printf_out(&info);
+       return (retval);
+}
+
+int
+rtld_fdprintf(int fd, const char *fmt, ...)
+{
+       va_list ap;
+       int retval;
+
+       va_start(ap, fmt);
+       retval = rtld_vfdprintf(fd, fmt, ap);
+       va_end(ap);
+       return (retval);
+}
+
+void
+rtld_fdputstr(int fd, const char *str)
+{
+
+       write(fd, str, strlen(str));
+}
+
+void
+rtld_fdputchar(int fd, int c)
+{
+       char c1;
+
+       c1 = c;
+       write(fd, &c1, 1);
+}
similarity index 67%
copy from libexec/rtld-elf/xmalloc.c
copy to libexec/rtld-elf/rtld_printf.h
index 7ee4c57..6125732 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright 1996-1998 John D. Polstra.
+ * Copyright 2011 Konstantin Belousov <kib@FreeBSD.org>.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * $FreeBSD$
  */
 
-#include <err.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
+#ifndef RTLD_PRINTF_H
+#define RTLD_PRINTF_H 1
 
-void *xcalloc(size_t);
-void *xmalloc(size_t);
-char *xstrdup(const char *);
+#include <sys/cdefs.h>
+#include <unistd.h>
 
-void *
-xcalloc(size_t size)
-{
-    return memset(xmalloc(size), 0, size);
-}
+int rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap);
+int rtld_vfdprintf(int fd, const char *fmt, va_list ap);
+int rtld_fdprintf(int fd, const char *fmt, ...) __printflike(2, 3);
+void rtld_fdputstr(int fd, const char *str);
+void rtld_fdputchar(int fd, int c);
 
-void *
-xmalloc(size_t size)
-{
-    void *p = malloc(size);
-    if (p == NULL)
-       err(1, "Out of memory");
-    return p;
-}
+#define        rtld_printf(...) rtld_fdprintf(STDOUT_FILENO, __VA_ARGS__)
+#define        rtld_putstr(str) rtld_fdputstr(STDOUT_FILENO, (str))
+#define        rtld_putchar(c) rtld_fdputchar(STDOUT_FILENO, (c))
 
-char *
-xstrdup(const char *s)
-{
-    char *p = strdup(s);
-    if (p == NULL)
-       err(1, "Out of memory");
-    return p;
-}
+#endif
index 7ee4c57..0d99225 100644 (file)
  * $FreeBSD$
  */
 
-#include <err.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include "rtld.h"
+#include "rtld_printf.h"
 
 void *xcalloc(size_t);
 void *xmalloc(size_t);
@@ -44,8 +46,10 @@ void *
 xmalloc(size_t size)
 {
     void *p = malloc(size);
-    if (p == NULL)
-       err(1, "Out of memory");
+    if (p == NULL) {
+       rtld_fdputstr(STDERR_FILENO, "Out of memory\n");
+       _exit(1);
+    }
     return p;
 }
 
@@ -53,7 +57,9 @@ char *
 xstrdup(const char *s)
 {
     char *p = strdup(s);
-    if (p == NULL)
-       err(1, "Out of memory");
+    if (p == NULL) {
+        rtld_fdputstr(STDERR_FILENO, "Out of memory\n");
+        _exit(1);
+    }
     return p;
 }