Debugging with GDB or LLDB
**************************

.. warning:: Some of the facilities described here are only
   available in builds from April 11, 2013 or later.
   :class: alert alert-block alert-warning

.. warning:: On Mac OS X, we recommend using lldb to debug
   rather than gdb.
   :class: alert alert-block alert-warning

Which compiler backend are you using?
=====================================

If you are using the C backend, then the information discussed here
will be useful for debugging. We use the C backend on 64 bit Linux,
64 bit FreeBSD and all Mac OS X versions.

If you're using the HARP backend (32 bit Linux or 32 bit FreeBSD), then
you'll be limited to getting stack traces.


Debugging with the C backend
============================

Debugging with the C backend is not a perfect experience but it is
improving.

Finding the generated C files
-----------------------------

The C files generated by the compiler will be found under the
``_build/build`` directory with a directory in there for each
library that was built as part of the project.

Finding the corresponding Dylan code
------------------------------------

The generated C files contain the file name and line number of the
corresponding Dylan source. However, this may be confusing in the
presence of inlined functions and macro expansions.

Understanding name mangling
---------------------------

*Fill this in, particularly with a link to the Hacker's Guide!*

Understanding stack traces
--------------------------

Let's look at part of a representative stack trace::

    #0  0x92b41b06 in read$NOCANCEL$UNIX2003 ()
    #1  0x0042c509 in Kunix_readYio_internalsVioI ()
    #2  0x000bc8e7 in xep_4 ()
    #3  0x0042ba99 in Kaccessor_read_intoXYstreams_internalsVioMM0I ()
    #4  0x000c0805 in key_mep_6 ()
    #5  0x000c43a4 in implicit_keyed_single_method_engine_4 ()
    #6  0x000c1dd5 in gf_optional_xep_4 ()
    #7  0x004139fb in Kload_bufferYstreams_internalsVioI ()
    #8  0x0041334a in Kdo_next_input_bufferYstreamsVioMM1I ()
    #9  0x000c04ab in key_mep_4 ()
    #10 0x000c3eaf in implicit_keyed_single_method_engine_1 ()
    #11 0x0040520f in Kread_lineYstreamsVioMM0I ()
    #12 0x000c0321 in key_mep_3 ()
    #13 0x000c3eaf in implicit_keyed_single_method_engine_1 ()
    #14 0x0079dcf6 in Kcommand_line_loopYcommand_linesVenvironment_commandsMM0I ()
    #15 0x000bf6b3 in rest_key_xep_5 ()
    #16 0x00007abe in Kdo_execute_commandVcommandsMdylan_compilerM0I ()
    #17 0x000bb9bb in primitive_engine_node_apply_with_optionals ()
    #18 0x0002b9ba in Khandle_missed_dispatchVKgI ()
    #19 0x0002aaef in KPgf_dispatch_absentVKgI ()
    #20 0x000c25e8 in general_engine_node_n_engine ()
    #21 0x004b19a8 in Kexecute_commandVcommandsMM0I ()
    #22 0x000bb9bb in primitive_engine_node_apply_with_optionals ()
    #23 0x0002b9ba in Khandle_missed_dispatchVKgI ()
    #24 0x0002aaef in KPgf_dispatch_absentVKgI ()
    #25 0x000c25e8 in general_engine_node_n_engine ()
    #26 0x000c11ab in gf_xep_1 ()
    #27 0x0000aa9e in KmainYconsole_environmentVdylan_compilerI ()
    #28 0x0000abb3 in _Init_dylan_compiler__X_start_for_user ()

Some things to notice:

* Method dispatch takes up the bulk of the stack frames with function calls
  like ``gf_xep_1``, ``general_engine_node_n_engine``, ``rest_key_xep_5``,
  ``key_mep_4``, ``xep_4``, ``implicit_keyed_single_method_engine_1`` and
  so on.
* Methods representing Dylan code are mangled as discussed in a section
  above.
* It may seem alarming to see methods like ``KPgf_dispatch_absentVKgI``
  or ``Khandle_missed_dispatchVKgI`` (where did dispatch go?!?). These
  function calls indicate that the dispatch data for a method hadn't
  been set up yet as this is the first invocation of that method.
  The method dispatch data is set up lazily, so this is normal and
  expected.
* There isn't any information on arguments or what file and line
  number contains the corresponding code. This means that you don't
  have the debug data for the compiler around. An easy way to
  address this is to build your own copy of the compiler.

Breaking on main
----------------

Unfortunately, you can't simply set a breakpoint on ``main``. This is because
the generated code runs from shared library constructor functions so the
entire Dylan application runs and exits prior to ``main`` being invoked.

A reasonable alternative is to determine the C name of your entry point
function and set a breakpoint on that instead.

Inspecting Dylan objects in LLDB
--------------------------------

In LLDB, you may import our Dylan support library::

    command script import /path/to/opendylan/share/opendylan/lldb/dylan

Do not import the scripts under that directory directly as that will not
work. Once this has been done, variables that are representing Dylan
values will automatically be shown with additional data about their
actual values.

Inspecting Dylan objects in GDB
-------------------------------

We do not yet have support for Dylan in GDB as we do for LLDB.

The C runtime contains a number of helper functions specifically for
improving the debugging process. These can be invoked from gdb or lldb
and will assist you in analyzing values.

.. c:function:: D dylan_object_class(D* instance)

   Returns the class instance for the given instance object.

.. c:function:: bool dylan_boolean_p (D instance)

   Tests whether instance is a :drm:`<boolean>`.

.. c:function:: bool dylan_true_p (D instance)

   Tests whether instance is ``#t``.

.. c:function:: bool dylan_float_p (D instance)

   Tests whether instance is a ``<float>``.

.. c:function:: bool dylan_single_float_p (D instance)

   Tests whether instance is a :drm:`<single-float>`.

.. c:function:: float dylan_single_float_data (D instance)

   Returns the ``float`` data stored in the instance.

.. c:function:: bool dylan_double_float_p (D instance)

   Tests whether instance is a :drm:`<double-float>`.

.. c:function:: double dylan_double_float_data (D instance)

   Returns the ``double`` data stored in the instance.

.. c:function:: bool dylan_symbol_p (D instance)

   Tests whether instance is a :drm:`<symbol>`.

.. c:function:: D dylan_symbol_name (D instance)

   Returns the string form of the given symbol.

.. c:function:: bool dylan_pair_p (D instance)

   Tests whether instance is a :drm:`<pair>`.

.. c:function:: bool dylan_empty_list_p (D instance)

   Tests whether instance is an empty list.

.. c:function:: D dylan_head (D instance)

   Returns the head of the given :drm:`<pair>` instance.

.. c:function:: D dylan_tail (D instance)

   Returns the tail of the given :drm:`<pair>` instance.

.. c:function:: bool dylan_vector_p (D instance)

   Tests whether instance is a :drm:`<vector>`.

.. c:function:: bool dylan_string_p (D instance)

   Tests whether instance is a :drm:`<string>`.

.. c:function:: char* dylan_string_data (D instance)

   Returns the C string data stored in the given instance.

.. c:function:: bool dylan_simple_condition_p (D instance)

   Tests whether instance is a ``<simple-condition>``.

.. c:function:: D dylan_simple_condition_format_string (D instance)

   Returns the format string stored in the given ``<simple-condition>``.

.. c:function:: D dylan_simple_condition_format_args (D instance)

   Returns the format string arguments stored in the given
   ``<simple-condition>``.

.. c:function:: bool dylan_class_p (D instance)

   Tests whether instance is a :drm:`<class>`.

.. c:function:: D dylan_class_debug_name (D instance)

   Returns the :drm:`<string>` object containing the class's name.

.. c:function:: bool dylan_function_p (D instance)

   Tests whether instance is a :drm:`<function>`.

.. c:function:: D dylan_function_debug_name (D instance)

   Returns the :drm:`<string>` object containing the function's name.
   Note that we do not store the name for all function objects.

.. c:function:: void dylan_print_object (D object)

   Print some information about the given object to ``stdout``.

Debugging with the HARP backend
===============================

As mentioned previously, this is largely limited to getting stack
traces.  If you try to run a Dylan application built with the
HARP backend under the debugger, you may need to adjust your
debugger's signal handling as the Memory Pool System GC that is
used employs the ``SIGSEGV`` signal.

To do this on Linux and FreeBSD in gdb, use this command::

    handle SIGSEGV pass nostop noprint

*Add more notes about this later.*
