--- ~~Title: Debugging Enlightenment~~ --- # Enlightenment Debugging # This tutorial provides information on debugging Enlightenment, and is aimed at developers with prior debugging experience. It is divided in two sections: Before debugging make sure your debug symbols are enabled. If they are not consult the [Get Source documentation](/docs/distros/#Enable_debug_symbols_Optional) for further instructions. ## Debugging Enlightenment with GDB ## In order to use the GNU Debugger (GDB), first simulate a crash in Enlightenment. Start by running Enlightenment, then switch to another terminal using CTRL+ALT+F1 for ``tty1``. Two processes are of interest: ``enlightenment`` and ``enlightenment_start``. In fact, ``enlightenment`` is traced by ``enlightenment_start``. Next send a ``SEGV`` signal to "segfault" Enlightenment. ```c kill -SIGSEGV $(pidof enlightenment) ``` ``enlightenment_start`` will open a pop-up named Enlightenment Error. This pop-up indicates that Enlightenment "segfaulted" and gives the option to recover or log out, but also detaches from the child process (Enlightenment) which allows advanced users to use GDB to debug it. Attach GDB to Enlightenment as follows: ```bash gdb enlightenment $(pidof enlightenment) ``` To save the traces in a log file: ```bash #save the traces in log.txt set logging file log.txt set logging on ``` ### Backtracing ### Use the backtrace command to get information about frames to know where the segfault is coming from. ```bash (gdb) bt #0 0xb7d539f8 in select () from /lib/tls/libc.so.6 #1 0xb7dff66a in _XEnq () from /usr/X11R6/lib/libX11.so.6 #2 0xb7dffa7e in _XRead () from /usr/X11R6/lib/libX11.so.6 #3 0xb7e01795 in _XReadEvents () from /usr/X11R6/lib/libX11.so.6 #4 0xb7defa88 in XNextEvent () from /usr/X11R6/lib/libX11.so.6 #5 0x0809b698 in e_alert_show ( text=0x80a34f0 "This is very bad. Enlightenment has segfaulted.\nThis is not meant to happen and is likely a sign of a\nbug in Enlightenment or the libraries it relies on.\n\nYou can gdb attach to this process now to try"...) at e_alert.c:136 #6 0x0808f706 in e_sigseg_act (x=11, info=0x80a9fb0, data=0x80aa030) at e_signals.c:54 #7 #8 0xb7d539f8 in select () from /lib/tls/libc.so.6 #9 0xb7f814ee in _ecore_main_select (timeout=0) at ecore_main.c:338 #10 0xb7f819ba in _ecore_main_loop_iterate_internal (once_only=0) at ecore_main.c:575 #11 xb7f81a2b in ecore_main_loop_begin () at ecore_main.c:79 #12 0x08059bb3 in main (argc=1, argv=0xbffff144) at e_main.c:551 ``` As you can see in the stack trace, GDB finds the segfault in ``libc`` and pops to the main function in ``e_main``. But it doesn't seem credible to have a bug in ``libc`` or ``x``; the important thing is Enlightenment has its own segfault handler which is very explicit on frame 5. The ``e_sigseg_act()`` function at frame 6 is called directly from the kernel when the program segfaults, meaning Enlightenment causes the segfault. So, the segfault comes from the ``select()`` function (a ``libc`` function) at frame 8 called in ``_e_core_main_select_function()`` at frame 9. ### Entering a Frame ### So, the reason of segfault seems to be at frame 9, when the ``select()`` function is called. Go to frame 9: ```bash fr 9 #9 0xb7f814ee in _ecore_main_select (timeout=0) at ecore_main.c:338 338 ret = select(max_fd + 1, &rfds, &wfds, &exfds, t); (gdb) l 333 } 334 } 335 #ifndef WIN32 336 if (_ecore_signal_count_get()) return -1; 337 #endif 338 ret = select(max_fd + 1, &rfds, &wfds, &exfds, t); 339 if (ret < 0) 340 { 341 if (errno ### EINTR) return -1; 342 } ``` The first command, ``fr 9``, gives useful information: name of the file, number of the line, the function called, and so on. The second command, ``l``, lists the code around the called function. Another useful command allows to print the variables, the parameters, helping you to find out the problem, a wrong parameter, a null pointer and so on: ```bash (gdb) p ret $1 = -4 (gdb) p rfds $2 = {__fds_bits = {1280, 0 }} (gdb) p wfds $3 = {__fds_bits = {0 }} (gdb) p exfds $4 = {__fds_bits = {0 }} ``` GDB is an important tool for debugging, and it will help you to trace the source of the problem even if it is sometimes not enough alone. ## Valgrind ## Valgrind aims at finding memory problems, but for that Enlightenment needs to be run through Valgrind. ### Prerequisites ### This tutorial will present 3 different ways to run enlightenment through Valgrind: * Remote debugging * Xephyr invocation * Xinit invocation The easiest way is certainly Xephyr because it allows to target a window on a X server host. Sadly Xephyr doesn't yet support OpenGL and any issue that may be related to it will need to use the Xinit version. ### Remote Debugging ### The ``enlightenment_start`` launcher will handle setting up environment variables, paths, and launching any other required services before Enlightenment starts. Fortunately, there are some options in ``enlightenment_start`` which allow to run Enlightenment through Valgrind: ```bash $enlightenment_start --help Options: -valgrind[=MODE] Run enlightenment from inside valgrind, mode is OR of: 1 = plain valgrind to catch crashes (default) 2 = trace children (thumbnailer, efm slaves, ...) 4 = check leak 8 = show reachable after processes finish. all = all of above -massif Run enlightenment from inside massif valgrind tool. -callgrind Run enlightenment from inside callgrind valgrind tool. -valgrind-log-file= Save valgrind log to file, see valgrind's --log-f ``` First of all get the IP address of your host machine and connect to it via SSH, then on your host machine launch X: ```bash #launch X on tty1 sudo X -ac :1 & ``` For example, if you want to check for a memory leak and save traces in a log file: ```bash export DISPLAY=:1 enlightenment_start -valgrind=4 -valgrind-log-file=log.txt ``` At this point Enlightenment should have started on your host machine. If the session is closed then the summary of Valgrind should look like: ```bash ### 1488### ### 1488### HEAP SUMMARY: ### 1488### in use at exit: 4,479,487 bytes in 24,302 blocks ### 1488### total heap usage: 336,239 allocs, 311,937 frees, 88,068,674 bytes allocated ### 1488### ### 1488### LEAK SUMMARY: ### 1488### definitely lost: 825 bytes in 15 blocks ### 1488### indirectly lost: 39 bytes in 2 blocks ### 1488### possibly lost: 384 bytes in 1 blocks ### 1488### still reachable: 4,478,239 bytes in 24,284 blocks ### 1488### suppressed: 0 bytes in 0 blocks ### 1488### Rerun with --leak-check=full to see details of leaked memory ### 1488### ### 1488### For counts of detected and suppressed errors, rerun with: -v ### 1488### ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) ``` ### Valgrind Invocation - Xinit ### Create a file called ".xinitrc-debug" in your home with the following content: ```bash #!/bin/sh ulimit -c unlimited log_file="$HOME/enlightenment-xinit-debug-valgrind.log" #path of you installation enlightenment_install_path=/usr/local #set vars LD_LIBRARY_PATH="$enlightenment_install_path/lib" PATH="$enlightenment_install_path/bin:$PATH" #log to file echo "using installation at $enlightenment_install_path" echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > $log_file echo "PATH=$enlightenment_install_path/bin: ... " >> $log_file #start e with valgrind $enlightenment_install_path/bin/enlightenment_start -valgrind 2>&1 | tee -a "$log_file" ``` You can now start a debugging session. If the session does not appear after X was closed log out: ```bash /usr/bin/xinit ~/.xinitrc-debug -- :1 -nolisten tcp ``` ### Valgrind Invocation - Xephyr ### Xephyr is a display server implementing the X11 display server protocol which targets a window on a X Server host. For this it is important that X is launched; you can do this in your usual window manager under X. First, install Xephyr, then run it using the following command: ```bash Xephyr -ac -br -noreset -screen 800x600 :1 ``` * ac - Disable access control restrictions. * br - Create root window with black background. * noreset - Don't reset after last client exits. * screen 800x600 - Specify the screen's characteristics. A black screen should now be displayed. You can now launch a window manager on it with Valgrind: ```bash DISPLAY=:1 enlightenment_start -valgrind ```