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