Fix the duplication in the debugging code.
We had two copies of the backtrace code, and two copies of the libcorkscrew /proc/pid/maps code. This patch gets us down to one. We also had hacks so we could log in the malloc debugging code. This patch pulls the non-allocating "printf" code out of the dynamic linker so everyone can share. This patch also makes the leak diagnostics easier to read, and makes it possible to paste them directly into the 'stack' tool (by using relative PCs). This patch also fixes the stdio standard stream leak that was causing a leak warning every time tf_daemon ran. Bug: 7291287 Change-Id: I66e4083ac2c5606c8d2737cb45c8ac8a32c7cfe8
This commit is contained in:
parent
e4ca88d9fa
commit
1e980b6bc8
@ -272,6 +272,7 @@ libc_common_src_files := \
|
|||||||
|
|
||||||
libc_bionic_src_files := \
|
libc_bionic_src_files := \
|
||||||
bionic/assert.cpp \
|
bionic/assert.cpp \
|
||||||
|
bionic/debug_format.cpp \
|
||||||
bionic/dirent.cpp \
|
bionic/dirent.cpp \
|
||||||
bionic/eventfd.cpp \
|
bionic/eventfd.cpp \
|
||||||
bionic/__fgets_chk.cpp \
|
bionic/__fgets_chk.cpp \
|
||||||
@ -881,7 +882,7 @@ LOCAL_SRC_FILES := \
|
|||||||
$(libc_static_common_src_files) \
|
$(libc_static_common_src_files) \
|
||||||
bionic/dlmalloc.c \
|
bionic/dlmalloc.c \
|
||||||
bionic/malloc_debug_common.cpp \
|
bionic/malloc_debug_common.cpp \
|
||||||
bionic/pthread_debug.c \
|
bionic/pthread_debug.cpp \
|
||||||
bionic/libc_init_dynamic.c
|
bionic/libc_init_dynamic.c
|
||||||
|
|
||||||
ifeq ($(TARGET_ARCH),arm)
|
ifeq ($(TARGET_ARCH),arm)
|
||||||
@ -934,10 +935,10 @@ LOCAL_CFLAGS := \
|
|||||||
LOCAL_C_INCLUDES := $(libc_common_c_includes)
|
LOCAL_C_INCLUDES := $(libc_common_c_includes)
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
bionic/debug_mapinfo.cpp \
|
||||||
|
bionic/debug_stacktrace.cpp \
|
||||||
bionic/malloc_debug_leak.cpp \
|
bionic/malloc_debug_leak.cpp \
|
||||||
bionic/malloc_debug_check.cpp \
|
bionic/malloc_debug_check.cpp \
|
||||||
bionic/malloc_debug_check_mapinfo.cpp \
|
|
||||||
bionic/malloc_debug_stacktrace.cpp
|
|
||||||
|
|
||||||
LOCAL_MODULE:= libc_malloc_debug_leak
|
LOCAL_MODULE:= libc_malloc_debug_leak
|
||||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||||
|
@ -50,10 +50,9 @@ atexit(void (*func)(void))
|
|||||||
* calling library may have been dlclose()'d, causing the program to
|
* calling library may have been dlclose()'d, causing the program to
|
||||||
* crash.
|
* crash.
|
||||||
*/
|
*/
|
||||||
static char const warning[] =
|
static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n";
|
||||||
"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);
|
fprintf(stderr, warning);
|
||||||
|
|
||||||
return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
|
return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
|
||||||
|
@ -29,9 +29,9 @@
|
|||||||
#include <sys/cachectl.h>
|
#include <sys/cachectl.h>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include <logd.h>
|
#include <private/logd.h>
|
||||||
#define XLOG(...) \
|
#include <private/debug_format.h>
|
||||||
__libc_android_log_print(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
|
#define XLOG(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <private/debug_format.h>
|
||||||
#include <private/logd.h>
|
#include <private/logd.h>
|
||||||
|
|
||||||
// We log to stderr for the benefit of "adb shell" users, and the log for the benefit
|
// 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) {
|
void __assert(const char* file, int line, const char* failed_expression) {
|
||||||
const char* fmt = "%s:%d: assertion \"%s\" failed\n";
|
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);
|
fprintf(stderr, fmt, file, line, failed_expression);
|
||||||
abort();
|
abort();
|
||||||
/* NOTREACHED */
|
/* 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) {
|
void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
|
||||||
const char* fmt = "%s:%d: %s: assertion \"%s\" failed\n";
|
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);
|
fprintf(stderr, fmt, file, line, function, failed_expression);
|
||||||
abort();
|
abort();
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
// compile under GCC 4.7
|
// compile under GCC 4.7
|
||||||
#undef _FORTIFY_SOURCE
|
#undef _FORTIFY_SOURCE
|
||||||
|
|
||||||
#include "linker_format.h"
|
#include "debug_format.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -40,8 +40,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "linker_debug.h"
|
|
||||||
|
|
||||||
/* define UNIT_TESTS to build this file as a single executable that runs
|
/* define UNIT_TESTS to build this file as a single executable that runs
|
||||||
* the formatter's unit tests
|
* the formatter's unit tests
|
||||||
*/
|
*/
|
||||||
@ -150,47 +148,14 @@ vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
|
|||||||
return buf_out_length(&bo);
|
return buf_out_length(&bo);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
|
||||||
format_buffer(char *buff, size_t buffsize, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
va_list args;
|
||||||
int ret;
|
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
ret = vformat_buffer(buff, buffsize, format, args);
|
int result = vformat_buffer(buffer, buffer_size, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
return result;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The __stack_chk_fail() function calls __libc_android_log_print()
|
|
||||||
* which calls vsnprintf().
|
|
||||||
*
|
|
||||||
* We define our version of the function here to avoid dragging
|
|
||||||
* about 25 KB of C library routines related to formatting.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
|
|
||||||
{
|
|
||||||
return format_buffer(buff, bufsize, format, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The pthread implementation uses snprintf(). If we define it here, we
|
|
||||||
* avoid pulling the stdio vfprintf() implementation into the linker
|
|
||||||
* saving about 19KB of machine code.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
snprintf(char* buff, size_t bufsize, const char* format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int ret;
|
|
||||||
va_start(args, format);
|
|
||||||
ret = vsnprintf(buff, bufsize, format, args);
|
|
||||||
va_end(args);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !LINKER_DEBUG_TO_LOG
|
|
||||||
|
|
||||||
/*** File descriptor output
|
/*** File descriptor output
|
||||||
***/
|
***/
|
||||||
@ -204,7 +169,7 @@ struct FdOut {
|
|||||||
static void
|
static void
|
||||||
fd_out_send(void *opaque, const char *data, int len)
|
fd_out_send(void *opaque, const char *data, int len)
|
||||||
{
|
{
|
||||||
FdOut *fdo = opaque;
|
FdOut *fdo = reinterpret_cast<FdOut*>(opaque);
|
||||||
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
len = strlen(data);
|
len = strlen(data);
|
||||||
@ -240,17 +205,14 @@ fd_out_length(FdOut *fdo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int __libc_format_fd(int fd, const char* format, ...) {
|
||||||
format_fd(int fd, const char *format, ...)
|
|
||||||
{
|
|
||||||
FdOut fdo;
|
FdOut fdo;
|
||||||
Out* out;
|
Out* out = fd_out_init(&fdo, fd);
|
||||||
va_list args;
|
if (out == NULL) {
|
||||||
|
|
||||||
out = fd_out_init(&fdo, fd);
|
|
||||||
if (out == NULL)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
out_vformat(out, format, args);
|
out_vformat(out, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@ -258,78 +220,46 @@ format_fd(int fd, const char *format, ...)
|
|||||||
return fd_out_length(&fdo);
|
return fd_out_length(&fdo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* LINKER_DEBUG_TO_LOG */
|
|
||||||
|
|
||||||
/*** Log output
|
/*** Log output
|
||||||
***/
|
***/
|
||||||
|
|
||||||
/* We need our own version of __libc_android_log_vprint, otherwise
|
|
||||||
* the log output is completely broken. Probably due to the fact
|
|
||||||
* that the C library is not initialized yet.
|
|
||||||
*
|
|
||||||
* You can test that by setting CUSTOM_LOG_VPRINT to 0
|
|
||||||
*/
|
|
||||||
#define CUSTOM_LOG_VPRINT 1
|
|
||||||
|
|
||||||
#if CUSTOM_LOG_VPRINT
|
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
static int log_vprint(int prio, const char *tag, const char *fmt, va_list args)
|
int __libc_format_log_va_list(int priority, const char* tag, const char* fmt, va_list args) {
|
||||||
{
|
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int result;
|
int result = vformat_buffer(buf, sizeof buf, fmt, args);
|
||||||
|
|
||||||
static int log_fd = -1;
|
static int log_fd = -1;
|
||||||
|
if (log_fd == -1) {
|
||||||
result = vformat_buffer(buf, sizeof buf, fmt, args);
|
|
||||||
|
|
||||||
if (log_fd < 0) {
|
|
||||||
log_fd = open("/dev/log/main", O_WRONLY);
|
log_fd = open("/dev/log/main", O_WRONLY);
|
||||||
if (log_fd < 0)
|
if (log_fd == -1) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
struct iovec vec[3];
|
struct iovec vec[3];
|
||||||
|
vec[0].iov_base = (unsigned char *) &priority;
|
||||||
vec[0].iov_base = (unsigned char *) &prio;
|
|
||||||
vec[0].iov_len = 1;
|
vec[0].iov_len = 1;
|
||||||
vec[1].iov_base = (void *) tag;
|
vec[1].iov_base = (void *) tag;
|
||||||
vec[1].iov_len = strlen(tag) + 1;
|
vec[1].iov_len = strlen(tag) + 1;
|
||||||
vec[2].iov_base = (void *) buf;
|
vec[2].iov_base = (void *) buf;
|
||||||
vec[2].iov_len = strlen(buf) + 1;
|
vec[2].iov_len = strlen(buf) + 1;
|
||||||
|
|
||||||
do {
|
TEMP_FAILURE_RETRY(writev(log_fd, vec, 3));
|
||||||
ret = writev(log_fd, vec, 3);
|
|
||||||
} while ((ret < 0) && (errno == EINTR));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __libc_android_log_vprint log_vprint
|
int __libc_format_log(int priority, const char* tag, const char* format, ...) {
|
||||||
|
|
||||||
#else /* !CUSTOM_LOG_VPRINT */
|
|
||||||
|
|
||||||
extern "C" int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap);
|
|
||||||
|
|
||||||
#endif /* !CUSTOM_LOG_VPRINT */
|
|
||||||
|
|
||||||
int
|
|
||||||
format_log(int prio, const char *tag, const char *format, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
ret = __libc_android_log_vprint(prio, tag, format, args);
|
int result = __libc_format_log_va_list(priority, tag, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return ret;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* LINKER_DEBUG_TO_LOG */
|
|
||||||
|
|
||||||
/*** formatted output implementation
|
/*** formatted output implementation
|
||||||
***/
|
***/
|
||||||
|
|
96
libc/bionic/debug_mapinfo.cpp
Normal file
96
libc/bionic/debug_mapinfo.cpp
Normal file
@ -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;
|
||||||
|
}
|
@ -26,21 +26,20 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MALLOC_DEBUG_CHECK_MAPINFO_H
|
#ifndef DEBUG_MAPINFO_H
|
||||||
#define MALLOC_DEBUG_CHECK_MAPINFO_H
|
#define DEBUG_MAPINFO_H
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
struct mapinfo {
|
struct mapinfo_t {
|
||||||
struct mapinfo* next;
|
struct mapinfo_t* next;
|
||||||
unsigned start;
|
unsigned start;
|
||||||
unsigned end;
|
unsigned end;
|
||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
__LIBC_HIDDEN__ mapinfo *init_mapinfo(int pid);
|
__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid);
|
||||||
__LIBC_HIDDEN__ void deinit_mapinfo(mapinfo *mi);
|
__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi);
|
||||||
__LIBC_HIDDEN__ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
|
__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc);
|
||||||
__LIBC_HIDDEN__ const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc);
|
|
||||||
|
|
||||||
#endif /*MALLOC_DEBUG_CHECK_MAPINFO_H*/
|
#endif /* DEBUG_MAPINFO_H */
|
112
libc/bionic/debug_stacktrace.cpp
Normal file
112
libc/bionic/debug_stacktrace.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
* Copyright (C) 2013 The Android Open Source Project
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -26,17 +26,20 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LINKER_FORMAT_H
|
#ifndef DEBUG_STACKTRACE_H
|
||||||
#define _LINKER_FORMAT_H
|
#define DEBUG_STACKTRACE_H
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
// Formatting routines for the dynamic linker's debug traces
|
struct stack_crawl_state_t {
|
||||||
// We want to avoid dragging the whole C library fprintf()
|
size_t count;
|
||||||
// implementation into the dynamic linker since this creates
|
intptr_t* addrs;
|
||||||
// issues (it uses malloc()/free()) and increases code size.
|
};
|
||||||
int format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
|
|
||||||
__attribute__((__format__(printf, 3, 4)));
|
|
||||||
|
|
||||||
#endif /* _LINKER_FORMAT_H */
|
struct mapinfo_t;
|
||||||
|
|
||||||
|
__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);
|
||||||
|
|
||||||
|
#endif /* DEBUG_STACKTRACE_H */
|
@ -250,9 +250,7 @@ void __libc_android_log_event_uid(int32_t tag)
|
|||||||
|
|
||||||
__LIBC_HIDDEN__
|
__LIBC_HIDDEN__
|
||||||
void __fortify_chk_fail(const char *msg, uint32_t tag) {
|
void __fortify_chk_fail(const char *msg, uint32_t tag) {
|
||||||
__libc_android_log_print(ANDROID_LOG_FATAL, "libc",
|
__libc_format_log(ANDROID_LOG_FATAL, "libc", "FORTIFY_SOURCE: %s. Calling abort().\n", msg);
|
||||||
"FORTIFY_SOURCE: %s. Calling abort().\n",
|
|
||||||
msg);
|
|
||||||
if (tag != 0) {
|
if (tag != 0) {
|
||||||
__libc_android_log_event_uid(tag);
|
__libc_android_log_event_uid(tag);
|
||||||
}
|
}
|
||||||
|
@ -45,18 +45,19 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <unwind.h>
|
#include <unwind.h>
|
||||||
|
|
||||||
|
#include "debug_mapinfo.h"
|
||||||
|
#include "debug_stacktrace.h"
|
||||||
#include "dlmalloc.h"
|
#include "dlmalloc.h"
|
||||||
#include "logd.h"
|
#include "logd.h"
|
||||||
#include "malloc_debug_check_mapinfo.h"
|
|
||||||
#include "malloc_debug_common.h"
|
#include "malloc_debug_common.h"
|
||||||
#include "ScopedPthreadMutexLocker.h"
|
#include "ScopedPthreadMutexLocker.h"
|
||||||
|
|
||||||
static mapinfo *milist;
|
static mapinfo_t* gMapInfo;
|
||||||
|
|
||||||
/* libc.debug.malloc.backlog */
|
/* libc.debug.malloc.backlog */
|
||||||
extern unsigned int malloc_double_free_backlog;
|
extern unsigned int malloc_double_free_backlog;
|
||||||
|
|
||||||
#define MAX_BACKTRACE_DEPTH 15
|
#define MAX_BACKTRACE_DEPTH 16
|
||||||
#define ALLOCATION_TAG 0x1ee7d00d
|
#define ALLOCATION_TAG 0x1ee7d00d
|
||||||
#define BACKLOG_TAG 0xbabecafe
|
#define BACKLOG_TAG 0xbabecafe
|
||||||
#define FREE_POISON 0xa5
|
#define FREE_POISON 0xa5
|
||||||
@ -67,20 +68,10 @@ extern unsigned int malloc_double_free_backlog;
|
|||||||
#define REAR_GUARD_LEN (1<<5)
|
#define REAR_GUARD_LEN (1<<5)
|
||||||
|
|
||||||
static void log_message(const char* format, ...) {
|
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;
|
va_list args;
|
||||||
{
|
|
||||||
ScopedPthreadMutexLocker locker(&gAllocationsMutex);
|
|
||||||
const MallocDebug* current_dispatch = __libc_malloc_dispatch;
|
|
||||||
__libc_malloc_dispatch = &__libc_malloc_default_dispatch;
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
__libc_android_log_vprint(ANDROID_LOG_ERROR, "libc", format, args);
|
__libc_format_log_va_list(ANDROID_LOG_ERROR, "libc", format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
__libc_malloc_dispatch = current_dispatch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hdr_t {
|
struct hdr_t {
|
||||||
@ -121,28 +112,6 @@ static hdr_t *backlog_tail;
|
|||||||
static hdr_t *backlog_head;
|
static hdr_t *backlog_head;
|
||||||
static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER;
|
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) {
|
static inline void init_front_guard(hdr_t *hdr) {
|
||||||
memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN);
|
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) {
|
if (!valid && *safe) {
|
||||||
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
user(hdr), hdr->size);
|
||||||
print_backtrace(hdr->bt, hdr->bt_depth);
|
log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
|
||||||
if (hdr->tag == BACKLOG_TAG) {
|
if (hdr->tag == BACKLOG_TAG) {
|
||||||
log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n",
|
log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
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);
|
user(hdr), hdr->size);
|
||||||
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
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 */
|
/* hdr->freed_bt_depth should be nonzero here */
|
||||||
log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
|
log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
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",
|
log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
user(hdr), hdr->size);
|
||||||
print_backtrace(bt, depth);
|
log_backtrace(gMapInfo, bt, depth);
|
||||||
} else {
|
} else {
|
||||||
log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
|
log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
|
||||||
user(hdr));
|
user(hdr));
|
||||||
print_backtrace(bt, depth);
|
log_backtrace(gMapInfo, bt, depth);
|
||||||
/* Leak here so that we do not crash */
|
/* Leak here so that we do not crash */
|
||||||
//dlfree(user(hdr));
|
//dlfree(user(hdr));
|
||||||
}
|
}
|
||||||
@ -428,14 +397,14 @@ extern "C" void *chk_realloc(void *ptr, size_t size) {
|
|||||||
user(hdr), size, hdr->size);
|
user(hdr), size, hdr->size);
|
||||||
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
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 */
|
/* hdr->freed_bt_depth should be nonzero here */
|
||||||
log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
|
log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
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",
|
log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n",
|
||||||
user(hdr), hdr->size);
|
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
|
/* We take the memory out of the backlog and fall through so the
|
||||||
* reallocation below succeeds. Since we didn't really free it, we
|
* 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 {
|
} else {
|
||||||
log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
|
log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
|
||||||
user(hdr), size);
|
user(hdr), size);
|
||||||
print_backtrace(bt, depth);
|
log_backtrace(gMapInfo, bt, depth);
|
||||||
// just get a whole new allocation and leak the old one
|
// just get a whole new allocation and leak the old one
|
||||||
return dlrealloc(0, size);
|
return dlrealloc(0, size);
|
||||||
// return dlrealloc(user(hdr), size); // assuming it was allocated externally
|
// 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;
|
size_t total_size = nmemb * size;
|
||||||
hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
|
hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
|
||||||
if (hdr) {
|
if (hdr) {
|
||||||
hdr->bt_depth = get_backtrace(
|
hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
|
||||||
hdr->bt, MAX_BACKTRACE_DEPTH);
|
|
||||||
add(hdr, total_size);
|
add(hdr, total_size);
|
||||||
return user(hdr);
|
return user(hdr);
|
||||||
}
|
}
|
||||||
@ -476,21 +444,20 @@ extern "C" void *chk_calloc(int nmemb, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void heaptracker_free_leaked_memory() {
|
static void heaptracker_free_leaked_memory() {
|
||||||
|
size_t total = num;
|
||||||
if (num) {
|
if (num) {
|
||||||
log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num);
|
log_message("+++ Leaked allocations: %d\n", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr_t *del = NULL;
|
hdr_t *del = NULL;
|
||||||
while (head) {
|
while (head) {
|
||||||
int safe;
|
int safe;
|
||||||
del = head;
|
del = head;
|
||||||
log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n",
|
log_message("+++ Leaked block of size %d at %p (leak %d of %d)\n",
|
||||||
del->size, user(del), num);
|
del->size, user(del), 1 + total - num, total);
|
||||||
if (del_leak(del, &safe)) {
|
if (del_leak(del, &safe)) {
|
||||||
/* safe == 1, because the allocation is valid */
|
/* safe == 1, because the allocation is valid */
|
||||||
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
|
log_backtrace(gMapInfo, del->bt, del->bt_depth);
|
||||||
user(del), del->size);
|
|
||||||
print_backtrace(del->bt, del->bt_depth);
|
|
||||||
}
|
}
|
||||||
dlfree(del);
|
dlfree(del);
|
||||||
}
|
}
|
||||||
@ -507,13 +474,14 @@ static void heaptracker_free_leaked_memory() {
|
|||||||
* See comments on MallocDebugInit in malloc_debug_common.h
|
* See comments on MallocDebugInit in malloc_debug_common.h
|
||||||
*/
|
*/
|
||||||
extern "C" int malloc_debug_initialize() {
|
extern "C" int malloc_debug_initialize() {
|
||||||
if (!malloc_double_free_backlog)
|
if (!malloc_double_free_backlog) {
|
||||||
malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
|
malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
|
||||||
milist = init_mapinfo(getpid());
|
}
|
||||||
|
gMapInfo = mapinfo_create(getpid());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void malloc_debug_finalize() {
|
extern "C" void malloc_debug_finalize() {
|
||||||
heaptracker_free_leaked_memory();
|
heaptracker_free_leaked_memory();
|
||||||
deinit_mapinfo(milist);
|
mapinfo_destroy(gMapInfo);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -294,7 +294,7 @@ static void* libc_malloc_impl_handle = NULL;
|
|||||||
unsigned int malloc_double_free_backlog;
|
unsigned int malloc_double_free_backlog;
|
||||||
|
|
||||||
static void InitMalloc(MallocDebug* table, int debug_level, const char* prefix) {
|
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",
|
__libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
|
||||||
__progname, debug_level, prefix);
|
__progname, debug_level, prefix);
|
||||||
|
|
||||||
char symbol[128];
|
char symbol[128];
|
||||||
@ -429,7 +429,7 @@ static void malloc_init_impl() {
|
|||||||
dlclose(libc_malloc_impl_handle);
|
dlclose(libc_malloc_impl_handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (malloc_debug_initialize()) {
|
if (malloc_debug_initialize() == -1) {
|
||||||
dlclose(libc_malloc_impl_handle);
|
dlclose(libc_malloc_impl_handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -487,11 +487,19 @@ static void malloc_init_impl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void malloc_fini_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 =
|
MallocDebugFini malloc_debug_finalize =
|
||||||
reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
|
reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
|
||||||
"malloc_debug_finalize"));
|
"malloc_debug_finalize"));
|
||||||
if (malloc_debug_finalize) {
|
if (malloc_debug_finalize != NULL) {
|
||||||
malloc_debug_finalize();
|
malloc_debug_finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <private/debug_format.h>
|
||||||
|
|
||||||
#define HASHTABLE_SIZE 1543
|
#define HASHTABLE_SIZE 1543
|
||||||
#define BACKTRACE_SIZE 32
|
#define BACKTRACE_SIZE 32
|
||||||
/* flag definitions, currently sharing storage with "size" */
|
/* flag definitions, currently sharing storage with "size" */
|
||||||
@ -97,10 +99,10 @@ typedef void (*MallocDebugFini)();
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
#define debug_log(format, ...) \
|
#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, ...) \
|
#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, ...) \
|
#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
|
#endif // MALLOC_DEBUG_COMMON_H
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <unwind.h>
|
#include <unwind.h>
|
||||||
|
|
||||||
|
#include "debug_stacktrace.h"
|
||||||
#include "dlmalloc.h"
|
#include "dlmalloc.h"
|
||||||
#include "logd.h"
|
#include "logd.h"
|
||||||
#include "malloc_debug_common.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);
|
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) {
|
extern "C" void* leak_malloc(size_t bytes) {
|
||||||
// allocate enough space infront of the allocation to store the pointer for
|
// allocate enough space infront of the allocation to store the pointer for
|
||||||
// the alloc structure. This will making free'ing the structer really fast!
|
// the alloc structure. This will making free'ing the structer really fast!
|
||||||
|
@ -257,8 +257,8 @@ static void dump_malloc_descriptor(char* str,
|
|||||||
INFO_TRACING_ENABLED)
|
INFO_TRACING_ENABLED)
|
||||||
|
|
||||||
/* Prints a string to the emulator's stdout.
|
/* Prints a string to the emulator's stdout.
|
||||||
* In early stages of system loading, logging mesages via
|
* In early stages of system loading, logging messages to logcat
|
||||||
* __libc_android_log_print API is not available, because ADB API has not been
|
* 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
|
* hooked up yet. So, in order to see such messages we need to print them to
|
||||||
* the emulator's stdout.
|
* the emulator's stdout.
|
||||||
* Parameters passed to this macro are the same as parameters for printf
|
* 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, ...) \
|
#define qemu_debug_log(format, ...) \
|
||||||
do { \
|
do { \
|
||||||
__libc_android_log_print(ANDROID_LOG_DEBUG, "memcheck", \
|
__libc_format_log(ANDROID_LOG_DEBUG, "memcheck", (format), ##__VA_ARGS__); \
|
||||||
(format), ##__VA_ARGS__); \
|
|
||||||
if (tracing_flags & DEBUG_TRACING_ENABLED) { \
|
if (tracing_flags & DEBUG_TRACING_ENABLED) { \
|
||||||
qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__); \
|
qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
@ -298,8 +297,7 @@ static void dump_malloc_descriptor(char* str,
|
|||||||
|
|
||||||
#define qemu_error_log(format, ...) \
|
#define qemu_error_log(format, ...) \
|
||||||
do { \
|
do { \
|
||||||
__libc_android_log_print(ANDROID_LOG_ERROR, "memcheck", \
|
__libc_format_log(ANDROID_LOG_ERROR, "memcheck", (format), ##__VA_ARGS__); \
|
||||||
(format), ##__VA_ARGS__); \
|
|
||||||
if (tracing_flags & ERROR_TRACING_ENABLED) { \
|
if (tracing_flags & ERROR_TRACING_ENABLED) { \
|
||||||
qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__); \
|
qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
@ -307,8 +305,7 @@ static void dump_malloc_descriptor(char* str,
|
|||||||
|
|
||||||
#define qemu_info_log(format, ...) \
|
#define qemu_info_log(format, ...) \
|
||||||
do { \
|
do { \
|
||||||
__libc_android_log_print(ANDROID_LOG_INFO, "memcheck", \
|
__libc_format_log(ANDROID_LOG_INFO, "memcheck", (format), ##__VA_ARGS__); \
|
||||||
(format), ##__VA_ARGS__); \
|
|
||||||
if (tracing_flags & INFO_TRACING_ENABLED) { \
|
if (tracing_flags & INFO_TRACING_ENABLED) { \
|
||||||
qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__); \
|
qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
@ -318,20 +315,19 @@ static void dump_malloc_descriptor(char* str,
|
|||||||
* Param:
|
* Param:
|
||||||
* type - Message type: debug, error, or info
|
* type - Message type: debug, error, or info
|
||||||
* desc - MallocDesc instance to dump.
|
* 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 { \
|
do { \
|
||||||
if (tracing_enabled(type)) { \
|
if (tracing_enabled(type)) { \
|
||||||
char log_str[4096]; \
|
char log_str[4096]; \
|
||||||
size_t str_len; \
|
__libc_format_buffer(log_str, sizeof(log_str), fmt, ##__VA_ARGS__); \
|
||||||
snprintf(log_str, sizeof(log_str), frmt, ##__VA_ARGS__); \
|
|
||||||
log_str[sizeof(log_str) - 1] = '\0'; \
|
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, \
|
dump_malloc_descriptor(log_str + str_len, \
|
||||||
sizeof(log_str) - str_len, \
|
sizeof(log_str) - str_len, \
|
||||||
(desc)); \
|
(desc)); \
|
||||||
type##_log(log_str); \
|
type##_log("%s", log_str); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "bionic_pthread.h"
|
#include "bionic_pthread.h"
|
||||||
#include "bionic_ssp.h"
|
#include "bionic_ssp.h"
|
||||||
#include "bionic_tls.h"
|
#include "bionic_tls.h"
|
||||||
|
#include "debug_format.h"
|
||||||
#include "pthread_internal.h"
|
#include "pthread_internal.h"
|
||||||
#include "thread_private.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.
|
// For backwards compatibility reasons, we just warn about failures here.
|
||||||
// error = errno;
|
// error = errno;
|
||||||
const char* msg = "pthread_create sched_setscheduler call failed: %s\n";
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,7 @@
|
|||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#if HAVE_DLADDR
|
//#include <dlfcn.h>
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -42,8 +40,12 @@
|
|||||||
#include <unwind.h>
|
#include <unwind.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "logd.h"
|
|
||||||
#include "bionic_tls.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, ...) \
|
#define LOGD(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_DEBUG, \
|
__libc_format_log(ANDROID_LOG_DEBUG, "pthread_debug", (format), ##__VA_ARGS__ )
|
||||||
"pthread_debug", (format), ##__VA_ARGS__ )
|
|
||||||
|
|
||||||
#define LOGW(format, ...) \
|
#define LOGW(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_WARN, \
|
__libc_format_log(ANDROID_LOG_WARN, "pthread_debug", (format), ##__VA_ARGS__ )
|
||||||
"pthread_debug", (format), ##__VA_ARGS__ )
|
|
||||||
|
|
||||||
#define LOGE(format, ...) \
|
#define LOGE(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_ERROR, \
|
__libc_format_log(ANDROID_LOG_ERROR, "pthread_debug", (format), ##__VA_ARGS__ )
|
||||||
"pthread_debug", (format), ##__VA_ARGS__ )
|
|
||||||
|
|
||||||
#define LOGI(format, ...) \
|
#define LOGI(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_INFO, \
|
__libc_format_log(ANDROID_LOG_INFO, "pthread_debug", (format), ##__VA_ARGS__ )
|
||||||
"pthread_debug", (format), ##__VA_ARGS__ )
|
|
||||||
|
|
||||||
static const char* const kStartBanner =
|
static const char* const kStartBanner =
|
||||||
"===============================================================";
|
"===============================================================";
|
||||||
@ -120,185 +118,9 @@ static const char* const kEndBanner =
|
|||||||
|
|
||||||
extern char* __progname;
|
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
|
#define STACK_TRACE_DEPTH 16
|
||||||
|
|
||||||
typedef struct
|
static mapinfo_t* gMapInfo;
|
||||||
{
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
@ -322,18 +144,21 @@ static pthread_mutex_t sDbgLock = PTHREAD_MUTEX_INITIALIZER;
|
|||||||
static size_t sDbgAllocOffset = DBG_ALLOC_BLOCK_SIZE;
|
static size_t sDbgAllocOffset = DBG_ALLOC_BLOCK_SIZE;
|
||||||
static char* sDbgAllocPtr = NULL;
|
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) {
|
if ((sDbgAllocOffset + size) > DBG_ALLOC_BLOCK_SIZE) {
|
||||||
sDbgAllocOffset = 0;
|
sDbgAllocOffset = 0;
|
||||||
sDbgAllocPtr = mmap(NULL, DBG_ALLOC_BLOCK_SIZE, PROT_READ|PROT_WRITE,
|
sDbgAllocPtr = reinterpret_cast<char*>(mmap(NULL, DBG_ALLOC_BLOCK_SIZE,
|
||||||
MAP_ANON | MAP_PRIVATE, 0, 0);
|
PROT_READ|PROT_WRITE,
|
||||||
|
MAP_ANON | MAP_PRIVATE, 0, 0));
|
||||||
if (sDbgAllocPtr == MAP_FAILED) {
|
if (sDbgAllocPtr == MAP_FAILED) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void* addr = sDbgAllocPtr + sDbgAllocOffset;
|
void* addr = sDbgAllocPtr + sDbgAllocOffset;
|
||||||
sDbgAllocOffset += size;
|
sDbgAllocOffset += size;
|
||||||
return addr;
|
return reinterpret_cast<T*>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* debug_realloc(void *ptr, size_t size, size_t old_size) {
|
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->depth = count;
|
||||||
stack->addrs = DbgAllocLocked(count * sizeof(intptr_t));
|
stack->addrs = DbgAllocLocked<intptr_t>(count);
|
||||||
memcpy(stack->addrs, addrs, count * sizeof(intptr_t));
|
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 */
|
/* Turn off prediction temporarily in this thread while logging */
|
||||||
sPthreadDebugDisabledThread = gettid();
|
sPthreadDebugDisabledThread = gettid();
|
||||||
|
|
||||||
if (sMapInfo == NULL) {
|
if (gMapInfo == NULL) {
|
||||||
// note: we're protected by sDbgLock
|
// note: we're protected by sDbgLock.
|
||||||
sMapInfo = init_mapinfo(getpid());
|
gMapInfo = mapinfo_create(getpid());
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGW("%s\n", kStartBanner);
|
LOGW("%s\n", kStartBanner);
|
||||||
@ -555,7 +380,7 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
|
|||||||
LOGW("Illegal lock attempt:\n");
|
LOGW("Illegal lock attempt:\n");
|
||||||
LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
|
LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
|
||||||
stackDepth = get_backtrace(addrs, STACK_TRACE_DEPTH);
|
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):");
|
LOGW("+++ Currently held locks in this thread (in reverse order):");
|
||||||
MutexInfo* cur = obj;
|
MutexInfo* cur = obj;
|
||||||
@ -566,7 +391,7 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
|
|||||||
if (parent->owner == ourtid) {
|
if (parent->owner == ourtid) {
|
||||||
LOGW("--- pthread_mutex_t at %p\n", parent->mutex);
|
LOGW("--- pthread_mutex_t at %p\n", parent->mutex);
|
||||||
if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
|
if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
|
||||||
log_backtrace(parent->stackTrace, parent->stackDepth);
|
log_backtrace(gMapInfo, parent->stackTrace, parent->stackDepth);
|
||||||
}
|
}
|
||||||
cur = parent;
|
cur = parent;
|
||||||
break;
|
break;
|
||||||
@ -589,11 +414,11 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent)
|
|||||||
if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
|
if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
|
||||||
int index = historyListHas(&obj->parents, objParent);
|
int index = historyListHas(&obj->parents, objParent);
|
||||||
if ((size_t)index < (size_t)obj->stacks.count) {
|
if ((size_t)index < (size_t)obj->stacks.count) {
|
||||||
log_backtrace(
|
log_backtrace(gMapInfo,
|
||||||
obj->stacks.stack[index].addrs,
|
obj->stacks.stack[index].addrs,
|
||||||
obj->stacks.stack[index].depth);
|
obj->stacks.stack[index].depth);
|
||||||
} else {
|
} else {
|
||||||
log_backtrace(
|
log_backtrace(gMapInfo,
|
||||||
obj->stackTrace,
|
obj->stackTrace,
|
||||||
obj->stackDepth);
|
obj->stackDepth);
|
||||||
}
|
}
|
||||||
@ -640,8 +465,8 @@ static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object)
|
|||||||
|
|
||||||
linkParentToChild(mrl, object);
|
linkParentToChild(mrl, object);
|
||||||
if (!traverseTree(object, mrl)) {
|
if (!traverseTree(object, mrl)) {
|
||||||
deinit_mapinfo(sMapInfo);
|
mapinfo_destroy(gMapInfo);
|
||||||
sMapInfo = NULL;
|
gMapInfo = NULL;
|
||||||
LOGW("%s\n", kEndBanner);
|
LOGW("%s\n", kEndBanner);
|
||||||
unlinkParentFromChild(mrl, object);
|
unlinkParentFromChild(mrl, object);
|
||||||
// reenable pthread debugging for this thread
|
// reenable pthread debugging for this thread
|
||||||
@ -758,7 +583,7 @@ static HashEntry* hashmap_lookup(HashTable* table,
|
|||||||
|
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
// create a new entry
|
// create a new entry
|
||||||
entry = (HashEntry*)DbgAllocLocked(sizeof(HashEntry));
|
entry = DbgAllocLocked<HashEntry>();
|
||||||
entry->data = NULL;
|
entry->data = NULL;
|
||||||
entry->slot = slot;
|
entry->slot = slot;
|
||||||
entry->prev = NULL;
|
entry->prev = NULL;
|
||||||
@ -785,8 +610,9 @@ static MutexInfo* get_mutex_info(pthread_mutex_t *mutex)
|
|||||||
&mutex, sizeof(mutex),
|
&mutex, sizeof(mutex),
|
||||||
&MutexInfo_equals);
|
&MutexInfo_equals);
|
||||||
if (entry->data == NULL) {
|
if (entry->data == NULL) {
|
||||||
entry->data = (MutexInfo*)DbgAllocLocked(sizeof(MutexInfo));
|
MutexInfo* mutex_info = DbgAllocLocked<MutexInfo>();
|
||||||
initMutexInfo(entry->data, mutex);
|
entry->data = mutex_info;
|
||||||
|
initMutexInfo(mutex_info, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock_unchecked(&sDbgLock);
|
pthread_mutex_unlock_unchecked(&sDbgLock);
|
||||||
@ -808,8 +634,9 @@ static ThreadInfo* get_thread_info(pid_t pid)
|
|||||||
&pid, sizeof(pid),
|
&pid, sizeof(pid),
|
||||||
&ThreadInfo_equals);
|
&ThreadInfo_equals);
|
||||||
if (entry->data == NULL) {
|
if (entry->data == NULL) {
|
||||||
entry->data = (ThreadInfo*)DbgAllocLocked(sizeof(ThreadInfo));
|
ThreadInfo* thread_info = DbgAllocLocked<ThreadInfo>();
|
||||||
initThreadInfo(entry->data, pid);
|
entry->data = thread_info;
|
||||||
|
initThreadInfo(thread_info, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock_unchecked(&sDbgLock);
|
pthread_mutex_unlock_unchecked(&sDbgLock);
|
||||||
@ -848,8 +675,7 @@ static MutexInfo* get_most_recently_locked() {
|
|||||||
* after system properties have been initialized
|
* after system properties have been initialized
|
||||||
*/
|
*/
|
||||||
|
|
||||||
__LIBC_HIDDEN__
|
extern "C" __LIBC_HIDDEN__ void pthread_debug_init() {
|
||||||
void pthread_debug_init(void) {
|
|
||||||
char env[PROP_VALUE_MAX];
|
char env[PROP_VALUE_MAX];
|
||||||
if (__system_property_get("debug.libc.pthread", env)) {
|
if (__system_property_get("debug.libc.pthread", env)) {
|
||||||
int level = atoi(env);
|
int level = atoi(env);
|
||||||
@ -872,8 +698,7 @@ void pthread_debug_init(void) {
|
|||||||
* the checks before the lock is held.)
|
* the checks before the lock is held.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
__LIBC_HIDDEN__
|
extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
|
||||||
void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
|
|
||||||
{
|
{
|
||||||
if (sPthreadDebugLevel == 0) return;
|
if (sPthreadDebugLevel == 0) return;
|
||||||
// prediction disabled for this thread
|
// 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)
|
* still held (ie: before calling the real unlock)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
__LIBC_HIDDEN__
|
extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
|
||||||
void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
|
|
||||||
{
|
{
|
||||||
if (sPthreadDebugLevel == 0) return;
|
if (sPthreadDebugLevel == 0) return;
|
||||||
// prediction disabled for this thread
|
// prediction disabled for this thread
|
@ -63,8 +63,8 @@ void __stack_chk_fail() {
|
|||||||
path[count] = '\0';
|
path[count] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a best effort at logging. This ends up calling writev(2).
|
// Do a best effort at logging.
|
||||||
__libc_android_log_print(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted");
|
__libc_android_log_write(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted");
|
||||||
|
|
||||||
// Make sure there is no default action for SIGABRT.
|
// Make sure there is no default action for SIGABRT.
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <private/android_filesystem_config.h>
|
#include <private/android_filesystem_config.h>
|
||||||
|
#include <private/debug_format.h>
|
||||||
#include <private/logd.h>
|
#include <private/logd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@ -435,7 +436,7 @@ protoent* getprotobynumber(int /*proto*/) {
|
|||||||
|
|
||||||
static void unimplemented_stub(const char* function) {
|
static void unimplemented_stub(const char* function) {
|
||||||
const char* fmt = "%s(3) is not implemented on Android\n";
|
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);
|
fprintf(stderr, fmt, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -25,48 +25,31 @@
|
|||||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include <unwind.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
// =============================================================================
|
#ifndef _DEBUG_FORMAT_H
|
||||||
// stack trace functions
|
#define _DEBUG_FORMAT_H
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
struct stack_crawl_state_t {
|
#include <sys/cdefs.h>
|
||||||
size_t count;
|
#include <stdarg.h>
|
||||||
intptr_t* addrs;
|
#include <stddef.h>
|
||||||
};
|
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
/* depends how the system includes define this */
|
// Formatting routines for the C library's internal debugging.
|
||||||
#ifdef HAVE_UNWIND_CONTEXT_STRUCT
|
// Unlike the usual alternatives, these don't allocate.
|
||||||
typedef struct _Unwind_Context __unwind_context;
|
|
||||||
#else
|
|
||||||
typedef _Unwind_Context __unwind_context;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) {
|
__LIBC_HIDDEN__ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
|
||||||
stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg);
|
__attribute__((__format__(printf, 3, 4)));
|
||||||
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) {
|
__LIBC_HIDDEN__ int __libc_format_fd(int fd, const char* format, ...)
|
||||||
stack_crawl_state_t state;
|
__attribute__((__format__(printf, 2, 3)));
|
||||||
state.count = max_entries;
|
|
||||||
state.addrs = addrs;
|
__LIBC_HIDDEN__ int __libc_format_log(int priority, const char* tag, const char* format, ...)
|
||||||
_Unwind_Backtrace(trace_function, &state);
|
__attribute__((__format__(printf, 3, 4)));
|
||||||
return max_entries - state.count;
|
|
||||||
}
|
__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 */
|
@ -13,7 +13,6 @@ LOCAL_SRC_FILES:= \
|
|||||||
dlfcn.cpp \
|
dlfcn.cpp \
|
||||||
linker.cpp \
|
linker.cpp \
|
||||||
linker_environ.cpp \
|
linker_environ.cpp \
|
||||||
linker_format.cpp \
|
|
||||||
linker_phdr.cpp \
|
linker_phdr.cpp \
|
||||||
rt.cpp
|
rt.cpp
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "linker.h"
|
#include "linker.h"
|
||||||
#include "linker_format.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -38,6 +37,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include <private/debug_format.h>
|
||||||
#include <private/logd.h>
|
#include <private/logd.h>
|
||||||
|
|
||||||
extern "C" int tgkill(int tgid, int tid, int sig);
|
extern "C" int tgkill(int tgid, int tid, int sig);
|
||||||
@ -135,12 +135,12 @@ static void logSignalSummary(int signum, const siginfo_t* info) {
|
|||||||
char buffer[128];
|
char buffer[128];
|
||||||
// "info" will be NULL if the siginfo_t information was not available.
|
// "info" will be NULL if the siginfo_t information was not available.
|
||||||
if (info != NULL) {
|
if (info != NULL) {
|
||||||
format_buffer(buffer, sizeof(buffer),
|
__libc_format_buffer(buffer, sizeof(buffer),
|
||||||
"Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
|
"Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
|
||||||
signum, signame, reinterpret_cast<uintptr_t>(info->si_addr),
|
signum, signame, reinterpret_cast<uintptr_t>(info->si_addr),
|
||||||
info->si_code, gettid(), threadname);
|
info->si_code, gettid(), threadname);
|
||||||
} else {
|
} else {
|
||||||
format_buffer(buffer, sizeof(buffer),
|
__libc_format_buffer(buffer, sizeof(buffer),
|
||||||
"Fatal signal %d (%s), thread %d (%s)",
|
"Fatal signal %d (%s), thread %d (%s)",
|
||||||
signum, signame, gettid(), threadname);
|
signum, signame, gettid(), threadname);
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ void debugger_signal_handler(int n, siginfo_t* info, void*) {
|
|||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* read or write failed -- broken connection? */
|
/* read or write failed -- broken connection? */
|
||||||
format_buffer(msgbuf, sizeof(msgbuf),
|
__libc_format_buffer(msgbuf, sizeof(msgbuf),
|
||||||
"Failed while talking to debuggerd: %s", strerror(errno));
|
"Failed while talking to debuggerd: %s", strerror(errno));
|
||||||
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
|
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
|
||||||
}
|
}
|
||||||
@ -223,7 +223,7 @@ void debugger_signal_handler(int n, siginfo_t* info, void*) {
|
|||||||
close(s);
|
close(s);
|
||||||
} else {
|
} else {
|
||||||
/* socket failed; maybe process ran out of fds */
|
/* socket failed; maybe process ran out of fds */
|
||||||
format_buffer(msgbuf, sizeof(msgbuf),
|
__libc_format_buffer(msgbuf, sizeof(msgbuf),
|
||||||
"Unable to open connection to debuggerd: %s", strerror(errno));
|
"Unable to open connection to debuggerd: %s", strerror(errno));
|
||||||
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
|
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,13 @@
|
|||||||
|
|
||||||
// Private C library headers.
|
// Private C library headers.
|
||||||
#include <private/bionic_tls.h>
|
#include <private/bionic_tls.h>
|
||||||
|
#include <private/debug_format.h>
|
||||||
#include <private/logd.h>
|
#include <private/logd.h>
|
||||||
#include <private/ScopedPthreadMutexLocker.h>
|
#include <private/ScopedPthreadMutexLocker.h>
|
||||||
|
|
||||||
#include "linker.h"
|
#include "linker.h"
|
||||||
#include "linker_debug.h"
|
#include "linker_debug.h"
|
||||||
#include "linker_environ.h"
|
#include "linker_environ.h"
|
||||||
#include "linker_format.h"
|
|
||||||
#include "linker_phdr.h"
|
#include "linker_phdr.h"
|
||||||
|
|
||||||
/* Assume average path length of 64 and max 8 paths */
|
/* Assume average path length of 64 and max 8 paths */
|
||||||
@ -159,7 +159,7 @@ static char tmp_err_buf[768];
|
|||||||
static char __linker_dl_err_buf[768];
|
static char __linker_dl_err_buf[768];
|
||||||
#define DL_ERR(fmt, x...) \
|
#define DL_ERR(fmt, x...) \
|
||||||
do { \
|
do { \
|
||||||
format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \
|
__libc_format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \
|
||||||
/* If LD_DEBUG is set high enough, send every dlerror(3) message to the log. */ \
|
/* If LD_DEBUG is set high enough, send every dlerror(3) message to the log. */ \
|
||||||
DEBUG(fmt "\n", ##x); \
|
DEBUG(fmt "\n", ##x); \
|
||||||
} while(0)
|
} while(0)
|
||||||
@ -674,7 +674,7 @@ static void dump(soinfo *si)
|
|||||||
static int open_library_on_path(const char* name, const char* const paths[]) {
|
static int open_library_on_path(const char* name, const char* const paths[]) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
for (size_t i = 0; paths[i] != NULL; ++i) {
|
for (size_t i = 0; paths[i] != NULL; ++i) {
|
||||||
int n = format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
|
int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
|
||||||
if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
|
if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
|
||||||
PRINT("Warning: ignoring very long library path: %s/%s\n", paths[i], name);
|
PRINT("Warning: ignoring very long library path: %s/%s\n", paths[i], name);
|
||||||
continue;
|
continue;
|
||||||
|
@ -52,19 +52,17 @@
|
|||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
|
||||||
#include "linker_format.h"
|
#include <private/debug_format.h>
|
||||||
|
|
||||||
#if LINKER_DEBUG_TO_LOG
|
#if LINKER_DEBUG_TO_LOG
|
||||||
extern int format_log(int, const char*, const char*, ...) __attribute__((__format__(printf, 3, 4)));
|
|
||||||
#define _PRINTVF(v,x...) \
|
#define _PRINTVF(v,x...) \
|
||||||
do { \
|
do { \
|
||||||
if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \
|
if (debug_verbosity > (v)) __libc_format_log(5-(v),"linker",x); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else /* !LINKER_DEBUG_TO_LOG */
|
#else /* !LINKER_DEBUG_TO_LOG */
|
||||||
extern int format_fd(int, const char *, ...) __attribute__((__format__(printf, 2, 3)));
|
|
||||||
#define _PRINTVF(v,x...) \
|
#define _PRINTVF(v,x...) \
|
||||||
do { \
|
do { \
|
||||||
if (debug_verbosity > (v)) format_fd(1, x); \
|
if (debug_verbosity > (v)) __libc_format_fd(1, x); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif /* !LINKER_DEBUG_TO_LOG */
|
#endif /* !LINKER_DEBUG_TO_LOG */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user