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 /*** File descriptor output
189 fd_out_send(void *opaque
, const char *data
, int len
)
197 int ret
= write(fdo
->fd
, data
, len
);
210 fd_out_init(FdOut
*fdo
, int fd
)
212 fdo
->out
->opaque
= fdo
;
213 fdo
->out
->send
= fd_out_send
;
221 fd_out_length(FdOut
*fdo
)
228 format_fd(int fd
, const char *format
, ...)
234 out
= fd_out_init(&fdo
, fd
);
238 va_start(args
, format
);
239 out_vformat(out
, format
, args
);
242 return fd_out_length(&fdo
);
248 /* We need our own version of __libc_android_log_vprint, otherwise
249 * the log output is completely broken. Probably due to the fact
250 * that the C library is not initialized yet.
252 * You can test that by setting CUSTOM_LOG_VPRINT to 0
254 #define CUSTOM_LOG_VPRINT 1
256 #if CUSTOM_LOG_VPRINT
262 static int log_vprint(int prio
, const char *tag
, const char *fmt
, va_list args
)
266 static int log_fd
= -1;
268 result
= vformat_buffer(buf
, sizeof buf
, fmt
, args
);
271 log_fd
= open("/dev/log/main", O_WRONLY
);
273 log_fd
= fileno(stdout
); // kernel doesn't have android log
282 vec
[0].iov_base
= (unsigned char *) &prio
;
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;
290 ret
= writev(log_fd
, vec
, 3);
291 } while ((ret
< 0) && (errno
== EINTR
));
296 #define __libc_android_log_vprint log_vprint
298 #else /* !CUSTOM_LOG_VPRINT */
300 extern int __libc_android_log_vprint(int prio
, const char* tag
, const char* format
, va_list ap
);
302 #endif /* !CUSTOM_LOG_VPRINT */
305 format_log(int prio
, const char *tag
, const char *format
, ...)
309 va_start(args
, format
);
310 ret
= __libc_android_log_vprint(prio
, tag
, format
, args
);
315 #endif /* LINKER_DEBUG */
317 /*** formatted output implementation
320 /* Parse a decimal string from 'format + *ppos',
321 * return the value, and writes the new position past
322 * the decimal string in '*ppos' on exit.
324 * NOTE: Does *not* handle a sign prefix.
327 parse_decimal(const char *format
, int *ppos
)
329 const char* p
= format
+ *ppos
;
334 unsigned d
= (unsigned)(ch
- '0');
339 result
= result
*10 + d
;
346 /* write an octal/decimal/number into a bounded buffer.
347 * assumes that bufsize > 0, and 'digits' is a string of
348 * digits of at least 'base' values.
351 format_number(char *buffer
, size_t bufsize
, uint64_t value
, int base
, const char *digits
)
354 char *end
= buffer
+ bufsize
- 1;
356 /* generate digit string in reverse order */
358 unsigned d
= value
% base
;
365 /* special case for 0 */
373 /* now reverse digit string in-place */
385 /* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
387 format_integer(char *buffer
, size_t buffsize
, uint64_t value
, int base
, int isSigned
)
389 if (isSigned
&& (int64_t)value
< 0) {
393 value
= (uint64_t)(-(int64_t)value
);
396 format_number(buffer
, buffsize
, value
, base
, "0123456789");
399 /* Write an octal into a buffer, assumes buffsize > 2 */
401 format_octal(char *buffer
, size_t buffsize
, uint64_t value
, int isSigned
)
403 format_integer(buffer
, buffsize
, value
, 8, isSigned
);
406 /* Write a decimal into a buffer, assumes buffsize > 2 */
408 format_decimal(char *buffer
, size_t buffsize
, uint64_t value
, int isSigned
)
410 format_integer(buffer
, buffsize
, value
, 10, isSigned
);
413 /* Write an hexadecimal into a buffer, isCap is true for capital alphas.
414 * Assumes bufsize > 2 */
416 format_hex(char *buffer
, size_t buffsize
, uint64_t value
, int isCap
)
418 const char *digits
= isCap
? "0123456789ABCDEF" : "0123456789abcdef";
420 format_number(buffer
, buffsize
, value
, 16, digits
);
424 /* Perform formatted output to an output target 'o' */
426 out_vformat(Out
*o
, const char *format
, va_list args
)
437 size_t bytelen
= sizeof(int);
440 char buffer
[32]; /* temporary buffer used to format numbers */
444 /* first, find all characters that are not 0 or '%' */
445 /* then send them to the output directly */
449 if (c
== '\0' || c
== '%')
455 out_send(o
, format
+nn
, mm
-nn
);
459 /* is this it ? then exit */
463 /* nope, we are at a '%' modifier */
469 if (c
== '\0') { /* single trailing '%' ? */
482 else if (c
== ' ' || c
== '+') {
489 /* parse field width */
490 if ((c
>= '0' && c
<= '9')) {
492 width
= (int)parse_decimal(format
, &nn
);
496 /* parse precision */
498 prec
= (int)parse_decimal(format
, &nn
);
502 /* length modifier */
505 bytelen
= sizeof(short);
506 if (format
[nn
] == 'h') {
507 bytelen
= sizeof(char);
513 bytelen
= sizeof(long);
514 if (format
[nn
] == 'l') {
515 bytelen
= sizeof(long long);
521 bytelen
= sizeof(size_t);
525 bytelen
= sizeof(ptrdiff_t);
532 /* conversion specifier */
535 str
= va_arg(args
, const char*);
536 } else if (c
== 'c') {
538 /* NOTE: char is promoted to int when passed through the stack */
539 buffer
[0] = (char) va_arg(args
, int);
542 } else if (c
== 'p') {
543 uint64_t value
= (uintptr_t) va_arg(args
, void*);
546 format_hex(buffer
+ 2, sizeof buffer
-2, value
, 0);
549 /* integers - first read value from stack */
551 int isSigned
= (c
== 'd' || c
== 'i' || c
== 'o');
553 /* NOTE: int8_t and int16_t are promoted to int when passed
557 case 1: value
= (uint8_t) va_arg(args
, int); break;
558 case 2: value
= (uint16_t) va_arg(args
, int); break;
559 case 4: value
= va_arg(args
, uint32_t); break;
560 case 8: value
= va_arg(args
, uint64_t); break;
561 default: return; /* should not happen */
564 /* sign extension, if needed */
566 int shift
= 64 - 8*bytelen
;
567 value
= (uint64_t)(((int64_t)(value
<< shift
)) >> shift
);
570 /* format the number properly into our buffer */
573 format_integer(buffer
, sizeof buffer
, value
, 10, isSigned
);
576 format_integer(buffer
, sizeof buffer
, value
, 8, isSigned
);
579 format_hex(buffer
, sizeof buffer
, value
, (c
== 'X'));
584 /* then point to it */
588 /* if we are here, 'str' points to the content that must be
589 * outputted. handle padding and alignment now */
593 if (slen
< width
&& !padLeft
) {
594 char padChar
= padZero
? '0' : ' ';
595 out_send_repeat(o
, padChar
, width
- slen
);
598 out_send(o
, str
, slen
);
600 if (slen
< width
&& padLeft
) {
601 char padChar
= padZero
? '0' : ' ';
602 out_send_repeat(o
, padChar
, width
- slen
);
612 static int gFails
= 0;
616 #define UTEST_CHECK(condition,message) \
617 printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
618 if (!(condition)) { \
634 out
= buf_out_init(bo
, buffer
, sizeof buffer
);
635 UTEST_CHECK(buffer
[0] == '\0', "buf_out_init clears initial byte");
636 out_send(out
, "abc", 3);
637 UTEST_CHECK(!memcmp(buffer
, "abc", 4), "out_send() works with BufOut");
638 out_send_repeat(out
, 'X', 4);
639 UTEST_CHECK(!memcmp(buffer
, "abcXXXX", 8), "out_send_repeat() works with BufOut");
640 buffer
[sizeof buffer
-1] = 'x';
641 out_send_repeat(out
, 'Y', 2*sizeof(buffer
));
642 UTEST_CHECK(buffer
[sizeof buffer
-1] == '\0', "overflows always zero-terminates");
644 out
= buf_out_init(bo
, buffer
, sizeof buffer
);
645 out_send_repeat(out
, 'X', 2*sizeof(buffer
));
646 ret
= buf_out_length(bo
);
647 UTEST_CHECK(ret
== 2*sizeof(buffer
), "correct size returned on overflow");
651 utest_expect(const char* result
, const char* format
, ...)
656 Out
* out
= buf_out_init(bo
, buffer
, sizeof buffer
);
658 printf("Checking %-*s: ", MARGIN
, format
); fflush(stdout
);
659 va_start(args
, format
);
660 out_vformat(out
, format
, args
);
663 if (strcmp(result
, buffer
)) {
664 printf("KO. got '%s' expecting '%s'\n", buffer
, result
);
667 printf("ok. got '%s'\n", result
);
674 utest_expect("", "");
675 utest_expect("a", "a");
676 utest_expect("01234", "01234", "");
677 utest_expect("01234", "%s", "01234");
678 utest_expect("aabbcc", "aa%scc", "bb");
679 utest_expect("a", "%c", 'a');
680 utest_expect("1234", "%d", 1234);
681 utest_expect("-8123", "%d", -8123);
682 utest_expect("16", "%hd", 0x7fff0010);
683 utest_expect("16", "%hhd", 0x7fffff10);
684 utest_expect("68719476736", "%lld", 0x1000000000LL
);
685 utest_expect("70000", "%ld", 70000);
686 utest_expect("0xb0001234", "%p", (void*)0xb0001234);
687 utest_expect("12ab", "%x", 0x12ab);
688 utest_expect("12AB", "%X", 0x12ab);
689 utest_expect("00123456", "%08x", 0x123456);
690 utest_expect("01234", "0%d", 1234);
691 utest_expect(" 1234", "%5d", 1234);
692 utest_expect("01234", "%05d", 1234);
693 utest_expect(" 1234", "%8d", 1234);
694 utest_expect("1234 ", "%-8d", 1234);
695 utest_expect("abcdef ", "%-11s", "abcdef");
696 utest_expect("something:1234", "%s:%d", "something", 1234);
697 utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
698 utest_expect("5,0x0", "%d,%p", 5, NULL
);
699 utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL
, 6, 7, 8);
703 #endif /* UNIT_TESTS */