• 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 #if LINKER_DEBUG
176 
177 #if !LINKER_DEBUG_TO_LOG
178 
179 /*** File descriptor output
180  ***/
181 
182 typedef struct {
183     Out out[1];
184     int fd;
185     int total;
186 } FdOut;
187 
188 static void
fd_out_send(void * opaque,const char * data,int len)189 fd_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 
209 static Out*
fd_out_init(FdOut * fdo,int fd)210 fd_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 
220 static int
fd_out_length(FdOut * fdo)221 fd_out_length(FdOut *fdo)
222 {
223     return fdo->total;
224 }
225 
226 
227 int
format_fd(int fd,const char * format,...)228 format_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 
log_vprint(int prio,const char * tag,const char * fmt,va_list args)264 static 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 
300 extern int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
301 
302 #endif /* !CUSTOM_LOG_VPRINT */
303 
304 int
format_log(int prio,const char * tag,const char * format,...)305 format_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  */
328 static unsigned
parse_decimal(const char * format,int * ppos)329 parse_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  */
352 static void
format_number(char * buffer,size_t bufsize,uint64_t value,int base,const char * digits)353 format_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 */
388 static void
format_integer(char * buffer,size_t buffsize,uint64_t value,int base,int isSigned)389 format_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 */
402 static void
format_octal(char * buffer,size_t buffsize,uint64_t value,int isSigned)403 format_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 */
409 static void
format_decimal(char * buffer,size_t buffsize,uint64_t value,int isSigned)410 format_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 */
417 static void
format_hex(char * buffer,size_t buffsize,uint64_t value,int isCap)418 format_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' */
427 static void
out_vformat(Out * o,const char * format,va_list args)428 out_vformat(Out *o, const char *format, va_list args)
429 {
430     int nn = 0, mm;
431     int padZero = 0;
432     int padLeft = 0;
433     char sign = '\0';
434     int width = -1;
435     int prec  = -1;
436     size_t bytelen = sizeof(int);
437     const char*  str;
438     int slen;
439     char buffer[32];  /* temporary buffer used to format numbers */
440 
441     for (;;) {
442         char  c;
443 
444         /* first, find all characters that are not 0 or '%' */
445         /* then send them to the output directly */
446         mm = nn;
447         do {
448             c = format[mm];
449             if (c == '\0' || c == '%')
450                 break;
451             mm++;
452         } while (1);
453 
454         if (mm > nn) {
455             out_send(o, format+nn, mm-nn);
456             nn = mm;
457         }
458 
459         /* is this it ? then exit */
460         if (c == '\0')
461             break;
462 
463         /* nope, we are at a '%' modifier */
464         nn++;  // skip it
465 
466         /* parse flags */
467         for (;;) {
468             c = format[nn++];
469             if (c == '\0') {  /* single trailing '%' ? */
470                 c = '%';
471                 out_send(o, &c, 1);
472                 return;
473             }
474             else if (c == '0') {
475                 padZero = 1;
476                 continue;
477             }
478             else if (c == '-') {
479                 padLeft = 1;
480                 continue;
481             }
482             else if (c == ' ' || c == '+') {
483                 sign = c;
484                 continue;
485             }
486             break;
487         }
488 
489         /* parse field width */
490         if ((c >= '0' && c <= '9')) {
491             nn --;
492             width = (int)parse_decimal(format, &nn);
493             c = format[nn++];
494         }
495 
496         /* parse precision */
497         if (c == '.') {
498             prec = (int)parse_decimal(format, &nn);
499             c = format[nn++];
500         }
501 
502         /* length modifier */
503         switch (c) {
504         case 'h':
505             bytelen = sizeof(short);
506             if (format[nn] == 'h') {
507                 bytelen = sizeof(char);
508                 nn += 1;
509             }
510             c = format[nn++];
511             break;
512         case 'l':
513             bytelen = sizeof(long);
514             if (format[nn] == 'l') {
515                 bytelen = sizeof(long long);
516                 nn += 1;
517             }
518             c = format[nn++];
519             break;
520         case 'z':
521             bytelen = sizeof(size_t);
522             c = format[nn++];
523             break;
524         case 't':
525             bytelen = sizeof(ptrdiff_t);
526             c = format[nn++];
527             break;
528         case 'p':
529             bytelen = sizeof(void*);
530             c = format[nn++];
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 = (uint64_t)(ptrdiff_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", 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);
700     return gFails != 0;
701 }
702 
703 #endif /* UNIT_TESTS */
704