[Title] fix file probe bug
[framework/system/dynamic-analysis-probe.git] / helper / libdaprobe.c
1 /*
2  *  DA probe
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: 
7  *
8  * Jaewon Lim <jaewon81.lim@samsung.com>
9  * Woojin Jung <woojin2.jung@samsung.com>
10  * Juyoung Kim <j0.kim@samsung.com>
11  * 
12  * This library is free software; you can redistribute it and/or modify it under
13  * the terms of the GNU Lesser General Public License as published by the
14  * Free Software Foundation; either version 2.1 of the License, or (at your option)
15  * any later version.
16  * 
17  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
18  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this library; if not, write to the Free Software Foundation, Inc., 51
24  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  * 
29  */
30
31 #include <stdio.h>                      // for sprintf
32 #include <stdlib.h>                     // for getenv
33 #include <string.h>                     // for strstr
34 #include <stdbool.h>            // for bool
35 #include <stdint.h>                     // fot uint32_t,uint64_t
36 #include <stdarg.h>                     // for va_list, va_arg(__appendTypeLog)
37 #include <execinfo.h>           // for backtrace, backtrace_symbols
38 #include <unistd.h>                     // for write, alarm function, syscall
39 #include <pthread.h>            // for pthread_mutex_lock
40 #include <signal.h>
41
42 #include <sys/syscall.h>        // for syscall
43 #include <sys/time.h>           // for gettimeofday
44 #include <sys/socket.h>         // for socket, connect
45 #include <sys/un.h>                     // for sockaddr_un
46 #include <sys/timerfd.h>        // for timerfd
47
48 #include <app.h>
49 #include "probeinfo.h"
50 #include "dautil.h"
51 #include "dahelper.h"
52 #include "dacollection.h"
53
54 #define APP_INSTALL_PATH                "/opt/apps"
55 #define OSP_APP_POSTFIX                 ".exe"
56 #define UDS_NAME                                "/tmp/da.socket"
57 #define TIMERFD_INTERVAL                100000000               // 0.1 sec
58
59 __thread int            gProbeBlockCount = 0;
60 __thread int            gProbeDepth = 0;
61 __thread pid_t          gTid = -1;
62
63 int                     g_timerfd = 0;
64 long            g_total_alloc_size = 0;
65 pthread_t       g_recvthread_id;
66
67 int getExecutableMappingAddress();
68
69 /******************************************************************************
70  * internal functions
71    (this means that these functions do not need to set enter/exit flag)
72  ******************************************************************************/
73
74 // runtime configure the probe option
75 static void _configure(char* configstr)
76 {
77         char buf[64];
78         gTraceInfo.optionflag = atoi(configstr);
79
80         sprintf(buf, "configure in probe : %s, %lx\n", configstr, gTraceInfo.optionflag);
81         PRINTMSG(buf);
82
83         if(isOptionEnabled(OPT_FUNC))
84         {
85                 __profil(1);
86         }
87         else
88         {
89                 __profil(0);
90         }
91 }
92
93 // create socket to daemon and connect
94 static int createSocket(void)
95 {
96         ssize_t recvlen;
97         int clientLen, ret = 0;
98         struct sockaddr_un clientAddr;
99         char buf[16];
100         log_t log;
101
102         if((gTraceInfo.socket.daemonSock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) != -1)
103         {
104                 bzero(&clientAddr, sizeof(clientAddr));
105                 clientAddr.sun_family = AF_UNIX;
106                 sprintf(clientAddr.sun_path, "%s", UDS_NAME);
107
108                 clientLen = sizeof(clientAddr);
109                 if(connect(gTraceInfo.socket.daemonSock, (struct sockaddr *)&clientAddr, clientLen) >= 0)
110                 {
111                         // recv initial configuration value
112                         recvlen = recv(gTraceInfo.socket.daemonSock, &log,
113                                         sizeof(log.type) + sizeof(log.length), MSG_WAITALL);
114
115                         if(recvlen > 0) // recv succeed
116                         {
117                                 if(log.length > 0)
118                                 {
119                                         if(log.length >= DA_LOG_MAX)
120                                                 log.length = DA_LOG_MAX - 1;
121                                         recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
122                                                 log.length, MSG_WAITALL);
123                                 }
124                                 else
125                                 {
126                                         log.length = 0;
127                                 }
128
129                                 log.data[log.length] = '\0';
130
131                                 if(log.type == MSG_CONFIG)
132                                 {
133                                         _configure(log.data);
134                                 }
135                                 else
136                                 {
137                                         // unexpected case
138                                 }
139                         }
140                         else if(recvlen < 0)
141                         {
142                                 char buf[64];
143                                 sprintf(buf, "recv failed in socket creation with error(%d)\n", recvlen);
144                                 PRINTMSG(buf);
145                         }
146                         else    // closed by other peer
147                         {
148
149                         }
150                         sprintf(buf, "%d|%u", getpid(), gTraceInfo.app.startTime);
151                         printLogStr(buf, MSG_PID);
152                         PRINTMSG("createSocket connect() success\n");
153                 }
154                 else
155                 {
156                         close(gTraceInfo.socket.daemonSock);
157                         gTraceInfo.socket.daemonSock = -1;
158                         ret = -1;
159                 }
160         }
161         else
162         {
163                 ret = -1;
164         }
165
166         return ret;
167 }
168
169
170 // parse backtrace string and find out the caller of probed api function
171 // return 0 if caller is user binary, otherwise return 1
172 static int determineCaller(char* tracestring)
173 {
174         char *substr;
175
176         // determine whether saveptr (caller binary name) is user binary or not
177         substr = strstr(tracestring, APP_INSTALL_PATH);
178
179         if(substr == NULL)      // not user binary
180         {
181                 return 1;
182         }
183         else                            // user binary
184         {
185 #ifdef OSPAPP
186                 substr = strstr(tracestring, OSP_APP_POSTFIX);
187                 if(substr == NULL)
188                         return 1;
189 #endif
190                 return 0;
191         }
192 }
193
194 // return current thread id
195 static pid_t _gettid()
196 {
197         if(gTid == -1)
198                 gTid = syscall(__NR_gettid);    // syscall is very expensive
199         return gTid;
200 }
201
202 static void* recvThread(void* data)
203 {
204         fd_set readfds, workfds;
205         int maxfd = 0, rc;
206         uint64_t xtime;
207         ssize_t recvlen;
208         log_t log;
209         sigset_t profsigmask;
210
211         if(gTraceInfo.socket.daemonSock == -1)
212                 return NULL;
213
214         probeBlockStart();
215
216         sigemptyset(&profsigmask);
217         sigaddset(&profsigmask, SIGPROF);
218         pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
219
220         FD_ZERO(&readfds);
221         if(g_timerfd > 0)
222         {
223                 maxfd = g_timerfd;
224                 FD_SET(g_timerfd, &readfds);
225         }
226         if(maxfd < gTraceInfo.socket.daemonSock)
227                 maxfd = gTraceInfo.socket.daemonSock;
228         FD_SET(gTraceInfo.socket.daemonSock, &readfds);
229
230         while(1)
231         {
232                 workfds = readfds;
233                 rc = select(maxfd + 1, &workfds, NULL, NULL, NULL);
234                 if(rc < 0)
235                 {
236                         continue;
237                 }
238
239                 if(g_timerfd > 0 && FD_ISSET(g_timerfd, &workfds))
240                 {
241                         recvlen = read(g_timerfd, &xtime, sizeof(xtime));
242                         if(recvlen > 0)
243                         {
244                                 log.length = sprintf(log.data, "%ld", g_total_alloc_size);
245                                 printLog(&log, MSG_ALLOC);
246                         }
247                         else
248                         {
249                                 // read failed
250                         }
251                         continue;
252                 }
253                 else if(FD_ISSET(gTraceInfo.socket.daemonSock, &workfds))
254                 {
255                         recvlen = recv(gTraceInfo.socket.daemonSock, &log,
256                                         sizeof(log.type) + sizeof(log.length), MSG_WAITALL);
257
258                         if(recvlen > 0) // recv succeed
259                         {
260                                 if(log.length > 0)
261                                 {
262                                         if(log.length >= DA_LOG_MAX)
263                                                 log.length = DA_LOG_MAX - 1;
264                                         recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
265                                                 log.length, MSG_WAITALL);
266                                 }
267                                 else
268                                 {
269                                         log.length = 0;
270                                 }
271
272                                 log.data[log.length] = '\0';
273
274                                 if(log.type == MSG_CONFIG)
275                                 {
276                                         _configure(log.data);
277                                 }
278                                 else if(log.type == MSG_STOP)
279                                 {
280                                         app_efl_exit();
281                                 }
282                                 else
283                                 {
284                                         char buf[64];
285                                         sprintf(buf, "recv unknown message(%d)\n", log.type);
286                                         PRINTMSG(buf);
287                                         continue;
288                                 }
289                         }
290                         else if(recvlen == 0)   // closed by other peer
291                         {
292                                 close(gTraceInfo.socket.daemonSock);
293                                 gTraceInfo.socket.daemonSock = -1;
294                                 break;
295                         }
296                         else    // recv error
297                         {
298                                 char buf[64];
299                                 sprintf(buf, "recv failed in recv thread with error(%d)\n", recvlen);
300                                 PRINTMSG(buf);
301                                 continue;
302                         }
303                 }
304                 else    // unknown case
305                 {
306                         PRINTMSG("unknown fd in recvThread\n");
307                         continue;
308                 }
309         }
310
311         probeBlockEnd();
312         return NULL;
313 }
314
315 /*****************************************************************************
316  * initialize / finalize function
317  *****************************************************************************/
318
319 void __attribute__((constructor)) _init_probe()
320 {
321         struct timeval ttime;
322         struct itimerspec ctime;
323
324         probeBlockStart();
325
326         initialize_hash_table();
327
328         initialize_screencapture();
329
330         initialize_event();
331
332         getExecutableMappingAddress();
333
334         // get app start time
335         gettimeofday(&ttime, NULL);
336         gTraceInfo.app.startTime = ((ttime.tv_sec * 10000 + (ttime.tv_usec/100)));
337
338         // create socket for communication with da_daemon
339         if(createSocket() == 0)
340         {
341                 // create timerfd
342                 g_timerfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
343                 if(g_timerfd > 0)
344                 {
345                         ctime.it_value.tv_sec = 0;
346                         ctime.it_value.tv_nsec = TIMERFD_INTERVAL;
347                         ctime.it_interval.tv_sec = 0;
348                         ctime.it_interval.tv_nsec = TIMERFD_INTERVAL;
349                         if(0 > timerfd_settime(g_timerfd, 0, &ctime, NULL))
350                         {
351                                 PRINTMSG("failed to set timerfd\n");
352                                 close(g_timerfd);
353                                 g_timerfd = 0;
354                         }
355                 }
356                 else
357                 {
358                         PRINTMSG("failed to create timerdf\n");
359                 }
360
361                 // create recv Thread
362                 if(pthread_create(&g_recvthread_id, NULL, recvThread, NULL) < 0)        // thread creation failed
363                 {
364                         PRINTMSG("failed to crate recv thread\n");
365                 }
366                 update_heap_memory_size(true, 0);
367         }
368         else
369         {
370
371         }
372
373         PRINTMSG("dynamic analyzer probe helper so loading...\n");
374
375         gTraceInfo.init_complete = 1;
376         probeBlockEnd();
377 }
378
379 void __attribute__((destructor)) _fini_probe()
380 {
381         int i;
382         probeBlockStart();
383
384         gTraceInfo.init_complete = -1;
385         PRINTMSG("dynamic analyzer probe helper so unloading...\n");
386
387         remove_all_glist();
388
389         // close timerfd
390         if(g_timerfd > 0)
391                 close(g_timerfd);
392
393         // close socket
394         if(gTraceInfo.socket.daemonSock != -1)
395         {
396                 printLogStr(NULL, MSG_TERMINATE);
397                 close(gTraceInfo.socket.daemonSock);
398                 gTraceInfo.socket.daemonSock = -1;
399         }
400
401         finalize_event();
402
403         finalize_screencapture();
404
405         finalize_hash_table();
406
407         for(i = 0; i < NUM_ORIGINAL_LIBRARY; i++)
408         {
409                 if(lib_handle[i] != NULL)
410                 {
411                         dlclose(lib_handle[i]);
412                 }
413         }
414
415         probeBlockEnd();
416 }
417
418
419 /**************************************************************************
420  * Helper APIs
421  **************************************************************************/
422
423 /************************************************************************
424  * manipulate and print log functions
425  ************************************************************************/
426
427 bool printLog(log_t* log, int msgType)
428 {
429         int res;
430         if(unlikely(gTraceInfo.socket.daemonSock == -1))
431                 return false;
432
433         if(unlikely(log == NULL))
434                 return false;
435
436         probeBlockStart();
437         log->type = msgType;
438         pthread_mutex_lock(&(gTraceInfo.socket.sockMutex));
439         res = send(gTraceInfo.socket.daemonSock, log, sizeof(log->type) + sizeof(log->length) + log->length, 0);
440         pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex));
441         probeBlockEnd();
442
443         return true;
444 }
445
446 bool printLogStr(const char* str, int msgType)
447 {
448         int res;
449         log_t log;
450
451         if(unlikely(gTraceInfo.socket.daemonSock == -1))
452                 return false;
453
454         probeBlockStart();
455
456         log.type = msgType;
457         if(str)
458         {
459                 sprintf(log.data, "%s", str);
460                 log.length = strlen(str);
461         }
462         else
463         {
464                 log.length = 0;
465         }
466
467         pthread_mutex_lock(&(gTraceInfo.socket.sockMutex));
468         res = send(gTraceInfo.socket.daemonSock, &log, sizeof(log.type) + sizeof(log.length) + log.length, MSG_DONTWAIT);
469         pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex));
470
471         probeBlockEnd();
472
473         return true;
474 }
475
476 // return 0 for successful case
477 // return non-zero for error
478 // if token is NULL then use DEFAULT TOKEN "`,"
479 // if token is not NULL then insert DEFAULT TOKEN before append input
480 int __appendTypeLog(log_t* log, int nInput, char* token, ...)
481 {
482         static char* default_token = DEFAULT_TOKEN;
483         va_list p_arg;
484         int i, type;
485         char* seperator = default_token;
486
487         if(nInput <= 0 || log == NULL)
488                 return -1;
489
490         probeBlockStart();
491
492         va_start(p_arg, token);
493
494         if(token != NULL)
495                 seperator = token;
496
497         for(i = 0; i < nInput; i++)
498         {
499                 type = va_arg(p_arg, int);
500
501                 if(likely(log->length > 0))     // append token or default token
502                 {
503                         if(unlikely(i == 0))
504                                 log->length += sprintf(log->data + log->length, "%s", default_token);
505                         else
506                                 log->length += sprintf(log->data + log->length, "%s", seperator);
507                 }
508
509                 switch(type)
510                 {
511                 case VT_INT:
512                         log->length += sprintf(log->data + log->length, "%d", va_arg(p_arg, int));
513                         break;
514                 case VT_UINT:
515                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, unsigned int));
516                         break;
517                 case VT_LONG:
518                         log->length += sprintf(log->data + log->length, "%ld", va_arg(p_arg, long));
519                         break;
520                 case VT_ULONG:
521                         log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, unsigned long));
522                         break;
523                 case VT_STR:
524                         log->length += sprintf(log->data + log->length, "%s", va_arg(p_arg, char*));
525                         break;
526                 case VT_CHAR:   // 'char' is promoted to 'int' when passed through '...'
527                         log->length += sprintf(log->data + log->length, "%c", va_arg(p_arg, int));
528                         break;
529                 case VT_PTR:
530                         log->length += sprintf(log->data + log->length, "%p", va_arg(p_arg, void*));
531                         break;
532                 case VT_NULL:
533                         va_arg(p_arg, unsigned int);
534                         break;
535                 case VT_OFF_T:
536                         log->length += sprintf(log->data + log->length, "%ld", va_arg(p_arg, off_t));
537                         break;
538                 case VT_SIZE_T:
539                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, size_t));
540                         break;
541                 case VT_SSIZE_T:
542                         log->length += sprintf(log->data + log->length, "%d", va_arg(p_arg, ssize_t));
543                         break;
544                 case VT_SOCKLEN_T:
545                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, socklen_t));
546                         break;
547                 case VT_UINT16_T:       // 'uint16_t' is promoted to 'int' when passed through '...'
548                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, int));
549                         break;
550                 case VT_UINT32_T:
551                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, uint32_t));
552                         break;
553                 case VT_UINT64_T:
554                         log->length += sprintf(log->data + log->length, "%llu", va_arg(p_arg, uint64_t));
555                         break;
556                 case VT_MODE_T:
557                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, mode_t));
558                         break;
559 /*              case VT_DEV_T:
560                         log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, dev_t));
561                         break;
562                 case VT_NFDS_T:
563                         log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, nfds_t));
564                         break;*/
565                 default:
566                         va_end(p_arg);
567                         probeBlockEnd();
568                         return -1;
569                 }
570         }
571
572         va_end(p_arg);
573
574         probeBlockEnd();
575         return 0;
576 }
577
578 // get backtrace string
579 // return stack depth if succeed, otherwise return 0
580 // parameter 'log' cannot be null
581 int getBacktraceString(log_t* log, int bufsize)
582 {
583         void* array[MAX_STACK_DEPTH];
584         char** strings = NULL;
585         size_t i, size;
586         int initsize;
587         int stringlen;
588
589         if(log == NULL)
590                 return 0;
591
592         probeBlockStart();
593
594         initsize = log->length;
595         log->data[log->length] = '\0';  // is this necessary ?
596         size = backtrace(array, MAX_STACK_DEPTH);
597         if(likely(size > TRIM_STACK_DEPTH))
598         {
599                 strings = BACKTRACE_SYMBOLS(array + TRIM_STACK_DEPTH, size - TRIM_STACK_DEPTH);
600
601                 if(likely(strings != NULL))
602                 {
603                         for(i = TRIM_STACK_DEPTH; i < size; i++)
604                         {
605                                 stringlen = strlen(strings[i - TRIM_STACK_DEPTH]) + 14;
606                                 if(log->length + stringlen >= bufsize + initsize)
607                                         break;
608
609                                 log->length += sprintf(log->data + log->length, "%010u`,%s`,", (unsigned int)(array[i]), strings[i - TRIM_STACK_DEPTH]);
610                         }
611                         log->data[log->length-2] = '\0';
612                         log->length -= 2;
613                         free(strings);
614                 }
615                 else    // failed to get backtrace symbols
616                 {
617                         // just print trace address
618                         for(i = TRIM_STACK_DEPTH; i < size; i++)
619                         {
620                                 stringlen = 23;
621                                 if(log->length + stringlen >= bufsize + initsize)
622                                         break;
623
624                                 log->length += sprintf(log->data + log->length, "%010u`,(unknown)`,", (unsigned int)(array[i]));
625                         }
626                         log->data[log->length-2] = '\0';
627                         log->length -= 2;
628                 }
629
630                 probeBlockEnd();
631                 return (int)(size - TRIM_STACK_DEPTH);
632         }
633         else
634         {
635                 probeBlockEnd();
636                 return 0;
637         }
638 }
639
640 /*************************************************************************
641  * probe block control functions
642  *************************************************************************/
643 int preBlockBegin(void* caller, bool bFiltering, enum DaOptions option)
644 {
645         bool user = false;
646         void* tarray[1];
647         char** strings;
648
649         if(gProbeBlockCount != 0 || gProbeDepth != 0)
650                 return 0;
651
652         if(gTraceInfo.init_complete <= 0)
653                 return 0;
654
655         if((gTraceInfo.optionflag & option) == 0)
656                 return 0;
657
658         probeBlockStart();
659
660         if(gTraceInfo.exec_map.map_start != NULL)
661         {
662                 // address comparison
663                 if(caller >= gTraceInfo.exec_map.map_start &&
664                                 caller <= gTraceInfo.exec_map.map_end)
665                 {
666                         user = true;
667                 }
668                 else
669                 {
670                         // nothing to do
671                 }
672         }
673         else
674         {
675                 // backtrace for filtering
676                 tarray[0] = caller;
677                 strings = BACKTRACE_SYMBOLS(tarray, 1);
678                 if(strings != NULL)
679                 {
680                         if((determineCaller(strings[0]) == 0))
681                                 user = true;
682                         free(strings);
683                 }
684                 else
685                 {
686                         // nothing to do
687                 }
688         }
689
690         if(user)
691         {
692                 probingStart();
693                 return 2;       // user call
694         }
695         else
696         {
697                 if(bFiltering)
698                 {
699                         probeBlockEnd();
700                         return 0;       // not probing
701                 }
702                 else
703                 {
704                         probingStart();
705                         return 1;       // internal call
706                 }
707         }
708 }
709
710 int postBlockBegin(int preresult)
711 {
712         if(preresult)
713         {
714                 probeBlockStart();
715         }
716
717         return preresult;
718 }
719
720 void preBlockEnd()
721 {
722         probeBlockEnd();
723 }
724
725 void postBlockEnd()
726 {
727         probingEnd();
728         probeBlockEnd();
729 }
730
731 /*************************************************************************
732  * helper info getter functions
733  *************************************************************************/
734 // return current time in 1/10000 sec unit
735 unsigned long getCurrentTime()
736 {
737         struct timeval cTime;
738
739         gettimeofday(&cTime, NULL);
740
741         return (unsigned long)((cTime.tv_sec * 10000 + (cTime.tv_usec/100)));
742 }
743
744 unsigned int getCurrentEventIndex()
745 {
746         return gTraceInfo.index.eventIndex;
747 }
748
749 /************************************************************************
750  * probe functions
751  ************************************************************************/
752 bool setProbePoint(probeInfo_t* iProbe)
753 {
754         if(unlikely(iProbe == NULL))
755         {
756                 return false;
757         }
758
759         probeBlockStart();
760
761         // atomic operaion(gcc builtin) is more expensive then pthread_mutex
762         pthread_mutex_lock(&(gTraceInfo.index.eventMutex));     
763         iProbe->eventIndex = gTraceInfo.index.eventIndex++;
764         pthread_mutex_unlock(&(gTraceInfo.index.eventMutex));
765
766         iProbe->currentTime = getCurrentTime();
767         iProbe->pID = getpid();
768         iProbe->tID = _gettid();
769         iProbe->callDepth = gProbeDepth;
770
771         probeBlockEnd();
772         return true;
773 }
774
775 // update heap memory size through socket
776 // return 0 if size is updated through socket
777 // return 1 if size is updated into global variable
778 int update_heap_memory_size(bool isAdd, size_t size)
779 {
780         long tmp;
781         if(isAdd)
782         {
783                 tmp = __sync_add_and_fetch(&g_total_alloc_size, (long)size);
784         }
785         else
786         {
787                 tmp = __sync_sub_and_fetch(&g_total_alloc_size, (long)size);
788         }
789
790         return 0;
791 }
792
793