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.
170 vsnprintf(char *buff
, size_t bufsize
, const char *format
, va_list args
)
172 return format_buffer(buff
, bufsize
, format
, args
);
177 #if !LINKER_DEBUG_TO_LOG
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
);
245 #else /* LINKER_DEBUG_TO_LOG */
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.
254 * You can test that by setting CUSTOM_LOG_VPRINT to 0
256 #define CUSTOM_LOG_VPRINT 1
258 #if CUSTOM_LOG_VPRINT
264 static int log_vprint(int prio
, const char *tag
, const char *fmt
, va_list args
)
268 static int log_fd
= -1;
270 result
= vformat_buffer(buf
, sizeof buf
, fmt
, args
);
273 log_fd
= open("/dev/log/main", O_WRONLY
);
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_TO_LOG */
317 #endif /* LINKER_DEBUG */
319 /*** formatted output implementation
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.
326 * NOTE: Does *not* handle a sign prefix.
329 parse_decimal(const char *format
, int *ppos
)
331 const char* p
= format
+ *ppos
;
336 unsigned d
= (unsigned)(ch
- '0');
341 result
= result
*10 + d
;
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.
353 format_number(char *buffer
, size_t bufsize
, uint64_t value
, int base
, const char *digits
)
356 char *end
= buffer
+ bufsize
- 1;
358 /* generate digit string in reverse order */
360 unsigned d
= value
% base
;
367 /* special case for 0 */
375 /* now reverse digit string in-place */
387 /* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
389 format_integer(char *buffer
, size_t buffsize
, uint64_t value
, int base
, int isSigned
)
391 if (isSigned
&& (int64_t)value
< 0) {
395 value
= (uint64_t)(-(int64_t)value
);
398 format_number(buffer
, buffsize
, value
, base
, "0123456789");
401 /* Write an octal into a buffer, assumes buffsize > 2 */
403 format_octal(char *buffer
, size_t buffsize
, uint64_t value
, int isSigned
)
405 format_integer(buffer
, buffsize
, value
, 8, isSigned
);
408 /* Write a decimal into a buffer, assumes buffsize > 2 */
410 format_decimal(char *buffer
, size_t buffsize
, uint64_t value
, int isSigned
)
412 format_integer(buffer
, buffsize
, value
, 10, isSigned
);
415 /* Write an hexadecimal into a buffer, isCap is true for capital alphas.
416 * Assumes bufsize > 2 */
418 format_hex(char *buffer
, size_t buffsize
, uint64_t value
, int isCap
)
420 const char *digits
= isCap
? "0123456789ABCDEF" : "0123456789abcdef";
422 format_number(buffer
, buffsize
, value
, 16, digits
);
426 /* Perform formatted output to an output target 'o' */
428 out_vformat(Out
*o
, const char *format
, va_list args
)
436 size_t bytelen
= sizeof(int);
439 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);
529 bytelen
= sizeof(void*);
535 /* conversion specifier */
538 str
= va_arg(args
, const char*);
539 } else if (c
== 'c') {
541 /* NOTE: char is promoted to int when passed through the stack */
542 buffer
[0] = (char) va_arg(args
, int);
545 } else if (c
== 'p') {
546 uint64_t value
= (uint64_t)(ptrdiff_t) va_arg(args
, void*);
549 format_hex(buffer
+ 2, sizeof buffer
-2, value
, 0);
552 /* integers - first read value from stack */
554 int isSigned
= (c
== 'd' || c
== 'i' || c
== 'o');
556 /* NOTE: int8_t and int16_t are promoted to int when passed
560 case 1: value
= (uint8_t) va_arg(args
, int); break;
561 case 2: value
= (uint16_t) va_arg(args
, int); break;
562 case 4: value
= va_arg(args
, uint32_t); break;
563 case 8: value
= va_arg(args
, uint64_t); break;
564 default: return; /* should not happen */
567 /* sign extension, if needed */
569 int shift
= 64 - 8*bytelen
;
570 value
= (uint64_t)(((int64_t)(value
<< shift
)) >> shift
);
573 /* format the number properly into our buffer */
576 format_integer(buffer
, sizeof buffer
, value
, 10, isSigned
);
579 format_integer(buffer
, sizeof buffer
, value
, 8, isSigned
);
582 format_hex(buffer
, sizeof buffer
, value
, (c
== 'X'));
587 /* then point to it */
591 /* if we are here, 'str' points to the content that must be
592 * outputted. handle padding and alignment now */
596 if (slen
< width
&& !padLeft
) {
597 char padChar
= padZero
? '0' : ' ';
598 out_send_repeat(o
, padChar
, width
- slen
);
601 out_send(o
, str
, slen
);
603 if (slen
< width
&& padLeft
) {
604 char padChar
= padZero
? '0' : ' ';
605 out_send_repeat(o
, padChar
, width
- slen
);
615 static int gFails
= 0;
619 #define UTEST_CHECK(condition,message) \
620 printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
621 if (!(condition)) { \
637 out
= buf_out_init(bo
, buffer
, sizeof buffer
);
638 UTEST_CHECK(buffer
[0] == '\0', "buf_out_init clears initial byte");
639 out_send(out
, "abc", 3);
640 UTEST_CHECK(!memcmp(buffer
, "abc", 4), "out_send() works with BufOut");
641 out_send_repeat(out
, 'X', 4);
642 UTEST_CHECK(!memcmp(buffer
, "abcXXXX", 8), "out_send_repeat() works with BufOut");
643 buffer
[sizeof buffer
-1] = 'x';
644 out_send_repeat(out
, 'Y', 2*sizeof(buffer
));
645 UTEST_CHECK(buffer
[sizeof buffer
-1] == '\0', "overflows always zero-terminates");
647 out
= buf_out_init(bo
, buffer
, sizeof buffer
);
648 out_send_repeat(out
, 'X', 2*sizeof(buffer
));
649 ret
= buf_out_length(bo
);
650 UTEST_CHECK(ret
== 2*sizeof(buffer
), "correct size returned on overflow");
654 utest_expect(const char* result
, const char* format
, ...)
659 Out
* out
= buf_out_init(bo
, buffer
, sizeof buffer
);
661 printf("Checking %-*s: ", MARGIN
, format
); fflush(stdout
);
662 va_start(args
, format
);
663 out_vformat(out
, format
, args
);
666 if (strcmp(result
, buffer
)) {
667 printf("KO. got '%s' expecting '%s'\n", buffer
, result
);
670 printf("ok. got '%s'\n", result
);
677 utest_expect("", "");
678 utest_expect("a", "a");
679 utest_expect("01234", "01234", "");
680 utest_expect("01234", "%s", "01234");
681 utest_expect("aabbcc", "aa%scc", "bb");
682 utest_expect("a", "%c", 'a');
683 utest_expect("1234", "%d", 1234);
684 utest_expect("-8123", "%d", -8123);
685 utest_expect("16", "%hd", 0x7fff0010);
686 utest_expect("16", "%hhd", 0x7fffff10);
687 utest_expect("68719476736", "%lld", 0x1000000000);
688 utest_expect("70000", "%ld", 70000);
689 utest_expect("0xb0001234", "%p", (void*)0xb0001234);
690 utest_expect("12ab", "%x", 0x12ab);
691 utest_expect("12AB", "%X", 0x12ab);
692 utest_expect("00123456", "%08x", 0x123456);
693 utest_expect("01234", "0%d", 1234);
694 utest_expect(" 1234", "%5d", 1234);
695 utest_expect("01234", "%05d", 1234);
696 utest_expect(" 1234", "%8d", 1234);
697 utest_expect("1234 ", "%-8d", 1234);
698 utest_expect("abcdef ", "%-11s", "abcdef");
699 utest_expect("something:1234", "%s:%d", "something", 1234);
703 #endif /* UNIT_TESTS */