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