libc_logging.cpp revision bae5b1dbd8dfe7318e208be917f4c9b9e8abced6
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/socket.h> 42#include <sys/types.h> 43#include <sys/uio.h> 44#include <sys/un.h> 45#include <time.h> 46#include <unistd.h> 47 48static pthread_mutex_t g_abort_msg_lock = PTHREAD_MUTEX_INITIALIZER; 49 50__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common. 51 52// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java. 53enum AndroidEventLogType { 54 EVENT_TYPE_INT = 0, 55 EVENT_TYPE_LONG = 1, 56 EVENT_TYPE_STRING = 2, 57 EVENT_TYPE_LIST = 3, 58}; 59 60struct BufferOutputStream { 61 public: 62 BufferOutputStream(char* buffer, size_t size) : total(0) { 63 buffer_ = buffer; 64 end_ = buffer + size - 1; 65 pos_ = buffer_; 66 pos_[0] = '\0'; 67 } 68 69 ~BufferOutputStream() { 70 } 71 72 void Send(const char* data, int len) { 73 if (len < 0) { 74 len = strlen(data); 75 } 76 77 while (len > 0) { 78 int avail = end_ - pos_; 79 if (avail == 0) { 80 break; 81 } 82 if (avail > len) { 83 avail = len; 84 } 85 memcpy(pos_, data, avail); 86 pos_ += avail; 87 pos_[0] = '\0'; 88 len -= avail; 89 total += avail; 90 } 91 } 92 93 int total; 94 95 private: 96 char* buffer_; 97 char* pos_; 98 char* end_; 99}; 100 101struct FdOutputStream { 102 public: 103 FdOutputStream(int fd) : total(0), fd_(fd) { 104 } 105 106 void Send(const char* data, int len) { 107 if (len < 0) { 108 len = strlen(data); 109 } 110 111 while (len > 0) { 112 int rc = TEMP_FAILURE_RETRY(write(fd_, data, len)); 113 if (rc == -1) { 114 break; 115 } 116 data += rc; 117 len -= rc; 118 total += rc; 119 } 120 } 121 122 int total; 123 124 private: 125 int fd_; 126}; 127 128/*** formatted output implementation 129 ***/ 130 131/* Parse a decimal string from 'format + *ppos', 132 * return the value, and writes the new position past 133 * the decimal string in '*ppos' on exit. 134 * 135 * NOTE: Does *not* handle a sign prefix. 136 */ 137static unsigned parse_decimal(const char *format, int *ppos) { 138 const char* p = format + *ppos; 139 unsigned result = 0; 140 141 for (;;) { 142 int ch = *p; 143 unsigned d = static_cast<unsigned>(ch - '0'); 144 145 if (d >= 10U) { 146 break; 147 } 148 149 result = result*10 + d; 150 p++; 151 } 152 *ppos = p - format; 153 return result; 154} 155 156// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes. 157// Assumes that buf_size > 0. 158static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) { 159 char* p = buf; 160 char* end = buf + buf_size - 1; 161 162 // Generate digit string in reverse order. 163 while (value) { 164 unsigned d = value % base; 165 value /= base; 166 if (p != end) { 167 char ch; 168 if (d < 10) { 169 ch = '0' + d; 170 } else { 171 ch = (caps ? 'A' : 'a') + (d - 10); 172 } 173 *p++ = ch; 174 } 175 } 176 177 // Special case for 0. 178 if (p == buf) { 179 if (p != end) { 180 *p++ = '0'; 181 } 182 } 183 *p = '\0'; 184 185 // Reverse digit string in-place. 186 size_t length = p - buf; 187 for (size_t i = 0, j = length - 1; i < j; ++i, --j) { 188 char ch = buf[i]; 189 buf[i] = buf[j]; 190 buf[j] = ch; 191 } 192} 193 194static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) { 195 // Decode the conversion specifier. 196 int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o'); 197 int base = 10; 198 if (conversion == 'x' || conversion == 'X') { 199 base = 16; 200 } else if (conversion == 'o') { 201 base = 8; 202 } 203 bool caps = (conversion == 'X'); 204 205 if (is_signed && static_cast<int64_t>(value) < 0) { 206 buf[0] = '-'; 207 buf += 1; 208 buf_size -= 1; 209 value = static_cast<uint64_t>(-static_cast<int64_t>(value)); 210 } 211 format_unsigned(buf, buf_size, value, base, caps); 212} 213 214template <typename Out> 215static void SendRepeat(Out& o, char ch, int count) { 216 char pad[8]; 217 memset(pad, ch, sizeof(pad)); 218 219 const int pad_size = static_cast<int>(sizeof(pad)); 220 while (count > 0) { 221 int avail = count; 222 if (avail > pad_size) { 223 avail = pad_size; 224 } 225 o.Send(pad, avail); 226 count -= avail; 227 } 228} 229 230/* Perform formatted output to an output target 'o' */ 231template <typename Out> 232static void out_vformat(Out& o, const char* format, va_list args) { 233 int nn = 0; 234 235 for (;;) { 236 int mm; 237 int padZero = 0; 238 int padLeft = 0; 239 char sign = '\0'; 240 int width = -1; 241 int prec = -1; 242 size_t bytelen = sizeof(int); 243 int slen; 244 char buffer[32]; /* temporary buffer used to format numbers */ 245 246 char c; 247 248 /* first, find all characters that are not 0 or '%' */ 249 /* then send them to the output directly */ 250 mm = nn; 251 do { 252 c = format[mm]; 253 if (c == '\0' || c == '%') 254 break; 255 mm++; 256 } while (1); 257 258 if (mm > nn) { 259 o.Send(format+nn, mm-nn); 260 nn = mm; 261 } 262 263 /* is this it ? then exit */ 264 if (c == '\0') 265 break; 266 267 /* nope, we are at a '%' modifier */ 268 nn++; // skip it 269 270 /* parse flags */ 271 for (;;) { 272 c = format[nn++]; 273 if (c == '\0') { /* single trailing '%' ? */ 274 c = '%'; 275 o.Send(&c, 1); 276 return; 277 } 278 else if (c == '0') { 279 padZero = 1; 280 continue; 281 } 282 else if (c == '-') { 283 padLeft = 1; 284 continue; 285 } 286 else if (c == ' ' || c == '+') { 287 sign = c; 288 continue; 289 } 290 break; 291 } 292 293 /* parse field width */ 294 if ((c >= '0' && c <= '9')) { 295 nn --; 296 width = static_cast<int>(parse_decimal(format, &nn)); 297 c = format[nn++]; 298 } 299 300 /* parse precision */ 301 if (c == '.') { 302 prec = static_cast<int>(parse_decimal(format, &nn)); 303 c = format[nn++]; 304 } 305 306 /* length modifier */ 307 switch (c) { 308 case 'h': 309 bytelen = sizeof(short); 310 if (format[nn] == 'h') { 311 bytelen = sizeof(char); 312 nn += 1; 313 } 314 c = format[nn++]; 315 break; 316 case 'l': 317 bytelen = sizeof(long); 318 if (format[nn] == 'l') { 319 bytelen = sizeof(long long); 320 nn += 1; 321 } 322 c = format[nn++]; 323 break; 324 case 'z': 325 bytelen = sizeof(size_t); 326 c = format[nn++]; 327 break; 328 case 't': 329 bytelen = sizeof(ptrdiff_t); 330 c = format[nn++]; 331 break; 332 default: 333 ; 334 } 335 336 /* conversion specifier */ 337 const char* str = buffer; 338 if (c == 's') { 339 /* string */ 340 str = va_arg(args, const char*); 341 if (str == NULL) { 342 str = "(null)"; 343 } 344 } else if (c == 'c') { 345 /* character */ 346 /* NOTE: char is promoted to int when passed through the stack */ 347 buffer[0] = static_cast<char>(va_arg(args, int)); 348 buffer[1] = '\0'; 349 } else if (c == 'p') { 350 uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*)); 351 buffer[0] = '0'; 352 buffer[1] = 'x'; 353 format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); 354 } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { 355 /* integers - first read value from stack */ 356 uint64_t value; 357 int is_signed = (c == 'd' || c == 'i' || c == 'o'); 358 359 /* NOTE: int8_t and int16_t are promoted to int when passed 360 * through the stack 361 */ 362 switch (bytelen) { 363 case 1: value = static_cast<uint8_t>(va_arg(args, int)); break; 364 case 2: value = static_cast<uint16_t>(va_arg(args, int)); break; 365 case 4: value = va_arg(args, uint32_t); break; 366 case 8: value = va_arg(args, uint64_t); break; 367 default: return; /* should not happen */ 368 } 369 370 /* sign extension, if needed */ 371 if (is_signed) { 372 int shift = 64 - 8*bytelen; 373 value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift); 374 } 375 376 /* format the number properly into our buffer */ 377 format_integer(buffer, sizeof(buffer), value, c); 378 } else if (c == '%') { 379 buffer[0] = '%'; 380 buffer[1] = '\0'; 381 } else { 382 __assert(__FILE__, __LINE__, "conversion specifier unsupported"); 383 } 384 385 /* if we are here, 'str' points to the content that must be 386 * outputted. handle padding and alignment now */ 387 388 slen = strlen(str); 389 390 if (sign != '\0' || prec != -1) { 391 __assert(__FILE__, __LINE__, "sign/precision unsupported"); 392 } 393 394 if (slen < width && !padLeft) { 395 char padChar = padZero ? '0' : ' '; 396 SendRepeat(o, padChar, width - slen); 397 } 398 399 o.Send(str, slen); 400 401 if (slen < width && padLeft) { 402 char padChar = padZero ? '0' : ' '; 403 SendRepeat(o, padChar, width - slen); 404 } 405 } 406} 407 408int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) { 409 BufferOutputStream os(buffer, buffer_size); 410 va_list args; 411 va_start(args, format); 412 out_vformat(os, format, args); 413 va_end(args); 414 return os.total; 415} 416 417int __libc_format_fd(int fd, const char* format, ...) { 418 FdOutputStream os(fd); 419 va_list args; 420 va_start(args, format); 421 out_vformat(os, format, args); 422 va_end(args); 423 return os.total; 424} 425 426static int __libc_write_stderr(const char* tag, const char* msg) { 427 int fd = TEMP_FAILURE_RETRY(open("/dev/stderr", O_CLOEXEC | O_WRONLY)); 428 if (fd == -1) { 429 return -1; 430 } 431 432 iovec vec[4]; 433 vec[0].iov_base = const_cast<char*>(tag); 434 vec[0].iov_len = strlen(tag); 435 vec[1].iov_base = const_cast<char*>(": "); 436 vec[1].iov_len = 2; 437 vec[2].iov_base = const_cast<char*>(msg); 438 vec[2].iov_len = strlen(msg) + 1; 439 vec[3].iov_base = const_cast<char*>("\n"); 440 vec[3].iov_len = 1; 441 442 int result = TEMP_FAILURE_RETRY(writev(fd, vec, 4)); 443 close(fd); 444 return result; 445} 446 447#ifdef TARGET_USES_LOGD 448static int __libc_open_log_socket() 449{ 450 // ToDo: Ideally we want this to fail if the gid of the current 451 // process is AID_LOGD, but will have to wait until we have 452 // registered this in private/android_filesystem_config.h. We have 453 // found that all logd crashes thus far have had no problem stuffing 454 // the UNIX domain socket and moving on so not critical *today*. 455 456 int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)); 457 if (log_fd < 0) { 458 return -1; 459 } 460 461 if (fcntl(log_fd, F_SETFL, O_NONBLOCK) == -1) { 462 close(log_fd); 463 return -1; 464 } 465 466 union { 467 struct sockaddr addr; 468 struct sockaddr_un addrUn; 469 } u; 470 memset(&u, 0, sizeof(u)); 471 u.addrUn.sun_family = AF_UNIX; 472 strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path)); 473 474 if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) { 475 close(log_fd); 476 return -1; 477 } 478 479 return log_fd; 480} 481 482struct log_time { // Wire format 483 uint32_t tv_sec; 484 uint32_t tv_nsec; 485}; 486#endif 487 488static int __libc_write_log(int priority, const char* tag, const char* msg) { 489#ifdef TARGET_USES_LOGD 490 int main_log_fd = __libc_open_log_socket(); 491 492 if (main_log_fd == -1) { 493 // Try stderr instead. 494 return __libc_write_stderr(tag, msg); 495 } 496 497 iovec vec[6]; 498 char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN; 499 vec[0].iov_base = &log_id; 500 vec[0].iov_len = sizeof(log_id); 501 uint16_t tid = gettid(); 502 vec[1].iov_base = &tid; 503 vec[1].iov_len = sizeof(tid); 504 timespec ts; 505 clock_gettime(CLOCK_REALTIME, &ts); 506 log_time realtime_ts; 507 realtime_ts.tv_sec = ts.tv_sec; 508 realtime_ts.tv_nsec = ts.tv_nsec; 509 vec[2].iov_base = &realtime_ts; 510 vec[2].iov_len = sizeof(realtime_ts); 511 512 vec[3].iov_base = &priority; 513 vec[3].iov_len = 1; 514 vec[4].iov_base = const_cast<char*>(tag); 515 vec[4].iov_len = strlen(tag) + 1; 516 vec[5].iov_base = const_cast<char*>(msg); 517 vec[5].iov_len = strlen(msg) + 1; 518#else 519 int main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY)); 520 if (main_log_fd == -1) { 521 if (errno == ENOTDIR) { 522 // /dev/log isn't a directory? Maybe we're running on the host? Try stderr instead. 523 return __libc_write_stderr(tag, msg); 524 } 525 return -1; 526 } 527 528 iovec vec[3]; 529 vec[0].iov_base = &priority; 530 vec[0].iov_len = 1; 531 vec[1].iov_base = const_cast<char*>(tag); 532 vec[1].iov_len = strlen(tag) + 1; 533 vec[2].iov_base = const_cast<char*>(msg); 534 vec[2].iov_len = strlen(msg) + 1; 535#endif 536 537 int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); 538 close(main_log_fd); 539 return result; 540} 541 542int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) { 543 char buffer[1024]; 544 BufferOutputStream os(buffer, sizeof(buffer)); 545 out_vformat(os, format, args); 546 return __libc_write_log(priority, tag, buffer); 547} 548 549int __libc_format_log(int priority, const char* tag, const char* format, ...) { 550 va_list args; 551 va_start(args, format); 552 int result = __libc_format_log_va_list(priority, tag, format, args); 553 va_end(args); 554 return result; 555} 556 557static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) { 558#ifdef TARGET_USES_LOGD 559 iovec vec[6]; 560 char log_id = LOG_ID_EVENTS; 561 vec[0].iov_base = &log_id; 562 vec[0].iov_len = sizeof(log_id); 563 uint16_t tid = gettid(); 564 vec[1].iov_base = &tid; 565 vec[1].iov_len = sizeof(tid); 566 timespec ts; 567 clock_gettime(CLOCK_REALTIME, &ts); 568 log_time realtime_ts; 569 realtime_ts.tv_sec = ts.tv_sec; 570 realtime_ts.tv_nsec = ts.tv_nsec; 571 vec[2].iov_base = &realtime_ts; 572 vec[2].iov_len = sizeof(realtime_ts); 573 574 vec[3].iov_base = &tag; 575 vec[3].iov_len = sizeof(tag); 576 vec[4].iov_base = &type; 577 vec[4].iov_len = sizeof(type); 578 vec[5].iov_base = const_cast<void*>(payload); 579 vec[5].iov_len = len; 580 581 int event_log_fd = __libc_open_log_socket(); 582#else 583 iovec vec[3]; 584 vec[0].iov_base = &tag; 585 vec[0].iov_len = sizeof(tag); 586 vec[1].iov_base = &type; 587 vec[1].iov_len = sizeof(type); 588 vec[2].iov_base = const_cast<void*>(payload); 589 vec[2].iov_len = len; 590 591 int event_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/events", O_CLOEXEC | O_WRONLY)); 592#endif 593 594 if (event_log_fd == -1) { 595 return -1; 596 } 597 int result = TEMP_FAILURE_RETRY(writev(event_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); 598 close(event_log_fd); 599 return result; 600} 601 602void __libc_android_log_event_int(int32_t tag, int value) { 603 __libc_android_log_event(tag, EVENT_TYPE_INT, &value, sizeof(value)); 604} 605 606void __libc_android_log_event_uid(int32_t tag) { 607 __libc_android_log_event_int(tag, getuid()); 608} 609 610void __fortify_chk_fail(const char* msg, uint32_t tag) { 611 if (tag != 0) { 612 __libc_android_log_event_uid(tag); 613 } 614 __libc_fatal("FORTIFY_SOURCE: %s. Calling abort().", msg); 615} 616 617static void __libc_fatal(const char* format, va_list args) { 618 char msg[1024]; 619 BufferOutputStream os(msg, sizeof(msg)); 620 out_vformat(os, format, args); 621 622 // log to stderr for the benefit of "adb shell" users. 623 write(2, msg, strlen(msg)); 624 625 // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed). 626 __libc_write_log(ANDROID_LOG_FATAL, "libc", msg); 627 628 __android_set_abort_message(msg); 629} 630 631void __libc_fatal_no_abort(const char* format, ...) { 632 va_list args; 633 va_start(args, format); 634 __libc_fatal(format, args); 635 va_end(args); 636} 637 638void __libc_fatal(const char* format, ...) { 639 va_list args; 640 va_start(args, format); 641 __libc_fatal(format, args); 642 va_end(args); 643 abort(); 644} 645 646void __android_set_abort_message(const char* msg) { 647 ScopedPthreadMutexLocker locker(&g_abort_msg_lock); 648 649 if (__abort_message_ptr == NULL) { 650 // We must have crashed _very_ early. 651 return; 652 } 653 654 if (*__abort_message_ptr != NULL) { 655 // We already have an abort message. 656 // Assume that the first crash is the one most worth reporting. 657 return; 658 } 659 660 size_t size = sizeof(abort_msg_t) + strlen(msg) + 1; 661 void* map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 662 if (map == MAP_FAILED) { 663 return; 664 } 665 666 // TODO: if we stick to the current "one-shot" scheme, we can remove this code and 667 // stop storing the size. 668 if (*__abort_message_ptr != NULL) { 669 munmap(*__abort_message_ptr, (*__abort_message_ptr)->size); 670 } 671 abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map); 672 new_abort_message->size = size; 673 strcpy(new_abort_message->msg, msg); 674 *__abort_message_ptr = new_abort_message; 675} 676