Imported Upstream version 0.1.0+git20131207+e452e83
[deb_libhybris.git] / hybris / common / jb / linker_format.c
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
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
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
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*
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
130 buf_out_length(BufOut *bo)
131 {
132 return bo->total;
133 }
134
135 static int
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
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 #if 0
170 int
171 vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
172 {
173 return format_buffer(buff, bufsize, format, args);
174 }
175 #endif
176
177 #if LINKER_DEBUG
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
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*
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
221 fd_out_length(FdOut *fdo)
222 {
223 return fdo->total;
224 }
225
226
227 int
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 /*** Log output
246 ***/
247
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.
251 *
252 * You can test that by setting CUSTOM_LOG_VPRINT to 0
253 */
254 #define CUSTOM_LOG_VPRINT 1
255
256 #if CUSTOM_LOG_VPRINT
257
258 #include <unistd.h>
259 #include <fcntl.h>
260 #include <sys/uio.h>
261
262 static int log_vprint(int prio, const char *tag, const char *fmt, va_list args)
263 {
264 char buf[1024];
265 int result;
266 static int log_fd = -1;
267
268 result = vformat_buffer(buf, sizeof buf, fmt, args);
269
270 if (log_fd < 0) {
271 log_fd = open("/dev/log/main", O_WRONLY);
272 if (log_fd < 0) {
273 log_fd = fileno(stdout); // kernel doesn't have android log
274 return result;
275 }
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
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 */
316
317 /*** formatted output implementation
318 ***/
319
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.
323 *
324 * NOTE: Does *not* handle a sign prefix.
325 */
326 static unsigned
327 parse_decimal(const char *format, int *ppos)
328 {
329 const char* p = format + *ppos;
330 unsigned result = 0;
331
332 for (;;) {
333 int ch = *p;
334 unsigned d = (unsigned)(ch - '0');
335
336 if (d >= 10U)
337 break;
338
339 result = result*10 + d;
340 p++;
341 }
342 *ppos = p - format;
343 return result;
344 }
345
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.
349 */
350 static void
351 format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
352 {
353 char *pos = buffer;
354 char *end = buffer + bufsize - 1;
355
356 /* generate digit string in reverse order */
357 while (value) {
358 unsigned d = value % base;
359 value /= base;
360 if (pos < end) {
361 *pos++ = digits[d];
362 }
363 }
364
365 /* special case for 0 */
366 if (pos == buffer) {
367 if (pos < end) {
368 *pos++ = '0';
369 }
370 }
371 pos[0] = '\0';
372
373 /* now reverse digit string in-place */
374 end = pos - 1;
375 pos = buffer;
376 while (pos < end) {
377 int ch = pos[0];
378 pos[0] = end[0];
379 end[0] = (char) ch;
380 pos++;
381 end--;
382 }
383 }
384
385 /* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
386 static void
387 format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
388 {
389 if (isSigned && (int64_t)value < 0) {
390 buffer[0] = '-';
391 buffer += 1;
392 buffsize -= 1;
393 value = (uint64_t)(-(int64_t)value);
394 }
395
396 format_number(buffer, buffsize, value, base, "0123456789");
397 }
398
399 /* Write an octal into a buffer, assumes buffsize > 2 */
400 static void
401 format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
402 {
403 format_integer(buffer, buffsize, value, 8, isSigned);
404 }
405
406 /* Write a decimal into a buffer, assumes buffsize > 2 */
407 static void
408 format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
409 {
410 format_integer(buffer, buffsize, value, 10, isSigned);
411 }
412
413 /* Write an hexadecimal into a buffer, isCap is true for capital alphas.
414 * Assumes bufsize > 2 */
415 static void
416 format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
417 {
418 const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
419
420 format_number(buffer, buffsize, value, 16, digits);
421 }
422
423
424 /* Perform formatted output to an output target 'o' */
425 static void
426 out_vformat(Out *o, const char *format, va_list args)
427 {
428 int nn = 0;
429
430 for (;;) {
431 int mm;
432 int padZero = 0;
433 int padLeft = 0;
434 char sign = '\0';
435 int width = -1;
436 int prec = -1;
437 size_t bytelen = sizeof(int);
438 const char* str;
439 int slen;
440 char buffer[32]; /* temporary buffer used to format numbers */
441
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 default:
529 ;
530 }
531
532 /* conversion specifier */
533 if (c == 's') {
534 /* string */
535 str = va_arg(args, const char*);
536 } else if (c == 'c') {
537 /* character */
538 /* NOTE: char is promoted to int when passed through the stack */
539 buffer[0] = (char) va_arg(args, int);
540 buffer[1] = '\0';
541 str = buffer;
542 } else if (c == 'p') {
543 uint64_t value = (uintptr_t) va_arg(args, void*);
544 buffer[0] = '0';
545 buffer[1] = 'x';
546 format_hex(buffer + 2, sizeof buffer-2, value, 0);
547 str = buffer;
548 } else {
549 /* integers - first read value from stack */
550 uint64_t value;
551 int isSigned = (c == 'd' || c == 'i' || c == 'o');
552
553 /* NOTE: int8_t and int16_t are promoted to int when passed
554 * through the stack
555 */
556 switch (bytelen) {
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 */
562 }
563
564 /* sign extension, if needed */
565 if (isSigned) {
566 int shift = 64 - 8*bytelen;
567 value = (uint64_t)(((int64_t)(value << shift)) >> shift);
568 }
569
570 /* format the number properly into our buffer */
571 switch (c) {
572 case 'i': case 'd':
573 format_integer(buffer, sizeof buffer, value, 10, isSigned);
574 break;
575 case 'o':
576 format_integer(buffer, sizeof buffer, value, 8, isSigned);
577 break;
578 case 'x': case 'X':
579 format_hex(buffer, sizeof buffer, value, (c == 'X'));
580 break;
581 default:
582 buffer[0] = '\0';
583 }
584 /* then point to it */
585 str = buffer;
586 }
587
588 /* if we are here, 'str' points to the content that must be
589 * outputted. handle padding and alignment now */
590
591 slen = strlen(str);
592
593 if (slen < width && !padLeft) {
594 char padChar = padZero ? '0' : ' ';
595 out_send_repeat(o, padChar, width - slen);
596 }
597
598 out_send(o, str, slen);
599
600 if (slen < width && padLeft) {
601 char padChar = padZero ? '0' : ' ';
602 out_send_repeat(o, padChar, width - slen);
603 }
604 }
605 }
606
607
608 #ifdef UNIT_TESTS
609
610 #include <stdio.h>
611
612 static int gFails = 0;
613
614 #define MARGIN 40
615
616 #define UTEST_CHECK(condition,message) \
617 printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
618 if (!(condition)) { \
619 printf("KO\n"); \
620 gFails += 1; \
621 } else { \
622 printf("ok\n"); \
623 }
624
625 static void
626 utest_BufOut(void)
627 {
628 char buffer[16];
629 BufOut bo[1];
630 Out* out;
631 int ret;
632
633 buffer[0] = '1';
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");
643
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");
648 }
649
650 static void
651 utest_expect(const char* result, const char* format, ...)
652 {
653 va_list args;
654 BufOut bo[1];
655 char buffer[256];
656 Out* out = buf_out_init(bo, buffer, sizeof buffer);
657
658 printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
659 va_start(args, format);
660 out_vformat(out, format, args);
661 va_end(args);
662
663 if (strcmp(result, buffer)) {
664 printf("KO. got '%s' expecting '%s'\n", buffer, result);
665 gFails += 1;
666 } else {
667 printf("ok. got '%s'\n", result);
668 }
669 }
670
671 int main(void)
672 {
673 utest_BufOut();
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);
700 return gFails != 0;
701 }
702
703 #endif /* UNIT_TESTS */