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