# Debugging with GDB #

The GNU Debugger (GDB) is an invaluable tool for tracking down the precise cause of a crash or other error. While more information on GDB is available on the [GNU website](https://www.gnu.org/software/gdb/documentation/), this document introduces its use specifically for debugging applications written with the Enlightenment Foundation Libraries (EFL).

NOTE: Always begin by running the problem application and walking through the steps needed to reproduce the crash. GDB is of most use when you have a reliable reproduction for your issue.

## Debugging an Incorrect Object ##

The code below creates three Elementary objects: ``win``, ``box`` and an anonymous button. It displays a window with a “Quit” button, which closes the window when it is clicked. Enter the following and save it as “hello.c”:

```c #define EFL_EO_API_SUPPORT 1 #define EFL_BETA_API_SUPPORT 1

#include <Eina.h> #include <Elementary.h> #include <Efl_Ui.h>

static void _quit(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) {

 // quit the mainloop
 efl_exit(0);

}

EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) {

 Efl_Ui_Win *win;
 Efl_Ui_Box *box;
 // new window - new background
 win = efl_add(EFL_UI_WIN_CLASS, NULL,
                efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC),
                efl_text_set(efl_added, "Hello World"),
                efl_ui_win_autodel_set(efl_added, EINA_TRUE));
 // when the user clicks "close" on a window there is a request to delete
 efl_event_callback_add(win, EFL_UI_WIN_EVENT_DELETE_REQUEST, _quit, NULL);
 // add a box object.
 box = efl_add(EFL_UI_BOX_CLASS, win,
               efl_content_set(win, efl_added),
               // set a min size as we will break layout
               efl_gfx_size_hint_min_set(efl_added, EINA_SIZE2D(100, 50)));
 // add a quit button
 efl_add(EFL_UI_BUTTON_CLASS, box,
         efl_text_set(efl_added, "Quit"),
         // **ERROR**
         efl_pack(win, efl_added),
         efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                _quit, efl_added));

} EFL_MAIN() ```

Compile with the ``-g`` flag to enable debugging symbols:

```bash gcc -Wall -O1 -march=native -g -ggdb3 -o hello hello.c `pkg-config –cflags –libs elementary` ```

Then execute the program:

```bash ./hello ERR<12993>:eo lib/eo/eo.c:605 _efl_object_call_resolve() in ../src/lib/efl/interfaces/efl_pack.eo.c:6: func 'efl_pack' (1656) could not be resolved for class 'Efl.Ui.Win'. ```

This error is caused by the ``efl_pack()`` function being called on an incorrect object, ``win``. The error log explains that the ``efl_pack`` is not in the ``Efl.Ui.Win`` API, and so that the error is coming from the application and not from EFL itself.

For a more complicated application, this basic trace is not enough to track down the precise location of the error. Fortunately, EFL provides a macro for backtraces: ``EINA_LOG_ABORT``.

A message generated by the ``EINA_LOG_CRI()`` macro can automatically call ``abort()`` once a message of a given log level is printed. This is controlled by the environment variable ``EINA_LOG_ABORT``, and the level to be considered critical by the environment variable ``EINA_LOG_ABORT_LEVEL``. When enabled the program will stop at the first error which meets both of the two requirements.

Run GDB over the application with ``EINA_LOG_ABORT_LEVEL=4`` and ``EINA_LOG_ABORT=1`` set to receive the following backtrace:

```gdb EINA_LOG_ABORT_LEVEL=4 EINA_LOG_ABORT=1 gdb hello (gdb) run Starting program: /home/efl/test/hello [Thread debugging using libthread_db enabled] Using host libthread_db library “/usr/lib/libthread_db.so.1”. [New Thread 0x7fffebf01700 (LWP 13092)] [New Thread 0x7fffe94d9700 (LWP 13093)] [New Thread 0x7fffe8cd8700 (LWP 13094)] [New Thread 0x7fffe84d7700 (LWP 13095)] [Thread 0x7fffe84d7700 (LWP 13095) exited] [New Thread 0x7fffe84d7700 (LWP 13096)] ERR<13088>:eo lib/eo/eo.c:605 _efl_object_call_resolve() in ../src/lib/efl/interfaces/efl_pack.eo.c:6: func 'efl_pack' (1656) could not be resolved for class 'Efl.Ui.Win'.

Thread 1 “debugging” received signal SIGABRT, Aborted. 0x00007ffff3e998a0 in raise () from /usr/lib/libc.so.6 (gdb) backtrace #0 0x00007ffff3e998a0 in raise () from /usr/lib/libc.so.6 #1 0x00007ffff3e9af09 in abort () from /usr/lib/libc.so.6 #2 0x00007ffff739ee25 in eina_log_print_unlocked (domain=<optimized out>, level=EINA_LOG_LEVEL_ERR,

  file=0x7ffff5ce0a5a "lib/eo/eo.c", fnc=0x7ffff5ce1f70 <__FUNCTION__.14772> "_efl_object_call_resolve",
  line=<optimized out>, fmt=0x7ffff5ce1410 "in %s:%d: func '%s' (%d) could not be resolved for class '%s'.",
  args=0x7fffffffdea0) at lib/eina/eina_log.c:1420

#3 0x00007ffff73a0153 in eina_log_print (domain=29, level=level@entry=EINA_LOG_LEVEL_ERR,

  file=file@entry=0x7ffff5ce0a5a "lib/eo/eo.c",
  fnc=fnc@entry=0x7ffff5ce1f70 <__FUNCTION__.14772> "_efl_object_call_resolve", line=605,
  fmt=0x7ffff5ce1410 "in %s:%d: func '%s' (%d) could not be resolved for class '%s'.") at lib/eina/eina_log.c:2259

#4 0x00007ffff5cd3fd4 in _efl_object_call_resolve (eo_id=eo_id@entry=0x40000000d32a,

  func_name=func_name@entry=0x7ffff7651b73 "efl_pack", call=call@entry=0x7fffffffe050, cache=0x7ffff7fa4b60,
  file=file@entry=0x7ffff7651b18 "../src/lib/efl/interfaces/efl_pack.eo.c", line=line@entry=6) at lib/eo/eo.c:614

#5 0x00007ffff762e80e in efl_pack (obj=0x40000000d32a, subobj=0x40000002578b) at ../src/lib/efl/interfaces/efl_pack.eo.c:6 #6 0x00005555555553d1 in efl_main (data=<optimized out>, ev=<optimized out>) at gdb.c:37 #7 0x00007ffff5cdeb57 in _event_callback_call (legacy_compare=0 '\000', event_info=<optimized out>,

  desc=0x7ffff6a78b80 <_EFL_LOOP_EVENT_ARGUMENTS>, pd=0x55555578bd50, obj_id=<optimized out>) at lib/eo/eo_base_class.c:1542

#8 _efl_object_event_callback_call (obj_id=<optimized out>, pd=0x55555578bd50,

  desc=0x7ffff6a78b80 <_EFL_LOOP_EVENT_ARGUMENTS>, event_info=<optimized out>) at lib/eo/eo_base_class.c:1603

#9 0x00007ffff5cd90fe in efl_event_callback_call (obj=0x4000000006f7,

  desc=desc@entry=0x7ffff6a78b80 <_EFL_LOOP_EVENT_ARGUMENTS>, event_info=event_info@entry=0x7fffffffe230)
  at lib/eo/eo_base_class.c:1606

#10 0x00007ffff6842c85 in _efl_loop_arguments_send (data=0x5555557a4f40, ev=<optimized out>) at lib/ecore/ecore_main.c:3151 #11 0x00007ffff684f856 in _efl_loop_future_success (ev=ev@entry=0x7fffffffe2b0, pd=pd@entry=0x5555557a8660, value=0x0)

  at lib/ecore/efl_promise.c:113

#12 0x00007ffff685080f in _efl_loop_future_propagate (obj=0x400000008316, pd=0x5555557a8660) at lib/ecore/efl_promise.c:192 #13 0x00007ffff685088b in _efl_promise_propagate (obj=0x400000007f15, pd=0x5555557a68b0) at lib/ecore/efl_promise.c:580 #14 0x00007ffff6851640 in ecore_loop_promise_fulfill (obj=<optimized out>) at lib/ecore/efl_promise.c:593 #15 0x00007ffff68416fd in _ecore_main_loop_iterate_internal (once_only=once_only@entry=0) at lib/ecore/ecore_main.c:2313 #16 0x00007ffff6841e77 in ecore_main_loop_begin () at lib/ecore/ecore_main.c:1313 #17 0x00007ffff6841eb9 in _efl_loop_begin (obj=<optimized out>, pd=<optimized out>) at lib/ecore/ecore_main.c:2889 #18 0x00007ffff683ea9e in efl_loop_begin (obj=0x4000000006f7) at lib/ecore/efl_loop.eo.c:44 #19 0x00005555555554a6 in main (argc=1, argv=0x7fffffffe4f8) at hello.c:44 ```

The ``efl_pack()`` function is in frame five, so is called from frame six.

Go to frame six:

```gdb (gdb) frame 6 #6 0x00005555555553d1 in efl_main (data=<optimized out>, ev=<optimized out>) at gdb.c:37 37 efl_add(EFL_UI_BUTTON_CLASS, box, win instead of box ``` This frame shows that the button constructor which begins on line 37 (``at gdb.c:37``) is responsible for the problem. Looking at the source code for the application, walk down from line 37 until you find the line in which ``win`` is used instead of ``box`` - which is line 40. This is the line which contains the error, and which must be corrected for the program to function correctly. ## Debugging a Callback Function ## To demonstrate the debugging of a callback function, create the following program: ```c #define EFL_EO_API_SUPPORT 1 #define EFL_BETA_API_SUPPORT 1 #include <Eina.h> #include <Elementary.h> #include <Efl_Ui.h> static void _quit(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) { int *pi; pi = (int *)0; pointer to 0x0!!!

 /**SEGFAULT**/
 printf("Pi = %d\n", *pi); // segfault accessing 0x0 address
 // quit the mainloop
 efl_exit(0);

}

EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) {

 Efl_Ui_Win *win;
 Efl_Ui_Box *box;
 // new window - new background
 win = efl_add(EFL_UI_WIN_CLASS, NULL,
                efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC),
                efl_text_set(efl_added, "Hello World"),
                efl_ui_win_autodel_set(efl_added, EINA_TRUE));
 // when the user clicks "close" on a window there is a request to delete
 efl_event_callback_add(win, EFL_UI_WIN_EVENT_DELETE_REQUEST, _quit, NULL);
 // add a box object.
 box = efl_add(EFL_UI_BOX_CLASS, win,
               efl_content_set(win, efl_added));
 // add a quit button
 efl_add(EFL_UI_BUTTON_CLASS, box,
         efl_text_set(efl_added, "Crash"),
         efl_pack(box, efl_added),
         efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                _quit, efl_added));

} EFL_MAIN() ```

Save the program as “helloworld.c”, compile it with the ``-g`` flag to include debugging symbols, and run it. The program will quit with a segmentation fault (segfault) error when the “Crash” button is clicked; in other words, during the callback function.

To debug this, load the program into GDB and run it:

```gdb gdb helloworld (gdb) run […] Thread 1 “debugging2” received signal SIGSEGV, Segmentation fault. _quit (data=0x400000025528, event=0x7fffffffdfe0) at gdb2.c:15 15 printf(“Pi = %d\n”, *pi); segfault accessing 0x0 address (gdb) backtrace #0 _quit (data=0x400000025528, event=0x7fffffffdfe0) at helloworld.c:15 #1 0x00007ffff5cdd967 in _event_callback_call (legacy_compare=1 '\001', event_info=<optimized out>, desc=<optimized out>, pd=0x555555b520c0, obj_id=<optimized out>) at lib/eo/eo_base_class.c:1542 #2 _efl_object_event_callback_legacy_call (obj_id=<optimized out>, pd=0x555555b520c0, desc=<optimized out>, event_info=<optimized out>) at lib/eo/eo_base_class.c:1615 #3 0x00007ffff5cd923e in efl_event_callback_legacy_call (obj=0x400000025528, desc=0x7ffff78625b0 <_EFL_UI_EVENT_CLICKED>, event_info=0x0) at lib/eo/eo_base_class.c:1618 #4 0x00007ffff5cd923e in efl_event_callback_legacy_call (obj=0x400000025528, desc=0x7ffff78625b0 <_EFL_UI_EVENT_CLICKED>, event_info=0x0) at lib/eo/eo_base_class.c:1618 #5 0x00007ffff5f8879b in edje_match_callback_exec_check_finals (prop=<optimized out>, ed=0x555555b71800, source=0xaaaaaaaaaaaaaaab <error: Cannot access memory at address 0xaaaaaaaaaaaaaaab>, sig=0x555555b52890 “”, source_states=<optimized out>, signal_states=<optimized out>, matches=<optimized out>, ssp=0x555555b71800) at lib/edje/edje_match.c:556 #6 edje_match_callback_exec (ssp=ssp@entry=0x555555b71800, matches=<optimized out>, sig=sig@entry=0x555555b4263c “elm,action,click”, source=source@entry=0x555555a42d90 “elm”, ed=ed@entry=0x555555b52890, prop=prop@entry=0 '\000') at lib/edje/edje_match.c:711 #7 0x00007ffff5f8faa2 in _edje_emit_cb (prop=0 '\000', data=0x0, src=0x555555a42d90 “elm”, sig=0x555555b4263c “elm,action,click”, ed=0x555555b52890) at lib/edje/edje_program.c:1592 #8 _edje_emit_handle (ed=0x555555b52890, sig=0x555555b4263c “elm,action,click”, src=0x555555a42d90 “elm”, sdata=0x0, prop=0 '\000') at lib/edje/edje_program.c:1544 #9 0x00007ffff5f8a2df in _edje_message_queue_process () at lib/edje/edje_message_queue.c:893 #10 0x00007ffff5f8a499 in _edje_message_queue_process () at lib/edje/edje_message_queue.c:859 #11 _edje_job (data=<optimized out>) at lib/edje/edje_message_queue.c:260 #12 0x00007ffff683da6b in _ecore_job_event_handler (data=<optimized out>, type=<optimized out>, ev=<optimized out>) at lib/ecore/ecore_job.c:98 #13 0x00007ffff6839301 in _ecore_call_handler_cb (event=<optimized out>, type=<optimized out>, data=<optimized out>, func=<optimized out>) at lib/ecore/ecore_private.h:331 #14 _ecore_event_call () at lib/ecore/ecore_events.c:629 #15 0x00007ffff6841a88 in _ecore_main_loop_iterate_internal (once_only=once_only@entry=0) at lib/ecore/ecore_main.c:2438 #16 0x00007ffff6841e77 in ecore_main_loop_begin () at lib/ecore/ecore_main.c:1313 #17 0x00007ffff6841eb9 in _efl_loop_begin (obj=<optimized out>, pd=<optimized out>) at lib/ecore/ecore_main.c:2889 #18 0x00007ffff683ea9e in efl_loop_begin (obj=0x400000000494) at lib/ecore/efl_loop.eo.c:44 #19 0x000055555555549c in main (argc=1, argv=0x7fffffffe528) at helloworld.c:47 ``` The program failed in the callback function, meaning the problem comes from the program itself and not the libraries - even if the callback is called from ``Efl.Event``. To look at the problem more deeply: * Go to frame zero, the callback function * Print the ``pi`` pointer * Print what it points to ```bash (gdb) frame 0 #0 _quit (data=0x400000025528, event=0x7fffffffdfe0) at gdb2.c:15 15 printf(“Pi = %d\n”, *pi); segfault accessing 0x0 address (gdb) print pi $1 (int *) 0x0 (gdb) print *pi Cannot access memory at address 0x0 ```

This demonstrates the problem: address ``0x0`` cannot be accessed. Using these techniques, even if the callback functions are called from ``Efl.Event`` and so generate lots of traces, it is quite simple to track down these types of bug.