2
* Copyright (C) 2010 The Android Open Source Project
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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
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
35
#include "linker_format.h"
36
#include "linker_debug.h"
38
/* define UNIT_TESTS to build this file as a single executable that runs
39
* the formatter's unit tests
43
/*** Generic output sink
48
void (*send)(void *opaque, const char *data, int len);
52
out_send(Out *o, const void *data, size_t len)
54
o->send(o->opaque, data, (int)len);
58
out_send_repeat(Out *o, char ch, int count)
61
const int padSize = (int)sizeof(pad);
63
memset(pad, ch, sizeof(pad));
66
if (avail > padSize) {
69
o->send(o->opaque, pad, avail);
74
/* forward declaration */
76
out_vformat(Out *o, const char *format, va_list args);
78
/*** Bounded buffer output
90
buf_out_send(void *opaque, const char *data, int len)
100
int avail = bo->end - bo->pos;
105
memcpy(bo->pos, data, avail);
113
buf_out_init(BufOut *bo, char *buffer, size_t size)
118
bo->out->opaque = bo;
119
bo->out->send = buf_out_send;
121
bo->end = buffer + size - 1;
122
bo->pos = bo->buffer;
130
buf_out_length(BufOut *bo)
136
vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
141
out = buf_out_init(&bo, buff, buffsize);
145
out_vformat(out, format, args);
147
return buf_out_length(&bo);
151
format_buffer(char *buff, size_t buffsize, const char *format, ...)
156
va_start(args, format);
157
ret = vformat_buffer(buff, buffsize, format, args);
163
/* The __stack_chk_fail() function calls __libc_android_log_print()
164
* which calls vsnprintf().
166
* We define our version of the function here to avoid dragging
167
* about 25 KB of C library routines related to formatting.
171
vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
173
return format_buffer(buff, bufsize, format, args);
179
#if !LINKER_DEBUG_TO_LOG
181
/*** File descriptor output
191
fd_out_send(void *opaque, const char *data, int len)
199
int ret = write(fdo->fd, data, len);
212
fd_out_init(FdOut *fdo, int fd)
214
fdo->out->opaque = fdo;
215
fdo->out->send = fd_out_send;
223
fd_out_length(FdOut *fdo)
230
format_fd(int fd, const char *format, ...)
236
out = fd_out_init(&fdo, fd);
240
va_start(args, format);
241
out_vformat(out, format, args);
244
return fd_out_length(&fdo);
247
#else /* LINKER_DEBUG_TO_LOG */
252
/* We need our own version of __libc_android_log_vprint, otherwise
253
* the log output is completely broken. Probably due to the fact
254
* that the C library is not initialized yet.
256
* You can test that by setting CUSTOM_LOG_VPRINT to 0
258
#define CUSTOM_LOG_VPRINT 1
260
#if CUSTOM_LOG_VPRINT
266
static int log_vprint(int prio, const char *tag, const char *fmt, va_list args)
270
static int log_fd = -1;
272
result = vformat_buffer(buf, sizeof buf, fmt, args);
275
log_fd = open("/dev/log/main", O_WRONLY);
277
log_fd = fileno(stdout); // kernel doesn't have android log
286
vec[0].iov_base = (unsigned char *) &prio;
288
vec[1].iov_base = (void *) tag;
289
vec[1].iov_len = strlen(tag) + 1;
290
vec[2].iov_base = (void *) buf;
291
vec[2].iov_len = strlen(buf) + 1;
294
ret = writev(log_fd, vec, 3);
295
} while ((ret < 0) && (errno == EINTR));
300
#define __libc_android_log_vprint log_vprint
302
#else /* !CUSTOM_LOG_VPRINT */
304
extern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap);
306
#endif /* !CUSTOM_LOG_VPRINT */
309
format_log(int prio, const char *tag, const char *format, ...)
313
va_start(args, format);
314
ret = __libc_android_log_vprint(prio, tag, format, args);
319
#endif /* LINKER_DEBUG_TO_LOG */
321
#endif /* LINKER_DEBUG */
323
/*** formatted output implementation
326
/* Parse a decimal string from 'format + *ppos',
327
* return the value, and writes the new position past
328
* the decimal string in '*ppos' on exit.
330
* NOTE: Does *not* handle a sign prefix.
333
parse_decimal(const char *format, int *ppos)
335
const char* p = format + *ppos;
340
unsigned d = (unsigned)(ch - '0');
345
result = result*10 + d;
352
/* write an octal/decimal/number into a bounded buffer.
353
* assumes that bufsize > 0, and 'digits' is a string of
354
* digits of at least 'base' values.
357
format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
360
char *end = buffer + bufsize - 1;
362
/* generate digit string in reverse order */
364
unsigned d = value % base;
371
/* special case for 0 */
379
/* now reverse digit string in-place */
391
/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
393
format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
395
if (isSigned && (int64_t)value < 0) {
399
value = (uint64_t)(-(int64_t)value);
402
format_number(buffer, buffsize, value, base, "0123456789");
405
/* Write an octal into a buffer, assumes buffsize > 2 */
407
format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
409
format_integer(buffer, buffsize, value, 8, isSigned);
412
/* Write a decimal into a buffer, assumes buffsize > 2 */
414
format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
416
format_integer(buffer, buffsize, value, 10, isSigned);
419
/* Write an hexadecimal into a buffer, isCap is true for capital alphas.
420
* Assumes bufsize > 2 */
422
format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
424
const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
426
format_number(buffer, buffsize, value, 16, digits);
430
/* Perform formatted output to an output target 'o' */
432
out_vformat(Out *o, const char *format, va_list args)
443
size_t bytelen = sizeof(int);
446
char buffer[32]; /* temporary buffer used to format numbers */
450
/* first, find all characters that are not 0 or '%' */
451
/* then send them to the output directly */
455
if (c == '\0' || c == '%')
461
out_send(o, format+nn, mm-nn);
465
/* is this it ? then exit */
469
/* nope, we are at a '%' modifier */
475
if (c == '\0') { /* single trailing '%' ? */
488
else if (c == ' ' || c == '+') {
495
/* parse field width */
496
if ((c >= '0' && c <= '9')) {
498
width = (int)parse_decimal(format, &nn);
502
/* parse precision */
504
prec = (int)parse_decimal(format, &nn);
508
/* length modifier */
511
bytelen = sizeof(short);
512
if (format[nn] == 'h') {
513
bytelen = sizeof(char);
519
bytelen = sizeof(long);
520
if (format[nn] == 'l') {
521
bytelen = sizeof(long long);
527
bytelen = sizeof(size_t);
531
bytelen = sizeof(ptrdiff_t);
538
/* conversion specifier */
541
str = va_arg(args, const char*);
542
} else if (c == 'c') {
544
/* NOTE: char is promoted to int when passed through the stack */
545
buffer[0] = (char) va_arg(args, int);
548
} else if (c == 'p') {
549
uint64_t value = (uintptr_t) va_arg(args, void*);
552
format_hex(buffer + 2, sizeof buffer-2, value, 0);
555
/* integers - first read value from stack */
557
int isSigned = (c == 'd' || c == 'i' || c == 'o');
559
/* NOTE: int8_t and int16_t are promoted to int when passed
563
case 1: value = (uint8_t) va_arg(args, int); break;
564
case 2: value = (uint16_t) va_arg(args, int); break;
565
case 4: value = va_arg(args, uint32_t); break;
566
case 8: value = va_arg(args, uint64_t); break;
567
default: return; /* should not happen */
570
/* sign extension, if needed */
572
int shift = 64 - 8*bytelen;
573
value = (uint64_t)(((int64_t)(value << shift)) >> shift);
576
/* format the number properly into our buffer */
579
format_integer(buffer, sizeof buffer, value, 10, isSigned);
582
format_integer(buffer, sizeof buffer, value, 8, isSigned);
585
format_hex(buffer, sizeof buffer, value, (c == 'X'));
590
/* then point to it */
594
/* if we are here, 'str' points to the content that must be
595
* outputted. handle padding and alignment now */
599
if (slen < width && !padLeft) {
600
char padChar = padZero ? '0' : ' ';
601
out_send_repeat(o, padChar, width - slen);
604
out_send(o, str, slen);
606
if (slen < width && padLeft) {
607
char padChar = padZero ? '0' : ' ';
608
out_send_repeat(o, padChar, width - slen);
618
static int gFails = 0;
622
#define UTEST_CHECK(condition,message) \
623
printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
624
if (!(condition)) { \
640
out = buf_out_init(bo, buffer, sizeof buffer);
641
UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
642
out_send(out, "abc", 3);
643
UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
644
out_send_repeat(out, 'X', 4);
645
UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
646
buffer[sizeof buffer-1] = 'x';
647
out_send_repeat(out, 'Y', 2*sizeof(buffer));
648
UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
650
out = buf_out_init(bo, buffer, sizeof buffer);
651
out_send_repeat(out, 'X', 2*sizeof(buffer));
652
ret = buf_out_length(bo);
653
UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
657
utest_expect(const char* result, const char* format, ...)
662
Out* out = buf_out_init(bo, buffer, sizeof buffer);
664
printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
665
va_start(args, format);
666
out_vformat(out, format, args);
669
if (strcmp(result, buffer)) {
670
printf("KO. got '%s' expecting '%s'\n", buffer, result);
673
printf("ok. got '%s'\n", result);
680
utest_expect("", "");
681
utest_expect("a", "a");
682
utest_expect("01234", "01234", "");
683
utest_expect("01234", "%s", "01234");
684
utest_expect("aabbcc", "aa%scc", "bb");
685
utest_expect("a", "%c", 'a');
686
utest_expect("1234", "%d", 1234);
687
utest_expect("-8123", "%d", -8123);
688
utest_expect("16", "%hd", 0x7fff0010);
689
utest_expect("16", "%hhd", 0x7fffff10);
690
utest_expect("68719476736", "%lld", 0x1000000000LL);
691
utest_expect("70000", "%ld", 70000);
692
utest_expect("0xb0001234", "%p", (void*)0xb0001234);
693
utest_expect("12ab", "%x", 0x12ab);
694
utest_expect("12AB", "%X", 0x12ab);
695
utest_expect("00123456", "%08x", 0x123456);
696
utest_expect("01234", "0%d", 1234);
697
utest_expect(" 1234", "%5d", 1234);
698
utest_expect("01234", "%05d", 1234);
699
utest_expect(" 1234", "%8d", 1234);
700
utest_expect("1234 ", "%-8d", 1234);
701
utest_expect("abcdef ", "%-11s", "abcdef");
702
utest_expect("something:1234", "%s:%d", "something", 1234);
703
utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
704
utest_expect("5,0x0", "%d,%p", 5, NULL);
705
utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
709
#endif /* UNIT_TESTS */