15c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* 25c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Copyright (C) 2010 The Android Open Source Project 35c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * All rights reserved. 45c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 55c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Redistribution and use in source and binary forms, with or without 65c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * modification, are permitted provided that the following conditions 75c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * are met: 85c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * * Redistributions of source code must retain the above copyright 95c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * notice, this list of conditions and the following disclaimer. 105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * * Redistributions in binary form must reproduce the above copyright 115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * notice, this list of conditions and the following disclaimer in 125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the documentation and/or other materials provided with the 135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * distribution. 145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * SUCH DAMAGE. 275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 29eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "../private/libc_logging.h" // Relative path so we can #include this .cpp file for testing. 30eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "../private/ScopedPthreadMutexLocker.h" 31eababde2141c7128155200b213e45291cd876e46Elliott Hughes 32ce6b1abbb1da797e716d8ec03da4e3b6304fd11dDan Albert#include <android/set_abort_message.h> 3318a206c81d9743481e364384affd43306911283dElliott Hughes#include <assert.h> 34870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn#include <ctype.h> 35eababde2141c7128155200b213e45291cd876e46Elliott Hughes#include <errno.h> 360d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes#include <fcntl.h> 378f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#include <pthread.h> 385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stdarg.h> 39eababde2141c7128155200b213e45291cd876e46Elliott Hughes#include <stddef.h> 408f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#include <stdlib.h> 415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <string.h> 420d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes#include <sys/mman.h> 430336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <sys/socket.h> 440336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <sys/types.h> 450d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes#include <sys/uio.h> 460336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <sys/un.h> 470336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <time.h> 485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <unistd.h> 49eababde2141c7128155200b213e45291cd876e46Elliott Hughes 50870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 51870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn#include <sys/_system_properties.h> 52870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 531728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g_abort_msg_lock = PTHREAD_MUTEX_INITIALIZER; 545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 550d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common. 565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 570d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java. 580d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesenum AndroidEventLogType { 590d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes EVENT_TYPE_INT = 0, 600d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes EVENT_TYPE_LONG = 1, 610d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes EVENT_TYPE_STRING = 2, 620d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes EVENT_TYPE_LIST = 3, 6311331f60dd735613eee902b43a02b646ae873032Jeff Brown EVENT_TYPE_FLOAT = 4, 6418a206c81d9743481e364384affd43306911283dElliott Hughes}; 655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 660d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstruct BufferOutputStream { 670d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes public: 680d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes BufferOutputStream(char* buffer, size_t size) : total(0) { 690d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes buffer_ = buffer; 700d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes end_ = buffer + size - 1; 710d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes pos_ = buffer_; 720d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes pos_[0] = '\0'; 730d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 750d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes ~BufferOutputStream() { 760d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 770d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 780d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes void Send(const char* data, int len) { 7918a206c81d9743481e364384affd43306911283dElliott Hughes if (len < 0) { 800d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes len = strlen(data); 8118a206c81d9743481e364384affd43306911283dElliott Hughes } 825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 83416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes total += len; 84416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes 855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (len > 0) { 860d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int avail = end_ - pos_; 870d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (avail == 0) { 88416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes return; 890d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 900d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (avail > len) { 910d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes avail = len; 920d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 930d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes memcpy(pos_, data, avail); 940d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes pos_ += avail; 950d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes pos_[0] = '\0'; 960d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes len -= avail; 975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 980d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 100416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes size_t total; 1015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1020d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes private: 1030d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char* buffer_; 1040d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char* pos_; 1050d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char* end_; 1060d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes}; 1075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1080d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstruct FdOutputStream { 1090d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes public: 1100d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes FdOutputStream(int fd) : total(0), fd_(fd) { 1111e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1130d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes void Send(const char* data, int len) { 1140d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (len < 0) { 1150d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes len = strlen(data); 1160d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 1178f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 118416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes total += len; 119416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes 1200d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes while (len > 0) { 1210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int rc = TEMP_FAILURE_RETRY(write(fd_, data, len)); 1220d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (rc == -1) { 123416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes return; 1240d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 1250d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes data += rc; 1260d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes len -= rc; 1275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 1281e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 130416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes size_t total; 1315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1320d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes private: 1330d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int fd_; 1340d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes}; 1355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** formatted output implementation 1375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 1385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Parse a decimal string from 'format + *ppos', 1405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * return the value, and writes the new position past 1415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the decimal string in '*ppos' on exit. 1425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 1435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * NOTE: Does *not* handle a sign prefix. 1445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 1450d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstatic unsigned parse_decimal(const char *format, int *ppos) { 1465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner const char* p = format + *ppos; 1475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned result = 0; 1485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 1505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ch = *p; 1510336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn unsigned d = static_cast<unsigned>(ch - '0'); 1525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1530d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (d >= 10U) { 1545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 1550d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 1565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner result = result*10 + d; 1585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner p++; 1595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 1605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *ppos = p - format; 1615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 1625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 164eababde2141c7128155200b213e45291cd876e46Elliott Hughes// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes. 165eababde2141c7128155200b213e45291cd876e46Elliott Hughes// Assumes that buf_size > 0. 16641b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughesstatic void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) { 167eababde2141c7128155200b213e45291cd876e46Elliott Hughes char* p = buf; 168eababde2141c7128155200b213e45291cd876e46Elliott Hughes char* end = buf + buf_size - 1; 169eababde2141c7128155200b213e45291cd876e46Elliott Hughes 170eababde2141c7128155200b213e45291cd876e46Elliott Hughes // Generate digit string in reverse order. 171eababde2141c7128155200b213e45291cd876e46Elliott Hughes while (value) { 172eababde2141c7128155200b213e45291cd876e46Elliott Hughes unsigned d = value % base; 173eababde2141c7128155200b213e45291cd876e46Elliott Hughes value /= base; 174eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (p != end) { 175eababde2141c7128155200b213e45291cd876e46Elliott Hughes char ch; 176eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (d < 10) { 177eababde2141c7128155200b213e45291cd876e46Elliott Hughes ch = '0' + d; 178eababde2141c7128155200b213e45291cd876e46Elliott Hughes } else { 179eababde2141c7128155200b213e45291cd876e46Elliott Hughes ch = (caps ? 'A' : 'a') + (d - 10); 180eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 181eababde2141c7128155200b213e45291cd876e46Elliott Hughes *p++ = ch; 1825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 183eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 1845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 185eababde2141c7128155200b213e45291cd876e46Elliott Hughes // Special case for 0. 186eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (p == buf) { 187eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (p != end) { 188eababde2141c7128155200b213e45291cd876e46Elliott Hughes *p++ = '0'; 1895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 190eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 191eababde2141c7128155200b213e45291cd876e46Elliott Hughes *p = '\0'; 192eababde2141c7128155200b213e45291cd876e46Elliott Hughes 193eababde2141c7128155200b213e45291cd876e46Elliott Hughes // Reverse digit string in-place. 194eababde2141c7128155200b213e45291cd876e46Elliott Hughes size_t length = p - buf; 195eababde2141c7128155200b213e45291cd876e46Elliott Hughes for (size_t i = 0, j = length - 1; i < j; ++i, --j) { 196eababde2141c7128155200b213e45291cd876e46Elliott Hughes char ch = buf[i]; 197eababde2141c7128155200b213e45291cd876e46Elliott Hughes buf[i] = buf[j]; 198eababde2141c7128155200b213e45291cd876e46Elliott Hughes buf[j] = ch; 199eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 2005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 20241b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughesstatic void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) { 20341b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes // Decode the conversion specifier. 20441b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o'); 20541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes int base = 10; 20641b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes if (conversion == 'x' || conversion == 'X') { 20741b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes base = 16; 20841b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } else if (conversion == 'o') { 20941b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes base = 8; 21041b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } 21141b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes bool caps = (conversion == 'X'); 2125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 21341b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes if (is_signed && static_cast<int64_t>(value) < 0) { 21441b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buf[0] = '-'; 21541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buf += 1; 21641b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buf_size -= 1; 21741b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes value = static_cast<uint64_t>(-static_cast<int64_t>(value)); 21841b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } 21941b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes format_unsigned(buf, buf_size, value, base, caps); 2205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2220d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughestemplate <typename Out> 2230d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstatic void SendRepeat(Out& o, char ch, int count) { 2240d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char pad[8]; 2250d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes memset(pad, ch, sizeof(pad)); 2260d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 2270d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes const int pad_size = static_cast<int>(sizeof(pad)); 2280d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes while (count > 0) { 2290d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int avail = count; 2300d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (avail > pad_size) { 2310d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes avail = pad_size; 2320d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 2330d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes o.Send(pad, avail); 2340d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes count -= avail; 2350d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 2360d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 2370d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 2385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Perform formatted output to an output target 'o' */ 2390d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughestemplate <typename Out> 2400d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstatic void out_vformat(Out& o, const char* format, va_list args) { 241ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int nn = 0; 2425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 244ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int mm; 245ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int padZero = 0; 246ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int padLeft = 0; 247ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden char sign = '\0'; 248ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int width = -1; 249ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int prec = -1; 250ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden size_t bytelen = sizeof(int); 251ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int slen; 252ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden char buffer[32]; /* temporary buffer used to format numbers */ 253ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden 2545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char c; 2555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* first, find all characters that are not 0 or '%' */ 2575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* then send them to the output directly */ 2585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner mm = nn; 2595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner do { 2605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[mm]; 2615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0' || c == '%') 2625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 2635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner mm++; 2645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } while (1); 2655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (mm > nn) { 2670d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes o.Send(format+nn, mm-nn); 2685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn = mm; 2695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* is this it ? then exit */ 2725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0') 2735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 2745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* nope, we are at a '%' modifier */ 2765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn++; // skip it 2775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse flags */ 2795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 2805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 2815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0') { /* single trailing '%' ? */ 2825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = '%'; 2830d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes o.Send(&c, 1); 2845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return; 2855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == '0') { 2875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner padZero = 1; 2885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 2895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == '-') { 2915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner padLeft = 1; 2925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 2935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == ' ' || c == '+') { 2955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner sign = c; 2965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 2975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 2995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse field width */ 3025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if ((c >= '0' && c <= '9')) { 3035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn --; 3040336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn width = static_cast<int>(parse_decimal(format, &nn)); 3055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 3065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse precision */ 3095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '.') { 3100336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn prec = static_cast<int>(parse_decimal(format, &nn)); 3115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 3125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* length modifier */ 3155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (c) { 3165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'h': 3175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(short); 3185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (format[nn] == 'h') { 3195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(char); 3205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn += 1; 3215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 3235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 3245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'l': 3255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(long); 3265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (format[nn] == 'l') { 3275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(long long); 3285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn += 1; 3295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 3315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 3325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'z': 3335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(size_t); 3345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 3355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 3365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 't': 3375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(ptrdiff_t); 3385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 3395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 3405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: 3415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ; 3425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* conversion specifier */ 34541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes const char* str = buffer; 3465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == 's') { 3475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* string */ 3485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = va_arg(args, const char*); 349239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes if (str == NULL) { 350239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes str = "(null)"; 351239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes } 3525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else if (c == 'c') { 3535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* character */ 3545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* NOTE: char is promoted to int when passed through the stack */ 3550336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn buffer[0] = static_cast<char>(va_arg(args, int)); 3565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[1] = '\0'; 3575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else if (c == 'p') { 3580336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*)); 3595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '0'; 3605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[1] = 'x'; 36141b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); 362885f3b9cad01b8158aadc55c159c17dbf34f622cChristopher Ferris } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { 3635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* integers - first read value from stack */ 3645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner uint64_t value; 36541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes int is_signed = (c == 'd' || c == 'i' || c == 'o'); 3665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* NOTE: int8_t and int16_t are promoted to int when passed 3685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * through the stack 3695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 3705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (bytelen) { 3710336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn case 1: value = static_cast<uint8_t>(va_arg(args, int)); break; 3720336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn case 2: value = static_cast<uint16_t>(va_arg(args, int)); break; 3735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 4: value = va_arg(args, uint32_t); break; 3745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 8: value = va_arg(args, uint64_t); break; 3755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: return; /* should not happen */ 3765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* sign extension, if needed */ 37941b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes if (is_signed) { 3805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int shift = 64 - 8*bytelen; 3810336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift); 3825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* format the number properly into our buffer */ 38541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes format_integer(buffer, sizeof(buffer), value, c); 38641b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } else if (c == '%') { 38741b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buffer[0] = '%'; 38841b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buffer[1] = '\0'; 38941b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } else { 39041b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes __assert(__FILE__, __LINE__, "conversion specifier unsupported"); 3915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* if we are here, 'str' points to the content that must be 3945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * outputted. handle padding and alignment now */ 3955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner slen = strlen(str); 3975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 39818a206c81d9743481e364384affd43306911283dElliott Hughes if (sign != '\0' || prec != -1) { 39918a206c81d9743481e364384affd43306911283dElliott Hughes __assert(__FILE__, __LINE__, "sign/precision unsupported"); 40018a206c81d9743481e364384affd43306911283dElliott Hughes } 40118a206c81d9743481e364384affd43306911283dElliott Hughes 4025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (slen < width && !padLeft) { 4035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char padChar = padZero ? '0' : ' '; 4040d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes SendRepeat(o, padChar, width - slen); 4055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4070d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes o.Send(str, slen); 4085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (slen < width && padLeft) { 4105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char padChar = padZero ? '0' : ' '; 4110d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes SendRepeat(o, padChar, width - slen); 4125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4158f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 4160d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesint __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) { 4170d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes BufferOutputStream os(buffer, buffer_size); 4180d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_list args; 4190d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_start(args, format); 4200d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 4210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_end(args); 4220d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return os.total; 4230d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 4240d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 4250d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesint __libc_format_fd(int fd, const char* format, ...) { 4260d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes FdOutputStream os(fd); 4270d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_list args; 4280d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_start(args, format); 4290d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 4300d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_end(args); 4310d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return os.total; 4320d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 4330d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 4340f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughesstatic int __libc_write_stderr(const char* tag, const char* msg) { 43528e69f75088684b41d30b051799d7687d33f2205Yabin Cui int fd = TEMP_FAILURE_RETRY(open("/dev/stderr", O_CLOEXEC | O_WRONLY | O_APPEND)); 4360f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes if (fd == -1) { 4370f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes return -1; 4380f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes } 4390f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes 4400f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes iovec vec[4]; 4410f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[0].iov_base = const_cast<char*>(tag); 4420f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[0].iov_len = strlen(tag); 4430f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[1].iov_base = const_cast<char*>(": "); 4440f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[1].iov_len = 2; 4450f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[2].iov_base = const_cast<char*>(msg); 44642084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes vec[2].iov_len = strlen(msg); 4470f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[3].iov_base = const_cast<char*>("\n"); 4480f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[3].iov_len = 1; 4490f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes 4500f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes int result = TEMP_FAILURE_RETRY(writev(fd, vec, 4)); 4510f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes close(fd); 4520f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes return result; 4530f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes} 4540f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes 45542084a265329538a9e696e41971fb5d6abe3c14fElliott Hughesstatic int __libc_open_log_socket() { 4560336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // ToDo: Ideally we want this to fail if the gid of the current 4570336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // process is AID_LOGD, but will have to wait until we have 4580336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // registered this in private/android_filesystem_config.h. We have 4590336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // found that all logd crashes thus far have had no problem stuffing 4600336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // the UNIX domain socket and moving on so not critical *today*. 4610336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 462bae5b1dbd8dfe7318e208be917f4c9b9e8abced6Nick Kralevich int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)); 4630336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn if (log_fd < 0) { 4640336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return -1; 4650336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 4660336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4670336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn if (fcntl(log_fd, F_SETFL, O_NONBLOCK) == -1) { 4680336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn close(log_fd); 4690336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return -1; 4700336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 4710336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4720336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn union { 4730336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn struct sockaddr addr; 4740336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn struct sockaddr_un addrUn; 4750336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } u; 4760336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn memset(&u, 0, sizeof(u)); 4770336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn u.addrUn.sun_family = AF_UNIX; 4780336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path)); 4790336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4800336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) { 4810336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn close(log_fd); 4820336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return -1; 4830336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 4840336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4850336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return log_fd; 4860336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn} 4879fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn 488870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzynstruct cache { 489870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn const prop_info* pinfo; 490870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn uint32_t serial; 491870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn char c; 492870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn}; 493870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 494870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzynstatic void refresh_cache(struct cache *cache, const char *key) 495870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn{ 496870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (!cache->pinfo) { 497870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn cache->pinfo = __system_property_find(key); 498870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (!cache->pinfo) { 499870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn return; 500870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 501870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 502870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn uint32_t serial = __system_property_serial(cache->pinfo); 503870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (serial == cache->serial) { 504870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn return; 505870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 506870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn cache->serial = serial; 507870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 508870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn char buf[PROP_VALUE_MAX]; 509870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn __system_property_read(cache->pinfo, 0, buf); 510870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn cache->c = buf[0]; 511870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn} 512870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 513870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn// Timestamp state generally remains constant, since a change is 514870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn// rare, we can accept a trylock failure gracefully. 515870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzynstatic pthread_mutex_t lock_clockid = PTHREAD_MUTEX_INITIALIZER; 516870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 5179da687e2f49c2a67135bf30d074de445728e109dMark Salyzynstatic clockid_t __android_log_clockid() 518870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn{ 519870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn static struct cache r_time_cache = { NULL, static_cast<uint32_t>(-1), 0 }; 520870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn static struct cache p_time_cache = { NULL, static_cast<uint32_t>(-1), 0 }; 521870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn char c; 522870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 523870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (pthread_mutex_trylock(&lock_clockid)) { 524870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn // We are willing to accept some race in this context 525870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (!(c = p_time_cache.c)) { 526870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn c = r_time_cache.c; 527870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 528870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } else { 529870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn static uint32_t serial; 530870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn uint32_t current_serial = __system_property_area_serial(); 531870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (current_serial != serial) { 532870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn refresh_cache(&r_time_cache, "ro.logd.timestamp"); 533870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn refresh_cache(&p_time_cache, "persist.logd.timestamp"); 534870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn serial = current_serial; 535870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 536870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn if (!(c = p_time_cache.c)) { 537870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn c = r_time_cache.c; 538870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 539870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 540870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn pthread_mutex_unlock(&lock_clockid); 541870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn } 542870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 543870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME; 544870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn} 545870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn 5469fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzynstruct log_time { // Wire format 5479fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn uint32_t tv_sec; 5489fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn uint32_t tv_nsec; 5499fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn}; 5500336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 5516deb3042df87f8569fb430dbf5f140f6a694ddfdColin Crossint __libc_write_log(int priority, const char* tag, const char* msg) { 5520336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn int main_log_fd = __libc_open_log_socket(); 5530336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn if (main_log_fd == -1) { 5540336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // Try stderr instead. 5550336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return __libc_write_stderr(tag, msg); 5560336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 5570336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 5588664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn iovec vec[6]; 559011101905d91b770893e8a2fb6c09552d1c63652Elliott Hughes char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN; 5600336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn vec[0].iov_base = &log_id; 5610336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn vec[0].iov_len = sizeof(log_id); 5628664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn uint16_t tid = gettid(); 5638664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[1].iov_base = &tid; 5648664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[1].iov_len = sizeof(tid); 5659fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn timespec ts; 5669da687e2f49c2a67135bf30d074de445728e109dMark Salyzyn clock_gettime(__android_log_clockid(), &ts); 5679fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn log_time realtime_ts; 5689fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn realtime_ts.tv_sec = ts.tv_sec; 5699fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn realtime_ts.tv_nsec = ts.tv_nsec; 5708664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[2].iov_base = &realtime_ts; 5718664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[2].iov_len = sizeof(realtime_ts); 5728664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn 5738664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[3].iov_base = &priority; 5748664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[3].iov_len = 1; 5758664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[4].iov_base = const_cast<char*>(tag); 576aba6f712d46577c45a89fd0626dc251885d7989dElliott Hughes vec[4].iov_len = strlen(tag) + 1; 5778664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[5].iov_base = const_cast<char*>(msg); 578aba6f712d46577c45a89fd0626dc251885d7989dElliott Hughes vec[5].iov_len = strlen(msg) + 1; 5790d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5800336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); 58117fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich close(main_log_fd); 58217fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich return result; 5830d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 5840d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5850d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesint __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) { 5860d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char buffer[1024]; 5870d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes BufferOutputStream os(buffer, sizeof(buffer)); 5880d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 5890d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return __libc_write_log(priority, tag, buffer); 5900d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 5910d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5920d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesint __libc_format_log(int priority, const char* tag, const char* format, ...) { 5930d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_list args; 5940d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_start(args, format); 5950d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int result = __libc_format_log_va_list(priority, tag, format, args); 5960d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_end(args); 5970d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return result; 5980d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 5998f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 6008f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughesstatic int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) { 6018664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn iovec vec[6]; 6020336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn char log_id = LOG_ID_EVENTS; 6030336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn vec[0].iov_base = &log_id; 6040336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn vec[0].iov_len = sizeof(log_id); 6058664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn uint16_t tid = gettid(); 6068664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[1].iov_base = &tid; 6078664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[1].iov_len = sizeof(tid); 6089fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn timespec ts; 6099da687e2f49c2a67135bf30d074de445728e109dMark Salyzyn clock_gettime(__android_log_clockid(), &ts); 6109fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn log_time realtime_ts; 6119fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn realtime_ts.tv_sec = ts.tv_sec; 6129fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn realtime_ts.tv_nsec = ts.tv_nsec; 6138664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[2].iov_base = &realtime_ts; 6148664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[2].iov_len = sizeof(realtime_ts); 6158664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn 6168664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[3].iov_base = &tag; 6178664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[3].iov_len = sizeof(tag); 6188664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[4].iov_base = &type; 6198664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[4].iov_len = sizeof(type); 6208664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[5].iov_base = const_cast<void*>(payload); 6218664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[5].iov_len = len; 6220336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 6230336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn int event_log_fd = __libc_open_log_socket(); 6240336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 6258f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes if (event_log_fd == -1) { 62617fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich return -1; 6278f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes } 6280336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn int result = TEMP_FAILURE_RETRY(writev(event_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); 62917fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich close(event_log_fd); 63017fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich return result; 6318f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes} 6328f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 6338f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughesvoid __libc_android_log_event_int(int32_t tag, int value) { 6348f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes __libc_android_log_event(tag, EVENT_TYPE_INT, &value, sizeof(value)); 6358f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes} 6368f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 6378f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughesvoid __libc_android_log_event_uid(int32_t tag) { 6388f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes __libc_android_log_event_int(tag, getuid()); 6398f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes} 6408f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 641d1eda33f012e46083b91e087fb79d14a5ce70f0eElliott Hughesvoid __fortify_chk_fail(const char* msg, uint32_t tag) { 6428f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes if (tag != 0) { 6438f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes __libc_android_log_event_uid(tag); 6448f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes } 64542084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes __libc_fatal("FORTIFY: %s", msg); 6460d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 6470d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 648c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughesstatic void __libc_fatal(const char* format, va_list args) { 6490d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char msg[1024]; 6500d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes BufferOutputStream os(msg, sizeof(msg)); 6510d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 6520d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 65342084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes // Log to stderr for the benefit of "adb shell" users. 65497e31dedf056b07bcfcd46c49b60bf0798c60843Dan Albert struct iovec iov[2] = { 65542084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes { msg, os.total }, 65642084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes { const_cast<char*>("\n"), 1 }, 65797e31dedf056b07bcfcd46c49b60bf0798c60843Dan Albert }; 65842084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes TEMP_FAILURE_RETRY(writev(2, iov, 2)); 6590d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 6600d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed). 661c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes __libc_write_log(ANDROID_LOG_FATAL, "libc", msg); 6620d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 663ce6b1abbb1da797e716d8ec03da4e3b6304fd11dDan Albert android_set_abort_message(msg); 66461e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes} 66561e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes 66661e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughesvoid __libc_fatal_no_abort(const char* format, ...) { 66761e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes va_list args; 66861e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes va_start(args, format); 669c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes __libc_fatal(format, args); 67061e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes va_end(args); 67161e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes} 6720d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 67361e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughesvoid __libc_fatal(const char* format, ...) { 67461e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes va_list args; 67561e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes va_start(args, format); 676c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes __libc_fatal(format, args); 6772e3b7108b5b3d3f3a4a0fb369016e854bcf92212Elliott Hughes va_end(args); 6782e3b7108b5b3d3f3a4a0fb369016e854bcf92212Elliott Hughes abort(); 6792e3b7108b5b3d3f3a4a0fb369016e854bcf92212Elliott Hughes} 6802e3b7108b5b3d3f3a4a0fb369016e854bcf92212Elliott Hughes 681ce6b1abbb1da797e716d8ec03da4e3b6304fd11dDan Albertvoid android_set_abort_message(const char* msg) { 6821728b2396591853345507a063ed6075dfd251706Elliott Hughes ScopedPthreadMutexLocker locker(&g_abort_msg_lock); 683c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes 684c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes if (__abort_message_ptr == NULL) { 685c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes // We must have crashed _very_ early. 686c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes return; 687c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes } 688c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes 689c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes if (*__abort_message_ptr != NULL) { 690c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes // We already have an abort message. 691c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes // Assume that the first crash is the one most worth reporting. 692c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes return; 693c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes } 6940d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 6950d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes size_t size = sizeof(abort_msg_t) + strlen(msg) + 1; 6960d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes void* map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 6970d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (map == MAP_FAILED) { 6980d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return; 6990d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 7000d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 701c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes // TODO: if we stick to the current "one-shot" scheme, we can remove this code and 702c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes // stop storing the size. 703c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes if (*__abort_message_ptr != NULL) { 704c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes munmap(*__abort_message_ptr, (*__abort_message_ptr)->size); 7050d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 706c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map); 707c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes new_abort_message->size = size; 708c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes strcpy(new_abort_message->msg, msg); 709c78368f04faa4ee17f546985809e7550f3f88636Elliott Hughes *__abort_message_ptr = new_abort_message; 7100d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 711