Home | History | Annotate | Download | only in linker
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <stdarg.h>
     30 #include <string.h>
     31 #include <errno.h>
     32 #include <unistd.h>
     33 #include <stdint.h>
     34 #include <stddef.h>
     35 #include "linker_format.h"
     36 #include "linker_debug.h"
     37 
     38 /* define UNIT_TESTS to build this file as a single executable that runs
     39  * the formatter's unit tests
     40  */
     41 #define xxUNIT_TESTS
     42 
     43 /*** Generic output sink
     44  ***/
     45 
     46 typedef struct {
     47     void *opaque;
     48     void (*send)(void *opaque, const char *data, int len);
     49 } Out;
     50 
     51 static void
     52 out_send(Out *o, const void *data, size_t len)
     53 {
     54     o->send(o->opaque, data, (int)len);
     55 }
     56 
     57 static void
     58 out_send_repeat(Out *o, char ch, int count)
     59 {
     60     char pad[8];
     61     const int padSize = (int)sizeof(pad);
     62 
     63     memset(pad, ch, sizeof(pad));
     64     while (count > 0) {
     65         int avail = count;
     66         if (avail > padSize) {
     67             avail = padSize;
     68         }
     69         o->send(o->opaque, pad, avail);
     70         count -= avail;
     71     }
     72 }
     73 
     74 /* forward declaration */
     75 static void
     76 out_vformat(Out *o, const char *format, va_list args);
     77 
     78 /*** Bounded buffer output
     79  ***/
     80 
     81 typedef struct {
     82     Out out[1];
     83     char *buffer;
     84     char *pos;
     85     char *end;
     86     int total;
     87 } BufOut;
     88 
     89 static void
     90 buf_out_send(void *opaque, const char *data, int len)
     91 {
     92     BufOut *bo = opaque;
     93 
     94     if (len < 0)
     95         len = strlen(data);
     96 
     97     bo->total += len;
     98 
     99     while (len > 0) {
    100         int avail = bo->end - bo->pos;
    101         if (avail == 0)
    102             break;
    103         if (avail > len)
    104             avail = len;
    105         memcpy(bo->pos, data, avail);
    106         bo->pos += avail;
    107         bo->pos[0] = '\0';
    108         len -= avail;
    109     }
    110 }
    111 
    112 static Out*
    113 buf_out_init(BufOut *bo, char *buffer, size_t size)
    114 {
    115     if (size == 0)
    116         return NULL;
    117 
    118     bo->out->opaque = bo;
    119     bo->out->send   = buf_out_send;
    120     bo->buffer      = buffer;
    121     bo->end         = buffer + size - 1;
    122     bo->pos         = bo->buffer;
    123     bo->pos[0]      = '\0';
    124     bo->total       = 0;
    125 
    126     return bo->out;
    127 }
    128 
    129 static int
    130 buf_out_length(BufOut *bo)
    131 {
    132     return bo->total;
    133 }
    134 
    135 static int
    136 vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
    137 {
    138     BufOut bo;
    139     Out *out;
    140 
    141     out = buf_out_init(&bo, buff, buffsize);
    142     if (out == NULL)
    143         return 0;
    144 
    145     out_vformat(out, format, args);
    146 
    147     return buf_out_length(&bo);
    148 }
    149 
    150 int
    151 format_buffer(char *buff, size_t buffsize, const char *format, ...)
    152 {
    153     va_list args;
    154     int ret;
    155 
    156     va_start(args, format);
    157     ret = vformat_buffer(buff, buffsize, format, args);
    158     va_end(args);
    159 
    160     return ret;
    161 }
    162 
    163 /* The __stack_chk_fail() function calls __libc_android_log_print()
    164  * which calls vsnprintf().
    165  *
    166  * We define our version of the function here to avoid dragging
    167  * about 25 KB of C library routines related to formatting.
    168  */
    169 int
    170 vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
    171 {
    172     return format_buffer(buff, bufsize, format, args);
    173 }
    174 
    175 #if LINKER_DEBUG
    176 
    177 #if !LINKER_DEBUG_TO_LOG
    178 
    179 /*** File descriptor output
    180  ***/
    181 
    182 typedef struct {
    183     Out out[1];
    184     int fd;
    185     int total;
    186 } FdOut;
    187 
    188 static void
    189 fd_out_send(void *opaque, const char *data, int len)
    190 {
    191     FdOut *fdo = opaque;
    192 
    193     if (len < 0)
    194         len = strlen(data);
    195 
    196     while (len > 0) {
    197         int ret = write(fdo->fd, data, len);
    198         if (ret < 0) {
    199             if (errno == EINTR)
    200                 continue;
    201             break;
    202         }
    203         data += ret;
    204         len -= ret;
    205         fdo->total += ret;
    206     }
    207 }
    208 
    209 static Out*
    210 fd_out_init(FdOut *fdo, int  fd)
    211 {
    212     fdo->out->opaque = fdo;
    213     fdo->out->send = fd_out_send;
    214     fdo->fd = fd;
    215     fdo->total = 0;
    216 
    217     return fdo->out;
    218 }
    219 
    220 static int
    221 fd_out_length(FdOut *fdo)
    222 {
    223     return fdo->total;
    224 }
    225 
    226 
    227 int
    228 format_fd(int fd, const char *format, ...)
    229 {
    230     FdOut fdo;
    231     Out* out;
    232     va_list args;
    233 
    234     out = fd_out_init(&fdo, fd);
    235     if (out == NULL)
    236         return 0;
    237 
    238     va_start(args, format);
    239     out_vformat(out, format, args);
    240     va_end(args);
    241 
    242     return fd_out_length(&fdo);
    243 }
    244 
    245 #else /* LINKER_DEBUG_TO_LOG */
    246 
    247 /*** Log output
    248  ***/
    249 
    250 /* We need our own version of __libc_android_log_vprint, otherwise
    251  * the log output is completely broken. Probably due to the fact
    252  * that the C library is not initialized yet.
    253  *
    254  * You can test that by setting CUSTOM_LOG_VPRINT to 0
    255  */
    256 #define  CUSTOM_LOG_VPRINT  1
    257 
    258 #if CUSTOM_LOG_VPRINT
    259 
    260 #include <unistd.h>
    261 #include <fcntl.h>
    262 #include <sys/uio.h>
    263 
    264 static int log_vprint(int prio, const char *tag, const char *fmt, va_list  args)
    265 {
    266     char buf[1024];
    267     int result;
    268     static int log_fd = -1;
    269 
    270     result = vformat_buffer(buf, sizeof buf, fmt, args);
    271 
    272     if (log_fd < 0) {
    273         log_fd = open("/dev/log/main", O_WRONLY);
    274         if (log_fd < 0)
    275             return result;
    276     }
    277 
    278     {
    279         ssize_t ret;
    280         struct iovec vec[3];
    281 
    282         vec[0].iov_base = (unsigned char *) &prio;
    283         vec[0].iov_len = 1;
    284         vec[1].iov_base = (void *) tag;
    285         vec[1].iov_len = strlen(tag) + 1;
    286         vec[2].iov_base = (void *) buf;
    287         vec[2].iov_len = strlen(buf) + 1;
    288 
    289         do {
    290             ret = writev(log_fd, vec, 3);
    291         } while ((ret < 0) && (errno == EINTR));
    292     }
    293     return result;
    294 }
    295 
    296 #define  __libc_android_log_vprint  log_vprint
    297 
    298 #else /* !CUSTOM_LOG_VPRINT */
    299 
    300 extern int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
    301 
    302 #endif /* !CUSTOM_LOG_VPRINT */
    303 
    304 int
    305 format_log(int prio, const char *tag, const char *format, ...)
    306 {
    307     int ret;
    308     va_list  args;
    309     va_start(args, format);
    310     ret = __libc_android_log_vprint(prio, tag, format, args);
    311     va_end(args);
    312     return ret;
    313 }
    314 
    315 #endif /* LINKER_DEBUG_TO_LOG */
    316 
    317 #endif /* LINKER_DEBUG */
    318 
    319 /*** formatted output implementation
    320  ***/
    321 
    322 /* Parse a decimal string from 'format + *ppos',
    323  * return the value, and writes the new position past
    324  * the decimal string in '*ppos' on exit.
    325  *
    326  * NOTE: Does *not* handle a sign prefix.
    327  */
    328 static unsigned
    329 parse_decimal(const char *format, int *ppos)
    330 {
    331     const char* p = format + *ppos;
    332     unsigned result = 0;
    333 
    334     for (;;) {
    335         int ch = *p;
    336         unsigned d = (unsigned)(ch - '0');
    337 
    338         if (d >= 10U)
    339             break;
    340 
    341         result = result*10 + d;
    342         p++;
    343     }
    344     *ppos = p - format;
    345     return result;
    346 }
    347 
    348 /* write an octal/decimal/number into a bounded buffer.
    349  * assumes that bufsize > 0, and 'digits' is a string of
    350  * digits of at least 'base' values.
    351  */
    352 static void
    353 format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
    354 {
    355     char *pos = buffer;
    356     char *end = buffer + bufsize - 1;
    357 
    358     /* generate digit string in reverse order */
    359     while (value) {
    360         unsigned d = value % base;
    361         value /= base;
    362         if (pos < end) {
    363             *pos++ = digits[d];
    364         }
    365     }
    366 
    367     /* special case for 0 */
    368     if (pos == buffer) {
    369         if (pos < end) {
    370             *pos++ = '0';
    371         }
    372     }
    373     pos[0] = '\0';
    374 
    375     /* now reverse digit string in-place */
    376     end = pos - 1;
    377     pos = buffer;
    378     while (pos < end) {
    379         int ch = pos[0];
    380         pos[0] = end[0];
    381         end[0] = (char) ch;
    382         pos++;
    383         end--;
    384     }
    385 }
    386 
    387 /* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
    388 static void
    389 format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
    390 {
    391     if (isSigned && (int64_t)value < 0) {
    392         buffer[0] = '-';
    393         buffer += 1;
    394         buffsize -= 1;
    395         value = (uint64_t)(-(int64_t)value);
    396     }
    397 
    398     format_number(buffer, buffsize, value, base, "0123456789");
    399 }
    400 
    401 /* Write an octal into a buffer, assumes buffsize > 2 */
    402 static void
    403 format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
    404 {
    405     format_integer(buffer, buffsize, value, 8, isSigned);
    406 }
    407 
    408 /* Write a decimal into a buffer, assumes buffsize > 2 */
    409 static void
    410 format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
    411 {
    412     format_integer(buffer, buffsize, value, 10, isSigned);
    413 }
    414 
    415 /* Write an hexadecimal into a buffer, isCap is true for capital alphas.
    416  * Assumes bufsize > 2 */
    417 static void
    418 format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
    419 {
    420     const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
    421 
    422     format_number(buffer, buffsize, value, 16, digits);
    423 }
    424 
    425 
    426 /* Perform formatted output to an output target 'o' */
    427 static void
    428 out_vformat(Out *o, const char *format, va_list args)
    429 {
    430     int nn = 0;
    431 
    432     for (;;) {
    433         int mm;
    434         int padZero = 0;
    435         int padLeft = 0;
    436         char sign = '\0';
    437         int width = -1;
    438         int prec  = -1;
    439         size_t bytelen = sizeof(int);
    440         const char*  str;
    441         int slen;
    442         char buffer[32];  /* temporary buffer used to format numbers */
    443 
    444         char  c;
    445 
    446         /* first, find all characters that are not 0 or '%' */
    447         /* then send them to the output directly */
    448         mm = nn;
    449         do {
    450             c = format[mm];
    451             if (c == '\0' || c == '%')
    452                 break;
    453             mm++;
    454         } while (1);
    455 
    456         if (mm > nn) {
    457             out_send(o, format+nn, mm-nn);
    458             nn = mm;
    459         }
    460 
    461         /* is this it ? then exit */
    462         if (c == '\0')
    463             break;
    464 
    465         /* nope, we are at a '%' modifier */
    466         nn++;  // skip it
    467 
    468         /* parse flags */
    469         for (;;) {
    470             c = format[nn++];
    471             if (c == '\0') {  /* single trailing '%' ? */
    472                 c = '%';
    473                 out_send(o, &c, 1);
    474                 return;
    475             }
    476             else if (c == '0') {
    477                 padZero = 1;
    478                 continue;
    479             }
    480             else if (c == '-') {
    481                 padLeft = 1;
    482                 continue;
    483             }
    484             else if (c == ' ' || c == '+') {
    485                 sign = c;
    486                 continue;
    487             }
    488             break;
    489         }
    490 
    491         /* parse field width */
    492         if ((c >= '0' && c <= '9')) {
    493             nn --;
    494             width = (int)parse_decimal(format, &nn);
    495             c = format[nn++];
    496         }
    497 
    498         /* parse precision */
    499         if (c == '.') {
    500             prec = (int)parse_decimal(format, &nn);
    501             c = format[nn++];
    502         }
    503 
    504         /* length modifier */
    505         switch (c) {
    506         case 'h':
    507             bytelen = sizeof(short);
    508             if (format[nn] == 'h') {
    509                 bytelen = sizeof(char);
    510                 nn += 1;
    511             }
    512             c = format[nn++];
    513             break;
    514         case 'l':
    515             bytelen = sizeof(long);
    516             if (format[nn] == 'l') {
    517                 bytelen = sizeof(long long);
    518                 nn += 1;
    519             }
    520             c = format[nn++];
    521             break;
    522         case 'z':
    523             bytelen = sizeof(size_t);
    524             c = format[nn++];
    525             break;
    526         case 't':
    527             bytelen = sizeof(ptrdiff_t);
    528             c = format[nn++];
    529             break;
    530         default:
    531             ;
    532         }
    533 
    534         /* conversion specifier */
    535         if (c == 's') {
    536             /* string */
    537             str = va_arg(args, const char*);
    538         } else if (c == 'c') {
    539             /* character */
    540             /* NOTE: char is promoted to int when passed through the stack */
    541             buffer[0] = (char) va_arg(args, int);
    542             buffer[1] = '\0';
    543             str = buffer;
    544         } else if (c == 'p') {
    545             uint64_t  value = (uintptr_t) va_arg(args, void*);
    546             buffer[0] = '0';
    547             buffer[1] = 'x';
    548             format_hex(buffer + 2, sizeof buffer-2, value, 0);
    549             str = buffer;
    550         } else {
    551             /* integers - first read value from stack */
    552             uint64_t value;
    553             int isSigned = (c == 'd' || c == 'i' || c == 'o');
    554 
    555             /* NOTE: int8_t and int16_t are promoted to int when passed
    556              *       through the stack
    557              */
    558             switch (bytelen) {
    559             case 1: value = (uint8_t)  va_arg(args, int); break;
    560             case 2: value = (uint16_t) va_arg(args, int); break;
    561             case 4: value = va_arg(args, uint32_t); break;
    562             case 8: value = va_arg(args, uint64_t); break;
    563             default: return;  /* should not happen */
    564             }
    565 
    566             /* sign extension, if needed */
    567             if (isSigned) {
    568                 int shift = 64 - 8*bytelen;
    569                 value = (uint64_t)(((int64_t)(value << shift)) >> shift);
    570             }
    571 
    572             /* format the number properly into our buffer */
    573             switch (c) {
    574             case 'i': case 'd':
    575                 format_integer(buffer, sizeof buffer, value, 10, isSigned);
    576                 break;
    577             case 'o':
    578                 format_integer(buffer, sizeof buffer, value, 8, isSigned);
    579                 break;
    580             case 'x': case 'X':
    581                 format_hex(buffer, sizeof buffer, value, (c == 'X'));
    582                 break;
    583             default:
    584                 buffer[0] = '\0';
    585             }
    586             /* then point to it */
    587             str = buffer;
    588         }
    589 
    590         /* if we are here, 'str' points to the content that must be
    591          * outputted. handle padding and alignment now */
    592 
    593         slen = strlen(str);
    594 
    595         if (slen < width && !padLeft) {
    596             char padChar = padZero ? '0' : ' ';
    597             out_send_repeat(o, padChar, width - slen);
    598         }
    599 
    600         out_send(o, str, slen);
    601 
    602         if (slen < width && padLeft) {
    603             char padChar = padZero ? '0' : ' ';
    604             out_send_repeat(o, padChar, width - slen);
    605         }
    606     }
    607 }
    608 
    609 
    610 #ifdef UNIT_TESTS
    611 
    612 #include <stdio.h>
    613 
    614 static int   gFails = 0;
    615 
    616 #define  MARGIN  40
    617 
    618 #define  UTEST_CHECK(condition,message) \
    619     printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
    620     if (!(condition)) { \
    621         printf("KO\n"); \
    622         gFails += 1; \
    623     } else { \
    624         printf("ok\n"); \
    625     }
    626 
    627 static void
    628 utest_BufOut(void)
    629 {
    630     char buffer[16];
    631     BufOut bo[1];
    632     Out* out;
    633     int ret;
    634 
    635     buffer[0] = '1';
    636     out = buf_out_init(bo, buffer, sizeof buffer);
    637     UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
    638     out_send(out, "abc", 3);
    639     UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
    640     out_send_repeat(out, 'X', 4);
    641     UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
    642     buffer[sizeof buffer-1] = 'x';
    643     out_send_repeat(out, 'Y', 2*sizeof(buffer));
    644     UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
    645 
    646     out = buf_out_init(bo, buffer, sizeof buffer);
    647     out_send_repeat(out, 'X', 2*sizeof(buffer));
    648     ret = buf_out_length(bo);
    649     UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
    650 }
    651 
    652 static void
    653 utest_expect(const char*  result, const char*  format, ...)
    654 {
    655     va_list args;
    656     BufOut bo[1];
    657     char buffer[256];
    658     Out* out = buf_out_init(bo, buffer, sizeof buffer);
    659 
    660     printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
    661     va_start(args, format);
    662     out_vformat(out, format, args);
    663     va_end(args);
    664 
    665     if (strcmp(result, buffer)) {
    666         printf("KO. got '%s' expecting '%s'\n", buffer, result);
    667         gFails += 1;
    668     } else {
    669         printf("ok. got '%s'\n", result);
    670     }
    671 }
    672 
    673 int  main(void)
    674 {
    675     utest_BufOut();
    676     utest_expect("", "");
    677     utest_expect("a", "a");
    678     utest_expect("01234", "01234", "");
    679     utest_expect("01234", "%s", "01234");
    680     utest_expect("aabbcc", "aa%scc", "bb");
    681     utest_expect("a", "%c", 'a');
    682     utest_expect("1234", "%d", 1234);
    683     utest_expect("-8123", "%d", -8123);
    684     utest_expect("16", "%hd", 0x7fff0010);
    685     utest_expect("16", "%hhd", 0x7fffff10);
    686     utest_expect("68719476736", "%lld", 0x1000000000LL);
    687     utest_expect("70000", "%ld", 70000);
    688     utest_expect("0xb0001234", "%p", (void*)0xb0001234);
    689     utest_expect("12ab", "%x", 0x12ab);
    690     utest_expect("12AB", "%X", 0x12ab);
    691     utest_expect("00123456", "%08x", 0x123456);
    692     utest_expect("01234", "0%d", 1234);
    693     utest_expect(" 1234", "%5d", 1234);
    694     utest_expect("01234", "%05d", 1234);
    695     utest_expect("    1234", "%8d", 1234);
    696     utest_expect("1234    ", "%-8d", 1234);
    697     utest_expect("abcdef     ", "%-11s", "abcdef");
    698     utest_expect("something:1234", "%s:%d", "something", 1234);
    699     utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
    700     utest_expect("5,0x0", "%d,%p", 5, NULL);
    701     utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
    702     return gFails != 0;
    703 }
    704 
    705 #endif /* UNIT_TESTS */
    706