• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
out_send(Out * o,const void * data,size_t len)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
out_send_repeat(Out * o,char ch,int count)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
buf_out_send(void * opaque,const char * data,int len)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*
buf_out_init(BufOut * bo,char * buffer,size_t size)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
buf_out_length(BufOut * bo)130 buf_out_length(BufOut *bo)
131 {
132     return bo->total;
133 }
134 
135 static int
vformat_buffer(char * buff,size_t buffsize,const char * format,va_list args)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
format_buffer(char * buff,size_t buffsize,const char * format,...)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
vsnprintf(char * buff,size_t bufsize,const char * format,va_list args)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 /* The pthread implementation uses snprintf(). If we define it here, we
176  * avoid pulling the stdio vfprintf() implementation into the linker
177  * saving about 19KB of machine code.
178  */
179 int
snprintf(char * buff,size_t bufsize,const char * format,...)180 snprintf(char* buff, size_t bufsize, const char* format, ...)
181 {
182     va_list args;
183     int ret;
184     va_start(args, format);
185     ret = vsnprintf(buff, bufsize, format, args);
186     va_end(args);
187     return ret;
188 }
189 
190 #if LINKER_DEBUG
191 
192 #if !LINKER_DEBUG_TO_LOG
193 
194 /*** File descriptor output
195  ***/
196 
197 typedef struct {
198     Out out[1];
199     int fd;
200     int total;
201 } FdOut;
202 
203 static void
fd_out_send(void * opaque,const char * data,int len)204 fd_out_send(void *opaque, const char *data, int len)
205 {
206     FdOut *fdo = opaque;
207 
208     if (len < 0)
209         len = strlen(data);
210 
211     while (len > 0) {
212         int ret = write(fdo->fd, data, len);
213         if (ret < 0) {
214             if (errno == EINTR)
215                 continue;
216             break;
217         }
218         data += ret;
219         len -= ret;
220         fdo->total += ret;
221     }
222 }
223 
224 static Out*
fd_out_init(FdOut * fdo,int fd)225 fd_out_init(FdOut *fdo, int  fd)
226 {
227     fdo->out->opaque = fdo;
228     fdo->out->send = fd_out_send;
229     fdo->fd = fd;
230     fdo->total = 0;
231 
232     return fdo->out;
233 }
234 
235 static int
fd_out_length(FdOut * fdo)236 fd_out_length(FdOut *fdo)
237 {
238     return fdo->total;
239 }
240 
241 
242 int
format_fd(int fd,const char * format,...)243 format_fd(int fd, const char *format, ...)
244 {
245     FdOut fdo;
246     Out* out;
247     va_list args;
248 
249     out = fd_out_init(&fdo, fd);
250     if (out == NULL)
251         return 0;
252 
253     va_start(args, format);
254     out_vformat(out, format, args);
255     va_end(args);
256 
257     return fd_out_length(&fdo);
258 }
259 
260 #else /* LINKER_DEBUG_TO_LOG */
261 
262 /*** Log output
263  ***/
264 
265 /* We need our own version of __libc_android_log_vprint, otherwise
266  * the log output is completely broken. Probably due to the fact
267  * that the C library is not initialized yet.
268  *
269  * You can test that by setting CUSTOM_LOG_VPRINT to 0
270  */
271 #define  CUSTOM_LOG_VPRINT  1
272 
273 #if CUSTOM_LOG_VPRINT
274 
275 #include <unistd.h>
276 #include <fcntl.h>
277 #include <sys/uio.h>
278 
log_vprint(int prio,const char * tag,const char * fmt,va_list args)279 static int log_vprint(int prio, const char *tag, const char *fmt, va_list  args)
280 {
281     char buf[1024];
282     int result;
283     static int log_fd = -1;
284 
285     result = vformat_buffer(buf, sizeof buf, fmt, args);
286 
287     if (log_fd < 0) {
288         log_fd = open("/dev/log/main", O_WRONLY);
289         if (log_fd < 0)
290             return result;
291     }
292 
293     {
294         ssize_t ret;
295         struct iovec vec[3];
296 
297         vec[0].iov_base = (unsigned char *) &prio;
298         vec[0].iov_len = 1;
299         vec[1].iov_base = (void *) tag;
300         vec[1].iov_len = strlen(tag) + 1;
301         vec[2].iov_base = (void *) buf;
302         vec[2].iov_len = strlen(buf) + 1;
303 
304         do {
305             ret = writev(log_fd, vec, 3);
306         } while ((ret < 0) && (errno == EINTR));
307     }
308     return result;
309 }
310 
311 #define  __libc_android_log_vprint  log_vprint
312 
313 #else /* !CUSTOM_LOG_VPRINT */
314 
315 extern "C" int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
316 
317 #endif /* !CUSTOM_LOG_VPRINT */
318 
319 int
format_log(int prio,const char * tag,const char * format,...)320 format_log(int prio, const char *tag, const char *format, ...)
321 {
322     int ret;
323     va_list  args;
324     va_start(args, format);
325     ret = __libc_android_log_vprint(prio, tag, format, args);
326     va_end(args);
327     return ret;
328 }
329 
330 #endif /* LINKER_DEBUG_TO_LOG */
331 
332 #endif /* LINKER_DEBUG */
333 
334 /*** formatted output implementation
335  ***/
336 
337 /* Parse a decimal string from 'format + *ppos',
338  * return the value, and writes the new position past
339  * the decimal string in '*ppos' on exit.
340  *
341  * NOTE: Does *not* handle a sign prefix.
342  */
343 static unsigned
parse_decimal(const char * format,int * ppos)344 parse_decimal(const char *format, int *ppos)
345 {
346     const char* p = format + *ppos;
347     unsigned result = 0;
348 
349     for (;;) {
350         int ch = *p;
351         unsigned d = (unsigned)(ch - '0');
352 
353         if (d >= 10U)
354             break;
355 
356         result = result*10 + d;
357         p++;
358     }
359     *ppos = p - format;
360     return result;
361 }
362 
363 /* write an octal/decimal/number into a bounded buffer.
364  * assumes that bufsize > 0, and 'digits' is a string of
365  * digits of at least 'base' values.
366  */
367 static void
format_number(char * buffer,size_t bufsize,uint64_t value,int base,const char * digits)368 format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
369 {
370     char *pos = buffer;
371     char *end = buffer + bufsize - 1;
372 
373     /* generate digit string in reverse order */
374     while (value) {
375         unsigned d = value % base;
376         value /= base;
377         if (pos < end) {
378             *pos++ = digits[d];
379         }
380     }
381 
382     /* special case for 0 */
383     if (pos == buffer) {
384         if (pos < end) {
385             *pos++ = '0';
386         }
387     }
388     pos[0] = '\0';
389 
390     /* now reverse digit string in-place */
391     end = pos - 1;
392     pos = buffer;
393     while (pos < end) {
394         int ch = pos[0];
395         pos[0] = end[0];
396         end[0] = (char) ch;
397         pos++;
398         end--;
399     }
400 }
401 
402 /* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
403 static void
format_integer(char * buffer,size_t buffsize,uint64_t value,int base,int isSigned)404 format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
405 {
406     if (isSigned && (int64_t)value < 0) {
407         buffer[0] = '-';
408         buffer += 1;
409         buffsize -= 1;
410         value = (uint64_t)(-(int64_t)value);
411     }
412 
413     format_number(buffer, buffsize, value, base, "0123456789");
414 }
415 
416 /* Write an hexadecimal into a buffer, isCap is true for capital alphas.
417  * Assumes bufsize > 2 */
418 static void
format_hex(char * buffer,size_t buffsize,uint64_t value,int isCap)419 format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
420 {
421     const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
422 
423     format_number(buffer, buffsize, value, 16, digits);
424 }
425 
426 
427 /* Perform formatted output to an output target 'o' */
428 static void
out_vformat(Out * o,const char * format,va_list args)429 out_vformat(Out *o, const char *format, va_list args)
430 {
431     int nn = 0;
432 
433     for (;;) {
434         int mm;
435         int padZero = 0;
436         int padLeft = 0;
437         char sign = '\0';
438         int width = -1;
439         int prec  = -1;
440         size_t bytelen = sizeof(int);
441         const char*  str;
442         int slen;
443         char buffer[32];  /* temporary buffer used to format numbers */
444 
445         char  c;
446 
447         /* first, find all characters that are not 0 or '%' */
448         /* then send them to the output directly */
449         mm = nn;
450         do {
451             c = format[mm];
452             if (c == '\0' || c == '%')
453                 break;
454             mm++;
455         } while (1);
456 
457         if (mm > nn) {
458             out_send(o, format+nn, mm-nn);
459             nn = mm;
460         }
461 
462         /* is this it ? then exit */
463         if (c == '\0')
464             break;
465 
466         /* nope, we are at a '%' modifier */
467         nn++;  // skip it
468 
469         /* parse flags */
470         for (;;) {
471             c = format[nn++];
472             if (c == '\0') {  /* single trailing '%' ? */
473                 c = '%';
474                 out_send(o, &c, 1);
475                 return;
476             }
477             else if (c == '0') {
478                 padZero = 1;
479                 continue;
480             }
481             else if (c == '-') {
482                 padLeft = 1;
483                 continue;
484             }
485             else if (c == ' ' || c == '+') {
486                 sign = c;
487                 continue;
488             }
489             break;
490         }
491 
492         /* parse field width */
493         if ((c >= '0' && c <= '9')) {
494             nn --;
495             width = (int)parse_decimal(format, &nn);
496             c = format[nn++];
497         }
498 
499         /* parse precision */
500         if (c == '.') {
501             prec = (int)parse_decimal(format, &nn);
502             c = format[nn++];
503         }
504 
505         /* length modifier */
506         switch (c) {
507         case 'h':
508             bytelen = sizeof(short);
509             if (format[nn] == 'h') {
510                 bytelen = sizeof(char);
511                 nn += 1;
512             }
513             c = format[nn++];
514             break;
515         case 'l':
516             bytelen = sizeof(long);
517             if (format[nn] == 'l') {
518                 bytelen = sizeof(long long);
519                 nn += 1;
520             }
521             c = format[nn++];
522             break;
523         case 'z':
524             bytelen = sizeof(size_t);
525             c = format[nn++];
526             break;
527         case 't':
528             bytelen = sizeof(ptrdiff_t);
529             c = format[nn++];
530             break;
531         default:
532             ;
533         }
534 
535         /* conversion specifier */
536         if (c == 's') {
537             /* string */
538             str = va_arg(args, const char*);
539         } else if (c == 'c') {
540             /* character */
541             /* NOTE: char is promoted to int when passed through the stack */
542             buffer[0] = (char) va_arg(args, int);
543             buffer[1] = '\0';
544             str = buffer;
545         } else if (c == 'p') {
546             uint64_t  value = (uintptr_t) va_arg(args, void*);
547             buffer[0] = '0';
548             buffer[1] = 'x';
549             format_hex(buffer + 2, sizeof buffer-2, value, 0);
550             str = buffer;
551         } else {
552             /* integers - first read value from stack */
553             uint64_t value;
554             int isSigned = (c == 'd' || c == 'i' || c == 'o');
555 
556             /* NOTE: int8_t and int16_t are promoted to int when passed
557              *       through the stack
558              */
559             switch (bytelen) {
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 */
565             }
566 
567             /* sign extension, if needed */
568             if (isSigned) {
569                 int shift = 64 - 8*bytelen;
570                 value = (uint64_t)(((int64_t)(value << shift)) >> shift);
571             }
572 
573             /* format the number properly into our buffer */
574             switch (c) {
575             case 'i': case 'd':
576                 format_integer(buffer, sizeof buffer, value, 10, isSigned);
577                 break;
578             case 'o':
579                 format_integer(buffer, sizeof buffer, value, 8, isSigned);
580                 break;
581             case 'x': case 'X':
582                 format_hex(buffer, sizeof buffer, value, (c == 'X'));
583                 break;
584             default:
585                 buffer[0] = '\0';
586             }
587             /* then point to it */
588             str = buffer;
589         }
590 
591         /* if we are here, 'str' points to the content that must be
592          * outputted. handle padding and alignment now */
593 
594         slen = strlen(str);
595 
596         if (slen < width && !padLeft) {
597             char padChar = padZero ? '0' : ' ';
598             out_send_repeat(o, padChar, width - slen);
599         }
600 
601         out_send(o, str, slen);
602 
603         if (slen < width && padLeft) {
604             char padChar = padZero ? '0' : ' ';
605             out_send_repeat(o, padChar, width - slen);
606         }
607     }
608 }
609 
610 
611 #ifdef UNIT_TESTS
612 
613 #include <stdio.h>
614 
615 static int   gFails = 0;
616 
617 #define  MARGIN  40
618 
619 #define  UTEST_CHECK(condition,message) \
620     printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
621     if (!(condition)) { \
622         printf("KO\n"); \
623         gFails += 1; \
624     } else { \
625         printf("ok\n"); \
626     }
627 
628 static void
utest_BufOut(void)629 utest_BufOut(void)
630 {
631     char buffer[16];
632     BufOut bo[1];
633     Out* out;
634     int ret;
635 
636     buffer[0] = '1';
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");
646 
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");
651 }
652 
653 static void
utest_expect(const char * result,const char * format,...)654 utest_expect(const char*  result, const char*  format, ...)
655 {
656     va_list args;
657     BufOut bo[1];
658     char buffer[256];
659     Out* out = buf_out_init(bo, buffer, sizeof buffer);
660 
661     printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
662     va_start(args, format);
663     out_vformat(out, format, args);
664     va_end(args);
665 
666     if (strcmp(result, buffer)) {
667         printf("KO. got '%s' expecting '%s'\n", buffer, result);
668         gFails += 1;
669     } else {
670         printf("ok. got '%s'\n", result);
671     }
672 }
673 
main(void)674 int  main(void)
675 {
676     utest_BufOut();
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", 0x1000000000LL);
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);
700     utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
701     utest_expect("5,0x0", "%d,%p", 5, NULL);
702     utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
703     return gFails != 0;
704 }
705 
706 #endif /* UNIT_TESTS */
707