libc_logging.cpp revision 885f3b9cad01b8158aadc55c159c17dbf34f622c
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 <../private/libc_logging.h> // Relative path so we can #include this .cpp file for testing.
30#include <../private/ScopedPthreadMutexLocker.h>
31
32#include <assert.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <pthread.h>
36#include <stdarg.h>
37#include <stddef.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/mman.h>
41#include <sys/uio.h>
42#include <unistd.h>
43
44static pthread_mutex_t gAbortMsgLock = PTHREAD_MUTEX_INITIALIZER;
45static pthread_mutex_t gLogInitializationLock = PTHREAD_MUTEX_INITIALIZER;
46
47__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
48
49// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
50enum AndroidEventLogType {
51  EVENT_TYPE_INT      = 0,
52  EVENT_TYPE_LONG     = 1,
53  EVENT_TYPE_STRING   = 2,
54  EVENT_TYPE_LIST     = 3,
55};
56
57struct BufferOutputStream {
58 public:
59  BufferOutputStream(char* buffer, size_t size) : total(0) {
60    buffer_ = buffer;
61    end_ = buffer + size - 1;
62    pos_ = buffer_;
63    pos_[0] = '\0';
64  }
65
66  ~BufferOutputStream() {
67  }
68
69  void Send(const char* data, int len) {
70    if (len < 0) {
71      len = strlen(data);
72    }
73
74    while (len > 0) {
75      int avail = end_ - pos_;
76      if (avail == 0) {
77        break;
78      }
79      if (avail > len) {
80        avail = len;
81      }
82      memcpy(pos_, data, avail);
83      pos_ += avail;
84      pos_[0] = '\0';
85      len -= avail;
86      total += avail;
87    }
88  }
89
90  int total;
91
92 private:
93  char* buffer_;
94  char* pos_;
95  char* end_;
96};
97
98struct FdOutputStream {
99 public:
100  FdOutputStream(int fd) : total(0), fd_(fd) {
101  }
102
103  void Send(const char* data, int len) {
104    if (len < 0) {
105      len = strlen(data);
106    }
107
108    while (len > 0) {
109      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
110      if (rc == -1) {
111        break;
112      }
113      data += rc;
114      len -= rc;
115      total += rc;
116    }
117  }
118
119  int total;
120
121 private:
122  int fd_;
123};
124
125/*** formatted output implementation
126 ***/
127
128/* Parse a decimal string from 'format + *ppos',
129 * return the value, and writes the new position past
130 * the decimal string in '*ppos' on exit.
131 *
132 * NOTE: Does *not* handle a sign prefix.
133 */
134static unsigned parse_decimal(const char *format, int *ppos) {
135    const char* p = format + *ppos;
136    unsigned result = 0;
137
138    for (;;) {
139        int ch = *p;
140        unsigned d = (unsigned)(ch - '0');
141
142        if (d >= 10U) {
143            break;
144        }
145
146        result = result*10 + d;
147        p++;
148    }
149    *ppos = p - format;
150    return result;
151}
152
153// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
154// Assumes that buf_size > 0.
155static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
156  char* p = buf;
157  char* end = buf + buf_size - 1;
158
159  // Generate digit string in reverse order.
160  while (value) {
161    unsigned d = value % base;
162    value /= base;
163    if (p != end) {
164      char ch;
165      if (d < 10) {
166        ch = '0' + d;
167      } else {
168        ch = (caps ? 'A' : 'a') + (d - 10);
169      }
170      *p++ = ch;
171    }
172  }
173
174  // Special case for 0.
175  if (p == buf) {
176    if (p != end) {
177      *p++ = '0';
178    }
179  }
180  *p = '\0';
181
182  // Reverse digit string in-place.
183  size_t length = p - buf;
184  for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
185    char ch = buf[i];
186    buf[i] = buf[j];
187    buf[j] = ch;
188  }
189}
190
191static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
192  // Decode the conversion specifier.
193  int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
194  int base = 10;
195  if (conversion == 'x' || conversion == 'X') {
196    base = 16;
197  } else if (conversion == 'o') {
198    base = 8;
199  }
200  bool caps = (conversion == 'X');
201
202  if (is_signed && static_cast<int64_t>(value) < 0) {
203    buf[0] = '-';
204    buf += 1;
205    buf_size -= 1;
206    value = static_cast<uint64_t>(-static_cast<int64_t>(value));
207  }
208  format_unsigned(buf, buf_size, value, base, caps);
209}
210
211template <typename Out>
212static void SendRepeat(Out& o, char ch, int count) {
213  char pad[8];
214  memset(pad, ch, sizeof(pad));
215
216  const int pad_size = static_cast<int>(sizeof(pad));
217  while (count > 0) {
218    int avail = count;
219    if (avail > pad_size) {
220      avail = pad_size;
221    }
222    o.Send(pad, avail);
223    count -= avail;
224  }
225}
226
227/* Perform formatted output to an output target 'o' */
228template <typename Out>
229static void out_vformat(Out& o, const char* format, va_list args) {
230    int nn = 0;
231
232    for (;;) {
233        int mm;
234        int padZero = 0;
235        int padLeft = 0;
236        char sign = '\0';
237        int width = -1;
238        int prec  = -1;
239        size_t bytelen = sizeof(int);
240        int slen;
241        char buffer[32];  /* temporary buffer used to format numbers */
242
243        char  c;
244
245        /* first, find all characters that are not 0 or '%' */
246        /* then send them to the output directly */
247        mm = nn;
248        do {
249            c = format[mm];
250            if (c == '\0' || c == '%')
251                break;
252            mm++;
253        } while (1);
254
255        if (mm > nn) {
256            o.Send(format+nn, mm-nn);
257            nn = mm;
258        }
259
260        /* is this it ? then exit */
261        if (c == '\0')
262            break;
263
264        /* nope, we are at a '%' modifier */
265        nn++;  // skip it
266
267        /* parse flags */
268        for (;;) {
269            c = format[nn++];
270            if (c == '\0') {  /* single trailing '%' ? */
271                c = '%';
272                o.Send(&c, 1);
273                return;
274            }
275            else if (c == '0') {
276                padZero = 1;
277                continue;
278            }
279            else if (c == '-') {
280                padLeft = 1;
281                continue;
282            }
283            else if (c == ' ' || c == '+') {
284                sign = c;
285                continue;
286            }
287            break;
288        }
289
290        /* parse field width */
291        if ((c >= '0' && c <= '9')) {
292            nn --;
293            width = (int)parse_decimal(format, &nn);
294            c = format[nn++];
295        }
296
297        /* parse precision */
298        if (c == '.') {
299            prec = (int)parse_decimal(format, &nn);
300            c = format[nn++];
301        }
302
303        /* length modifier */
304        switch (c) {
305        case 'h':
306            bytelen = sizeof(short);
307            if (format[nn] == 'h') {
308                bytelen = sizeof(char);
309                nn += 1;
310            }
311            c = format[nn++];
312            break;
313        case 'l':
314            bytelen = sizeof(long);
315            if (format[nn] == 'l') {
316                bytelen = sizeof(long long);
317                nn += 1;
318            }
319            c = format[nn++];
320            break;
321        case 'z':
322            bytelen = sizeof(size_t);
323            c = format[nn++];
324            break;
325        case 't':
326            bytelen = sizeof(ptrdiff_t);
327            c = format[nn++];
328            break;
329        default:
330            ;
331        }
332
333        /* conversion specifier */
334        const char* str = buffer;
335        if (c == 's') {
336            /* string */
337            str = va_arg(args, const char*);
338            if (str == NULL) {
339                str = "(null)";
340            }
341        } else if (c == 'c') {
342            /* character */
343            /* NOTE: char is promoted to int when passed through the stack */
344            buffer[0] = (char) va_arg(args, int);
345            buffer[1] = '\0';
346        } else if (c == 'p') {
347            uint64_t  value = (uintptr_t) va_arg(args, void*);
348            buffer[0] = '0';
349            buffer[1] = 'x';
350            format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
351        } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
352            /* integers - first read value from stack */
353            uint64_t value;
354            int is_signed = (c == 'd' || c == 'i' || c == 'o');
355
356            /* NOTE: int8_t and int16_t are promoted to int when passed
357             *       through the stack
358             */
359            switch (bytelen) {
360            case 1: value = (uint8_t)  va_arg(args, int); break;
361            case 2: value = (uint16_t) va_arg(args, int); break;
362            case 4: value = va_arg(args, uint32_t); break;
363            case 8: value = va_arg(args, uint64_t); break;
364            default: return;  /* should not happen */
365            }
366
367            /* sign extension, if needed */
368            if (is_signed) {
369                int shift = 64 - 8*bytelen;
370                value = (uint64_t)(((int64_t)(value << shift)) >> shift);
371            }
372
373            /* format the number properly into our buffer */
374            format_integer(buffer, sizeof(buffer), value, c);
375        } else if (c == '%') {
376            buffer[0] = '%';
377            buffer[1] = '\0';
378        } else {
379            __assert(__FILE__, __LINE__, "conversion specifier unsupported");
380        }
381
382        /* if we are here, 'str' points to the content that must be
383         * outputted. handle padding and alignment now */
384
385        slen = strlen(str);
386
387        if (sign != '\0' || prec != -1) {
388            __assert(__FILE__, __LINE__, "sign/precision unsupported");
389        }
390
391        if (slen < width && !padLeft) {
392            char padChar = padZero ? '0' : ' ';
393            SendRepeat(o, padChar, width - slen);
394        }
395
396        o.Send(str, slen);
397
398        if (slen < width && padLeft) {
399            char padChar = padZero ? '0' : ' ';
400            SendRepeat(o, padChar, width - slen);
401        }
402    }
403}
404
405int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
406  BufferOutputStream os(buffer, buffer_size);
407  va_list args;
408  va_start(args, format);
409  out_vformat(os, format, args);
410  va_end(args);
411  return os.total;
412}
413
414int __libc_format_fd(int fd, const char* format, ...) {
415  FdOutputStream os(fd);
416  va_list args;
417  va_start(args, format);
418  out_vformat(os, format, args);
419  va_end(args);
420  return os.total;
421}
422
423static int __libc_write_log(int priority, const char* tag, const char* msg) {
424  static int main_log_fd = -1;
425  if (main_log_fd == -1) {
426    ScopedPthreadMutexLocker locker(&gLogInitializationLock);
427    main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
428    if (main_log_fd == -1) {
429      return -1;
430    }
431  }
432
433  iovec vec[3];
434  vec[0].iov_base = &priority;
435  vec[0].iov_len = 1;
436  vec[1].iov_base = const_cast<char*>(tag);
437  vec[1].iov_len = strlen(tag) + 1;
438  vec[2].iov_base = const_cast<char*>(msg);
439  vec[2].iov_len = strlen(msg) + 1;
440
441  return TEMP_FAILURE_RETRY(writev(main_log_fd, vec, 3));
442}
443
444int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
445  char buffer[1024];
446  BufferOutputStream os(buffer, sizeof(buffer));
447  out_vformat(os, format, args);
448  return __libc_write_log(priority, tag, buffer);
449}
450
451int __libc_format_log(int priority, const char* tag, const char* format, ...) {
452  va_list args;
453  va_start(args, format);
454  int result = __libc_format_log_va_list(priority, tag, format, args);
455  va_end(args);
456  return result;
457}
458
459static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
460  iovec vec[3];
461  vec[0].iov_base = &tag;
462  vec[0].iov_len = sizeof(tag);
463  vec[1].iov_base = &type;
464  vec[1].iov_len = sizeof(type);
465  vec[2].iov_base = const_cast<void*>(payload);
466  vec[2].iov_len = len;
467
468  static int event_log_fd = -1;
469  if (event_log_fd == -1) {
470    ScopedPthreadMutexLocker locker(&gLogInitializationLock);
471    event_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/events", O_CLOEXEC | O_WRONLY));
472  }
473  return TEMP_FAILURE_RETRY(writev(event_log_fd, vec, 3));
474}
475
476void __libc_android_log_event_int(int32_t tag, int value) {
477  __libc_android_log_event(tag, EVENT_TYPE_INT, &value, sizeof(value));
478}
479
480void __libc_android_log_event_uid(int32_t tag) {
481  __libc_android_log_event_int(tag, getuid());
482}
483
484void __fortify_chk_fail(const char *msg, uint32_t tag) {
485  if (tag != 0) {
486    __libc_android_log_event_uid(tag);
487  }
488  __libc_fatal("FORTIFY_SOURCE: %s. Calling abort().", msg);
489}
490
491void __libc_fatal(const char* format, ...) {
492  char msg[1024];
493  BufferOutputStream os(msg, sizeof(msg));
494  va_list args;
495  va_start(args, format);
496  out_vformat(os, format, args);
497  va_end(args);
498
499  // TODO: log to stderr for the benefit of "adb shell" users.
500
501  // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
502  __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
503
504  __libc_set_abort_message(msg);
505
506  abort();
507}
508
509void __libc_set_abort_message(const char* msg) {
510  size_t size = sizeof(abort_msg_t) + strlen(msg) + 1;
511  void* map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
512  if (map == MAP_FAILED) {
513    return;
514  }
515
516  if (__abort_message_ptr != NULL) {
517    ScopedPthreadMutexLocker locker(&gAbortMsgLock);
518    if (*__abort_message_ptr != NULL) {
519      munmap(*__abort_message_ptr, (*__abort_message_ptr)->size);
520    }
521    abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map);
522    new_abort_message->size = size;
523    strcpy(new_abort_message->msg, msg);
524    *__abort_message_ptr = new_abort_message;
525  }
526}
527