INCLUDE_CPPFLAGS = \
-I./include \
+ -I./src \
-I./probe_thread \
-I./probe_event \
-I./probe_capi \
CFLAGS+= -DPROBELIB_SCREENSHOT=\"$(PROBELIB_SCREENSHOT)\"
CFLAGS+= -DPROBELIB_UI=\"$(PROBELIB_UI)\"
CFLAGS+= -DPROBELIB_LSAN=\"$(PROBELIB_LSAN)\"
+CFLAGS+= -DLIBCORE_PATH=\"$(LIBDIR)/libswapcore.so\"
+CFLAGS+= -DLIBLSAN_PATH=\"$(LIBDIR)/liblsan.so\"
CFLAGS+= -DPROBELIB_UIHV=\"$(PROBELIB_UIHV)\"
CPPFLAGS = $(INCLUDE_CPPFLAGS) -D_GNU_SOURCE -fPIC
#define UDS_NAME "/run/swap/lib.socket"
#define TIMERFD_INTERVAL 100000000 /* 0.1 sec */
+static bool g_lsan_is_enabled = false;
pid_t gPid = -1;
__thread pid_t gTid = -1;
_process_target_bins_remove((char *)log->data, log->length);
} else if (log->type == APP_MSG_STOP) {
/* Do leaks check if LSan is enabled. */
- leak_check();
+ if (g_lsan_is_enabled)
+ leak_check();
/* Send acknowlege message to manager */
printLog(log, APP_MSG_STOP);
return 1;
} else if (log->type == APP_MSG_STOP_WITHOUT_KILL) {
/* Do leaks check if LSan is enabled. */
- leak_check();
+ if (g_lsan_is_enabled)
+ leak_check();
/* Send acknowlege message to manager */
printLog(log, APP_MSG_STOP);
update_heap_memory_size(true, 0);
}
- lsan_init();
+ if (isOptionEnabled(FL_LSAN, 0)) {
+ g_lsan_is_enabled = lsan_init();
+ if (!g_lsan_is_enabled)
+ LOGE("Cannot init LSan\n");
+ }
+
process_features();
PRINTMSG("dynamic analyzer probe helper so loading... pid[%d]\n",
/* init library */
_init_();
- /* register LSan report callback for app closing case */
- ret = atexit(leak_check);
- if (ret)
- PRINTERR("Cannot register leak_check(), ret=%d\n", ret);
+ if (g_lsan_is_enabled) {
+ /* register LSan report callback for app closing case */
+ ret = atexit(leak_check);
+ if (ret)
+ PRINTERR("Cannot register leak_check(), ret=%d\n", ret);
+ }
PRINTMSG("<-lib construnctor");
}
{
int i;
- lsan_uninit();
+ if (g_lsan_is_enabled) {
+ lsan_uninit();
+ g_lsan_is_enabled = false;
+ }
+
cleanup_binaries();
gTraceInfo.init_complete = -1;
*
*/
-#include <stdio.h>
-#include <string.h>
-#include <ulimit.h>
-#include <assert.h>
+#include <dlfcn.h>
#include "lsan_open.h"
+#include "log.h"
#include "binproto.h"
-#include "daprobe.h"
-#include "dahelper.h"
#include "file_buffer.h"
-#include "lsan/lsan_interface.h"
+#include "core/core.h"
-#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
-
-
-static void *liblsan_handle;
-int lsan_init_succeeded;
-
enum lsan_status {
LSAN_MSG_ERR = 0x0,
LSAN_MSG_STATUS = 0x1,
LSAN_INIT_DONE = 0x4
};
-typedef enum lsan_status lsan_status;
-typedef int (*lsan_int_fun)();
-typedef const void *(*lsan_const_void_star_fun)();
-typedef struct LeakedObject LeakedObject;
-
-
-static const char *const sym_name_table[] = {
- /* libc interceptors */
- "__interceptor_malloc",
- "__interceptor_calloc",
- "__interceptor_realloc",
- "__interceptor_free",
- "__interceptor_posix_memalign",
- "__interceptor_strdup",
-
- /* pthread interceptors */
- "__interceptor_pthread_create",
- "__interceptor_pthread_join",
-};
-
-static_assert(LSAN_SID_CNT == ARRAY_SIZE(sym_name_table),
- "LSan: Incorrect table of symbol names");
-
-static void *sym_table[LSAN_SID_CNT];
-
-static bool sym_table_init(void *lsan_handle)
-{
- for (size_t i = 0; i < ARRAY_SIZE(sym_table); ++i) {
- const char *sym_name = sym_name_table[i];
- void *addr = dlsym(lsan_handle, sym_name);
- if (addr) {
- PRINTMSG("Loaded LSan symbol %s at address %p",
- sym_name, addr);
- } else {
- PRINTERR("Cannot found LSan symbol: %s", sym_name);
- return false;
- }
-
- sym_table[i] = addr;
- }
-
- return true;
-}
-
-static void sym_table_uninit()
-{
- for (size_t i = 0; i < ARRAY_SIZE(sym_table); ++i)
- sym_table[i] = NULL;
-}
-
-void *lsan_sym(enum lsan_sym_id id)
-{
- unsigned int idx = id;
-
- if (idx < ARRAY_SIZE(sym_table))
- return sym_table[idx];
-
- PRINTERR("LSan: Incorrect sym_id: %u", idx);
- return NULL;
-}
-
static size_t pack_report_msg(char *p, const char *path, size_t *path_offset)
{
return p - msg_buf;
}
-static void send_msg_to_host(const char *msg, lsan_status status)
+static void send_msg_to_host(const char *msg, enum lsan_status status)
{
char *msg_buf = (char *)malloc(MAX_LOCAL_BUF_SIZE);
char *p = msg_buf;
free(report_msg);
}
-static char *get_report_file_name()
-{
- const char report_file_name_base[] = "/run/swap/tmp/lsan.log";
- static char report_file_name[MAX_PATH_LENGTH];
- snprintf(report_file_name, MAX_PATH_LENGTH, "%s.%d",
- report_file_name_base, _getpid());
- return report_file_name;
-}
-bool lsan_init()
+static void *LIBCORE_handle;
+static int (*LIBCORE_API__swap_init)(struct core_init_info *init_info);
+static int (*LIBCORE_API__swap_lsan_adapter_init)(const char *lsan_path);
+static void (*LIBCORE_API__swap_lsan_adapter_leak_check)();
+static const char *(*LIBCORE_API__swap_lsan_adapter_report_file)();
+
+static bool libcore_api_init(void *handle)
{
- if (!isOptionEnabled(FL_LSAN, 0))
- return false;
+ const char *sym_name;
- if (!isOptionEnabled(FL_MEMORY_ALLOC_ALWAYS_PROBING, 0)) {
- PRINTERR("lsan cannot operate "
- "with disabled alloc always feature");
- return false;
- }
+ sym_name = "__swap_init";
+ LIBCORE_API__swap_init = (void *)dlsym(handle, sym_name);
+ if (!LIBCORE_API__swap_init)
+ goto fail_dlsym;
- liblsan_handle = dlopen(PROBELIB_LSAN, RTLD_NOW);
- if (liblsan_handle == NULL) {
- PRINTERR("Cannot dlopen due to reason: %s!",
- PROBELIB_LSAN, dlerror());
- return false;
- }
+ sym_name = "__swap_lsan_adapter_init";
+ LIBCORE_API__swap_lsan_adapter_init = (void *)dlsym(handle, sym_name);
+ if (!LIBCORE_API__swap_lsan_adapter_init)
+ goto fail_dlsym;
- bool ret = sym_table_init(liblsan_handle);
- if (!ret) {
- dlclose(liblsan_handle);
- liblsan_handle = NULL;
- }
+ sym_name = "__swap_lsan_adapter_leak_check";
+ LIBCORE_API__swap_lsan_adapter_leak_check = (void *)dlsym(handle, sym_name);
+ if (!LIBCORE_API__swap_lsan_adapter_leak_check)
+ goto fail_dlsym;
- lsan_init_succeeded = 1;
- send_msg_to_host("da_swap_lsan.so init done!\n",
- LSAN_MSG_STATUS | LSAN_INIT_DONE);
+ sym_name = "__swap_lsan_adapter_report_file";
+ LIBCORE_API__swap_lsan_adapter_report_file = (void *)dlsym(handle, sym_name);
+ if (!LIBCORE_API__swap_lsan_adapter_report_file)
+ goto fail_dlsym;
return true;
-}
-void lsan_uninit()
-{
- if (liblsan_handle) {
- sym_table_uninit();
- dlclose(liblsan_handle);
- }
+fail_dlsym:
+ LOGE("Symbol '%s' not found!", sym_name);
+ return false;
}
-static int lsan_call_int_cb(const char *func_name)
+bool lsan_init()
{
- int result = -1;
- lsan_int_fun callback = (lsan_int_fun)lsan_get_sym(func_name);
+ LIBCORE_handle = dlopen(LIBCORE_PATH, RTLD_NOW);
+ if (LIBCORE_handle == NULL) {
+ LOGI("Cannot dlopen %s due to reason: %s!",
+ LIBCORE_PATH , dlerror());
+ return false;
+ }
+ PRINTMSG("Libcore has been opened: %s", LIBCORE_handle);
- if (callback) {
- PRINTMSG("Calling lsan callback %s\n", func_name);
- result = callback();
+ if (!libcore_api_init(LIBCORE_handle)) {
+ LOGE("Cannot init libcore API");
+ goto fail;
}
- return result;
-}
-static void send_leaked_objects_to_host(int leaked_objects_num,
- LeakedObject *leaked_objects)
-{
- int i;
- unsigned long res = 0;
- const char *report_file_name = get_report_file_name();
- FILE *report_file = fopen(report_file_name, "w+");
-
- if (!report_file) {
- PRINTERR(
- "Cannot open tmp file for LSan report due to reason: %s\n!",
- strerror(errno));
- send_msg_to_host("Failed to open LSan report file!\n",
- LSAN_MSG_ERR);
- return;
+ struct core_init_info init_info = {
+ .vraw_log = (void (*)(int, const char *, va_list))vraw_log,
+ };
+
+ if (LIBCORE_API__swap_init(&init_info)) {
+ LOGE("Cannot init libcore!");
+ goto fail;
}
- for (i = 0; i < leaked_objects_num; ++i) {
- res += leaked_objects[i].size;
- fprintf(report_file, "%lu %lu %u\n", leaked_objects[i].addr,
- leaked_objects[i].size,
- leaked_objects[i].first_four_bytes);
+ if (LIBCORE_API__swap_lsan_adapter_init(LIBLSAN_PATH)) {
+ LOGE("Cannot init LSan adapter");
+ goto fail;
}
- fclose(report_file);
+ send_msg_to_host("LSan init done!", LSAN_MSG_STATUS | LSAN_INIT_DONE);
+ LOGI("LSan initialized");
+ return true;
- send_report_to_manager(report_file_name);
+fail:
+ send_msg_to_host("Failed to init LSan library!", LSAN_MSG_ERR);
+ dlclose(LIBCORE_handle);
+ LIBCORE_handle = NULL;
+ return false;
}
-static void report_leaked_chunks(int leaked_objects_num)
+void lsan_uninit()
{
- lsan_const_void_star_fun func = (lsan_const_void_star_fun)lsan_get_sym(
- "__lsan_get_leaked_objects_ptr");
-
- if (func) {
- LeakedObject *leaked_objects = (LeakedObject *)func();
- send_leaked_objects_to_host(leaked_objects_num, leaked_objects);
+ if (LIBCORE_handle) {
+ dlclose(LIBCORE_handle);
+ LIBCORE_handle = NULL;
}
}
void lsan_do_leak_check()
{
- if (!liblsan_handle)
- return;
-
- lsan_call_int_cb("__lsan_do_recoverable_leak_check");
-
- int leaked_objects_num =
- lsan_call_int_cb("__lsan_get_leaked_objects_num");
+ const char *report_file;
- if (leaked_objects_num != -1)
- report_leaked_chunks(leaked_objects_num);
- else
- send_msg_to_host("Error occurred during "
- "__lsan_get_leaked_objects_num!\n",
- LSAN_MSG_ERR);
-}
-
-void *lsan_get_sym(const char *symbol_name)
-{
- if (!liblsan_handle) {
- PRINTERR("liblsan.so wasn't loaded, get_sym_from_lsan for %s "
- "failed!\n",
- symbol_name);
- return NULL;
+ if (!LIBCORE_handle) {
+ LOGE("LSan library is not initialized!");
+ return;
}
- void *sym = dlsym(liblsan_handle, symbol_name);
- if (!sym)
- PRINTERR("Failed to get symbol %s from liblsan.so due to "
- "reason %s!\n",
- symbol_name, dlerror());
- else
- PRINTMSG("Loaded symbol %s at address %p\n", symbol_name, sym);
+ LIBCORE_API__swap_lsan_adapter_leak_check();
+ report_file = LIBCORE_API__swap_lsan_adapter_report_file();
+ LOGI("Created LSan report file: %s", report_file);
+ send_report_to_manager(report_file);
- return sym;
+ /*
+ * Remove the LSan report file because only
+ * this application can remove it.
+ */
+ LOGI("Remove LSan report file: %s", report_file);
+ if (remove(report_file) == -1) {
+ char buf[128];
+ LOGE("Cannot remove report file, errno=%d (%s)",
+ errno, strerror_r(errno, buf, sizeof(buf)));
+ }
}
# include <stdbool.h>
#endif
-enum lsan_sym_id {
- /* libc symbols ID */
- LSAN_SID_MALLOC,
- LSAN_SID_CALLOC,
- LSAN_SID_REALLOC,
- LSAN_SID_FREE,
- LSAN_SID_POSIX_MEMALIGN,
- LSAN_SID_STRDUP,
-
- /* pthread symbols ID */
- LSAN_SID_PTHREAD_CREATE,
- LSAN_SID_PTHREAD_JOIN,
-
- /* number of symbols */
- LSAN_SID_CNT
-};
-
-extern int lsan_init_succeeded;
-
bool lsan_init();
void lsan_uninit();
-void *lsan_sym(enum lsan_sym_id id);
void lsan_do_leak_check();
-/* TODO: Deprecated function, remove it. */
-void *lsan_get_sym(const char *symbol_name);
-
#ifdef __cplusplus
}
#endif
This library will be installed in target.
%package -n swap-probe
+Requires: liblsan
Requires: swap-probe-lsan
Provides: swap-probe
Summary: SWAP probe library
#include "binproto.h"
#include "memory_probes_list.h"
#include "probe_memory.h"
-#include "lsan_open.h"
HANDLER_WRAPPERS(memory_feature, void *, malloc, size_t, size)
{
- /* TODO Split LSan */
- static void* (*lsan_mallocp)(size_t);
- void* (*mallocp)(size_t);
- DECLARE_VARIABLE_STANDARD;
void *pret;
-
- if (lsan_init_succeeded && lsan_mallocp == NULL)
- lsan_mallocp = lsan_sym(LSAN_SID_MALLOC);
-
- /* If LSan is used - call LSan allocator instead of origin */
- mallocp = lsan_init_succeeded ? lsan_mallocp :
- (void *)PROBE_GET_FUNC(probe_data);
-
+ void *(*mallocp)(size_t) = (void *)PROBE_GET_FUNC(probe_data);
+ DECLARE_VARIABLE_STANDARD;
PRE_PROBEBLOCK();
pret = (*mallocp)(size);
HANDLER_WRAPPERS_VOID(memory_feature, void, free, void*, ptr)
{
- /* TODO Split LSan */
- static void (*lsan_freep)(void *);
- void (*freep)(void *);
+ void (*freep)(void *) = (void *)PROBE_GET_FUNC(probe_data);
DECLARE_VARIABLE_STANDARD;
-
- if (lsan_init_succeeded && lsan_freep == NULL)
- lsan_freep = lsan_sym(LSAN_SID_FREE);
-
- /* If LSan is used - call LSan free instead of origin */
- freep = lsan_init_succeeded ? lsan_freep :
- (void *)PROBE_GET_FUNC(probe_data);
-
PRE_PROBEBLOCK();
if (ptr)
HANDLER_WRAPPERS(memory_feature, void *, realloc, void *, memblock,
size_t, size)
{
- /* TODO Split LSan */
- static void* (*lsan_reallocp)(void*, size_t);
- void* (*reallocp)(void*, size_t);
- DECLARE_VARIABLE_STANDARD;
void *pret;
-
- if (lsan_init_succeeded && lsan_reallocp == NULL)
- lsan_reallocp = lsan_sym(LSAN_SID_REALLOC);
-
- /* If LSan is used - call LSan realloc instead of origin */
- reallocp = lsan_init_succeeded ? lsan_reallocp :
- (void *)PROBE_GET_FUNC(probe_data);
+ void *(*reallocp)(void *, size_t) = (void *)PROBE_GET_FUNC(probe_data);
+ DECLARE_VARIABLE_STANDARD;
PRE_PROBEBLOCK();
if (memblock)
HANDLER_WRAPPERS(memory_feature, void *, calloc, size_t, nelem, size_t, elsize)
{
- /* TODO Split LSan */
- static void* (*lsan_callocp)(size_t, size_t);
- void* (*callocp)(size_t, size_t);
- DECLARE_VARIABLE_STANDARD;
void *pret;
+ void *(*callocp)(size_t, size_t) = (void *)PROBE_GET_FUNC(probe_data);
+ DECLARE_VARIABLE_STANDARD;
+ PRE_PROBEBLOCK();
/* TODO Support old preload */
// if (!callocp) {
// callocp = rtdl_next("calloc");
// }
- if (lsan_init_succeeded && lsan_callocp == NULL)
- lsan_callocp = lsan_sym(LSAN_SID_CALLOC);
-
- /* If LSan is used - call LSan calloc instead of origin */
- callocp = lsan_init_succeeded ? lsan_callocp :
- (void *)PROBE_GET_FUNC(probe_data);
-
- PRE_PROBEBLOCK();
-
pret = (*callocp)(nelem, elsize);
if (pret)
HANDLER_WRAPPERS(memory_feature, int, posix_memalign, void**, memptr,
size_t, alignment, size_t, size)
{
- /* TODO Split LSan */
- static int (*lsan_posix_memalignp)(void **, size_t, size_t);
- int (*posix_memalignp)(void **, size_t, size_t);
- DECLARE_VARIABLE_STANDARD;
int iret;
-
- if (lsan_init_succeeded && lsan_posix_memalignp == NULL)
- lsan_posix_memalignp = lsan_sym(LSAN_SID_POSIX_MEMALIGN);
-
- /* If LSan is used - call LSan calloc instead of origin */
- posix_memalignp = lsan_init_succeeded ?
- lsan_posix_memalignp :
- (void *)PROBE_GET_FUNC(probe_data);
-
+ int (*posix_memalignp)(void **, size_t, size_t) =
+ (void *)PROBE_GET_FUNC(probe_data);
+ DECLARE_VARIABLE_STANDARD;
PRE_PROBEBLOCK();
iret = (*posix_memalignp)(memptr, alignment, size);
HANDLER_WRAPPERS(memory_feature, char *, strdup, const char*, s)
{
- /* TODO Split LSan */
- static char* (*lsan_strdupp)(const char *);
- char* (*strdupp)(const char *);
- DECLARE_VARIABLE_STANDARD;
char *pret;
int size = strlen(s);
-
- if (lsan_init_succeeded && lsan_strdupp == NULL)
- lsan_strdupp = lsan_sym(LSAN_SID_STRDUP);
-
- /* If LSan is used - call LSan strdup instead of origin */
- strdupp = lsan_init_succeeded ? lsan_strdupp :
- (void *)PROBE_GET_FUNC(probe_data);
-
+ char *(*strdupp)(const char *) = (void *)PROBE_GET_FUNC(probe_data);
+ DECLARE_VARIABLE_STANDARD;
PRE_PROBEBLOCK();
pret = (*strdupp)(s);
#include "binproto.h"
#include "thread_probes_list.h"
#include "probe_thread.h"
-#include "lsan_open.h"
-
typedef struct thread_routine_call_t {
const pthread_attr_t *, attr, start_routine_t, start_routine,
void *, arg)
{
- /* TODO Split LSan */
- static int (*lsan_pthread_createp)(pthread_t *thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg);
int (*pthread_createp)(pthread_t *thread,
const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg);
+ void *(*start_routine)(void *), void *arg) =
+ (void *)PROBE_GET_FUNC(probe_data);
DECLARE_VARIABLE_STANDARD;
- if (lsan_init_succeeded && lsan_pthread_createp == NULL)
- lsan_pthread_createp = lsan_sym(LSAN_SID_PTHREAD_CREATE);
-
- pthread_createp = lsan_init_succeeded ? lsan_pthread_createp :
- (void *)PROBE_GET_FUNC(probe_data);
-
PRE_PROBEBLOCK();
if (blockresult) {
HANDLER_WRAPPERS(thread_feature, int , pthread_join, pthread_t, thread,
void **, retval)
{
- /* TODO Split LSan */
- static int (*lsan_pthread_joinp)(pthread_t thread, void **retval);
- int (*pthread_joinp)(pthread_t thread, void **retval);
+ int (*pthread_joinp)(pthread_t thread, void **retval) =
+ (void *)PROBE_GET_FUNC(probe_data);
DECLARE_VARIABLE_STANDARD;
- if (lsan_init_succeeded && lsan_pthread_joinp == NULL)
- lsan_pthread_joinp = lsan_sym(LSAN_SID_PTHREAD_JOIN);
-
- pthread_joinp = lsan_init_succeeded ? lsan_pthread_joinp :
- (void *)PROBE_GET_FUNC(probe_data);
-
PRE_PROBEBLOCK_BEGIN();
PREPARE_LOCAL_BUF();
void *memcpy(void *dest, const void *src, uptr n) noexcept
{
- char *d = (char*)dest;
+ char *d = (char *)dest;
const char *s = (const char *)src;
for (uptr i = 0; i < n; ++i)
d[i] = s[i];