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
46typedef struct {
47    void *opaque;
48    void (*send)(void *opaque, const char *data, int len);
49} Out;
50
51static void
52out_send(Out *o, const void *data, size_t len)
53{
54    o->send(o->opaque, data, (int)len);
55}
56
57static void
58out_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 */
75static void
76out_vformat(Out *o, const char *format, va_list args);
77
78/*** Bounded buffer output
79 ***/
80
81typedef struct {
82    Out out[1];
83    char *buffer;
84    char *pos;
85    char *end;
86    int total;
87} BufOut;
88
89static void
90buf_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
112static Out*
113buf_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
129static int
130buf_out_length(BufOut *bo)
131{
132    return bo->total;
133}
134
135static int
136vformat_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
150int
151format_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 */
169int
170vsnprintf(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
182typedef struct {
183    Out out[1];
184    int fd;
185    int total;
186} FdOut;
187
188static void
189fd_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
209static Out*
210fd_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
220static int
221fd_out_length(FdOut *fdo)
222{
223    return fdo->total;
224}
225
226
227int
228format_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
264static 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
300extern int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
301
302#endif /* !CUSTOM_LOG_VPRINT */
303
304int
305format_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 */
328static unsigned
329parse_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 */
352static void
353format_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 */
388static void
389format_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 */
402static void
403format_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 */
409static void
410format_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 */
417static void
418format_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' */
427static void
428out_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
614static 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
627static void
628utest_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
652static void
653utest_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
673int  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