1 /* EINA - EFL data type library
2  * Copyright (C) 2015 Carsten Haitzler
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 # ifndef _GNU_SOURCE
20 #  define _GNU_SOURCE 1
21 # endif
22 
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #ifdef HAVE_SYS_EPOLL_H
33 # include <sys/epoll.h>
34 #endif
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <pthread.h>
39 #include <signal.h>
40 #include <time.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #ifdef HAVE_SYS_SOCKET_H
44 # include <sys/socket.h>
45 #endif
46 #ifdef HAVE_SYS_UN_H
47 # include <sys/un.h>
48 #endif
49 #ifdef HAVE_NETINET_IN_H
50 # include <netinet/in.h>
51 #endif
52 #ifdef HAVE_ARPA_INET_H
53 # include <arpa/inet.h>
54 #endif
55 #include <fcntl.h>
56 
57 #ifdef _WIN32
58 # include <ws2tcpip.h>
59 # include <evil_private.h> /* fcntl */
60 #endif
61 
62 #include "eina_alloca.h"
63 #include "eina_debug.h"
64 #include "eina_cpu.h"
65 #include "eina_types.h"
66 #include "eina_list.h"
67 #include "eina_mempool.h"
68 #include "eina_util.h"
69 #include "eina_evlog.h"
70 #include "eina_hash.h"
71 #include "eina_stringshare.h"
72 #include "eina_debug_private.h"
73 #include "eina_vpath.h"
74 #include "eina_internal.h"
75 
76 #ifdef EINA_HAVE_PTHREAD_SETNAME
77 # ifndef __linux__
78 # include <pthread_np.h>
79 # endif
80 #endif
81 
82 #if defined(__CYGWIN__) || defined (_WIN32)
83 # define LIBEXT ".dll"
84 #else
85 # define LIBEXT ".so"
86 #endif
87 
88 #if __BYTE_ORDER == __LITTLE_ENDIAN
89 #define SWAP_64(x) x
90 #define SWAP_32(x) x
91 #define SWAP_16(x) x
92 #else
93 #define SWAP_64(x) eina_swap64(x)
94 #define SWAP_32(x) eina_swap32(x)
95 #define SWAP_16(x) eina_swap16(x)
96 #endif
97 
98 // yes - a global debug spinlock. i expect contention to be low for now, and
99 // when needed we can split this up into mroe locks to reduce contention when
100 // and if that day comes
101 Eina_Spinlock _eina_debug_lock;
102 
103 #ifdef __linux__
104 extern char *__progname;
105 #endif
106 
107 extern Eina_Bool eina_module_init(void);
108 extern Eina_Bool eina_mempool_init(void);
109 extern Eina_Bool eina_list_init(void);
110 
111 extern Eina_Spinlock _eina_debug_thread_lock;
112 static Eina_List *sessions;
113 
114 static Eina_Bool _debug_disabled = EINA_FALSE;
115 
116 /* Local session */
117 /* __thread here to allow debuggers to be master and slave by using two different threads */
118 static Eina_Debug_Session *_last_local_session = NULL;
119 
120 typedef struct
121 {
122    const Eina_Debug_Opcode *ops;
123    Eina_Debug_Opcode_Status_Cb status_cb;
124    void *status_data;
125    Eina_Bool sent : 1;
126 } _opcode_reply_info;
127 
128 struct _Eina_Debug_Session
129 {
130    Eina_List **cbs; /* Table of callbacks lists indexed by opcode id */
131    Eina_List *opcode_reply_infos;
132    Eina_Debug_Dispatch_Cb dispatch_cb; /* Session dispatcher */
133    void *data; /* User data */
134    int cbs_length; /* cbs table size */
135    int fd; /* File descriptor */
136    Eina_Lock lock; /* deletion lock */
137    Eina_Bool deleted : 1; /* set if session is dead */
138 };
139 
140 #ifndef _WIN32
141 static void _opcodes_register_all(Eina_Debug_Session *session);
142 #endif
143 static void _thread_start(Eina_Debug_Session *session);
144 
145 EAPI int
eina_debug_session_send(Eina_Debug_Session * session,int dest,int op,void * data,int size)146 eina_debug_session_send(Eina_Debug_Session *session, int dest, int op, void *data, int size)
147 {
148    Eina_Debug_Packet_Header hdr;
149 
150    if (!session) return -1;
151    if (op == EINA_DEBUG_OPCODE_INVALID) return -1;
152    /* Preparation of the packet header */
153    hdr.size = SWAP_32(size + sizeof(Eina_Debug_Packet_Header));
154    hdr.opcode = SWAP_32(op);
155    hdr.cid = SWAP_32(dest);
156    e_debug("socket: %d / opcode %X / bytes to send: %d",
157          session->fd, op, size + sizeof(*hdr));
158 #ifndef _WIN32
159    eina_spinlock_take(&_eina_debug_lock);
160    /* Sending header */
161    if (write(session->fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto err;
162    /* Sending payload */
163    if (size)
164      {
165         if (write(session->fd, data, size) != size) goto err;
166      }
167    eina_spinlock_release(&_eina_debug_lock);
168 #else
169    (void)data;
170 #endif
171    return size;
172 #ifndef _WIN32
173 err:
174    eina_spinlock_release(&_eina_debug_lock);
175    e_debug("Cannot write to eina debug session");
176    return 0;
177 #endif
178 }
179 
180 #ifndef _WIN32
181 static void
_daemon_greet(Eina_Debug_Session * session)182 _daemon_greet(Eina_Debug_Session *session)
183 {
184    /* say hello to our debug daemon - tell them our PID and protocol
185       version we speak */
186    /* Version + Pid + App name */
187 #ifdef __linux__
188    char *app_name = __progname;
189 #else
190    char *app_name = NULL;
191 #endif
192    int size = 8 + (app_name ? strlen(app_name) : 0) + 1;
193    unsigned char *buf = alloca(size);
194    int version = SWAP_32(1); // version of protocol we speak
195    int pid = getpid();
196    pid = SWAP_32(pid);
197    memcpy(buf + 0, &version, 4);
198    memcpy(buf + 4, &pid, 4);
199    if (app_name)
200       memcpy(buf + 8, app_name, strlen(app_name) + 1);
201    else
202       buf[8] = '\0';
203    eina_debug_session_send(session, 0, EINA_DEBUG_OPCODE_HELLO, buf, size);
204 }
205 
206 static int
_packet_receive(Eina_Debug_Session * session,unsigned char ** buffer)207 _packet_receive(Eina_Debug_Session *session, unsigned char **buffer)
208 {
209    unsigned char *packet_buf = NULL;
210    int rret = -1;
211    unsigned int size = 0;
212 
213    rret = read(session->fd, &size, 4);
214    if (rret == 4)
215      {
216         size = SWAP_32(size);
217         if (size > EINA_DEBUG_MAX_PACKET_SIZE)
218           {
219              e_debug("Packet too big: %d. The maximum allowed is %d", size, EINA_DEBUG_MAX_PACKET_SIZE);
220              rret = -1;
221              goto end;
222           }
223         e_debug("Begin to receive a packet of %d bytes", size);
224         // allocate a buffer for the next bytes to receive
225         packet_buf = malloc(size);
226         if (packet_buf)
227           {
228              unsigned int cur_packet_size = 4;
229              memcpy(packet_buf, &size, 4);
230              /* Receive all the remaining packet bytes */
231              while (cur_packet_size < size)
232                {
233                   rret = read(session->fd, packet_buf + cur_packet_size, size - cur_packet_size);
234                   if (rret <= 0)
235                     {
236                        e_debug("Error on read: %d", rret);
237                        perror("Read");
238                        goto end;
239                     }
240                   cur_packet_size += rret;
241                }
242              *buffer = packet_buf;
243              rret = cur_packet_size;
244              e_debug("Received a packet of %d bytes", cur_packet_size);
245           }
246         else
247           {
248              // we couldn't allocate memory for payload buffer
249              // internal memory limit error
250              e_debug("Cannot allocate %u bytes for op", size);
251              goto end;
252           }
253      }
254    else
255      {
256         e_debug("Invalid size read %i != %i", rret, size_sz);
257         goto end;
258      }
259 end:
260    if (rret <= 0 && packet_buf) free(packet_buf);
261    return rret;
262 }
263 #endif
264 
265 EAPI void
eina_debug_disable()266 eina_debug_disable()
267 {
268    _debug_disabled = EINA_TRUE;
269 }
270 
271 EAPI void
eina_debug_session_terminate(Eina_Debug_Session * session)272 eina_debug_session_terminate(Eina_Debug_Session *session)
273 {
274    /* Close fd here so the thread terminates its own session by itself */
275    if (!session) return;
276    close(session->fd);
277    eina_lock_take(&session->lock);
278    if (session->deleted)
279      {
280         eina_lock_release(&session->lock);
281         free(session);
282      }
283    else
284      {
285         session->deleted = 1;
286         eina_lock_release(&session->lock);
287      }
288 }
289 
290 EAPI void
eina_debug_session_dispatch_override(Eina_Debug_Session * session,Eina_Debug_Dispatch_Cb disp_cb)291 eina_debug_session_dispatch_override(Eina_Debug_Session *session, Eina_Debug_Dispatch_Cb disp_cb)
292 {
293    if (!session) return;
294    if (!disp_cb) disp_cb = eina_debug_dispatch;
295    session->dispatch_cb = disp_cb;
296 }
297 
298 EAPI Eina_Debug_Dispatch_Cb
eina_debug_session_dispatch_get(Eina_Debug_Session * session)299 eina_debug_session_dispatch_get(Eina_Debug_Session *session)
300 {
301    if (session) return session->dispatch_cb;
302    else return NULL;
303 }
304 
305 #ifndef _WIN32
306 static void
_static_opcode_register(Eina_Debug_Session * session,int op_id,Eina_Debug_Cb cb)307 _static_opcode_register(Eina_Debug_Session *session,
308       int op_id, Eina_Debug_Cb cb)
309 {
310    if(session->cbs_length < op_id + 1)
311      {
312         int i = session->cbs_length;
313         session->cbs_length = op_id + 16;
314         session->cbs = realloc(session->cbs, session->cbs_length * sizeof(Eina_List *));
315         for(; i < session->cbs_length; i++) session->cbs[i] = NULL;
316      }
317    if (cb)
318      {
319         session->cbs[op_id] = eina_list_append(session->cbs[op_id], cb);
320      }
321 }
322 
323 /*
324  * Response of the daemon containing the ids of the requested opcodes.
325  * PTR64 + (opcode id)*
326  */
327 static Eina_Bool
_callbacks_register_cb(Eina_Debug_Session * session,int src_id EINA_UNUSED,void * buffer,int size)328 _callbacks_register_cb(Eina_Debug_Session *session, int src_id EINA_UNUSED, void *buffer, int size)
329 {
330    _opcode_reply_info *info = NULL, *info2;
331    Eina_List *itr;
332    int *os;
333    unsigned int count, i;
334 
335    uint64_t info_64;
336    memcpy(&info_64, buffer, sizeof(uint64_t));
337    // cast to a ptr, so on 32bit we just take the lower 32bits and on 64
338    // we take all of it so we're fine
339    info = (_opcode_reply_info *)(uintptr_t)info_64;
340 
341    if (!info) return EINA_FALSE;
342    EINA_LIST_FOREACH(session->opcode_reply_infos, itr, info2)
343      {
344         if (info2 == info)
345           {
346              os = (int *)((unsigned char *)buffer + sizeof(uint64_t));
347              count = (size - sizeof(uint64_t)) / sizeof(int);
348 
349              for (i = 0; i < count; i++)
350                {
351                   int op = SWAP_32(os[i]);
352                   if (info->ops[i].opcode_id) *(info->ops[i].opcode_id) = op;
353                   _static_opcode_register(session, op, info->ops[i].cb);
354                   e_debug("Opcode %s -> %d", info->ops[i].opcode_name, op);
355                }
356              if (info->status_cb) info->status_cb(info->status_data, EINA_TRUE);
357              return EINA_TRUE;
358           }
359      }
360 
361    return EINA_FALSE;
362 }
363 #endif
364 
365 static void
_opcodes_registration_send(Eina_Debug_Session * session,_opcode_reply_info * info)366 _opcodes_registration_send(Eina_Debug_Session *session,
367       _opcode_reply_info *info)
368 {
369    unsigned char *buf;
370 
371    int count = 0;
372    int size = sizeof(uint64_t);
373    Eina_Bool already_sent;
374 
375    eina_spinlock_take(&_eina_debug_lock);
376    already_sent = info->sent;
377    info->sent = EINA_TRUE;
378    eina_spinlock_release(&_eina_debug_lock);
379    if (already_sent) return;
380 
381    while (info->ops[count].opcode_name)
382      {
383         size += strlen(info->ops[count].opcode_name) + 1;
384         count++;
385      }
386 
387    buf = malloc(size);
388 
389    // cast to a ptr, so on 32bit we just pad out the upper 32bits with 0
390    // and on 64bit we are fine as we use all of it
391    uint64_t info_64 = (uint64_t)(uintptr_t)info;
392    memcpy(buf, &info_64, sizeof(uint64_t));
393    int size_curr = sizeof(uint64_t);
394 
395    count = 0;
396    while (info->ops[count].opcode_name)
397      {
398         int len = strlen(info->ops[count].opcode_name) + 1;
399         memcpy(buf + size_curr, info->ops[count].opcode_name, len);
400         size_curr += len;
401         count++;
402      }
403 
404    eina_debug_session_send(session, 0, EINA_DEBUG_OPCODE_REGISTER, buf, size);
405    free(buf);
406 }
407 
408 #ifndef _WIN32
409 static void
_opcodes_register_all(Eina_Debug_Session * session)410 _opcodes_register_all(Eina_Debug_Session *session)
411 {
412    Eina_List *l;
413    _opcode_reply_info *info = NULL;
414 
415    _static_opcode_register(session,
416          EINA_DEBUG_OPCODE_REGISTER, _callbacks_register_cb);
417    EINA_LIST_FOREACH(session->opcode_reply_infos, l, info)
418         _opcodes_registration_send(session, info);;
419 }
420 
421 static void
_opcodes_unregister_all(Eina_Debug_Session * session)422 _opcodes_unregister_all(Eina_Debug_Session *session)
423 {
424    Eina_List *l;
425    int i;
426    _opcode_reply_info *info = NULL;
427 
428    if (!session) return;
429    for (i = 0; i < session->cbs_length; i++)
430       eina_list_free(session->cbs[i]);
431    free(session->cbs);
432    session->cbs_length = 0;
433    session->cbs = NULL;
434 
435    EINA_LIST_FOREACH(session->opcode_reply_infos, l, info)
436      {
437         const Eina_Debug_Opcode *op = info->ops;
438         while(!op->opcode_name)
439           {
440              if (op->opcode_id) *(op->opcode_id) = EINA_DEBUG_OPCODE_INVALID;
441              op++;
442           }
443         if (info->status_cb) info->status_cb(info->status_data, EINA_FALSE);
444      }
445 }
446 
447 #define LENGTH_OF_SOCKADDR_UN(s) \
448    (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
449 #endif
450 
451 static Eina_Debug_Session *
_session_create(int fd)452 _session_create(int fd)
453 {
454    Eina_Debug_Session *session = calloc(1, sizeof(*session));
455    if (!session) return NULL;
456    session->dispatch_cb = eina_debug_dispatch;
457    session->fd = fd;
458    eina_lock_new(&session->lock);
459    sessions = eina_list_append(sessions, session);
460    // start the monitor thread
461    _thread_start(session);
462    return session;
463 }
464 
465 EAPI Eina_Debug_Session *
eina_debug_remote_connect(int port)466 eina_debug_remote_connect(int port)
467 {
468    int fd;
469    struct sockaddr_in server;
470 
471    //Create socket
472    fd = socket(AF_INET, SOCK_STREAM, 0);
473    if (fd < 0) goto err;
474    // set the socket to close when we exec things so they don't inherit it
475    if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) goto err;
476 
477    //Prepare the sockaddr_in structure
478    server.sin_family = AF_INET;
479    if (inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr) != 1) goto err;
480    server.sin_port = eina_htons(port);
481 
482    if (connect(fd, (struct sockaddr *)&server, sizeof(server)) < 0)
483     {
484         perror("connect failed. Error");
485         goto err;
486     }
487    return _session_create(fd);
488 err:
489    // some kind of connection failure here, so close a valid socket and
490    // get out of here
491    if (fd >= 0) close(fd);
492    return NULL;
493 }
494 
495 EAPI Eina_Debug_Session *
eina_debug_local_connect(Eina_Bool is_master)496 eina_debug_local_connect(Eina_Bool is_master)
497 {
498 #ifndef _WIN32
499    int fd, socket_unix_len, curstate = 0;
500    struct sockaddr_un socket_unix;
501    char buf[sizeof(socket_unix.sun_path)];
502 
503    if (is_master) return eina_debug_remote_connect(REMOTE_SERVER_PORT);
504 
505    // try this socket file - it will likely be:
506    //   ~/.ecore/efl_debug/0
507    // or maybe
508    //   /var/run/UID/.ecore/efl_debug/0
509    eina_vpath_resolve_snprintf(buf, sizeof(buf), "(:usr.run:)/%s/%s/%i",
510          LOCAL_SERVER_PATH, LOCAL_SERVER_NAME, LOCAL_SERVER_PORT);
511    // create the socket
512    fd = socket(AF_UNIX, SOCK_STREAM, 0);
513    if (fd < 0) goto err;
514    // set the socket to close when we exec things so they don't inherit it
515    if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) goto err;
516    // set up some socket options on addr re-use
517    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate,
518                   sizeof(curstate)) < 0)
519      goto err;
520    // sa that it's a unix socket and where the path is
521    memset(&socket_unix, 0, sizeof(socket_unix));
522    socket_unix.sun_family = AF_UNIX;
523    strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
524    socket_unix.sun_path[sizeof(socket_unix.sun_path) - 1] = 0;
525    socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
526    // actually connect to efl_debugd service
527    if (connect(fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
528       goto err;
529 
530    _last_local_session = _session_create(fd);
531 
532    return _last_local_session;
533 err:
534    // some kind of connection failure here, so close a valid socket and
535    // get out of here
536    if (fd >= 0) close(fd);
537 #else
538    (void) is_master;
539 #endif
540    return NULL;
541 }
542 
543 // this is a DEDICATED debug thread to monitor the application so it works
544 // even if the mainloop is blocked or the app otherwise deadlocked in some
545 // way. this is an alternative to using external debuggers so we can get
546 // users or developers to get useful information about an app at all times
547 
548 #ifndef _WIN32
549 static void *
_monitor(void * _data)550 _monitor(void *_data)
551 {
552    Eina_Debug_Session *session = _data;
553 
554    _daemon_greet(session);
555    _opcodes_register_all(session);
556 
557    // set a name for this thread for system debugging
558 #ifdef EINA_HAVE_PTHREAD_SETNAME
559 # ifndef __linux__
560    pthread_set_name_np
561 # else
562    pthread_setname_np
563 # endif
564      (pthread_self(), "Edbg-mon");
565 #endif
566 
567    // sit forever processing commands or timeouts in the debug monitor
568    // thread - this is separate to the rest of the app so it shouldn't
569    // impact the application specifically
570    while (1)
571      {
572         unsigned char *buffer = NULL;
573         int size;
574 
575         size = _packet_receive(session, &buffer);
576         // if not negative - we have a real message
577         if (size > 0)
578           {
579              Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
580              hdr->cid = SWAP_32(hdr->cid);
581              hdr->opcode = SWAP_32(hdr->opcode);
582              if (EINA_TRUE != session->dispatch_cb(session, buffer))
583                {
584                   // something we don't understand
585                   e_debug("EINA DEBUG ERROR: Unknown command");
586                }
587              /* Free the buffer only if the default dispatcher is used */
588              if (session->dispatch_cb == eina_debug_dispatch)
589                 free(buffer);
590           }
591         else
592           {
593              _opcodes_unregister_all(session);
594              eina_debug_session_terminate(session);
595              break;
596           }
597      }
598    return NULL;
599 }
600 #endif
601 
602 // start up the debug monitor if we haven't already
603 static void
_thread_start(Eina_Debug_Session * session)604 _thread_start(Eina_Debug_Session *session)
605 {
606 #ifndef _WIN32
607    pthread_t monitor_thread;
608    int err;
609    sigset_t oldset, newset;
610 
611    sigemptyset(&newset);
612    sigaddset(&newset, SIGPIPE);
613    sigaddset(&newset, SIGALRM);
614    sigaddset(&newset, SIGCHLD);
615    sigaddset(&newset, SIGUSR1);
616    sigaddset(&newset, SIGUSR2);
617    sigaddset(&newset, SIGHUP);
618    sigaddset(&newset, SIGQUIT);
619    sigaddset(&newset, SIGINT);
620    sigaddset(&newset, SIGTERM);
621 #ifdef SIGPWR
622    sigaddset(&newset, SIGPWR);
623 #endif
624    pthread_sigmask(SIG_BLOCK, &newset, &oldset);
625 
626    err = pthread_create(&monitor_thread, NULL, _monitor, session);
627 
628    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
629    if (err != 0)
630      {
631         e_debug("EINA DEBUG ERROR: Can't create monitor debug thread!");
632         abort();
633      }
634 #else
635    (void)session;
636 #endif
637 }
638 
639 /*
640  * Sends to daemon:
641  * - Pointer to ops: returned in the response to determine which opcodes have been added
642  * - List of opcode names separated by \0
643  */
644 EAPI void
eina_debug_opcodes_register(Eina_Debug_Session * session,const Eina_Debug_Opcode ops[],Eina_Debug_Opcode_Status_Cb status_cb,void * data)645 eina_debug_opcodes_register(Eina_Debug_Session *session, const Eina_Debug_Opcode ops[],
646       Eina_Debug_Opcode_Status_Cb status_cb, void *data)
647 {
648    if (!session) session = _last_local_session;
649    if (!session) return;
650 
651    _opcode_reply_info *info = malloc(sizeof(*info));
652    info->ops = ops;
653    info->status_cb = status_cb;
654    info->status_data = data;
655    info->sent = EINA_FALSE;
656 
657    session->opcode_reply_infos = eina_list_append(
658          session->opcode_reply_infos, info);
659 
660    /* Send only if session's fd connected.
661     * Otherwise, it will be sent when connected */
662    if(session && session->fd!= -1)
663       _opcodes_registration_send(session, info);
664 }
665 
666 EAPI Eina_Bool
eina_debug_dispatch(Eina_Debug_Session * session,void * buffer)667 eina_debug_dispatch(Eina_Debug_Session *session, void *buffer)
668 {
669    Eina_Debug_Packet_Header *hdr = buffer;
670    Eina_List *itr;
671    int opcode = hdr->opcode;
672    Eina_Debug_Cb cb = NULL;
673 
674    if (opcode >= session->cbs_length)
675      {
676         e_debug("Invalid opcode %d", opcode);
677         return EINA_FALSE;
678      }
679 
680    EINA_LIST_FOREACH(session->cbs[opcode], itr, cb)
681      {
682         if (!cb) continue;
683         Eina_Bool ret = cb(session, hdr->cid,
684               (unsigned char *)buffer + sizeof(*hdr),
685               hdr->size - sizeof(*hdr));
686         if (ret == EINA_FALSE) return ret;
687      }
688    return EINA_TRUE;
689 }
690 
691 EAPI void
eina_debug_session_data_set(Eina_Debug_Session * session,void * data)692 eina_debug_session_data_set(Eina_Debug_Session *session, void *data)
693 {
694    if (session) session->data = data;
695 }
696 
697 EAPI void *
eina_debug_session_data_get(Eina_Debug_Session * session)698 eina_debug_session_data_get(Eina_Debug_Session *session)
699 {
700    if (session) return session->data;
701    else return NULL;
702 }
703 
704 Eina_Bool
eina_debug_init(void)705 eina_debug_init(void)
706 {
707    pthread_t self;
708 
709    eina_threads_init();
710    // For Windows support GetModuleFileName can be used
711    // set up thread things
712    eina_spinlock_new(&_eina_debug_lock);
713    eina_spinlock_new(&_eina_debug_thread_lock);
714    self = pthread_self();
715    _eina_debug_thread_mainloop_set(&self);
716    _eina_debug_thread_add(&self);
717    _eina_debug_cpu_init();
718    _eina_debug_bt_init();
719    _eina_debug_timer_init();
720 #if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
721    // if we are setuid - don't debug!
722    if (getuid() != geteuid()) return EINA_TRUE;
723 #endif
724    // if someone uses the EFL_NODEBUG env var or disabled debug - do not do
725    // debugging. handy for when this debug code is buggy itself
726 
727    if (!getenv("EFL_NODEBUG") && !_debug_disabled)
728      {
729         eina_debug_local_connect(EINA_FALSE);
730      }
731    return EINA_TRUE;
732 }
733 
734 Eina_Bool
eina_debug_shutdown(void)735 eina_debug_shutdown(void)
736 {
737    Eina_Debug_Session *session;
738    pthread_t self = pthread_self();
739 
740    EINA_LIST_FREE(sessions, session)
741      eina_debug_session_terminate(session);
742 
743    _eina_debug_timer_shutdown();
744    _eina_debug_bt_shutdown();
745    _eina_debug_cpu_shutdown();
746    _eina_debug_thread_del(&self);
747    eina_spinlock_free(&_eina_debug_lock);
748    eina_spinlock_free(&_eina_debug_thread_lock);
749    eina_threads_shutdown();
750    return EINA_TRUE;
751 }
752 
753 EAPI void
eina_debug_fork_reset(void)754 eina_debug_fork_reset(void)
755 {
756    extern Eina_Bool fork_resetting;
757 
758    fork_resetting = EINA_TRUE;
759    eina_debug_shutdown();
760    eina_debug_init();
761    fork_resetting = EINA_FALSE;
762 }
763