summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSung-jae Park <nicesj.park@samsung.com>2013-08-23 17:40:23 +0900
committerSung-jae Park <nicesj.park@samsung.com>2013-08-23 17:40:44 +0900
commit63e7612ece0337c8e78364392988b41f90fbb65f (patch)
treeea6814d23a38ad9a0ea4dafe227ea37a26e5640c
parent76f3cf0505fe8586ae6a29bc87014345369e4647 (diff)
downloadheap-monitor-63e7612ece0337c8e78364392988b41f90fbb65f.tar.gz
heap-monitor-63e7612ece0337c8e78364392988b41f90fbb65f.tar.bz2
heap-monitor-63e7612ece0337c8e78364392988b41f90fbb65f.zip
Replace malloc_hook with preload
Change-Id: Icc6979bc5e64b6cfd98e862d44b28a580749963b
-rw-r--r--CMakeLists.txt16
-rw-r--r--include/allocator.h25
-rw-r--r--include/debug.h99
-rw-r--r--include/heap-monitor.h6
-rw-r--r--include/heap-monitor_internal.h22
-rw-r--r--packaging/libheap-monitor.spec5
-rw-r--r--src/allocator.c283
-rw-r--r--src/dlist.c7
-rw-r--r--src/heap-monitor.c780
9 files changed, 840 insertions, 403 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e0469e8..78549d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,32 +13,26 @@ set(CMAKE_SKIP_BUILD_RPATH true)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
-INCLUDE(FindPkgConfig)
-pkg_check_modules(pkgs REQUIRED
- dlog
-)
-
-FOREACH(flag ${pkgs_CFLAGS})
- SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -fno-builtin-malloc -O3 -g -Wno-error=deprecated-declarations")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wno-error=deprecated-declarations")
ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
ADD_DEFINITIONS("-DNDEBUG")
+ADD_DEFINITIONS("-DFLOG")
ADD_DEFINITIONS("-DLOG_TAG=\"HEAP_MONITOR\"")
ADD_DEFINITIONS("-D_THREAD_SAFETY")
+ADD_DEFINITIONS("-D_ESTIMATE_PERFORMANCE")
ADD_LIBRARY(${PROJECT_NAME} SHARED
- src/heap-monitor.c
+ src/allocator.c
src/dlist.c
+ src/heap-monitor.c
)
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} "-lpthread")
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} "-lpthread -ldl")
CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc")
diff --git a/include/allocator.h b/include/allocator.h
new file mode 100644
index 0000000..406ec06
--- /dev/null
+++ b/include/allocator.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+struct allocator;
+extern struct allocator *allocator_init(unsigned int base, unsigned int size);
+extern int allocator_fini(struct allocator *handle);
+extern void *allocator_alloc(struct allocator *handle, int size);
+extern void allocator_free(struct allocator *handle, void *ptr);
+extern unsigned int allocator_allocated_size(void *ptr);
+extern int allocator_in_scope(struct allocator *handle, void *addr);
+
+/* End of a file */
diff --git a/include/debug.h b/include/debug.h
new file mode 100644
index 0000000..ac0cb53
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(FLOG)
+#define DbgPrint(format, arg...)
+#define ErrPrint(format, arg...)
+#define WarnPrint(format, arg...)
+#else
+extern FILE *__file_log_fp;
+#define DbgPrint(format, arg...) do { if (__file_log_fp) { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } } while (0)
+#define ErrPrint(format, arg...) do { if (__file_log_fp) { fprintf(__file_log_fp, "[ERR] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } } while (0)
+#define WarnPrint(format, arg...) do { if (__file_log_fp) { fprintf(__file_log_fp, "[WRN] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } } while (0)
+#endif
+
+#if defined(_ESTIMATE_PERFORMANCE)
+#define ESTIMATE_START() \
+do { \
+ struct timeval stv; \
+ struct timeval etv; \
+ struct timeval rtv; \
+ static struct timeval ttv; \
+ static int initialized = 0; \
+ if (!initialized) { \
+ timerclear(&ttv); \
+ initialized = 1; \
+ } \
+ DbgPrint("Start\n"); \
+ gettimeofday(&stv, NULL)
+
+#define ESTIMATE_END() \
+ gettimeofday(&etv, NULL); \
+ gettimeofday(&etv, NULL); \
+ timersub(&etv, &stv, &rtv); \
+ timeradd(&rtv, &ttv, &ttv); \
+ DbgPrint("Elapsed time: %lu.%lf\n", rtv.tv_sec, (double)rtv.tv_usec / 1000000.0f); \
+ DbgPrint("Total: %lu.%lf\n", ttv.tv_sec, (double)ttv.tv_usec / 1000000.0f); \
+} while (0)
+
+
+#else
+#define ESTIMATE_START() // pthread_mutex_lock(&s_info.mutex)
+#define ESTIMATE_END() // pthread_mutex_unlock(&s_info.mutex)
+#endif
+
+#if defined(_THREAD_SAFETY)
+#define CRITICAL_SECTION_BEGIN(handle) \
+do { \
+ int ret; \
+ ret = pthread_mutex_lock(handle); \
+ if (ret != 0) { \
+ ErrPrint("Failed to lock: %s\n", strerror(ret)); \
+ } \
+} while (0)
+
+#define CRITICAL_SECTION_END(handle) \
+do { \
+ int ret; \
+ ret = pthread_mutex_unlock(handle); \
+ if (ret != 0) { \
+ ErrPrint("Failed to unlock: %s\n", strerror(ret)); \
+ } \
+} while (0)
+
+#define CANCEL_SECTION_BEGIN() do { \
+ int ret; \
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \
+ if (ret != 0) { \
+ ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \
+ } \
+} while (0)
+
+#define CANCEL_SECTION_END() do { \
+ int ret; \
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \
+ if (ret != 0) { \
+ ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \
+ } \
+} while (0)
+
+#else
+#define CRITICAL_SECTION_BEGIN(handle)
+#define CRITICAL_SECTION_END(handle)
+#define CANCEL_SECTION_BEGIN(handle)
+#define CANCEL_SECTION_END(handle)
+#endif
+
diff --git a/include/heap-monitor.h b/include/heap-monitor.h
index e8a460b..2de6adf 100644
--- a/include/heap-monitor.h
+++ b/include/heap-monitor.h
@@ -15,12 +15,10 @@
*/
extern int heap_monitor_initialized(void);
-extern void heap_monitor_init(void);
-extern void heap_monitor_start(void);
-extern void heap_monitor_stop(void);
extern size_t heap_monitor_target_usage(const char *name);
extern int heap_monitor_add_target(const char *name);
extern int heap_monitor_del_target(const char *name);
-extern void heap_monitor_set_stack_boundary(unsigned long stack_boundary);
+extern void heap_monitor_fini(void);
+extern void heap_monitor_init(void);
/* End of a file */
diff --git a/include/heap-monitor_internal.h b/include/heap-monitor_internal.h
new file mode 100644
index 0000000..699eaf1
--- /dev/null
+++ b/include/heap-monitor_internal.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern void *malloc_wrapper(size_t size);
+extern void *realloc_wrapper(void *ptr, size_t size);
+extern void free_wrapper(void *ptr);
+extern void *memalign_wrapper(size_t align, size_t size);
+
+/* End of all */
diff --git a/packaging/libheap-monitor.spec b/packaging/libheap-monitor.spec
index d6227cf..8c1e010 100644
--- a/packaging/libheap-monitor.spec
+++ b/packaging/libheap-monitor.spec
@@ -1,12 +1,11 @@
Name: libheap-monitor
Summary: Library for monitoring the heap usage
-Version: 0.0.15
+Version: 0.0.16
Release: 1
Group: HomeTF/Livebox
License: Flora License
Source0: %{name}-%{version}.tar.gz
BuildRequires: cmake, gettext-tools, coreutils
-BuildRequires: pkgconfig(dlog)
%description
Monitoring the heap usage to manage them safely.
@@ -28,7 +27,7 @@ export CFLAGS="${CFLAGS} -DTIZEN_ENGINEER_MODE"
export CXXFLAGS="${CXXFLAGS} -DTIZEN_ENGINEER_MODE"
export FFLAGS="${FFLAGS} -DTIZEN_ENGINEER_MODE"
%endif
-%cmake .
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
CFLAGS+="${CFLAGS} -fvisibility=hidden -Wall -Werror -Winline -fno-builtin-malloc" make %{?jobs:-j%jobs}
%install
diff --git a/src/allocator.c b/src/allocator.c
new file mode 100644
index 0000000..347aa0c
--- /dev/null
+++ b/src/allocator.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include "debug.h"
+
+int errno;
+
+struct chunk {
+ struct chunk *prev;
+ struct chunk *next;
+
+ unsigned int size;
+ char data[];
+};
+
+struct allocator {
+ pthread_mutex_t mutex;
+ unsigned int size;
+ struct chunk *used;
+ struct chunk *freed;
+ char data[];
+};
+
+struct allocator *allocator_init(unsigned int base, unsigned int size)
+{
+ struct allocator *handle = (struct allocator *)base;
+ struct chunk *chunk;
+
+ handle->size = size - sizeof(*handle);
+
+ chunk = (struct chunk *)handle->data;
+
+ pthread_mutex_init(&handle->mutex, NULL);
+
+ handle->freed = chunk;
+ handle->used = NULL;
+
+ chunk->size = handle->size - sizeof(*chunk);
+ chunk->next = chunk;
+ chunk->prev = chunk;
+
+ return handle;
+}
+
+int allocator_fini(struct allocator *handle)
+{
+ pthread_mutex_destroy(&handle->mutex);
+ return 0;
+}
+
+unsigned int allocator_allocated_size(void *ptr)
+{
+ struct chunk *tmp = (struct chunk *)ptr;
+ return tmp->size;
+}
+
+void *allocator_alloc(struct allocator *handle, int size)
+{
+ struct chunk *tmp;
+ struct chunk *chunk;
+ void *ret = NULL;
+
+ if (!handle) {
+ return NULL;
+ }
+
+ CRITICAL_SECTION_BEGIN(&handle->mutex);
+ tmp = handle->freed;
+ if (!tmp) {
+ goto out;
+ }
+
+ do {
+ if (size > tmp->size) {
+ continue;
+ } else if (tmp->size <= size + sizeof(*tmp)) {
+ /*!
+ * \note
+ * If the remained free size is more smaller than "chunk structure" size,
+ * Allocating a new chunk does not need make a new free node.
+ * It cannot be used anymore, in this case,
+ * Don't divide it into more smaller chunks.
+ *
+ * We call this "INTERNAL FRAGMENTATION".
+ */
+ chunk = tmp;
+
+ chunk->prev->next = chunk->next;
+ chunk->next->prev = chunk->prev;
+
+ if (chunk == handle->freed) {
+ handle->freed = chunk->next;
+
+ if (handle->freed == chunk) {
+ handle->freed = NULL;
+ }
+ }
+ } else {
+ tmp->size -= size + sizeof(*chunk);
+
+ chunk = (struct chunk *)(tmp->data + tmp->size);
+ chunk->size = size;
+ }
+
+ if (!handle->used) {
+ handle->used = chunk;
+ ret = (void *)chunk->data;
+
+ chunk->next = chunk;
+ chunk->prev = chunk;
+ break;
+ }
+
+ /*!
+ * \note
+ * Now, we can re-use the "tmp".
+ * Because we will not take outer loop anymore.
+ * So re-use the "tmp" for insertion sorting.
+ */
+ tmp = handle->used;
+ if (tmp > chunk) {
+ /*!
+ * \note
+ * Reassign the "chunk" to handle->used.
+ */
+ handle->used = chunk;
+ } else {
+ do {
+ if (tmp > chunk) {
+ break;
+ }
+ } while ((tmp = tmp->next) && tmp != handle->used);
+ }
+
+ tmp->prev->next = chunk;
+ chunk->prev = tmp->prev;
+ chunk->next = tmp;
+ tmp->prev = chunk;
+ ret = (void *)chunk->data;
+ break;
+ } while ((tmp = tmp->next) && tmp != handle->freed);
+
+out:
+ CRITICAL_SECTION_END(&handle->mutex);
+ return ret;
+}
+
+void allocator_free(struct allocator *handle, void *ptr)
+{
+ struct chunk *tmp;
+ struct chunk *chunk;
+
+ if (!ptr) {
+ return;
+ }
+
+ chunk = (struct chunk *)(((char *)ptr) - (unsigned int)(&((struct chunk *)0)->data));
+
+ CRITICAL_SECTION_BEGIN(&handle->mutex);
+ /*!
+ * \note
+ * Disconnecting from the used list.
+ */
+ chunk->prev->next = chunk->next;
+ chunk->next->prev = chunk->prev;
+
+ if (chunk == handle->used) {
+ handle->used = chunk->next;
+ if (handle->used == chunk) {
+ handle->used = NULL;
+ }
+ }
+
+ /*!
+ * \note
+ * Insert a chunk to the free'd list.
+ */
+ if (!handle->freed) {
+ handle->freed = chunk;
+ chunk->next = chunk;
+ chunk->prev = chunk;
+ goto out;
+ }
+
+ tmp = handle->freed;
+
+ do {
+ if (tmp > chunk) {
+ break;
+ }
+ } while ((tmp = tmp->next) && tmp != handle->freed);
+
+ if ((unsigned int)(chunk->data + chunk->size) == (unsigned int)tmp) {
+ /*!
+ * \note
+ * tmp is merged with the chunk.
+ * and if the tmp is same with handle->freed,
+ * assign chunk to handle->freed.
+ */
+ chunk->size += tmp->size + sizeof(*tmp);
+
+ chunk->next = tmp->next;
+ chunk->prev = tmp->prev;
+ chunk->next->prev = chunk;
+ chunk->prev->next = chunk;
+
+ if (handle->freed == tmp) {
+ handle->freed = chunk;
+ }
+
+ /* Previous node is changed. try to merge with prev node again */
+ tmp = chunk->prev;
+ if ((unsigned int)(tmp->data + tmp->size) == (unsigned int)chunk) {
+ tmp->size += chunk->size + sizeof(*chunk);
+
+ tmp->next = chunk->next;
+ chunk->next->prev = tmp;
+
+ if (handle->freed == chunk) {
+ handle->freed = tmp;
+ }
+ }
+ } else if ((unsigned int)(tmp->data + tmp->size) == (unsigned int)chunk) {
+ /*!
+ * \note
+ * chunk is merged with the tmp.
+ * and if the chunk is same with handle->freed.
+ * assign tmp to handle->freed.
+ */
+ tmp->size += chunk->size + sizeof(*chunk);
+
+ /* Size of the node is changed. try to merge with next node again */
+ chunk = tmp->next;
+ if ((unsigned int)(tmp->data + tmp->size) == (unsigned int)chunk) {
+ tmp->size += chunk->size + sizeof(*chunk);
+
+ tmp->next = chunk->next;
+ chunk->next->prev = tmp;
+ }
+ } else {
+ chunk->prev = tmp->prev;
+ tmp->prev->next = chunk;
+
+ chunk->next = tmp;
+ tmp->prev = chunk;
+ }
+
+out:
+ CRITICAL_SECTION_END(&handle->mutex);
+}
+
+int allocator_in_scope(struct allocator *handle, void *addr)
+{
+ unsigned int base = (unsigned int)handle;
+ unsigned int size = handle->size;
+ int valid;
+
+ valid = (base <= (unsigned int)addr && (unsigned int)addr < (base + size));
+ DbgPrint("Validate: %p (%d)\n", addr, valid);
+ return valid;
+}
+
+/* End of a file */
diff --git a/src/dlist.c b/src/dlist.c
index 3ae571b..f947edc 100644
--- a/src/dlist.c
+++ b/src/dlist.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include "dlist.h"
+#include "heap-monitor_internal.h"
/*!
* \brief
@@ -44,7 +45,7 @@ struct dlist *dlist_append(struct dlist *list, void *data)
{
struct dlist *item;
- item = malloc(sizeof(*item));
+ item = malloc_wrapper(sizeof(*item));
if (!item) {
return NULL;
}
@@ -71,7 +72,7 @@ struct dlist *dlist_prepend(struct dlist *list, void *data)
{
struct dlist *item;
- item = malloc(sizeof(*item));
+ item = malloc_wrapper(sizeof(*item));
if (!item) {
return NULL;
}
@@ -123,7 +124,7 @@ struct dlist *dlist_remove(struct dlist *list, struct dlist *l)
list->prev = l->prev;
}
- free(l);
+ free_wrapper(l);
return list;
}
diff --git a/src/heap-monitor.c b/src/heap-monitor.c
index 054a76a..5e91cec 100644
--- a/src/heap-monitor.c
+++ b/src/heap-monitor.c
@@ -27,101 +27,48 @@
#include <pthread.h>
#include <link.h>
#include <elf.h>
+#include <unistd.h>
+#include <stddef.h>
#include <mcheck.h>
-#include <dlog.h>
-
#include "dlist.h"
#include "heap-monitor.h"
-
-#if !defined(SECURE_LOGD)
-#define SECURE_LOGD LOGD
-#endif
-
-#if !defined(SECURE_LOGE)
-#define SECURE_LOGE LOGE
-#endif
-
-#if !defined(SECURE_LOGW)
-#define SECURE_LOGW LOGW
-#endif
-
-#if !defined(FLOG)
-#define DbgPrint(format, arg...) SECURE_LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
-#define ErrPrint(format, arg...) SECURE_LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
-#else
-extern FILE *__file_log_fp;
-#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
-
-#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
-#endif
-/* End of a file */
+#include "allocator.h"
+#include "debug.h"
+#include "heap-monitor_internal.h"
#define container_of(ptr, type, member) \
({ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
+ (type *)( (char *)__mptr - offsetof(type, member) );})
#define API __attribute__((visibility("default")))
#define DUMP_DEPTH 80000
-#if defined(_ESTIMATE_PERFORMANCE)
-#define ESTIMATE_START() \
-do { \
- struct timeval stv; \
- struct timeval etv; \
- struct timeval rtv; \
- static struct timeval ttv; \
- static int initialized = 0; \
- if (!initialized) { \
- timerclear(&ttv); \
- initialized = 1; \
- } \
- gettimeofday(&stv, NULL)
-
-#define ESTIMATE_END() \
- gettimeofday(&etv, NULL); \
- gettimeofday(&etv, NULL); \
- timersub(&etv, &stv, &rtv); \
- timeradd(&rtv, &ttv, &ttv); \
- DbgPrint("Elapsed time: %lu.%lf\n", rtv.tv_sec, (double)rtv.tv_usec / 1000000.0f); \
- DbgPrint("Total: %lu.%lf\n", ttv.tv_sec, (double)ttv.tv_usec / 1000000.0f); \
-} while (0)
-#else
-#define ESTIMATE_START() // pthread_mutex_lock(&s_info.mutex)
-#define ESTIMATE_END() // pthread_mutex_unlock(&s_info.mutex)
-#endif
-
-#if defined(_THREAD_SAFETY)
-#define LOCK() pthread_mutex_lock(&s_info.mutex)
-#define UNLOCK() pthread_mutex_unlock(&s_info.mutex)
-#else
-#define LOCK()
-#define UNLOCK()
-#endif
+typedef void *(*malloc_t)(size_t size);
+typedef void *(*realloc_t)(void *ptr, size_t size);
+typedef void (*free_t)(void *ptr);
+typedef void *(*memalign_t)(size_t align, size_t size);
+typedef void *(*calloc_t)(size_t nmemb, size_t size);
-typedef void *(*malloc_t)(size_t size, const void *caller);
-typedef void *(*realloc_t)(void *ptr, size_t size, const void *caller);
-typedef void (*free_t)(void *ptr, const void *caller);
-typedef void *(*memalign_t)(size_t align, size_t size, const void *caller);
+extern char etext, edata, end;
+FILE *__file_log_fp;
int errno;
+enum state {
+ VALID = 0xbeefbeef,
+ INVALID = 0xdeaddead,
+ STACK = 0x00beef00,
+};
+
struct chunk {
struct target *info;
int size;
int pad;
- enum {
- VALID = 0xbeefbeef,
- INVALID = 0xdeaddead
- } state;
+ int state;
char data[];
};
-#define SET_PAD(ptr, pad) (*(((int *)ptr) - 2) = (pad))
-#define SET_STATE(ptr, state) (*(((int *)ptr) - 1) = (state))
-#define PAD(ptr) (*(((int *)ptr) - 2))
-#define STATE(ptr) (*(((int *)ptr) - 1))
-
struct target {
char *name;
int usage;
@@ -137,15 +84,19 @@ static struct {
struct dlist *target_list;
int hook;
int dump_depth;
- unsigned long stack_boundary;
- unsigned long stack_base;
size_t stack_size;
- pthread_mutex_t mutex;
+ unsigned long stack_base;
int debugger;
int target_cnt;
pthread_t main_tid;
int initialized;
- int m_check;
+ int hooked;
+ struct allocator *alloc_handle;
+ char stack_memory[1048576];
+ unsigned int bloom_filter;
+#if defined(_THREAD_SAFETY)
+ pthread_mutex_t mutex;
+#endif
} s_info = {
._malloc = NULL,
._realloc = NULL,
@@ -154,43 +105,55 @@ static struct {
.target_list = NULL,
.hook = 0,
.dump_depth = DUMP_DEPTH,
- .stack_boundary = 0,
- .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .stack_size = 0,
.debugger = 0,
.target_cnt = 0,
.initialized = 0,
- .m_check = 0,
+ .hooked = 0,
+ .alloc_handle = NULL,
+ .stack_memory = { 0, },
+ .bloom_filter = 0,
+#if defined(_THREAD_SAFETY)
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
+#endif
};
-static void unhook(void);
-static void hook(void);
-
static inline struct target *find_target_by_name(const char *name)
{
struct dlist *l;
- struct target *target;
+ struct target *target = NULL;
dlist_foreach(s_info.target_list, l, target) {
if (!strcmp(target->name, name)) {
- return target;
+ break;
}
+ target = NULL;
}
-
- return NULL;
+ return target;
}
static inline struct target *find_target_by_addr(unsigned long addr)
{
struct dlist *l;
- struct target *target;
+ struct target *target = NULL;
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
dlist_foreach(s_info.target_list, l, target) {
if (target->begin <= addr && addr < target->end) {
- return target;
+ break;
}
+ target = NULL;
}
+ CRITICAL_SECTION_END(&s_info.mutex);
- return NULL;
+ return target;
+}
+
+static inline int MPROBE(void *ptr)
+{
+ enum mcheck_status status;
+ status = mprobe(ptr);
+ return status == MCHECK_DISABLED || status == MCHECK_OK;
}
/*!
@@ -215,7 +178,7 @@ static struct target *find_target_info(void)
stack = (unsigned long *)&ret;
- if (s_info.stack_boundary) {
+ if (s_info.stack_size) {
pthread_t tid;
unsigned long base;
unsigned long boundary;
@@ -234,15 +197,14 @@ static struct target *find_target_info(void)
}
} else {
base = s_info.stack_base;
- boundary = s_info.stack_boundary;
+ boundary = s_info.stack_base + s_info.stack_size;
}
i = 0;
while ((unsigned long)stack >= base && (unsigned long)stack < boundary) {
i++;
if (s_info.debugger) {
- DbgPrint("FP: %p, boundary: %p, INDEX: %d, ret: 0x%X\n",
- stack, boundary, i, *stack);
+ DbgPrint("FP: %p, boundary: %p, INDEX: %d, ret: 0x%X\n", stack, (void *)boundary, i, (unsigned int)*stack);
}
target = find_target_by_addr(*stack++);
@@ -266,7 +228,6 @@ static struct target *find_target_info(void)
if (s_info.debugger) {
DbgPrint("[%d] Target[%s]: %d\n", i, target->name, target->usage);
}
-
return target;
}
}
@@ -274,85 +235,97 @@ static struct target *find_target_info(void)
return NULL;
}
-static void mcheck_cb(enum mcheck_status status)
+void *malloc_wrapper(size_t size)
{
- struct target *target;
- switch (status) {
- case MCHECK_DISABLED:
- ErrPrint("mcheck is disabled\n");
- break;
- case MCHECK_OK:
- ErrPrint("Consitency is ok\n");
- break;
- case MCHECK_HEAD:
- target = find_target_info();
- if (target) {
- ErrPrint("[HEAD] Inconsistency: %s\n", target->name);
- }
- break;
- case MCHECK_TAIL:
- target = find_target_info();
- if (target) {
- ErrPrint("[HEAD] Inconsistency: %s\n", target->name);
- }
- break;
- case MCHECK_FREE:
- target = find_target_info();
- if (target) {
- ErrPrint("[FREE] Inconsistency: %s\n", target->name);
- }
- break;
- default:
- break;
- }
+ return s_info._malloc ? s_info._malloc(size) : NULL;
}
-static inline int MPROBE(void *ptr)
+void *realloc_wrapper(void *ptr, size_t size)
{
- enum mcheck_status status;
+ return s_info._realloc ? s_info._realloc(ptr, size) : NULL;
+}
- status = mprobe(ptr);
- if (status == MCHECK_DISABLED) {
- return 1;
+void free_wrapper(void *ptr)
+{
+ if (!s_info._free) {
+ s_info._free = dlsym(RTLD_NEXT, "free");
+ if (!s_info._free) {
+ ErrPrint("Failed to find \"free\"\n");
+ return;
+ }
}
- if (status != MCHECK_OK) {
- mcheck_cb(status);
- return 0;
- }
+ s_info._free(ptr);
+}
- return 1;
+void *memalign_wrapper(size_t align, size_t size)
+{
+ return s_info._memalign ? s_info._memalign(align, size) : NULL;
}
-static void *heap_monitor_malloc(size_t size, const void *caller)
+API void *malloc(size_t size)
{
struct chunk *chunk;
void *ptr = NULL;
- LOCK();
- unhook();
ESTIMATE_START();
- chunk = malloc(size + sizeof(*chunk));
- if (chunk) {
- chunk->info = find_target_info();
- chunk->size = size;
+ if (s_info.initialized) {
+ chunk = malloc_wrapper(size + sizeof(*chunk));
+ if (!chunk) {
+ goto out;
+ }
- ptr = chunk->data;
- SET_PAD(ptr, 0);
- SET_STATE(ptr, VALID);
+ chunk->state = VALID;
+ } else {
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ if (!s_info.alloc_handle) {
+ s_info.alloc_handle = allocator_init((unsigned int)s_info.stack_memory, sizeof(s_info.stack_memory));
+ }
+ CRITICAL_SECTION_END(&s_info.mutex);
- if (chunk->info) {
- chunk->info->usage += size;
+ chunk = allocator_alloc(s_info.alloc_handle, size + sizeof(*chunk));
+ if (!chunk) {
+ DbgPrint("Failed stack alloc\n");
+ goto out;
}
+
+ chunk->state = STACK;
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ chunk->info = find_target_info();
+ if (chunk->info) {
+ chunk->info->usage += size;
}
+ CRITICAL_SECTION_END(&s_info.mutex);
+ chunk->size = size;
+ chunk->pad = 0;
+ ptr = chunk->data;
+
+out:
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ s_info.bloom_filter |= (unsigned int)ptr;
+ CRITICAL_SECTION_END(&s_info.mutex);
ESTIMATE_END();
- hook();
- UNLOCK();
return ptr;
}
-static void heap_monitor_free(void *ptr, const void *caller)
+API void *calloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ size *= nmemb;
+
+ ptr = malloc(size);
+ if (ptr) {
+ memset(ptr, 0, size);
+ }
+
+ return ptr;
+}
+
+API void free(void *ptr)
{
struct chunk *chunk;
@@ -360,169 +333,154 @@ static void heap_monitor_free(void *ptr, const void *caller)
return;
}
- LOCK();
- unhook();
ESTIMATE_START();
-
- if (STATE(ptr) != VALID) {
- DbgPrint("Unrecognizable chunk, do default operation\n");
- chunk = ptr;
- goto out;
- }
-
- chunk = container_of((void *)(((char *)ptr) - PAD(ptr)), struct chunk, data);
- if (chunk->info) {
- chunk->info->usage -= chunk->size;
+ if (!s_info.initialized) {
+ if (!s_info._free) {
+ /*!
+ * \note
+ * If the "free" is called before initiate the heap-monitor,
+ * Bind the "free" from here
+ */
+ s_info._free = dlsym(RTLD_NEXT, "free");
+ if (!s_info._free) {
+ exit(-EINVAL);
+ }
+ }
}
- if (MPROBE(chunk)) {
- SET_STATE(ptr, INVALID);
+ if (!s_info.alloc_handle) {
+ /*!
+ * \note
+ * If the allocator is not initiated,
+ * We don't need to validate the address.
+ * Just "free" it.
+ */
+ DbgPrint("Allocator is not initiated\n");
+ free_wrapper(ptr);
+ } else if ((s_info.bloom_filter & (unsigned int)ptr) != (unsigned int)ptr) {
+ DbgPrint("Bloom filtered\n");
+ free_wrapper(ptr);
} else {
- chunk = ptr;
- if (MPROBE(chunk)) {
- DbgPrint("Successfully recovered\n");
+ chunk = container_of(ptr, struct chunk, data);
+ if(chunk->state == VALID) {
+ if (MPROBE(chunk)) {
+ if (chunk->info) {
+ chunk->info->usage -= chunk->size;
+ }
+
+ chunk->state = INVALID;
+ ptr = (char *)chunk - chunk->pad;
+ } else {
+ DbgPrint("native free\n");
+ ptr = chunk;
+ }
+
+ free_wrapper(ptr);
+ } else if (chunk->state == STACK || allocator_in_scope(s_info.alloc_handle, ptr)) {
+ chunk->state = INVALID;
+ ptr = (char *)chunk - chunk->pad;
+ allocator_free(s_info.alloc_handle, ptr);
+ } else if (chunk->state == INVALID) {
+ struct target *target;
+
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ target = find_target_info();
+ ErrPrint("====== %p, %s\n", ptr, target->name);
+ CRITICAL_SECTION_END(&s_info.mutex);
} else {
- ErrPrint("Failed to recover\n");
- chunk = NULL; /* Do nothing */
- goto out;
+ DbgPrint("native free\n");
+ free_wrapper(ptr);
}
}
-out:
- free(chunk);
ESTIMATE_END();
- hook();
- UNLOCK();
return;
}
-static void *heap_monitor_realloc(void *__ptr, size_t size, const void *caller)
+API void *realloc(void *__ptr, size_t size)
{
void *ptr = NULL;
struct chunk *chunk;
- LOCK();
- unhook();
+ if (!size) {
+ free(__ptr);
+ } else if (!__ptr) {
+ return malloc(size);
+ }
+
ESTIMATE_START();
- if (!__ptr) {
- if (!size) {
+ /* Re-allocation */
+ if ((s_info.bloom_filter & (unsigned int)__ptr) != (unsigned int)__ptr) {
+ /* Move this to our boundary */
+
+ ptr = malloc(size);
+ if (!ptr) {
goto out;
}
- /* Allocation */
- chunk = realloc(__ptr, size + sizeof(*chunk));
- if (chunk) {
- chunk->info = find_target_info();
- chunk->size = size;
- ptr = chunk->data;
+ memcpy(ptr, __ptr, size);
- SET_PAD(ptr, 0);
- SET_STATE(ptr, VALID);
+ free_wrapper(__ptr);
+ goto out;
+ }
- if (chunk->info) {
- chunk->info->usage += size;
- }
+ if (!s_info.initialized) {
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ /*!
+ * We can do this. because allocator_free function has "void" return type.
+ * This is a small trick. ;) just for fun. Don't be mad with this trick.
+ */
+ if (!s_info.alloc_handle) {
+ s_info.alloc_handle = allocator_init((unsigned int)s_info.stack_memory, sizeof(s_info.stack_memory));
}
- } else if (size == 0) {
- /* Free */
- if (STATE(__ptr) != VALID) {
- DbgPrint("Unrecognizable chunk, do default operation\n");
- ptr = realloc(__ptr, size);
- } else {
- chunk = container_of((void *)(((char *)__ptr) - PAD(__ptr)), struct chunk, data);
- if (chunk->info) {
- chunk->info->usage -= chunk->size;
- }
+ CRITICAL_SECTION_END(&s_info.mutex);
+ }
- if (MPROBE(chunk)) {
- SET_STATE(__ptr, INVALID);
- } else {
- chunk = __ptr;
- if (MPROBE(chunk)) {
- DbgPrint("Successfully recovered\n");
- } else {
- ErrPrint("Failed to recover\n");
- ptr = NULL;
- goto out;
- }
- }
+ chunk = container_of(__ptr, struct chunk, data);
+ if (chunk->state == VALID) {
+ if (MPROBE((unsigned char *)chunk - chunk->pad)) {
+ ptr = (unsigned char *)chunk - chunk->pad;
- ptr = realloc(chunk, size);
- }
- } else {
- if (STATE(__ptr) != VALID) {
- DbgPrint("Unrecognizable chunk, do default operation\n");
- ptr = realloc(__ptr, size);
- } else {
- int pad = PAD(__ptr);
+ ptr = realloc_wrapper(ptr, size + sizeof(*chunk));
+ if (ptr) {
+ chunk = ptr;
- chunk = container_of((void *)(((char *)__ptr) - pad), struct chunk, data);
- if (MPROBE(chunk)) {
- ptr = realloc(chunk, size + sizeof(*chunk) + pad);
- if (ptr) {
- struct chunk *new_chunk = ptr;
-
- if (new_chunk->info) {
- new_chunk->info->usage -= new_chunk->size;
- new_chunk->info->usage += size;
- }
- new_chunk->size = size;
- ptr = new_chunk->data + pad;
-
- SET_STATE(ptr, VALID);
- SET_PAD(ptr, pad);
- /* Consider this, do we need to keep the alignment for realloc? */
- }
- } else {
- chunk = __ptr;
- if (!MPROBE(chunk)) {
- ErrPrint("Failed to recover\n");
- ptr = NULL;
- goto out;
+ if (chunk->info) {
+ /* Update allocation info */
+ chunk->info->usage -= chunk->size;
+ chunk->info->usage += size;
}
+ chunk->size = size;
+ chunk->pad = 0;
+ chunk->state = VALID;
- ptr = realloc(chunk, size + sizeof(*chunk));
- if (ptr) {
- void *tmp;
- struct chunk *new_chunk;
-
- tmp = malloc(size);
- if (!tmp) {
- ErrPrint("Heap: %s\n", strerror(errno));
- ptr = NULL;
- goto out;
- }
-
- memcpy(tmp, ptr, size);
- memcpy(((char *)ptr) + sizeof(*chunk), tmp, size);
- free(tmp);
-
- new_chunk = ptr;
- new_chunk->info = find_target_info();
- if (new_chunk->info) {
- new_chunk->info->usage += size;
- }
- new_chunk->size = size;
- ptr = new_chunk->data;
- SET_STATE(ptr, VALID);
- SET_PAD(ptr, 0);
-
- DbgPrint("Successfully recovered\n");
- } else {
- DbgPrint("Failed to recover\n");
- }
+ ptr = chunk->data;
}
}
+ } else if (chunk->state == STACK || allocator_in_scope(s_info.alloc_handle, __ptr)) {
+ /*!
+ * Try allocate heap first.
+ * At last, we will replace all stack based chunk with heap based chunk via "realloc".
+ */
+ ptr = malloc(size);
+ if (!ptr) {
+ goto out;
+ }
+
+ memcpy(ptr, __ptr, size);
+ allocator_free(s_info.alloc_handle, (char *)chunk - chunk->pad);
}
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ s_info.bloom_filter |= (unsigned int)ptr;
+ CRITICAL_SECTION_END(&s_info.mutex);
+
out:
ESTIMATE_END();
- hook();
- UNLOCK();
return ptr;
}
-static void *heap_monitor_memalign(size_t align, size_t __size, const void *caller)
+API void *memalign(size_t align, size_t __size)
{
void *ptr = NULL;
struct chunk *chunk;
@@ -533,66 +491,77 @@ static void *heap_monitor_memalign(size_t align, size_t __size, const void *call
return NULL;
}
- LOCK();
- unhook();
- ESTIMATE_START();
-
pad = align - (sizeof(*chunk) % align);
size = sizeof(*chunk) + pad;
- chunk = memalign(align, size + __size);
- if (!chunk) {
- goto out;
+
+ ESTIMATE_START();
+
+ if (!s_info.initialized) {
+ unsigned int aligned_offset;
+
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ if (!s_info.alloc_handle) {
+ s_info.alloc_handle = allocator_init((unsigned int)s_info.stack_memory, sizeof(s_info.stack_memory));
+ }
+ CRITICAL_SECTION_END(&s_info.mutex);
+
+ /* Make more space for alignment the address */
+ size += align;
+ ptr = allocator_alloc(s_info.alloc_handle, size + __size);
+
+ aligned_offset = align - (((unsigned int)ptr) % align);
+ chunk = (struct chunk *)((char *)ptr + aligned_offset + pad);
+
+ chunk->pad = pad + aligned_offset;
+ chunk->state = STACK;
+
+ DbgPrint("Aligned stack: %p size: %d, pad: %d, offset: %d\n", ptr, size + __size, pad, aligned_offset);
+ } else {
+ ptr = memalign_wrapper(align, size + __size);
+ if (!ptr) {
+ goto out;
+ }
+
+ chunk = (struct chunk *)((char *)ptr + pad);
+
+ chunk->pad = pad;
+ chunk->state = VALID;
}
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
chunk->info = find_target_info();
if (chunk->info) {
chunk->info->usage += __size;
}
+ CRITICAL_SECTION_END(&s_info.mutex);
chunk->size = __size;
-
- ptr = chunk->data + pad;
- SET_PAD(ptr, pad);
- SET_STATE(ptr, VALID);
+ ptr = chunk->data;
out:
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
+ s_info.bloom_filter |= (unsigned int)ptr;
+ CRITICAL_SECTION_END(&s_info.mutex);
ESTIMATE_END();
- hook();
- UNLOCK();
return ptr;
}
-static void hook(void)
+API int posix_memalign(void **memptr, size_t alignment, size_t size)
{
- s_info.hook++;
- if (s_info.hook == 1) {
- __malloc_hook = heap_monitor_malloc;
- __realloc_hook = heap_monitor_realloc;
- __memalign_hook = heap_monitor_memalign;
- __free_hook = heap_monitor_free;
+ if (!memptr) {
+ return -EINVAL;
}
+
+ *memptr = memalign(alignment, size);
+
+ return *memptr ? 0 : -ENOMEM;
}
-static void unhook(void)
+API void *vmalloc(size_t size)
{
- s_info.hook--;
- if (s_info.hook == 0) {
- __malloc_hook = s_info._malloc;
- __realloc_hook = s_info._realloc;
- __memalign_hook = s_info._memalign;
- __free_hook = s_info._free;
- }
+ return memalign(sysconf(_SC_PAGESIZE), size);
}
-/* From GNU libc 2.14 this macro is defined, to declare
- hook variables as volatile. Define it as empty for
- older glibc versions */
-#ifndef __MALLOC_HOOK_VOLATILE
- #define __MALLOC_HOOK_VOLATILE
-#endif
-
-void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook)(void) = heap_monitor_init;
-
static int iterator_cb(struct dl_phdr_info *info, size_t size, void *data)
{
struct target *target;
@@ -602,6 +571,7 @@ static int iterator_cb(struct dl_phdr_info *info, size_t size, void *data)
target = data;
if (strcmp(info->dlpi_name, target->name)) {
+ DbgPrint("\n");
return 0;
}
@@ -611,8 +581,7 @@ static int iterator_cb(struct dl_phdr_info *info, size_t size, void *data)
target->begin = info->dlpi_addr + (unsigned long)phdr->p_vaddr;
target->end = target->begin + phdr->p_memsz;
if (s_info.debugger) {
- DbgPrint("Target: %s - [%s] 0x%lX - 0x%lX\n",
- target->name, info->dlpi_name, target->begin, target->end);
+ DbgPrint("Target: %s - [%s] 0x%lX - 0x%lX\n", target->name, info->dlpi_name, target->begin, target->end);
}
break;
}
@@ -625,80 +594,88 @@ API int heap_monitor_del_target(const char *name)
{
struct dlist *l;
struct dlist *n;
- struct target *target;
- int ret;
+ struct target *target = NULL;
- LOCK();
- unhook();
- ret = -ENOENT;
+ if (!s_info.initialized) {
+ return -EINVAL;
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
dlist_foreach_safe(s_info.target_list, l, n, target) {
if (!strcmp(target->name, name)) {
s_info.target_list = dlist_remove(s_info.target_list, l);
- free(target->name);
- free(target);
s_info.target_cnt--;
- ret = 0;
break;
}
+ target = NULL;
+ }
+ CRITICAL_SECTION_END(&s_info.mutex);
+
+ if (target) {
+ DbgPrint("%s <> %s\n", target->name, name);
+ free_wrapper(target->name);
+ free_wrapper(target);
}
- hook();
- UNLOCK();
- return ret;
+ return target ? 0 : -ENOENT;
}
API int heap_monitor_add_target(const char *name)
{
struct target *target;
- int ret;
- LOCK();
- unhook();
+ if (!s_info.initialized) {
+ return -EINVAL;
+ }
- ret = 0;
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
target = find_target_by_name(name);
if (target) {
- goto out;
+ ErrPrint("Target[%s] is already exists\n", name);
+ CRITICAL_SECTION_END(&s_info.mutex);
+ return 0;
}
+ CRITICAL_SECTION_END(&s_info.mutex);
- target = malloc(sizeof(*target));
+ target = malloc_wrapper(sizeof(*target));
if (!target) {
DbgPrint("Heap: %s\n", strerror(errno));
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
- target->name = strdup(name);
+ target->name = malloc_wrapper(strlen(name));
if (!target->name) {
DbgPrint("Heap: %s\n", strerror(errno));
- free(target);
- ret = -ENOMEM;
- goto out;
+ free_wrapper(target);
+ return -ENOMEM;
}
+ strcpy(target->name, name);
target->usage = 0;
target->begin = 0;
target->end = 0;
dl_iterate_phdr(iterator_cb, target);
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
s_info.target_cnt++;
s_info.target_list = dlist_append(s_info.target_list, target);
-out:
- hook();
- UNLOCK();
- return ret;
+ CRITICAL_SECTION_END(&s_info.mutex);
+
+ DbgPrint("Target[%s] is added\n", name);
+ return 0;
}
API size_t heap_monitor_target_usage(const char *name)
{
struct target *target;
- LOCK();
- unhook();
+ size_t usage = 0;
+
+ CRITICAL_SECTION_BEGIN(&s_info.mutex);
target = find_target_by_name(name);
- hook();
- UNLOCK();
- return target ? target->usage : 0;
+ usage = target ? target->usage: 0;
+ CRITICAL_SECTION_END(&s_info.mutex);
+ return usage;
}
API int heap_monitor_initialized(void)
@@ -706,33 +683,58 @@ API int heap_monitor_initialized(void)
return s_info.initialized;
}
-API void heap_monitor_set_stack_boundary(unsigned long stack_boundary)
-{
- s_info.stack_boundary = stack_boundary;
-}
-
API void heap_monitor_init(void)
{
const char *var;
pthread_attr_t attr;
+ int ret;
if (s_info.initialized) {
return;
}
-
-#if defined(_ENABLE_MCHECK)
- s_info.m_check = mcheck(mcheck_cb);
- if (s_info.m_check < 0) {
- ErrPrint("Failed to install mcheck[%d]\n", s_info.m_check);
- } else {
- DbgPrint("mcheck installed: %d\n", s_info.m_check);
+
+ __file_log_fp = fopen("/tmp/heap_log.tmp", "w+");
+
+ if (!s_info.alloc_handle) {
+ s_info.alloc_handle = allocator_init((unsigned int)s_info.stack_memory, sizeof(s_info.stack_memory));
+ if (!s_info.alloc_handle) {
+ exit(-EFAULT);
+ }
}
-#endif
- s_info._malloc = __malloc_hook;
- s_info._realloc = __realloc_hook;
- s_info._free = __free_hook;
- s_info._memalign = __memalign_hook;
+ if (!s_info._malloc) {
+ s_info._malloc = dlsym(RTLD_NEXT, "malloc");
+ if (!s_info._malloc) {
+ ErrPrint("malloc: %s\n", dlerror());
+ exit(-EINVAL);
+ }
+ }
+ DbgPrint("malloc: %p & %p\n", s_info._malloc, malloc);
+
+ if (!s_info._free) {
+ s_info._free = dlsym(RTLD_NEXT, "free");
+ if (!s_info._free) {
+ ErrPrint("free: %s\n", dlerror());
+ exit(-EINVAL);
+ }
+ }
+ DbgPrint("free: %p & %p\n", s_info._free, free);
+
+ s_info._realloc = dlsym(RTLD_NEXT, "realloc");
+ if (!s_info._realloc) {
+ ErrPrint("realloc: %s\n", dlerror());
+ exit(-EINVAL);
+ }
+ DbgPrint("realloc: %p & %p\n", s_info._realloc, realloc);
+
+ s_info._memalign = dlsym(RTLD_NEXT, "memalign");
+ if (!s_info._memalign) {
+ ErrPrint("memalign: %s\n", dlerror());
+ exit(-EINVAL);
+ }
+ DbgPrint("memalign: %p & %p\n", s_info._memalign, memalign);
+
+ s_info.initialized = 1;
var = getenv("HEAP_MONITOR_DUMP_DEPTH");
if (var) {
@@ -745,39 +747,53 @@ API void heap_monitor_init(void)
}
s_info.main_tid = pthread_self();
- s_info.initialized = 1;
- if (pthread_getattr_np(s_info.main_tid, &attr)) {
- return;
+ ret = pthread_getattr_np(s_info.main_tid, &attr);
+ if (ret != 0) {
+ ErrPrint("destroy: %s\n", strerror(ret));
+ exit(-EINVAL);
}
- if (pthread_attr_getstack(&attr, (void *)&s_info.stack_base, &s_info.stack_size)) {
+ ret = pthread_attr_getstack(&attr, (void *)&s_info.stack_base, &s_info.stack_size);
+ if (ret) {
s_info.stack_base = 0;
s_info.stack_size = 0;
- } else {
- s_info.stack_boundary = s_info.stack_base + s_info.stack_size;
}
- pthread_attr_destroy(&attr);
- DbgPrint("Initialized\n");
+ ret = pthread_attr_destroy(&attr);
+ if (ret != 0) {
+ ErrPrint("destroy: %s\n", strerror(ret));
+ }
+
+ heap_monitor_add_target("");
+
+ DbgPrint("program text (etext): %p, "
+ "initialized data (edata): %p, "
+ "uninitialized data (end): %p, "
+ "break: %p, stack: %lu, stack_size: %u\n",
+ &etext, &edata, &end, sbrk(0), s_info.stack_base, s_info.stack_size);
+
+ return;
}
-API void heap_monitor_start(void)
+API void heap_monitor_fini(void)
{
- if (!s_info.initialized) {
- return;
+ DbgPrint("Usage: %d\n", heap_monitor_target_usage(""));
+ if (__file_log_fp) {
+ fclose(__file_log_fp);
}
-
- hook();
}
-API void heap_monitor_stop(void)
+API __attribute__((destructor)) int destructor(void)
{
- if (!s_info.initialized) {
- return;
- }
+ heap_monitor_fini();
+ return 0;
+}
- unhook();
+API __attribute__((constructor)) int constructor(void)
+{
+ heap_monitor_init();
+ return 0;
}
/* End of a file */