[FIX] correct processing multi-process applications 82/15582/11
authorVitaliy Cherepanov <v.cherepanov@samsung.com>
Thu, 23 Jan 2014 16:14:24 +0000 (20:14 +0400)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Fri, 28 Mar 2014 07:17:11 +0000 (00:17 -0700)
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 <v.cherepanov@samsung.com>
Makefile
helper/da_call_original.S [new file with mode: 0644]
helper/daforkexec.c [new file with mode: 0644]
helper/daforkexec.h [new file with mode: 0644]
helper/libdaprobe.c
include/binproto.h

index decaee5..ae68397 100644 (file)
--- 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 (file)
index 0000000..11119bc
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *  DA probe
+ *
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * 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
+ *  <some ret type> _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 <dlfcn.h>
+ *     #include <dlsym.h>
+ *
+ *     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 <path> and <arg> 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 (file)
index 0000000..e439bc0
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *  DA probe
+ *
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * 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 <sys/types.h>
+#include <signal.h>
+
+#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, "<fork = %d>", 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 (file)
index 0000000..320f6c1
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  DA probe
+ *
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Vitaliy Cherepanov <v.cherepanov@samsung.com>
+ *
+ * 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_ */
index 8473392..bcf87d6 100755 (executable)
@@ -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
index db5601c..ca9cb44 100644 (file)
@@ -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__ */