4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
8 * Jaewon Lim <jaewon81.lim@samsung.com>
9 * Woojin Jung <woojin2.jung@samsung.com>
10 * Juyoung Kim <j0.kim@samsung.com>
11 * Nikita Kalyazin <n.kalyazin@samsung.com>
12 * Anastasia Lyupa <a.lyupa@samsung.com>
14 * This library is free software; you can redistribute it and/or modify it under
15 * the terms of the GNU Lesser General Public License as published by the
16 * Free Software Foundation; either version 2.1 of the License, or (at your option)
19 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
20 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
22 * License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this library; if not, write to the Free Software Foundation, Inc., 51
26 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 * - Samsung RnD Institute Russia
34 #include <stdio.h> // for sprintf
35 #include <stdlib.h> // for getenv
36 #include <string.h> // for strstr
37 #include <stdbool.h> // for bool
38 #include <stdint.h> // fot uint32_t,uint64_t
39 #include <stdarg.h> // for va_list, va_arg(__appendTypeLog)
40 #include <execinfo.h> // for backtrace, backtrace_symbols
41 #include <unistd.h> // for write, alarm function, syscall
42 #include <pthread.h> // for pthread_mutex_lock
46 #include <sys/syscall.h> // for syscall
47 #include <sys/time.h> // for gettimeofday
48 #include <sys/socket.h> // for socket, connect
49 #include <sys/un.h> // for sockaddr_un
50 #include <sys/timerfd.h> // for timerfd
53 #include "probeinfo.h"
56 #include "dacollection.h"
62 #define APP_INSTALL_PATH "/opt/apps"
63 #define TISEN_APP_POSTFIX ".exe"
64 #define UDS_NAME "/tmp/da.socket"
65 #define TIMERFD_INTERVAL 100000000 // 0.1 sec
67 __thread int gProbeBlockCount = 0;
68 __thread int gProbeDepth = 0;
70 __thread pid_t gTid = -1;
73 long g_total_alloc_size = 0;
74 pthread_t g_recvthread_id;
78 int getExecutableMappingAddress();
80 bool printLog(log_t* log, int msgType);
81 /******************************************************************************
83 (this means that these functions do not need to set enter/exit flag)
84 ******************************************************************************/
86 // runtime configure the probe option
87 static void _configure(char* configstr)
90 gTraceInfo.optionflag = atoll(configstr);
92 sprintf(buf, "configure in probe : %s, %lx\n", configstr, gTraceInfo.optionflag);
96 // create socket to daemon and connect
97 static int createSocket(void)
100 int clientLen, ret = 0;
101 struct sockaddr_un clientAddr;
104 gTraceInfo.socket.daemonSock =
105 socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
106 if (gTraceInfo.socket.daemonSock != -1) {
107 memset(&clientAddr, '\0', sizeof(clientAddr));
108 clientAddr.sun_family = AF_UNIX;
109 sprintf(clientAddr.sun_path, "%s", UDS_NAME);
111 clientLen = sizeof(clientAddr);
112 if (connect(gTraceInfo.socket.daemonSock,
113 (struct sockaddr *)&clientAddr, clientLen) >= 0)
116 /* recv initial configuration value */
117 recvlen = recv(gTraceInfo.socket.daemonSock, &log,
118 sizeof(log.type) + sizeof(log.length),
121 if (recvlen > 0) {/* recv succeed */
122 if (log.length > 0) {
123 if(log.length >= DA_LOG_MAX)
124 log.length = DA_LOG_MAX - 1;
125 recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
126 log.length, MSG_WAITALL);
131 log.data[log.length] = '\0';
133 if(log.type == MSG_CONFIG)
135 _configure(log.data);
141 } else if (recvlen < 0) {
142 sprintf(buf, "recv failed in socket creation with error(%d)\n", recvlen);
144 /* closed by other peer */
147 sprintf(buf, "%d|%llu", getpid(),
148 gTraceInfo.app.startTime);
149 printLogStr(buf, MSG_PID);
150 PRINTMSG("createSocket connect() success\n");
152 close(gTraceInfo.socket.daemonSock);
153 gTraceInfo.socket.daemonSock = -1;
164 // parse backtrace string and find out the caller of probed api function
165 // return 0 if caller is user binary, otherwise return 1
166 static int determineCaller(char* tracestring)
170 // determine whether saveptr (caller binary name) is user binary or not
171 substr = strstr(tracestring, APP_INSTALL_PATH);
173 if(substr == NULL) // not user binary
180 substr = strstr(tracestring, TISEN_APP_POSTFIX);
188 // return current process id
189 static pid_t _getpid()
196 // return current thread id
197 static pid_t _gettid()
200 gTid = syscall(__NR_gettid); // syscall is very expensive
204 static void *recvThread(void __unused * data)
206 fd_set readfds, workfds;
211 sigset_t profsigmask;
213 if(gTraceInfo.socket.daemonSock == -1)
218 sigemptyset(&profsigmask);
219 sigaddset(&profsigmask, SIGPROF);
220 pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
226 FD_SET(g_timerfd, &readfds);
228 if(maxfd < gTraceInfo.socket.daemonSock)
229 maxfd = gTraceInfo.socket.daemonSock;
230 FD_SET(gTraceInfo.socket.daemonSock, &readfds);
235 rc = select(maxfd + 1, &workfds, NULL, NULL, NULL);
241 if(g_timerfd > 0 && FD_ISSET(g_timerfd, &workfds))
243 recvlen = read(g_timerfd, &xtime, sizeof(xtime));
246 log.length = sprintf(log.data, "%ld", g_total_alloc_size);
247 printLog(&log, MSG_ALLOC);
255 else if(FD_ISSET(gTraceInfo.socket.daemonSock, &workfds))
257 recvlen = recv(gTraceInfo.socket.daemonSock, &log,
258 sizeof(log.type) + sizeof(log.length), MSG_WAITALL);
260 if(recvlen > 0) // recv succeed
264 if(log.length >= DA_LOG_MAX)
265 log.length = DA_LOG_MAX - 1;
266 recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
267 log.length, MSG_WAITALL);
274 log.data[log.length] = '\0';
276 if (log.type == MSG_CAPTURE_SCREEN) {
278 } else if (log.type == MSG_CONFIG) {
279 _configure(log.data);
281 else if(log.type == MSG_STOP)
288 sprintf(buf, "recv unknown message(%d)\n", log.type);
292 else if(recvlen == 0) // closed by other peer
294 close(gTraceInfo.socket.daemonSock);
295 gTraceInfo.socket.daemonSock = -1;
301 sprintf(buf, "recv failed in recv thread with error(%d)\n", recvlen);
315 /*****************************************************************************
316 * initialize / finalize function
317 *****************************************************************************/
318 static int init_timerfd(void)
320 const struct timespec interval = {
322 .tv_nsec = TIMERFD_INTERVAL
324 const struct itimerspec ctime = {
325 .it_interval = interval,
329 int timer = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
332 PRINTMSG("failed to create timerdf\n");
336 if (timerfd_settime(timer, 0, &ctime, NULL) != 0) {
337 PRINTMSG("failed to set timerfd\n");
345 void __attribute__((constructor)) _init_probe()
347 struct timeval ttime;
352 initialize_hash_table();
354 initialize_screencapture();
358 getExecutableMappingAddress();
360 // get app start time
361 gettimeofday(&ttime, NULL);
362 gTraceInfo.app.startTime = (uint64_t)ttime.tv_sec * 1000 * 1000
365 // create socket for communication with da_daemon
366 if (createSocket() == 0) {
367 g_timerfd = init_timerfd();
369 // create recv Thread
370 if(pthread_create(&g_recvthread_id, NULL, recvThread, NULL) < 0) // thread creation failed
372 PRINTMSG("failed to crate recv thread\n");
374 update_heap_memory_size(true, 0);
381 PRINTMSG("dynamic analyzer probe helper so loading...\n");
383 gTraceInfo.init_complete = 1;
387 void __attribute__((destructor)) _fini_probe()
392 gTraceInfo.init_complete = -1;
393 PRINTMSG("dynamic analyzer probe helper so unloading...\n");
402 if(gTraceInfo.socket.daemonSock != -1)
404 printLogStr(NULL, MSG_TERMINATE);
405 close(gTraceInfo.socket.daemonSock);
406 gTraceInfo.socket.daemonSock = -1;
411 finalize_screencapture();
413 finalize_hash_table();
415 for(i = 0; i < NUM_ORIGINAL_LIBRARY; i++)
417 if(lib_handle[i] != NULL)
419 dlclose(lib_handle[i]);
427 /**************************************************************************
429 **************************************************************************/
431 /************************************************************************
432 * manipulate and print log functions
433 ************************************************************************/
434 bool printLog(log_t *log, int msgType)
437 if(unlikely(gTraceInfo.socket.daemonSock == -1))
440 if(unlikely(log == NULL))
445 real_pthread_mutex_lock(&(gTraceInfo.socket.sockMutex));
446 res = send(gTraceInfo.socket.daemonSock, log, sizeof(log->type) + sizeof(log->length) + log->length, 0);
447 real_pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex));
453 bool printLogStr(const char* str, int msgType)
458 if(unlikely(gTraceInfo.socket.daemonSock == -1))
466 sprintf(log.data, "%s", str);
467 log.length = strlen(str);
474 real_pthread_mutex_lock(&(gTraceInfo.socket.sockMutex));
475 res = send(gTraceInfo.socket.daemonSock, &log, sizeof(log.type) + sizeof(log.length) + log.length, MSG_DONTWAIT);
476 real_pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex));
483 // return 0 for successful case
484 // return non-zero for error
485 // if token is NULL then use DEFAULT TOKEN "`,"
486 // if token is not NULL then insert DEFAULT TOKEN before append input
487 int __appendTypeLog(log_t* log, int nInput, char* token, ...)
489 static const char *default_token = DEFAULT_TOKEN;
492 const char *seperator = default_token;
494 if(nInput <= 0 || log == NULL)
499 va_start(p_arg, token);
504 for(i = 0; i < nInput; i++)
506 type = va_arg(p_arg, int);
508 if(likely(log->length > 0)) // append token or default token
511 log->length += sprintf(log->data + log->length, "%s", default_token);
513 log->length += sprintf(log->data + log->length, "%s", seperator);
519 log->length += sprintf(log->data + log->length, "%d", va_arg(p_arg, int));
522 log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, unsigned int));
525 log->length += sprintf(log->data + log->length, "%ld", va_arg(p_arg, long));
528 log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, unsigned long));
531 log->length += sprintf(log->data + log->length, "%s", va_arg(p_arg, char*));
533 case VT_CHAR: // 'char' is promoted to 'int' when passed through '...'
534 log->length += sprintf(log->data + log->length, "%c", va_arg(p_arg, int));
537 log->length += sprintf(log->data + log->length, "%p", va_arg(p_arg, void*));
540 va_arg(p_arg, unsigned int);
543 log->length += sprintf(log->data + log->length, "%ld", va_arg(p_arg, off_t));
546 log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, size_t));
549 log->length += sprintf(log->data + log->length, "%d", va_arg(p_arg, ssize_t));
552 log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, socklen_t));
554 case VT_UINT16_T: // 'uint16_t' is promoted to 'int' when passed through '...'
555 log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, int));
558 log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, uint32_t));
561 log->length += sprintf(log->data + log->length, "%llu", va_arg(p_arg, uint64_t));
564 log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, mode_t));
567 log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, dev_t));
570 log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, nfds_t));
585 // get backtrace string
586 // return stack depth if succeed, otherwise return 0
587 // parameter 'log' cannot be null
588 int getBacktraceString(log_t* log, int bufsize)
590 void* array[MAX_STACK_DEPTH];
591 char** strings = NULL;
601 initsize = log->length;
602 log->data[log->length] = '\0'; // is this necessary ?
603 size = backtrace(array, MAX_STACK_DEPTH);
604 if(likely(size > TRIM_STACK_DEPTH))
606 strings = BACKTRACE_SYMBOLS(array + TRIM_STACK_DEPTH, size - TRIM_STACK_DEPTH);
608 if(likely(strings != NULL))
610 for(i = TRIM_STACK_DEPTH; i < size; i++)
612 stringlen = strlen(strings[i - TRIM_STACK_DEPTH]) + 14;
613 if(log->length + stringlen >= bufsize + initsize)
616 log->length += sprintf(log->data + log->length, "%010u`,%s`,", (unsigned int)(array[i]), strings[i - TRIM_STACK_DEPTH]);
618 log->data[log->length-2] = '\0';
622 else // failed to get backtrace symbols
624 // just print trace address
625 for(i = TRIM_STACK_DEPTH; i < size; i++)
628 if(log->length + stringlen >= bufsize + initsize)
631 log->length += sprintf(log->data + log->length, "%010u`,(unknown)`,", (unsigned int)(array[i]));
633 log->data[log->length-2] = '\0';
638 return (int)(size - TRIM_STACK_DEPTH);
647 /*************************************************************************
648 * probe block control functions
649 *************************************************************************/
650 int preBlockBegin(void* caller, bool bFiltering, enum DaOptions option)
656 if(gProbeBlockCount != 0 || gProbeDepth != 0)
659 if(gTraceInfo.init_complete <= 0)
662 if((gTraceInfo.optionflag & option) == 0)
667 if(gTraceInfo.exec_map.map_start != NULL)
669 // address comparison
670 if(caller >= gTraceInfo.exec_map.map_start &&
671 caller <= gTraceInfo.exec_map.map_end)
682 // backtrace for filtering
684 strings = BACKTRACE_SYMBOLS(tarray, 1);
687 if((determineCaller(strings[0]) == 0))
700 return 2; // user call
707 return 0; // not probing
712 return 1; // internal call
717 int postBlockBegin(int preresult)
738 /*************************************************************************
739 * helper info getter functions
740 *************************************************************************/
741 // return current time in 1/10000 sec unit
742 unsigned long getCurrentTime()
744 struct timeval cTime;
746 gettimeofday(&cTime, NULL);
748 return (unsigned long)((cTime.tv_sec * 10000 + (cTime.tv_usec/100)));
751 unsigned int getCurrentEventIndex()
753 return gTraceInfo.index.eventIndex;
756 uint64_t get_current_nsec(void)
759 gettimeofday(&tv, NULL);
760 return (uint64_t)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
763 /************************************************************************
765 ************************************************************************/
766 bool setProbePoint(probeInfo_t* iProbe)
768 if(unlikely(iProbe == NULL))
775 // atomic operaion(gcc builtin) is more expensive then pthread_mutex
776 real_pthread_mutex_lock(&(gTraceInfo.index.eventMutex));
777 iProbe->eventIndex = gTraceInfo.index.eventIndex++;
778 real_pthread_mutex_unlock(&(gTraceInfo.index.eventMutex));
780 iProbe->currentTime = getCurrentTime();
781 iProbe->pID = _getpid();
782 iProbe->tID = _gettid();
783 iProbe->callDepth = gProbeDepth;
789 // update heap memory size through socket
790 // return 0 if size is updated through socket
791 // return 1 if size is updated into global variable
792 int update_heap_memory_size(bool isAdd, size_t size)
797 tmp = __sync_add_and_fetch(&g_total_alloc_size, (long)size);
801 tmp = __sync_sub_and_fetch(&g_total_alloc_size, (long)size);