summaryrefslogtreecommitdiffstats
path: root/libc
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2013-01-22 17:44:15 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2013-01-22 17:44:15 +0000
commitca483765bd0dc16294b9e67dd0de5c6d53b1bfa3 (patch)
treef3676bbac701bc026573ee833e8e9cb50478c445 /libc
parent5496bbf6a3592fd99cee6b8c20c8624c2aeea0c1 (diff)
parent1e980b6bc8315d00a07312b25486531247abd98c (diff)
downloadbionic-ca483765bd0dc16294b9e67dd0de5c6d53b1bfa3.zip
bionic-ca483765bd0dc16294b9e67dd0de5c6d53b1bfa3.tar.gz
bionic-ca483765bd0dc16294b9e67dd0de5c6d53b1bfa3.tar.bz2
Merge "Fix the duplication in the debugging code."
Diffstat (limited to 'libc')
-rw-r--r--libc/Android.mk7
-rw-r--r--libc/arch-arm/bionic/atexit_legacy.c5
-rw-r--r--libc/arch-mips/bionic/cacheflush.c6
-rw-r--r--libc/bionic/assert.cpp5
-rw-r--r--libc/bionic/debug_format.cpp634
-rw-r--r--libc/bionic/debug_mapinfo.cpp96
-rw-r--r--libc/bionic/debug_mapinfo.h (renamed from libc/bionic/malloc_debug_check_mapinfo.h)17
-rw-r--r--libc/bionic/debug_stacktrace.cpp112
-rw-r--r--libc/bionic/debug_stacktrace.h (renamed from libc/bionic/malloc_debug_stacktrace.cpp)51
-rw-r--r--libc/bionic/logd_write.c4
-rw-r--r--libc/bionic/malloc_debug_check.cpp94
-rw-r--r--libc/bionic/malloc_debug_check_mapinfo.cpp120
-rw-r--r--libc/bionic/malloc_debug_common.cpp18
-rw-r--r--libc/bionic/malloc_debug_common.h8
-rw-r--r--libc/bionic/malloc_debug_leak.cpp3
-rw-r--r--libc/bionic/malloc_debug_qemu.cpp24
-rw-r--r--libc/bionic/pthread.c3
-rw-r--r--libc/bionic/pthread_debug.cpp (renamed from libc/bionic/pthread_debug.c)262
-rw-r--r--libc/bionic/ssp.cpp4
-rw-r--r--libc/bionic/stubs.cpp3
-rw-r--r--libc/private/debug_format.h55
21 files changed, 1039 insertions, 492 deletions
diff --git a/libc/Android.mk b/libc/Android.mk
index c98d2ff..05373dc 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -272,6 +272,7 @@ libc_common_src_files := \
libc_bionic_src_files := \
bionic/assert.cpp \
+ bionic/debug_format.cpp \
bionic/dirent.cpp \
bionic/eventfd.cpp \
bionic/__fgets_chk.cpp \
@@ -881,7 +882,7 @@ LOCAL_SRC_FILES := \
$(libc_static_common_src_files) \
bionic/dlmalloc.c \
bionic/malloc_debug_common.cpp \
- bionic/pthread_debug.c \
+ bionic/pthread_debug.cpp \
bionic/libc_init_dynamic.c
ifeq ($(TARGET_ARCH),arm)
@@ -934,10 +935,10 @@ LOCAL_CFLAGS := \
LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_SRC_FILES := \
+ bionic/debug_mapinfo.cpp \
+ bionic/debug_stacktrace.cpp \
bionic/malloc_debug_leak.cpp \
bionic/malloc_debug_check.cpp \
- bionic/malloc_debug_check_mapinfo.cpp \
- bionic/malloc_debug_stacktrace.cpp
LOCAL_MODULE:= libc_malloc_debug_leak
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/libc/arch-arm/bionic/atexit_legacy.c b/libc/arch-arm/bionic/atexit_legacy.c
index 4abe839..6e299ac 100644
--- a/libc/arch-arm/bionic/atexit_legacy.c
+++ b/libc/arch-arm/bionic/atexit_legacy.c
@@ -50,10 +50,9 @@ atexit(void (*func)(void))
* calling library may have been dlclose()'d, causing the program to
* crash.
*/
- static char const warning[] =
- "WARNING: generic atexit() called from legacy shared library\n";
+ static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n";
- __libc_android_log_print(ANDROID_LOG_WARN, "libc", warning);
+ __libc_android_log_write(ANDROID_LOG_WARN, "libc", warning);
fprintf(stderr, warning);
return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
diff --git a/libc/arch-mips/bionic/cacheflush.c b/libc/arch-mips/bionic/cacheflush.c
index 05085b6..1911687 100644
--- a/libc/arch-mips/bionic/cacheflush.c
+++ b/libc/arch-mips/bionic/cacheflush.c
@@ -29,9 +29,9 @@
#include <sys/cachectl.h>
#ifdef DEBUG
-#include <logd.h>
-#define XLOG(...) \
- __libc_android_log_print(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
+#include <private/logd.h>
+#include <private/debug_format.h>
+#define XLOG(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
#endif
/*
diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp
index 7c0a860..e38c16d 100644
--- a/libc/bionic/assert.cpp
+++ b/libc/bionic/assert.cpp
@@ -32,6 +32,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <private/debug_format.h>
#include <private/logd.h>
// We log to stderr for the benefit of "adb shell" users, and the log for the benefit
@@ -39,7 +40,7 @@
void __assert(const char* file, int line, const char* failed_expression) {
const char* fmt = "%s:%d: assertion \"%s\" failed\n";
- __libc_android_log_print(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression);
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression);
fprintf(stderr, fmt, file, line, failed_expression);
abort();
/* NOTREACHED */
@@ -47,7 +48,7 @@ void __assert(const char* file, int line, const char* failed_expression) {
void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
const char* fmt = "%s:%d: %s: assertion \"%s\" failed\n";
- __libc_android_log_print(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression);
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression);
fprintf(stderr, fmt, file, line, function, failed_expression);
abort();
/* NOTREACHED */
diff --git a/libc/bionic/debug_format.cpp b/libc/bionic/debug_format.cpp
new file mode 100644
index 0000000..e8d6a45
--- /dev/null
+++ b/libc/bionic/debug_format.cpp
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Temporarily disable _FORTIFY_SOURCE to get this code to
+// compile under GCC 4.7
+#undef _FORTIFY_SOURCE
+
+#include "debug_format.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+/* define UNIT_TESTS to build this file as a single executable that runs
+ * the formatter's unit tests
+ */
+#define xxUNIT_TESTS
+
+/*** Generic output sink
+ ***/
+
+struct Out {
+ void *opaque;
+ void (*send)(void *opaque, const char *data, int len);
+};
+
+static void out_send(Out *o, const char *data, size_t len) {
+ o->send(o->opaque, data, (int)len);
+}
+
+static void
+out_send_repeat(Out *o, char ch, int count)
+{
+ char pad[8];
+ const int padSize = (int)sizeof(pad);
+
+ memset(pad, ch, sizeof(pad));
+ while (count > 0) {
+ int avail = count;
+ if (avail > padSize) {
+ avail = padSize;
+ }
+ o->send(o->opaque, pad, avail);
+ count -= avail;
+ }
+}
+
+/* forward declaration */
+static void out_vformat(Out* o, const char* format, va_list args);
+
+/*** Bounded buffer output
+ ***/
+
+struct BufOut {
+ Out out[1];
+ char *buffer;
+ char *pos;
+ char *end;
+ int total;
+};
+
+static void buf_out_send(void *opaque, const char *data, int len) {
+ BufOut *bo = reinterpret_cast<BufOut*>(opaque);
+
+ if (len < 0) {
+ len = strlen(data);
+ }
+
+ bo->total += len;
+
+ while (len > 0) {
+ int avail = bo->end - bo->pos;
+ if (avail == 0)
+ break;
+ if (avail > len)
+ avail = len;
+ memcpy(bo->pos, data, avail);
+ bo->pos += avail;
+ bo->pos[0] = '\0';
+ len -= avail;
+ }
+}
+
+static Out*
+buf_out_init(BufOut *bo, char *buffer, size_t size)
+{
+ if (size == 0)
+ return NULL;
+
+ bo->out->opaque = bo;
+ bo->out->send = buf_out_send;
+ bo->buffer = buffer;
+ bo->end = buffer + size - 1;
+ bo->pos = bo->buffer;
+ bo->pos[0] = '\0';
+ bo->total = 0;
+
+ return bo->out;
+}
+
+static int
+buf_out_length(BufOut *bo)
+{
+ return bo->total;
+}
+
+static int
+vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
+{
+ BufOut bo;
+ Out *out;
+
+ out = buf_out_init(&bo, buff, buffsize);
+ if (out == NULL)
+ return 0;
+
+ out_vformat(out, format, args);
+
+ return buf_out_length(&bo);
+}
+
+int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ int result = vformat_buffer(buffer, buffer_size, format, args);
+ va_end(args);
+ return result;
+}
+
+
+/*** File descriptor output
+ ***/
+
+struct FdOut {
+ Out out[1];
+ int fd;
+ int total;
+};
+
+static void
+fd_out_send(void *opaque, const char *data, int len)
+{
+ FdOut *fdo = reinterpret_cast<FdOut*>(opaque);
+
+ if (len < 0)
+ len = strlen(data);
+
+ while (len > 0) {
+ int ret = write(fdo->fd, data, len);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+ data += ret;
+ len -= ret;
+ fdo->total += ret;
+ }
+}
+
+static Out*
+fd_out_init(FdOut *fdo, int fd)
+{
+ fdo->out->opaque = fdo;
+ fdo->out->send = fd_out_send;
+ fdo->fd = fd;
+ fdo->total = 0;
+
+ return fdo->out;
+}
+
+static int
+fd_out_length(FdOut *fdo)
+{
+ return fdo->total;
+}
+
+
+int __libc_format_fd(int fd, const char* format, ...) {
+ FdOut fdo;
+ Out* out = fd_out_init(&fdo, fd);
+ if (out == NULL) {
+ return 0;
+ }
+
+ va_list args;
+ va_start(args, format);
+ out_vformat(out, format, args);
+ va_end(args);
+
+ return fd_out_length(&fdo);
+}
+
+/*** Log output
+ ***/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+
+int __libc_format_log_va_list(int priority, const char* tag, const char* fmt, va_list args) {
+ char buf[1024];
+ int result = vformat_buffer(buf, sizeof buf, fmt, args);
+
+ static int log_fd = -1;
+ if (log_fd == -1) {
+ log_fd = open("/dev/log/main", O_WRONLY);
+ if (log_fd == -1) {
+ return result;
+ }
+ }
+
+ struct iovec vec[3];
+ vec[0].iov_base = (unsigned char *) &priority;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void *) tag;
+ vec[1].iov_len = strlen(tag) + 1;
+ vec[2].iov_base = (void *) buf;
+ vec[2].iov_len = strlen(buf) + 1;
+
+ TEMP_FAILURE_RETRY(writev(log_fd, vec, 3));
+
+ return result;
+}
+
+int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ int result = __libc_format_log_va_list(priority, tag, format, args);
+ va_end(args);
+ return result;
+}
+
+/*** formatted output implementation
+ ***/
+
+/* Parse a decimal string from 'format + *ppos',
+ * return the value, and writes the new position past
+ * the decimal string in '*ppos' on exit.
+ *
+ * NOTE: Does *not* handle a sign prefix.
+ */
+static unsigned
+parse_decimal(const char *format, int *ppos)
+{
+ const char* p = format + *ppos;
+ unsigned result = 0;
+
+ for (;;) {
+ int ch = *p;
+ unsigned d = (unsigned)(ch - '0');
+
+ if (d >= 10U)
+ break;
+
+ result = result*10 + d;
+ p++;
+ }
+ *ppos = p - format;
+ return result;
+}
+
+// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
+// Assumes that buf_size > 0.
+static void format_number(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
+ char* p = buf;
+ char* end = buf + buf_size - 1;
+
+ // Generate digit string in reverse order.
+ while (value) {
+ unsigned d = value % base;
+ value /= base;
+ if (p != end) {
+ char ch;
+ if (d < 10) {
+ ch = '0' + d;
+ } else {
+ ch = (caps ? 'A' : 'a') + (d - 10);
+ }
+ *p++ = ch;
+ }
+ }
+
+ // Special case for 0.
+ if (p == buf) {
+ if (p != end) {
+ *p++ = '0';
+ }
+ }
+ *p = '\0';
+
+ // Reverse digit string in-place.
+ size_t length = p - buf;
+ for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
+ char ch = buf[i];
+ buf[i] = buf[j];
+ buf[j] = ch;
+ }
+}
+
+/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
+static void
+format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
+{
+ // TODO: this is incorrect for MIN_INT.
+ if (isSigned && (int64_t)value < 0) {
+ buffer[0] = '-';
+ buffer += 1;
+ buffsize -= 1;
+ value = (uint64_t)(-(int64_t)value);
+ }
+
+ format_number(buffer, buffsize, value, base, false);
+}
+
+// Assumes buf_size > 2.
+static void format_hex(char* buf, size_t buf_size, uint64_t value, bool caps) {
+ format_number(buf, buf_size, value, 16, caps);
+}
+
+
+/* Perform formatted output to an output target 'o' */
+static void
+out_vformat(Out *o, const char *format, va_list args)
+{
+ int nn = 0;
+
+ for (;;) {
+ int mm;
+ int padZero = 0;
+ int padLeft = 0;
+ char sign = '\0';
+ int width = -1;
+ int prec = -1;
+ size_t bytelen = sizeof(int);
+ const char* str;
+ int slen;
+ char buffer[32]; /* temporary buffer used to format numbers */
+
+ char c;
+
+ /* first, find all characters that are not 0 or '%' */
+ /* then send them to the output directly */
+ mm = nn;
+ do {
+ c = format[mm];
+ if (c == '\0' || c == '%')
+ break;
+ mm++;
+ } while (1);
+
+ if (mm > nn) {
+ out_send(o, format+nn, mm-nn);
+ nn = mm;
+ }
+
+ /* is this it ? then exit */
+ if (c == '\0')
+ break;
+
+ /* nope, we are at a '%' modifier */
+ nn++; // skip it
+
+ /* parse flags */
+ for (;;) {
+ c = format[nn++];
+ if (c == '\0') { /* single trailing '%' ? */
+ c = '%';
+ out_send(o, &c, 1);
+ return;
+ }
+ else if (c == '0') {
+ padZero = 1;
+ continue;
+ }
+ else if (c == '-') {
+ padLeft = 1;
+ continue;
+ }
+ else if (c == ' ' || c == '+') {
+ sign = c;
+ continue;
+ }
+ break;
+ }
+
+ /* parse field width */
+ if ((c >= '0' && c <= '9')) {
+ nn --;
+ width = (int)parse_decimal(format, &nn);
+ c = format[nn++];
+ }
+
+ /* parse precision */
+ if (c == '.') {
+ prec = (int)parse_decimal(format, &nn);
+ c = format[nn++];
+ }
+
+ /* length modifier */
+ switch (c) {
+ case 'h':
+ bytelen = sizeof(short);
+ if (format[nn] == 'h') {
+ bytelen = sizeof(char);
+ nn += 1;
+ }
+ c = format[nn++];
+ break;
+ case 'l':
+ bytelen = sizeof(long);
+ if (format[nn] == 'l') {
+ bytelen = sizeof(long long);
+ nn += 1;
+ }
+ c = format[nn++];
+ break;
+ case 'z':
+ bytelen = sizeof(size_t);
+ c = format[nn++];
+ break;
+ case 't':
+ bytelen = sizeof(ptrdiff_t);
+ c = format[nn++];
+ break;
+ default:
+ ;
+ }
+
+ /* conversion specifier */
+ if (c == 's') {
+ /* string */
+ str = va_arg(args, const char*);
+ } else if (c == 'c') {
+ /* character */
+ /* NOTE: char is promoted to int when passed through the stack */
+ buffer[0] = (char) va_arg(args, int);
+ buffer[1] = '\0';
+ str = buffer;
+ } else if (c == 'p') {
+ uint64_t value = (uintptr_t) va_arg(args, void*);
+ buffer[0] = '0';
+ buffer[1] = 'x';
+ format_hex(buffer + 2, sizeof buffer-2, value, false);
+ str = buffer;
+ } else {
+ /* integers - first read value from stack */
+ uint64_t value;
+ int isSigned = (c == 'd' || c == 'i' || c == 'o');
+
+ /* NOTE: int8_t and int16_t are promoted to int when passed
+ * through the stack
+ */
+ switch (bytelen) {
+ case 1: value = (uint8_t) va_arg(args, int); break;
+ case 2: value = (uint16_t) va_arg(args, int); break;
+ case 4: value = va_arg(args, uint32_t); break;
+ case 8: value = va_arg(args, uint64_t); break;
+ default: return; /* should not happen */
+ }
+
+ /* sign extension, if needed */
+ if (isSigned) {
+ int shift = 64 - 8*bytelen;
+ value = (uint64_t)(((int64_t)(value << shift)) >> shift);
+ }
+
+ /* format the number properly into our buffer */
+ switch (c) {
+ case 'i': case 'd':
+ format_integer(buffer, sizeof buffer, value, 10, isSigned);
+ break;
+ case 'o':
+ format_integer(buffer, sizeof buffer, value, 8, isSigned);
+ break;
+ case 'x': case 'X':
+ format_hex(buffer, sizeof buffer, value, (c == 'X'));
+ break;
+ default:
+ buffer[0] = '\0';
+ }
+ /* then point to it */
+ str = buffer;
+ }
+
+ /* if we are here, 'str' points to the content that must be
+ * outputted. handle padding and alignment now */
+
+ slen = strlen(str);
+
+ if (sign != '\0' || prec != -1) {
+ __assert(__FILE__, __LINE__, "sign/precision unsupported");
+ }
+
+ if (slen < width && !padLeft) {
+ char padChar = padZero ? '0' : ' ';
+ out_send_repeat(o, padChar, width - slen);
+ }
+
+ out_send(o, str, slen);
+
+ if (slen < width && padLeft) {
+ char padChar = padZero ? '0' : ' ';
+ out_send_repeat(o, padChar, width - slen);
+ }
+ }
+}
+
+
+#ifdef UNIT_TESTS
+
+#include <stdio.h>
+
+static int gFails = 0;
+
+#define MARGIN 40
+
+#define UTEST_CHECK(condition,message) \
+ printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
+ if (!(condition)) { \
+ printf("KO\n"); \
+ gFails += 1; \
+ } else { \
+ printf("ok\n"); \
+ }
+
+static void
+utest_BufOut(void)
+{
+ char buffer[16];
+ BufOut bo[1];
+ Out* out;
+ int ret;
+
+ buffer[0] = '1';
+ out = buf_out_init(bo, buffer, sizeof buffer);
+ UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
+ out_send(out, "abc", 3);
+ UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
+ out_send_repeat(out, 'X', 4);
+ UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
+ buffer[sizeof buffer-1] = 'x';
+ out_send_repeat(out, 'Y', 2*sizeof(buffer));
+ UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
+
+ out = buf_out_init(bo, buffer, sizeof buffer);
+ out_send_repeat(out, 'X', 2*sizeof(buffer));
+ ret = buf_out_length(bo);
+ UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
+}
+
+static void
+utest_expect(const char* result, const char* format, ...)
+{
+ va_list args;
+ BufOut bo[1];
+ char buffer[256];
+ Out* out = buf_out_init(bo, buffer, sizeof buffer);
+
+ printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
+ va_start(args, format);
+ out_vformat(out, format, args);
+ va_end(args);
+
+ if (strcmp(result, buffer)) {
+ printf("KO. got '%s' expecting '%s'\n", buffer, result);
+ gFails += 1;
+ } else {
+ printf("ok. got '%s'\n", result);
+ }
+}
+
+int main(void)
+{
+ utest_BufOut();
+ utest_expect("", "");
+ utest_expect("a", "a");
+ utest_expect("01234", "01234", "");
+ utest_expect("01234", "%s", "01234");
+ utest_expect("aabbcc", "aa%scc", "bb");
+ utest_expect("a", "%c", 'a');
+ utest_expect("1234", "%d", 1234);
+ utest_expect("-8123", "%d", -8123);
+ utest_expect("16", "%hd", 0x7fff0010);
+ utest_expect("16", "%hhd", 0x7fffff10);
+ utest_expect("68719476736", "%lld", 0x1000000000LL);
+ utest_expect("70000", "%ld", 70000);
+ utest_expect("0xb0001234", "%p", (void*)0xb0001234);
+ utest_expect("12ab", "%x", 0x12ab);
+ utest_expect("12AB", "%X", 0x12ab);
+ utest_expect("00123456", "%08x", 0x123456);
+ utest_expect("01234", "0%d", 1234);
+ utest_expect(" 1234", "%5d", 1234);
+ utest_expect("01234", "%05d", 1234);
+ utest_expect(" 1234", "%8d", 1234);
+ utest_expect("1234 ", "%-8d", 1234);
+ utest_expect("abcdef ", "%-11s", "abcdef");
+ utest_expect("something:1234", "%s:%d", "something", 1234);
+ utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
+ utest_expect("5,0x0", "%d,%p", 5, NULL);
+ utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
+ return gFails != 0;
+}
+
+#endif /* UNIT_TESTS */
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
new file mode 100644
index 0000000..174cc28
--- /dev/null
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dlmalloc.h"
+#include "debug_mapinfo.h"
+
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+
+static mapinfo_t* parse_maps_line(char* line) {
+ int len = strlen(line);
+
+ if (len < 1) return 0;
+ line[--len] = 0;
+
+ if (len < 50) return 0;
+ if (line[20] != 'x') return 0;
+
+ mapinfo_t* mi = static_cast<mapinfo_t*>(dlmalloc(sizeof(mapinfo_t) + (len - 47)));
+ if (mi == 0) return 0;
+
+ mi->start = strtoul(line, 0, 16);
+ mi->end = strtoul(line + 9, 0, 16);
+ mi->next = 0;
+ strcpy(mi->name, line + 49);
+
+ return mi;
+}
+
+__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid) {
+ struct mapinfo_t* milist = NULL;
+ char data[1024]; // Used to read lines as well as to construct the filename.
+ snprintf(data, sizeof(data), "/proc/%d/maps", pid);
+ FILE* fp = fopen(data, "r");
+ if (fp != NULL) {
+ while (fgets(data, sizeof(data), fp) != NULL) {
+ mapinfo_t* mi = parse_maps_line(data);
+ if (mi) {
+ mi->next = milist;
+ milist = mi;
+ }
+ }
+ fclose(fp);
+ }
+ return milist;
+}
+
+__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
+ while (mi) {
+ mapinfo_t* del = mi;
+ mi = mi->next;
+ dlfree(del);
+ }
+}
+
+// Find the containing map info for the PC.
+__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc) {
+ *rel_pc = pc;
+ for (; mi != NULL; mi = mi->next) {
+ if ((pc >= mi->start) && (pc < mi->end)) {
+ *rel_pc -= mi->start;
+ return mi;
+ }
+ }
+ return NULL;
+}
diff --git a/libc/bionic/malloc_debug_check_mapinfo.h b/libc/bionic/debug_mapinfo.h
index e19f71e..6df55c5 100644
--- a/libc/bionic/malloc_debug_check_mapinfo.h
+++ b/libc/bionic/debug_mapinfo.h
@@ -26,21 +26,20 @@
* SUCH DAMAGE.
*/
-#ifndef MALLOC_DEBUG_CHECK_MAPINFO_H
-#define MALLOC_DEBUG_CHECK_MAPINFO_H
+#ifndef DEBUG_MAPINFO_H
+#define DEBUG_MAPINFO_H
#include <sys/cdefs.h>
-struct mapinfo {
- struct mapinfo* next;
+struct mapinfo_t {
+ struct mapinfo_t* next;
unsigned start;
unsigned end;
char name[];
};
-__LIBC_HIDDEN__ mapinfo *init_mapinfo(int pid);
-__LIBC_HIDDEN__ void deinit_mapinfo(mapinfo *mi);
-__LIBC_HIDDEN__ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
-__LIBC_HIDDEN__ const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc);
+__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid);
+__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi);
+__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc);
-#endif /*MALLOC_DEBUG_CHECK_MAPINFO_H*/
+#endif /* DEBUG_MAPINFO_H */
diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp
new file mode 100644
index 0000000..4b080a4
--- /dev/null
+++ b/libc/bionic/debug_stacktrace.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "debug_stacktrace.h"
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <unwind.h>
+#include <sys/types.h>
+
+#include "debug_format.h"
+#include "debug_mapinfo.h"
+#include "logd.h"
+
+/* depends how the system includes define this */
+#ifdef HAVE_UNWIND_CONTEXT_STRUCT
+typedef struct _Unwind_Context __unwind_context;
+#else
+typedef _Unwind_Context __unwind_context;
+#endif
+
+static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) {
+ stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg);
+ if (state->count) {
+ intptr_t ip = (intptr_t)_Unwind_GetIP(context);
+ if (ip) {
+ state->addrs[0] = ip;
+ state->addrs++;
+ state->count--;
+ return _URC_NO_REASON;
+ }
+ }
+ // If we run out of space to record the address or 0 has been seen, stop
+ // unwinding the stack.
+ return _URC_END_OF_STACK;
+}
+
+__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) {
+ stack_crawl_state_t state;
+ state.count = max_entries;
+ state.addrs = addrs;
+ _Unwind_Backtrace(trace_function, &state);
+ return max_entries - state.count;
+}
+
+__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* addrs, size_t c) {
+ intptr_t self_bt[16];
+ if (addrs == NULL) {
+ c = get_backtrace(self_bt, 16);
+ addrs = self_bt;
+ }
+
+ __libc_format_log(ANDROID_LOG_ERROR, "libc",
+ "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+
+ int index = 0;
+ for (size_t i = 0 ; i < c; ++i) {
+ void* offset = 0;
+ const char* symbol = NULL;
+
+ Dl_info info;
+ if (dladdr((void*) addrs[i], &info) != 0) {
+ offset = info.dli_saddr;
+ symbol = info.dli_sname;
+ }
+
+ // This test is a bit sketchy, but it allows us to skip the
+ // stack trace entries due to this debugging code. it works
+ // because those don't have a symbol (they're not exported).
+ if (symbol != NULL || index > 0) {
+ unsigned int rel_pc;
+ const mapinfo_t* mi = mapinfo_find(map_info, addrs[i], &rel_pc);
+ const char* soname = mi ? mi->name : info.dli_fname;
+ if (soname == NULL) {
+ soname = "unknown";
+ }
+ if (symbol) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", " #%02d pc %08x %s (%s+0x%x)",
+ index, rel_pc, soname, symbol, addrs[i] - (intptr_t)offset);
+ } else {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", " #%02d pc %08x %s",
+ index, rel_pc, soname);
+ }
+ ++index;
+ }
+ }
+}
diff --git a/libc/bionic/malloc_debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.h
index 32b8ac0..3c66ea6 100644
--- a/libc/bionic/malloc_debug_stacktrace.cpp
+++ b/libc/bionic/debug_stacktrace.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,48 +25,21 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <unwind.h>
-#include <sys/types.h>
-// =============================================================================
-// stack trace functions
-// =============================================================================
+#ifndef DEBUG_STACKTRACE_H
+#define DEBUG_STACKTRACE_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
struct stack_crawl_state_t {
- size_t count;
- intptr_t* addrs;
+ size_t count;
+ intptr_t* addrs;
};
+struct mapinfo_t;
-/* depends how the system includes define this */
-#ifdef HAVE_UNWIND_CONTEXT_STRUCT
-typedef struct _Unwind_Context __unwind_context;
-#else
-typedef _Unwind_Context __unwind_context;
-#endif
-
-static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) {
- stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg);
- if (state->count) {
- intptr_t ip = (intptr_t)_Unwind_GetIP(context);
- if (ip) {
- state->addrs[0] = ip;
- state->addrs++;
- state->count--;
- return _URC_NO_REASON;
- }
- }
- /*
- * If we run out of space to record the address or 0 has been seen, stop
- * unwinding the stack.
- */
- return _URC_END_OF_STACK;
-}
+__LIBC_HIDDEN__ int get_backtrace(intptr_t* stack_frames, size_t max_entries);
+__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* stack_frames, size_t frame_count);
-__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) {
- stack_crawl_state_t state;
- state.count = max_entries;
- state.addrs = addrs;
- _Unwind_Backtrace(trace_function, &state);
- return max_entries - state.count;
-}
+#endif /* DEBUG_STACKTRACE_H */
diff --git a/libc/bionic/logd_write.c b/libc/bionic/logd_write.c
index 71a6f8e..11c0e68 100644
--- a/libc/bionic/logd_write.c
+++ b/libc/bionic/logd_write.c
@@ -250,9 +250,7 @@ void __libc_android_log_event_uid(int32_t tag)
__LIBC_HIDDEN__
void __fortify_chk_fail(const char *msg, uint32_t tag) {
- __libc_android_log_print(ANDROID_LOG_FATAL, "libc",
- "FORTIFY_SOURCE: %s. Calling abort().\n",
- msg);
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "FORTIFY_SOURCE: %s. Calling abort().\n", msg);
if (tag != 0) {
__libc_android_log_event_uid(tag);
}
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 5ad3486..60ee0cc 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -45,18 +45,19 @@
#include <unistd.h>
#include <unwind.h>
+#include "debug_mapinfo.h"
+#include "debug_stacktrace.h"
#include "dlmalloc.h"
#include "logd.h"
-#include "malloc_debug_check_mapinfo.h"
#include "malloc_debug_common.h"
#include "ScopedPthreadMutexLocker.h"
-static mapinfo *milist;
+static mapinfo_t* gMapInfo;
/* libc.debug.malloc.backlog */
extern unsigned int malloc_double_free_backlog;
-#define MAX_BACKTRACE_DEPTH 15
+#define MAX_BACKTRACE_DEPTH 16
#define ALLOCATION_TAG 0x1ee7d00d
#define BACKLOG_TAG 0xbabecafe
#define FREE_POISON 0xa5
@@ -67,20 +68,10 @@ extern unsigned int malloc_double_free_backlog;
#define REAR_GUARD_LEN (1<<5)
static void log_message(const char* format, ...) {
- extern const MallocDebug __libc_malloc_default_dispatch;
- extern const MallocDebug* __libc_malloc_dispatch;
- extern pthread_mutex_t gAllocationsMutex;
-
- va_list args;
- {
- ScopedPthreadMutexLocker locker(&gAllocationsMutex);
- const MallocDebug* current_dispatch = __libc_malloc_dispatch;
- __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
- va_start(args, format);
- __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc", format, args);
- va_end(args);
- __libc_malloc_dispatch = current_dispatch;
- }
+ va_list args;
+ va_start(args, format);
+ __libc_format_log_va_list(ANDROID_LOG_ERROR, "libc", format, args);
+ va_end(args);
}
struct hdr_t {
@@ -121,28 +112,6 @@ static hdr_t *backlog_tail;
static hdr_t *backlog_head;
static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER;
-extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries);
-
-static void print_backtrace(const intptr_t *bt, unsigned int depth) {
- const mapinfo *mi;
- unsigned int cnt;
- unsigned int rel_pc;
- intptr_t self_bt[MAX_BACKTRACE_DEPTH];
-
- if (!bt) {
- depth = get_backtrace(self_bt, MAX_BACKTRACE_DEPTH);
- bt = self_bt;
- }
-
- log_message("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
- for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) {
- mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc);
- log_message("\t#%02d pc %08x %s\n", cnt,
- mi ? (intptr_t)rel_pc : bt[cnt],
- mi ? mi->name : "(unknown)");
- }
-}
-
static inline void init_front_guard(hdr_t *hdr) {
memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN);
}
@@ -292,11 +261,11 @@ static inline int check_allocation_locked(hdr_t *hdr, int *safe) {
if (!valid && *safe) {
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(hdr->bt, hdr->bt_depth);
+ log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
if (hdr->tag == BACKLOG_TAG) {
log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+ log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth);
}
}
@@ -381,18 +350,18 @@ extern "C" void chk_free(void *ptr) {
user(hdr), hdr->size);
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(hdr->bt, hdr->bt_depth);
+ log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
/* hdr->freed_bt_depth should be nonzero here */
log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+ log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth);
log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(bt, depth);
+ log_backtrace(gMapInfo, bt, depth);
} else {
log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
user(hdr));
- print_backtrace(bt, depth);
+ log_backtrace(gMapInfo, bt, depth);
/* Leak here so that we do not crash */
//dlfree(user(hdr));
}
@@ -428,14 +397,14 @@ extern "C" void *chk_realloc(void *ptr, size_t size) {
user(hdr), size, hdr->size);
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(hdr->bt, hdr->bt_depth);
+ log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
/* hdr->freed_bt_depth should be nonzero here */
log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+ log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth);
log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n",
user(hdr), hdr->size);
- print_backtrace(bt, depth);
+ log_backtrace(gMapInfo, bt, depth);
/* We take the memory out of the backlog and fall through so the
* reallocation below succeeds. Since we didn't really free it, we
@@ -445,7 +414,7 @@ extern "C" void *chk_realloc(void *ptr, size_t size) {
} else {
log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
user(hdr), size);
- print_backtrace(bt, depth);
+ log_backtrace(gMapInfo, bt, depth);
// just get a whole new allocation and leak the old one
return dlrealloc(0, size);
// return dlrealloc(user(hdr), size); // assuming it was allocated externally
@@ -467,8 +436,7 @@ extern "C" void *chk_calloc(int nmemb, size_t size) {
size_t total_size = nmemb * size;
hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
if (hdr) {
- hdr->bt_depth = get_backtrace(
- hdr->bt, MAX_BACKTRACE_DEPTH);
+ hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
add(hdr, total_size);
return user(hdr);
}
@@ -476,21 +444,20 @@ extern "C" void *chk_calloc(int nmemb, size_t size) {
}
static void heaptracker_free_leaked_memory() {
+ size_t total = num;
if (num) {
- log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num);
+ log_message("+++ Leaked allocations: %d\n", num);
}
hdr_t *del = NULL;
while (head) {
int safe;
del = head;
- log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n",
- del->size, user(del), num);
+ log_message("+++ Leaked block of size %d at %p (leak %d of %d)\n",
+ del->size, user(del), 1 + total - num, total);
if (del_leak(del, &safe)) {
/* safe == 1, because the allocation is valid */
- log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
- user(del), del->size);
- print_backtrace(del->bt, del->bt_depth);
+ log_backtrace(gMapInfo, del->bt, del->bt_depth);
}
dlfree(del);
}
@@ -507,13 +474,14 @@ static void heaptracker_free_leaked_memory() {
* See comments on MallocDebugInit in malloc_debug_common.h
*/
extern "C" int malloc_debug_initialize() {
- if (!malloc_double_free_backlog)
- malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
- milist = init_mapinfo(getpid());
- return 0;
+ if (!malloc_double_free_backlog) {
+ malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
+ }
+ gMapInfo = mapinfo_create(getpid());
+ return 0;
}
extern "C" void malloc_debug_finalize() {
- heaptracker_free_leaked_memory();
- deinit_mapinfo(milist);
+ heaptracker_free_leaked_memory();
+ mapinfo_destroy(gMapInfo);
}
diff --git a/libc/bionic/malloc_debug_check_mapinfo.cpp b/libc/bionic/malloc_debug_check_mapinfo.cpp
deleted file mode 100644
index 8cc2c99..0000000
--- a/libc/bionic/malloc_debug_check_mapinfo.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "dlmalloc.h"
-#include "malloc_debug_check_mapinfo.h"
-
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
-// 012345678901234567890123456789012345678901234567890123456789
-// 0 1 2 3 4 5
-
-static mapinfo* parse_maps_line(char* line) {
- int len = strlen(line);
-
- if (len < 1) return 0;
- line[--len] = 0;
-
- if (len < 50) return 0;
- if (line[20] != 'x') return 0;
-
- mapinfo* mi = static_cast<mapinfo*>(dlmalloc(sizeof(mapinfo) + (len - 47)));
- if (mi == 0) return 0;
-
- mi->start = strtoul(line, 0, 16);
- mi->end = strtoul(line + 9, 0, 16);
- /* To be filled in parse_elf_info if the mapped section starts with
- * elf_header
- */
- mi->next = 0;
- strcpy(mi->name, line + 49);
-
- return mi;
-}
-
-__LIBC_HIDDEN__
-mapinfo *init_mapinfo(int pid) {
- struct mapinfo *milist = NULL;
- char data[1024]; // Used to read lines as well as to construct the filename.
- snprintf(data, sizeof(data), "/proc/%d/maps", pid);
- FILE *fp = fopen(data, "r");
- if (fp) {
- while (fgets(data, sizeof(data), fp)) {
- mapinfo *mi = parse_maps_line(data);
- if (mi) {
- mi->next = milist;
- milist = mi;
- }
- }
- fclose(fp);
- }
-
- return milist;
-}
-
-__LIBC_HIDDEN__
-void deinit_mapinfo(mapinfo *mi) {
- mapinfo *del;
- while (mi) {
- del = mi;
- mi = mi->next;
- dlfree(del);
- }
-}
-
-/* Map a pc address to the name of the containing ELF file */
-__LIBC_HIDDEN__
-const char *map_to_name(mapinfo *mi, unsigned pc, const char* def) {
- while (mi) {
- if ((pc >= mi->start) && (pc < mi->end)) {
- return mi->name;
- }
- mi = mi->next;
- }
- return def;
-}
-
-/* Find the containing map info for the pc */
-__LIBC_HIDDEN__
-const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc) {
- *rel_pc = pc;
- while (mi) {
- if ((pc >= mi->start) && (pc < mi->end)) {
- // Only calculate the relative offset for shared libraries
- if (strstr(mi->name, ".so")) {
- *rel_pc -= mi->start;
- }
- return mi;
- }
- mi = mi->next;
- }
- return NULL;
-}
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index 624a40e..bba0472 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -294,8 +294,8 @@ static void* libc_malloc_impl_handle = NULL;
unsigned int malloc_double_free_backlog;
static void InitMalloc(MallocDebug* table, int debug_level, const char* prefix) {
- __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
- __progname, debug_level, prefix);
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
+ __progname, debug_level, prefix);
char symbol[128];
@@ -429,7 +429,7 @@ static void malloc_init_impl() {
dlclose(libc_malloc_impl_handle);
return;
}
- if (malloc_debug_initialize()) {
+ if (malloc_debug_initialize() == -1) {
dlclose(libc_malloc_impl_handle);
return;
}
@@ -487,11 +487,19 @@ static void malloc_init_impl() {
}
static void malloc_fini_impl() {
- if (libc_malloc_impl_handle) {
+ // Our BSD stdio implementation doesn't close the standard streams, it only flushes them.
+ // And it doesn't do that until its atexit handler (_cleanup) is run, and we run first!
+ // It's great that other unclosed FILE*s show up as malloc leaks, but we need to manually
+ // clean up the standard streams ourselves.
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+
+ if (libc_malloc_impl_handle != NULL) {
MallocDebugFini malloc_debug_finalize =
reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
"malloc_debug_finalize"));
- if (malloc_debug_finalize) {
+ if (malloc_debug_finalize != NULL) {
malloc_debug_finalize();
}
}
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
index 78ad5e5..3d12f87 100644
--- a/libc/bionic/malloc_debug_common.h
+++ b/libc/bionic/malloc_debug_common.h
@@ -35,6 +35,8 @@
#include <stdlib.h>
+#include <private/debug_format.h>
+
#define HASHTABLE_SIZE 1543
#define BACKTRACE_SIZE 32
/* flag definitions, currently sharing storage with "size" */
@@ -97,10 +99,10 @@ typedef void (*MallocDebugFini)();
// =============================================================================
#define debug_log(format, ...) \
- __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ )
#define error_log(format, ...) \
- __libc_android_log_print(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ )
#define info_log(format, ...) \
- __libc_android_log_print(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ )
#endif // MALLOC_DEBUG_COMMON_H
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 090a981..68b6ae2 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -45,6 +45,7 @@
#include <unistd.h>
#include <unwind.h>
+#include "debug_stacktrace.h"
#include "dlmalloc.h"
#include "logd.h"
#include "malloc_debug_common.h"
@@ -255,8 +256,6 @@ extern "C" void* fill_memalign(size_t alignment, size_t bytes) {
static void* MEMALIGN_GUARD = reinterpret_cast<void*>(0xA1A41520);
-extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries);
-
extern "C" void* leak_malloc(size_t bytes) {
// allocate enough space infront of the allocation to store the pointer for
// the alloc structure. This will making free'ing the structer really fast!
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index e586b1b..812a451 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -257,8 +257,8 @@ static void dump_malloc_descriptor(char* str,
INFO_TRACING_ENABLED)
/* Prints a string to the emulator's stdout.
- * In early stages of system loading, logging mesages via
- * __libc_android_log_print API is not available, because ADB API has not been
+ * In early stages of system loading, logging messages to logcat
+ * is not available, because ADB API has not been
* hooked up yet. So, in order to see such messages we need to print them to
* the emulator's stdout.
* Parameters passed to this macro are the same as parameters for printf
@@ -289,8 +289,7 @@ static void dump_malloc_descriptor(char* str,
*/
#define qemu_debug_log(format, ...) \
do { \
- __libc_android_log_print(ANDROID_LOG_DEBUG, "memcheck", \
- (format), ##__VA_ARGS__); \
+ __libc_format_log(ANDROID_LOG_DEBUG, "memcheck", (format), ##__VA_ARGS__); \
if (tracing_flags & DEBUG_TRACING_ENABLED) { \
qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__); \
} \
@@ -298,8 +297,7 @@ static void dump_malloc_descriptor(char* str,
#define qemu_error_log(format, ...) \
do { \
- __libc_android_log_print(ANDROID_LOG_ERROR, "memcheck", \
- (format), ##__VA_ARGS__); \
+ __libc_format_log(ANDROID_LOG_ERROR, "memcheck", (format), ##__VA_ARGS__); \
if (tracing_flags & ERROR_TRACING_ENABLED) { \
qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__); \
} \
@@ -307,8 +305,7 @@ static void dump_malloc_descriptor(char* str,
#define qemu_info_log(format, ...) \
do { \
- __libc_android_log_print(ANDROID_LOG_INFO, "memcheck", \
- (format), ##__VA_ARGS__); \
+ __libc_format_log(ANDROID_LOG_INFO, "memcheck", (format), ##__VA_ARGS__); \
if (tracing_flags & INFO_TRACING_ENABLED) { \
qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__); \
} \
@@ -318,20 +315,19 @@ static void dump_malloc_descriptor(char* str,
* Param:
* type - Message type: debug, error, or info
* desc - MallocDesc instance to dump.
- * frmt + rest - Formats message preceding dumped descriptor.
+ * fmt + rest - Formats message preceding dumped descriptor.
*/
-#define log_mdesc(type, desc, frmt, ...) \
+#define log_mdesc(type, desc, fmt, ...) \
do { \
if (tracing_enabled(type)) { \
char log_str[4096]; \
- size_t str_len; \
- snprintf(log_str, sizeof(log_str), frmt, ##__VA_ARGS__); \
+ __libc_format_buffer(log_str, sizeof(log_str), fmt, ##__VA_ARGS__); \
log_str[sizeof(log_str) - 1] = '\0'; \
- str_len = strlen(log_str); \
+ size_t str_len = strlen(log_str); \
dump_malloc_descriptor(log_str + str_len, \
sizeof(log_str) - str_len, \
(desc)); \
- type##_log(log_str); \
+ type##_log("%s", log_str); \
} \
} while (0)
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index f294723..f2a7ebe 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -50,6 +50,7 @@
#include "bionic_pthread.h"
#include "bionic_ssp.h"
#include "bionic_tls.h"
+#include "debug_format.h"
#include "pthread_internal.h"
#include "thread_private.h"
@@ -229,7 +230,7 @@ int _init_thread(pthread_internal_t* thread, pid_t kernel_id, const pthread_attr
// For backwards compatibility reasons, we just warn about failures here.
// error = errno;
const char* msg = "pthread_create sched_setscheduler call failed: %s\n";
- __libc_android_log_print(ANDROID_LOG_WARN, "libc", msg, strerror(errno));
+ __libc_format_log(ANDROID_LOG_WARN, "libc", msg, strerror(errno));
}
}
diff --git a/libc/bionic/pthread_debug.c b/libc/bionic/pthread_debug.cpp
index 7ee208c..c557211 100644
--- a/libc/bionic/pthread_debug.c
+++ b/libc/bionic/pthread_debug.cpp
@@ -31,9 +31,7 @@
#include <sys/system_properties.h>
#include <sys/mman.h>
-#if HAVE_DLADDR
-#include <dlfcn.h>
-#endif
+//#include <dlfcn.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -42,8 +40,12 @@
#include <unwind.h>
#include <unistd.h>
-#include "logd.h"
#include "bionic_tls.h"
+#include "debug_mapinfo.h"
+#include "debug_stacktrace.h"
+#include "logd.h"
+
+#include <private/debug_format.h>
/*
* ===========================================================================
@@ -97,20 +99,16 @@ the lock has been acquired.
// =============================================================================
#define LOGD(format, ...) \
- __libc_android_log_print(ANDROID_LOG_DEBUG, \
- "pthread_debug", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_DEBUG, "pthread_debug", (format), ##__VA_ARGS__ )
#define LOGW(format, ...) \
- __libc_android_log_print(ANDROID_LOG_WARN, \
- "pthread_debug", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_WARN, "pthread_debug", (format), ##__VA_ARGS__ )
#define LOGE(format, ...) \
- __libc_android_log_print(ANDROID_LOG_ERROR, \
- "pthread_debug", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_ERROR, "pthread_debug", (format), ##__VA_ARGS__ )
#define LOGI(format, ...) \
- __libc_android_log_print(ANDROID_LOG_INFO, \
- "pthread_debug", (format), ##__VA_ARGS__ )
+ __libc_format_log(ANDROID_LOG_INFO, "pthread_debug", (format), ##__VA_ARGS__ )
static const char* const kStartBanner =
"===============================================================";
@@ -120,185 +118,9 @@ static const char* const kEndBanner =
extern char* __progname;
-// =============================================================================
-// map info functions
-// =============================================================================
-
-typedef struct mapinfo {
- struct mapinfo *next;
- unsigned start;
- unsigned end;
- char name[];
-} mapinfo;
-
-static mapinfo* sMapInfo = NULL;
-
-static mapinfo *parse_maps_line(char *line)
-{
- mapinfo *mi;
- int len = strlen(line);
-
- if(len < 1) return 0;
- line[--len] = 0;
-
- if(len < 50) return 0;
- if(line[20] != 'x') return 0;
-
- mi = malloc(sizeof(mapinfo) + (len - 47));
- if(mi == 0) return 0;
-
- mi->start = strtoul(line, 0, 16);
- mi->end = strtoul(line + 9, 0, 16);
- /* To be filled in parse_elf_info if the mapped section starts with
- * elf_header
- */
- mi->next = 0;
- strcpy(mi->name, line + 49);
-
- return mi;
-}
-
-static mapinfo *init_mapinfo(int pid)
-{
- struct mapinfo *milist = NULL;
- char data[1024];
- sprintf(data, "/proc/%d/maps", pid);
- FILE *fp = fopen(data, "r");
- if(fp) {
- while(fgets(data, sizeof(data), fp)) {
- mapinfo *mi = parse_maps_line(data);
- if(mi) {
- mi->next = milist;
- milist = mi;
- }
- }
- fclose(fp);
- }
-
- return milist;
-}
-
-static void deinit_mapinfo(mapinfo *mi)
-{
- mapinfo *del;
- while(mi) {
- del = mi;
- mi = mi->next;
- free(del);
- }
-}
-
-/* Find the containing map info for the pc */
-static const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
-{
- *rel_pc = pc;
- while(mi) {
- if((pc >= mi->start) && (pc < mi->end)){
- // Only calculate the relative offset for shared libraries
- if (strstr(mi->name, ".so")) {
- *rel_pc -= mi->start;
- }
- return mi;
- }
- mi = mi->next;
- }
- return NULL;
-}
-
-// =============================================================================
-// stack trace functions
-// =============================================================================
-
#define STACK_TRACE_DEPTH 16
-typedef struct
-{
- size_t count;
- intptr_t* addrs;
-} stack_crawl_state_t;
-
-/* depends how the system includes define this */
-#ifdef HAVE_UNWIND_CONTEXT_STRUCT
-typedef struct _Unwind_Context __unwind_context;
-#else
-typedef _Unwind_Context __unwind_context;
-#endif
-
-static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg)
-{
- stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
- if (state->count) {
- intptr_t ip = (intptr_t)_Unwind_GetIP(context);
- if (ip) {
- state->addrs[0] = ip;
- state->addrs++;
- state->count--;
- return _URC_NO_REASON;
- }
- }
- /*
- * If we run out of space to record the address or 0 has been seen, stop
- * unwinding the stack.
- */
- return _URC_END_OF_STACK;
-}
-
-static inline
-int get_backtrace(intptr_t* addrs, size_t max_entries)
-{
- stack_crawl_state_t state;
- state.count = max_entries;
- state.addrs = (intptr_t*)addrs;
- _Unwind_Backtrace(trace_function, (void*)&state);
- return max_entries - state.count;
-}
-
-static void log_backtrace(intptr_t* addrs, size_t c)
-{
- int index = 0;
- size_t i;
- for (i=0 ; i<c; i++) {
- unsigned int relpc;
- void* offset = 0;
- const char* symbol = NULL;
-
-#if HAVE_DLADDR
- Dl_info info;
- if (dladdr((void*)addrs[i], &info)) {
- offset = info.dli_saddr;
- symbol = info.dli_sname;
- }
-#endif
-
- if (symbol || index>0 || !HAVE_DLADDR) {
- /*
- * this test is a bit sketchy, but it allows us to skip the
- * stack trace entries due to this debugging code. it works
- * because those don't have a symbol (they're not exported)
- */
- mapinfo const* mi = pc_to_mapinfo(sMapInfo, addrs[i], &relpc);
- char const* soname = mi ? mi->name : NULL;
-#if HAVE_DLADDR
- if (!soname)
- soname = info.dli_fname;
-#endif
- if (!soname)
- soname = "unknown";
-
- if (symbol) {
- LOGW(" "
- "#%02d pc %08lx %s (%s+0x%x)",
- index, relpc, soname, symbol,
- addrs[i] - (intptr_t)offset);
- } else {
- LOGW(" "
- "#%02d pc %08lx %s",
- index, relpc, soname);
- }
- index++;
- }
- }
-}
+static mapinfo_t* gMapInfo;
/****************************************************************************/
@@ -322,18 +144,21 @@ static pthread_mutex_t sDbgLock = PTHREAD_MUTEX_INITIALIZER;
static size_t sDbgAllocOffset = DBG_ALLOC_BLOCK_SIZE;
static char* sDbgAllocPtr = NULL;
-static void* DbgAllocLocked(size_t size) {
+template <typename T>
+static T* DbgAllocLocked(size_t count = 1) {
+ size_t size = sizeof(T) * count;
if ((sDbgAllocOffset + size) > DBG_ALLOC_BLOCK_SIZE) {
sDbgAllocOffset = 0;
- sDbgAllocPtr = mmap(NULL, DBG_ALLOC_BLOCK_SIZE, PROT_READ|PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, 0, 0);
+ sDbgAllocPtr = reinterpret_cast<char*>(mmap(NULL, DBG_ALLOC_BLOCK_SIZE,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, 0, 0));
if (sDbgAllocPtr == MAP_FAILED) {
return NULL;
}
}
void* addr = sDbgAllocPtr + sDbgAllocOffset;
sDbgAllocOffset += size;
- return addr;
+ return reinterpret_cast<T*>(addr);
}
static void* debug_realloc(void *ptr, size_t size, size_t old_size) {
@@ -460,9 +285,9 @@ static int pthread_mutex_unlock_unchecked(pthread_mutex_t *mutex) {
/****************************************************************************/
-static void dup_backtrace(CallStack* stack, int count, intptr_t const* addrs) {
+static void dup_backtrace(CallStack* stack, size_t count, intptr_t const* addrs) {
stack->depth = count;
- stack->addrs = DbgAllocLocked(count * sizeof(intptr_t));
+ stack->addrs = DbgAllocLocked<intptr_t>(count);
memcpy(stack->addrs, addrs, count * sizeof(intptr_t));
}
@@ -545,9 +370,9 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
/* Turn off prediction temporarily in this thread while logging */
sPthreadDebugDisabledThread = gettid();
- if (sMapInfo == NULL) {
- // note: we're protected by sDbgLock
- sMapInfo = init_mapinfo(getpid());
+ if (gMapInfo == NULL) {
+ // note: we're protected by sDbgLock.
+ gMapInfo = mapinfo_create(getpid());
}
LOGW("%s\n", kStartBanner);
@@ -555,7 +380,7 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
LOGW("Illegal lock attempt:\n");
LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
stackDepth = get_backtrace(addrs, STACK_TRACE_DEPTH);
- log_backtrace(addrs, stackDepth);
+ log_backtrace(gMapInfo, addrs, stackDepth);
LOGW("+++ Currently held locks in this thread (in reverse order):");
MutexInfo* cur = obj;
@@ -566,7 +391,7 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
if (parent->owner == ourtid) {
LOGW("--- pthread_mutex_t at %p\n", parent->mutex);
if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
- log_backtrace(parent->stackTrace, parent->stackDepth);
+ log_backtrace(gMapInfo, parent->stackTrace, parent->stackDepth);
}
cur = parent;
break;
@@ -589,13 +414,13 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
int index = historyListHas(&obj->parents, objParent);
if ((size_t)index < (size_t)obj->stacks.count) {
- log_backtrace(
- obj->stacks.stack[index].addrs,
- obj->stacks.stack[index].depth);
+ log_backtrace(gMapInfo,
+ obj->stacks.stack[index].addrs,
+ obj->stacks.stack[index].depth);
} else {
- log_backtrace(
- obj->stackTrace,
- obj->stackDepth);
+ log_backtrace(gMapInfo,
+ obj->stackTrace,
+ obj->stackDepth);
}
}
result = 0;
@@ -640,8 +465,8 @@ static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object)
linkParentToChild(mrl, object);
if (!traverseTree(object, mrl)) {
- deinit_mapinfo(sMapInfo);
- sMapInfo = NULL;
+ mapinfo_destroy(gMapInfo);
+ gMapInfo = NULL;
LOGW("%s\n", kEndBanner);
unlinkParentFromChild(mrl, object);
// reenable pthread debugging for this thread
@@ -758,7 +583,7 @@ static HashEntry* hashmap_lookup(HashTable* table,
if (entry == NULL) {
// create a new entry
- entry = (HashEntry*)DbgAllocLocked(sizeof(HashEntry));
+ entry = DbgAllocLocked<HashEntry>();
entry->data = NULL;
entry->slot = slot;
entry->prev = NULL;
@@ -785,8 +610,9 @@ static MutexInfo* get_mutex_info(pthread_mutex_t *mutex)
&mutex, sizeof(mutex),
&MutexInfo_equals);
if (entry->data == NULL) {
- entry->data = (MutexInfo*)DbgAllocLocked(sizeof(MutexInfo));
- initMutexInfo(entry->data, mutex);
+ MutexInfo* mutex_info = DbgAllocLocked<MutexInfo>();
+ entry->data = mutex_info;
+ initMutexInfo(mutex_info, mutex);
}
pthread_mutex_unlock_unchecked(&sDbgLock);
@@ -808,8 +634,9 @@ static ThreadInfo* get_thread_info(pid_t pid)
&pid, sizeof(pid),
&ThreadInfo_equals);
if (entry->data == NULL) {
- entry->data = (ThreadInfo*)DbgAllocLocked(sizeof(ThreadInfo));
- initThreadInfo(entry->data, pid);
+ ThreadInfo* thread_info = DbgAllocLocked<ThreadInfo>();
+ entry->data = thread_info;
+ initThreadInfo(thread_info, pid);
}
pthread_mutex_unlock_unchecked(&sDbgLock);
@@ -848,8 +675,7 @@ static MutexInfo* get_most_recently_locked() {
* after system properties have been initialized
*/
-__LIBC_HIDDEN__
-void pthread_debug_init(void) {
+extern "C" __LIBC_HIDDEN__ void pthread_debug_init() {
char env[PROP_VALUE_MAX];
if (__system_property_get("debug.libc.pthread", env)) {
int level = atoi(env);
@@ -872,8 +698,7 @@ void pthread_debug_init(void) {
* the checks before the lock is held.)
*/
-__LIBC_HIDDEN__
-void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
+extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
{
if (sPthreadDebugLevel == 0) return;
// prediction disabled for this thread
@@ -890,8 +715,7 @@ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
* still held (ie: before calling the real unlock)
*/
-__LIBC_HIDDEN__
-void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
+extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
{
if (sPthreadDebugLevel == 0) return;
// prediction disabled for this thread
diff --git a/libc/bionic/ssp.cpp b/libc/bionic/ssp.cpp
index fdf8832..08c36c5 100644
--- a/libc/bionic/ssp.cpp
+++ b/libc/bionic/ssp.cpp
@@ -63,8 +63,8 @@ void __stack_chk_fail() {
path[count] = '\0';
}
- // Do a best effort at logging. This ends up calling writev(2).
- __libc_android_log_print(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted");
+ // Do a best effort at logging.
+ __libc_android_log_write(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted");
// Make sure there is no default action for SIGABRT.
struct sigaction sa;
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 48281b4..3f24d1b 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -32,6 +32,7 @@
#include <mntent.h>
#include <netdb.h>
#include <private/android_filesystem_config.h>
+#include <private/debug_format.h>
#include <private/logd.h>
#include <pthread.h>
#include <pwd.h>
@@ -435,7 +436,7 @@ protoent* getprotobynumber(int /*proto*/) {
static void unimplemented_stub(const char* function) {
const char* fmt = "%s(3) is not implemented on Android\n";
- __libc_android_log_print(ANDROID_LOG_WARN, "libc", fmt, function);
+ __libc_format_log(ANDROID_LOG_WARN, "libc", fmt, function);
fprintf(stderr, fmt, function);
}
diff --git a/libc/private/debug_format.h b/libc/private/debug_format.h
new file mode 100644
index 0000000..0bc1148
--- /dev/null
+++ b/libc/private/debug_format.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEBUG_FORMAT_H
+#define _DEBUG_FORMAT_H
+
+#include <sys/cdefs.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+// Formatting routines for the C library's internal debugging.
+// Unlike the usual alternatives, these don't allocate.
+
+__LIBC_HIDDEN__ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
+ __attribute__((__format__(printf, 3, 4)));
+
+__LIBC_HIDDEN__ int __libc_format_fd(int fd, const char* format, ...)
+ __attribute__((__format__(printf, 2, 3)));
+
+__LIBC_HIDDEN__ int __libc_format_log(int priority, const char* tag, const char* format, ...)
+ __attribute__((__format__(printf, 3, 4)));
+
+__LIBC_HIDDEN__ int __libc_format_log_va_list(int priority, const char* tag, const char* format,
+ va_list ap);
+
+__END_DECLS
+
+#endif /* _DEBUG_FORMAT_H */