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