From: Vitaliy Cherepanov Date: Thu, 23 Jan 2014 16:14:24 +0000 (+0400) Subject: [FIX] correct processing multi-process applications X-Git-Tag: Tizen_SDK_2.3~81 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F82%2F15582%2F11;p=platform%2Fcore%2Fsystem%2Fswap-probe.git [FIX] correct processing multi-process applications On fork call reconnect to swap daemon as separate process. On call exec disconnect from swap daemon. If exec returns error connect to swap daemon again. Change-Id: I0f99b96507e2f1d52460fba5e4ed0eb997e39981 Signed-off-by: Vitaliy Cherepanov --- diff --git a/Makefile b/Makefile index decaee5..ae68397 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,8 @@ LDFLAGS = -shared -L/usr/lib/osp \ -lpthread \ -lrt +ASMFLAG = -O0 -g + ## FIXME: Ideally, UTILITY_SRCS is sources for probe infrastructure and ## PROBE_SRCS is sources for actual replacement functions. Unfortunatelly, ## it is not so easy and UTILITY_SRCS do not link alone. @@ -69,6 +71,7 @@ UTILITY_SRCS = \ ./helper/btsym.c \ ./helper/dacollection.c \ ./helper/dacapture.c \ + ./helper/daforkexec.c \ ./custom_chart/da_chart.c \ PROBE_SRCS = \ @@ -112,10 +115,13 @@ TIZEN_SRCS = $(COMMON_SRCS) \ ./probe_graphics/da_gles20_tizen.cpp \ ./probe_graphics/da_gles20_native.cpp +ASM_SRC = ./helper/da_call_original.S + ## Totally brain-dead. ## FIXME: Rewrite this normally with eval. -CAPI_OBJS = $(patsubst %.c,%.o, $(CAPI_SRCS)) -TIZEN_OBJS = $(patsubst %.cpp,%.o, $(patsubst %.c,%.o, $(TIZEN_SRCS))) +ASM_OBJ = $(patsubst %.S,%.o, $(ASM_SRC)) +CAPI_OBJS = $(patsubst %.c,%.o, $(CAPI_SRCS)) $(ASM_OBJ) +TIZEN_OBJS = $(patsubst %.cpp,%.o, $(patsubst %.c,%.o, $(TIZEN_SRCS))) $(ASM_OBJ) DUMMY_OBJS = $(patsubst %.c,%.o, $(DUMMY_SRCS)) @@ -135,6 +141,9 @@ capi: headers $(CAPI_TARGET) tizen: headers $(TIZEN_TARGET) dummy: headers $(DUMMY_TARGET) +$(ASM_OBJ): $(ASM_SRC) + $(CC) $(ASMFLAG) -c $^ -o $@ + GENERATED_HEADERS = include/api_id_mapping.h include/api_id_list.h include/id_list headers: $(GENERATED_HEADERS) diff --git a/helper/da_call_original.S b/helper/da_call_original.S new file mode 100644 index 0000000..11119bc --- /dev/null +++ b/helper/da_call_original.S @@ -0,0 +1,238 @@ +/* + * DA probe + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Vitaliy Cherepanov + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ + +/* + * function + * _da_call_original(void *funcp, char *args[], int args_count); + * + * arguments: + * funcp - function pointer address to call + * args - params array for function + * args_count - params count + * return values: + * depends on original function (funcp) + * + * use this function to call original function with variable arguments count + * in ld-preloaded probes + * + * example: + * #include + * #include + * + * typedef int (*execl_type)(const char *path, const char *arg, ...); + * static execl_type execl_real; + * //.... + * //_da_call_original function prototype + * int call_original(void *funcp, char *args[], int args_count); + * //... + * execl_real = (execl_type)dlsym(RTLD_NEXT , "execl"); + * //... + * //probe execl + * int execl(const char *path, const char *arg, ...) + * { + * int res = 0; + * va_list ap; + * int args_count = 0, i; + * + * //additional argumets list terminates with NULL pointer on execl call + * //calculate arguments count with terminate NULL + * va_start(ap, arg); + * do + * args_count++; + * while (va_arg(ap, char *) != 0); + * va_end(ap); + * + * //add 2 for and params + * args_count += 2; + * + * //create and fill args arras + * char *all_args[args_count]; + * + * va_start(ap, arg); + * + * all_args[0] = (char *)path; + * all_args[1] = (char *)arg; + * for (i = 2; i < args_count; i++) + * all_args[i] = va_arg(ap, char *); + * //do something + * //..... + * //call original function + * res = _da_call_original(&execl_real, all_args, args_count); + * //do something + * //...... + * return res; + * + * } + * + * this function is written in asm because there is no other way to prepare + * variable count of arguments for original function call + */ + +#define stack_size 0x40 + +#if defined(__x86_64__) + /* x86 64-bit ----------------------------------------------- */ + +.text +.global _da_call_original +.type _da_call_original, @function +_da_call_original: + mov $-1, %rax + ret +#elif defined(__i386) + +.text +.global _da_call_original +.type _da_call_original, @function +_da_call_original: + #save stack position + push %ebp + mov %esp, %ebp + + #create local stack + sub $stack_size, %esp + + #store registers + push %ebx + push %ecx + push %edx + + #load args array pointer + movl 0xc(%ebp),%ecx + #load args_count + movl 0x10(%ebp), %ebx + + #calculate stack size for original function call + #stack size = (args_count) * 4 + shl $2, %ebx + #create stack for original function call + sub %ebx, %esp + + #push all arguments to stack + #for (i = 0; i < args_count; i++) { + movl $0, %eax + jmp for_i_cmp + for_i: + #args[i] -> stack + mov (%ecx), %edx + mov %edx, (%esp) + #stack++ + add $4, %esp + add $4, %ecx + add $4, %eax + for_i_cmp: + cmpl %ebx, %eax + jl for_i + #} + + #shift stack back + sub %ebx, %esp + + #call original function (funcp) + movl 8(%ebp), %eax + call *(%eax) + #now function result in %eax + + #restore stack after call function + add %ebx, %esp + + #restore registers + pop %edx + pop %ecx + pop %ebx + + #restore local stack + add $stack_size, %esp + #return + pop %ebp + ret + +#elif defined(__arm__) +.text +.global _da_call_original +.type _da_call_original, %function + +_da_call_original: + push {fp, lr, r5, r6, r7, r8} + #create local stack + add fp, sp, #4 + sub sp, sp, #stack_size + #store params to stack + str r0, [fp, #-12] + str r1, [fp, #-16] + str r2, [fp, #-20] + + #load args array pointer + ldr r5, [fp, #-16] + #load args_count + ldr r6, [fp, #-20] + + #calculate stack size for original function call + #stack size = (args_count) * 4 + lsl r6, r6, #2 + #create stack for original function call + sub sp, sp, r6 + #first 4 params pass throw r0-r3 + #so move stack to 4 words + sub sp, sp, #16 + + #for (i = 4; i < arg; i++) { + mov r7, #16 + b for_i_cmp + for_i: + #args[i] -> stack[i] + ldr r8, [r5, r7] + str r8, [sp, r7] + add r7, r7, #4 + for_i_cmp: + cmp r7, r6 + blt for_i + #} + + #move stack pointer back to 4 words + add sp, sp, #16 + #load first 4 args + ldr r0, [r5, #0 ] + ldr r1, [r5, #4 ] + ldr r2, [r5, #8 ] + ldr r3, [r5, #12] + + #call original function (funcp) + ldr r5, [fp, #-12] + ldr r5, [r5] + blx r5 + #now function result in r0 + + #restore stack after original fincion call + add sp, sp, r6 + + #local stack restore + add sp, sp, #stack_size + #return + pop {fp, pc, r5, r6, r7, r8} +#endif diff --git a/helper/daforkexec.c b/helper/daforkexec.c new file mode 100644 index 0000000..e439bc0 --- /dev/null +++ b/helper/daforkexec.c @@ -0,0 +1,241 @@ +/* + * DA probe + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Vitaliy Cherepanov + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ +#include +#include + +#include "daprobe.h" +#include "dahelper.h" +#include "binproto.h" +#include "daforkexec.h" + +DECLARE(int, execl , const char *path, const char *arg, ...); +DECLARE(int, execlp, const char *file, const char *arg, ...); +DECLARE(int, execle, const char *path, const char *arg, ...);//, char * const envp[]); +DECLARE(int, execv, const char *path, char *const argv[]); +DECLARE(int, execve, const char *filename, char *const argv[],char *const envp[]); +DECLARE(int, execvp, const char *file, char *const argv[]); +DECLARE(int, execvpe, const char *file, char *const argv[],char *const envp[]); +DECLARE(pid_t, fork, void); + +void init_exec_fork() +{ + INIT_FUNC_EXEC(fork); + INIT_FUNC_EXEC(execl); + INIT_FUNC_EXEC(execlp); + INIT_FUNC_EXEC(execle); + INIT_FUNC_EXEC(execv); + INIT_FUNC_EXEC(execve); + INIT_FUNC_EXEC(execvp); + INIT_FUNC_EXEC(execvpe); +} + +#define prepare_params( FUNCTION , p1, p2) \ + va_list ap; \ + int args_count = 0; \ + int i; \ + \ + INIT_FUNC_EXEC( FUNCTION ); \ + \ + va_start(ap, p2); \ + do \ + args_count++; \ + while (va_arg(ap, char *)); \ + va_end(ap); \ + args_count += 2 + 1; \ + \ + char *arg_arr[args_count]; \ + \ + va_start(ap, p2); \ + \ + arg_arr[0] = (char *)p1; \ + arg_arr[1] = (char *)p2; \ + for (i = 2; i < args_count; i++) \ + arg_arr[i] = va_arg(ap, char *); \ + \ + va_end(ap) + +int _da_call_original(void *funcp, char *args[], int args_count); + +#define print_params(buf, p1, p2) \ + char *p = buf; \ + char *pp; \ + va_list par; \ + p += sprintf(p, "--> %s ", __FUNCTION__); \ + p += sprintf(p, "[%d]: <", getpid()); \ + p += sprintf(p, " \"%s\",", p1); \ + p += sprintf(p, " \"%s\",", p2); \ + va_start(par, p2); \ + while ( (pp = va_arg(par, char *)) != NULL) \ + p += sprintf(p, " \"%s\",", pp); \ + va_end(par); \ + p += sprintf(p, ">"); + +int execl(const char *path, const char *arg, ...) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execl [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + prepare_params(execl, path, arg); + res = _da_call_original(&execl_p, arg_arr, args_count); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +int execlp(const char *file, const char *arg, ...) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execlp [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + prepare_params(execlp, file, arg); + res = _da_call_original(&execlp_p, arg_arr, args_count); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +int execle(const char *path, const char *arg, ... + /* original func have one more argument but + * i can't leave it in code by compilation reasons + * so it is commented: + * + *,__attribute__((unused)) char * const envp[] */ + ) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execle [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + prepare_params(execle, path, arg); + res = _da_call_original(&execle_p, arg_arr, args_count); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +int execv(const char *path, char *const argv[]) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execv [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + res = execv_p(path, argv); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +int execvp(const char *file, char *const argv[]) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execvp [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + res = execvp_p(file, argv); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +int execve(const char *filename, char *const argv[],char *const envp[]) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execve [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + res = execve_p(filename, argv, envp); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +int execvpe(const char *file, char *const argv[],char *const envp[]) +{ + int res; + char buf[DA_LOG_MAX]; + + sprintf(buf, "execvpe [%d] ", getpid()); + PRINTMSG(buf); + + _uninit_(); + res = execvpe_p(file, argv, envp); + _init_(); + + sprintf(buf, "%s return %d [%d]", __FUNCTION__, res, getpid()); + PRINTMSG(buf); + return res; +} + +pid_t fork(void) +{ + char msg[DA_LOG_MAX]; + pid_t res = fork_p(); + + sprintf(msg, "", res); + if (res == 0) { + if (gTraceInfo.socket.daemonSock >= 0) { + close(gTraceInfo.socket.daemonSock); + _init_(); + } + } + PRINTMSG(msg); + + return res; +} diff --git a/helper/daforkexec.h b/helper/daforkexec.h new file mode 100644 index 0000000..320f6c1 --- /dev/null +++ b/helper/daforkexec.h @@ -0,0 +1,47 @@ +/* + * DA probe + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * + * Vitaliy Cherepanov + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Contributors: + * - Samsung RnD Institute Russia + * + */ +#ifndef __DAFORKEXEC_H_ +#define __DAFORKEXEC_H_ + +#define INIT_FUNC_EXEC(FUNCNAME) \ + if(!FUNCNAME##_p) { \ + void *tmpPtr = dlsym(RTLD_NEXT , #FUNCNAME); \ + if (tmpPtr == NULL || dlerror() != NULL) { \ + perror("dlsym failed : " #FUNCNAME); \ + exit(0); \ + } \ + memcpy(&FUNCNAME##_p, &tmpPtr, sizeof(tmpPtr)); \ + } + +#define DECLARE(RET, FUNCTION, ...) \ + typedef RET (* FUNCTION ## _p_t)(__VA_ARGS__); \ + static FUNCTION ## _p_t FUNCTION ## _p = 0 + +void init_exec_fork(); + +#endif /* __DAFORKEXEC_H_ */ diff --git a/helper/libdaprobe.c b/helper/libdaprobe.c index 8473392..bcf87d6 100755 --- a/helper/libdaprobe.c +++ b/helper/libdaprobe.c @@ -58,6 +58,7 @@ #include "daprobe.h" #include "binproto.h" +#include "daforkexec.h" #define APP_INSTALL_PATH "/opt/apps" #define TISEN_APP_POSTFIX ".exe" @@ -113,6 +114,11 @@ static int createSocket(void) (struct sockaddr *)&clientAddr, clientLen) >= 0) { char buf[64]; + /* send pid */ + sprintf(buf, "%d|%llu", getpid(), + gTraceInfo.app.startTime); + printLogStr(buf, MSG_PID); + /* recv initial configuration value */ recvlen = recv(gTraceInfo.socket.daemonSock, &log, sizeof(log.type) + sizeof(log.length), @@ -144,9 +150,6 @@ static int createSocket(void) /* closed by other peer */ } - sprintf(buf, "%d|%llu", getpid(), - gTraceInfo.app.startTime); - printLogStr(buf, MSG_PID); PRINTMSG("createSocket connect() success\n"); } else { close(gTraceInfo.socket.daemonSock); @@ -361,10 +364,12 @@ static int create_recv_thread() return err; } -void __attribute__((constructor)) _init_probe() +void _init_(void) { + char msg[DA_LOG_MAX]; probeBlockStart(); + init_exec_fork(); initialize_hash_table(); initialize_screencapture(); @@ -383,19 +388,33 @@ void __attribute__((constructor)) _init_probe() } - PRINTMSG("dynamic analyzer probe helper so loading...\n"); + sprintf(msg, "dynamic analyzer probe helper so loading... pid[%d]\n", + getpid()); + PRINTMSG(msg); gTraceInfo.init_complete = 1; probeBlockEnd(); + } -void __attribute__((destructor)) _fini_probe() +void __attribute__((constructor)) _init_probe() +{ + _init_(); + char msg[DA_LOG_MAX]; + sprintf(msg, "<-lib construnctor"); + PRINTMSG(msg); +} + +void _uninit_(void) { int i; + char msg[DA_LOG_MAX]; probeBlockStart(); gTraceInfo.init_complete = -1; - PRINTMSG("dynamic analyzer probe helper so unloading...\n"); + sprintf(msg, "dynamic analyzer probe helper so unloading... pid[%d]\n", + getpid()); + PRINTMSG(msg); remove_all_glist(); @@ -428,6 +447,14 @@ void __attribute__((destructor)) _fini_probe() probeBlockEnd(); } +void __attribute__((destructor)) _fini_probe() +{ + char msg[DA_LOG_MAX]; + sprintf(msg, "->lib destructor. pid[%d]\n", getpid()); + PRINTMSG(msg); + _uninit_(); +} + /************************************************************************** * Helper APIs diff --git a/include/binproto.h b/include/binproto.h index db5601c..ca9cb44 100644 --- a/include/binproto.h +++ b/include/binproto.h @@ -424,4 +424,7 @@ static char __attribute__((used)) *pack_ret(char *to, char ret_type, ...) /* return 0; */ /* } */ +extern void _init_(void); +extern void _uninit_(void); + #endif /* __BIN_PROTO_H__ */