debugging.rst 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. .. include:: /substitutions.rst
  2. .. _debugging:
  3. =========
  4. Debugging
  5. =========
  6. Finding and fixing bugs is an important part of the hardware and software development process. Sometimes you also need
  7. to use debugging techniques to understand how the system works. Two tools that are helpful are debug logging and
  8. debugging using the GNU Debugger (gdb).
  9. Debug Logging
  10. =============
  11. NuttX has a powerful system logging facility (syslog) with ``info``, ``warn``, and ``error`` levels. You can enable
  12. debugging for your build for the subsystem or feature by using the ``menuconfig`` system.
  13. The debug options are available under :menuselection:`Build Setup --> Debug Options`. You will most likely have to enable the
  14. following options:
  15. * :menuselection:`Enable Debug Features` — selecting this will turn on subsystem-level debugging options, they will become visible
  16. on the page below. You can then select the ones you want.
  17. * :menuselection:`Enable Error Output` — this will only log errors.
  18. * :menuselection:`Enable Warnings Output` — this will log warnings and errors.
  19. * :menuselection:`Enable Informational Debug Output` — this will produce informational output, warnings, and errors.
  20. You can then select from the subsystems that are available, Network, Scheduler, USB, etc. Note that you will need to
  21. separately enable the subsystem elsewhere in the ``menuconfig`` system. To see the ``CONFIG`` define that is set,
  22. use the arrow keys to highlight the subsystem (for instance, :menuselection:`Network Debug Features`) and type :kbd:`?`. This will show
  23. you that the C macro that is set is called ``CONFIG_DEBUG_NET``. ``debug.h`` defines the ``netinfo()`` logging
  24. function that will log output if this macro is set. You can search the source code for ``netinfo`` to see how it is
  25. used.
  26. .. image:: ../_static/images/menuconfig-debug.png
  27. :width: 800px
  28. :align: center
  29. :alt: Screenshot of menuconfig system main screen
  30. Note that enabling all these will produce an incredible amount of logging output. Enable the level you want and
  31. the area you're interested in, and leave the rest disabled, save the config, and then recompile. You can see the full
  32. list of debug feature logging functions in the file
  33. `debug.h <https://github.com/apache/incubator-nuttx/blob/master/include/debug.h>`__.
  34. Syslog timestamps can be enabled in the configuration in :menuselection:`Device Drivers --> System Logging --> Prepend
  35. timestamp to syslog message` (``CONFIG_SYSLOG_TIMESTAMP``).
  36. You may need to do a little bit of experimenting to find the combination of logging settings that work for the problem
  37. you're trying to solve. See the file `debug.h <https://github.com/apache/incubator-nuttx/blob/master/include/debug.h>`_
  38. for available debug settings that are available.
  39. There are also subsystems that enable USB trace debugging, and you can log to memory too, if you need the logging to be
  40. faster than what the console can output.
  41. Debugging with ``openocd`` and ``gdb``
  42. ======================================
  43. To debug our Nucleo board using its embedded SWD debug adapter,
  44. start ``openocd`` with the following command:
  45. .. code-block:: console
  46. $ openocd -f interface/st-link-v2.cfg -f target/stm32f1x.cfg
  47. This will start a ``gdb`` server. Then, start ``gdb`` with:
  48. .. code-block:: console
  49. $ cd nuttx/
  50. $ gdb-multiarch nuttx/nuttx
  51. Inside ``gdb`` console, connect to the ``gdb`` server with:
  52. .. code-block::
  53. (gdb) target extended-remote :3333
  54. You can now use standard ``gdb`` commands. For example, to
  55. reset the board:
  56. .. code-block::
  57. (gdb) mon reset
  58. To halt the board:
  59. .. code-block::
  60. (gdb) mon halt
  61. To set a breakpoint:
  62. .. code-block::
  63. (gdb) breakpoint nsh_main
  64. and to finally start nuttx:
  65. .. code-block::
  66. (gdb) continue
  67. Continuing.
  68. Breakpoint 1, nsh_main (argc=1, argv=0x200ddfac) at nsh_main.c:208
  69. 208 sched_getparam(0, &param);
  70. (gdb) continue
  71. Continuing.
  72. .. tip::
  73. You can abbreviate ``gdb`` commands: ``info b`` is a shortcut for
  74. ``information breakpoints``; ``c`` works the same as ``continue``, etc.
  75. NuttX aware debugging
  76. ---------------------
  77. Since NuttX is actually an RTOS, it is useful to have ``gdb`` be aware of the different
  78. tasks/threads that are running. There are two ways to do this: via ``openocd``
  79. itself or via ``gdb``. Note that in both cases, you need to enable debug symbols
  80. (``CONFIG_DEBUG_SYMBOLS``).
  81. With openocd
  82. ~~~~~~~~~~~~
  83. ``openocd`` supports various RTOS directly, including NuttX. It works by reading
  84. into internal NuttX symbols which define the active tasks and their properties.
  85. As a result, the ``gdb`` server will directly be aware of each task as a different
  86. `thread`. The downside of this approach is that it depends on how you build NuttX
  87. as there are some options hardcoded into
  88. opencd. By default, it assumes:
  89. * ``CONFIG_DISABLE_MQUEUE=y``
  90. * ``CONFIG_PAGING=n``
  91. If you need these options to be set differently, you will have to edit ``./src/rtos/nuttx_header.h`` from ``openocd``,
  92. change the corresponding settings and then rebuild it.
  93. Finally, to enable NuttX integration, you need to supply an additional ``openocd`` argument:
  94. .. code-block:: console
  95. $ openocd -f interface/st-link-v2.cfg -f target/stm32f1x.cfg -c '$_TARGETNAME configure -rtos nuttx'
  96. Since ``openocd`` also needs to know the memory layout of certain datastructures, you need to have ``gdb``
  97. run the following commands once the ``nuttx`` binary is loaded:
  98. .. code-block::
  99. eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
  100. eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
  101. eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
  102. eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
  103. eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
  104. One way to do this is to define a gdb `hook` function that will be called when running ``file`` command:
  105. .. code-block::
  106. define hookpost-file
  107. eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
  108. eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
  109. eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
  110. eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
  111. eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
  112. end
  113. You will see that ``openocd`` has received the memory offsets in its output:
  114. .. code-block::
  115. Open On-Chip Debugger 0.10.0+dev-01514-ga8edbd020-dirty (2020-11-20-14:23)
  116. Licensed under GNU GPL v2
  117. For bug reports, read
  118. http://openocd.org/doc/doxygen/bugs.html
  119. Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
  120. Info : target type name = cortex_m
  121. Info : Listening on port 6666 for tcl connections
  122. Info : Listening on port 4444 for telnet connections
  123. 15:41:23: Debugging starts
  124. Info : CMSIS-DAP: SWD Supported
  125. Info : CMSIS-DAP: FW Version = 1.10
  126. Info : CMSIS-DAP: Interface Initialised (SWD)
  127. Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
  128. Info : CMSIS-DAP: Interface ready
  129. Info : clock speed 1000 kHz
  130. Info : SWD DPIDR 0x2ba01477
  131. Info : nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints
  132. Info : starting gdb server for nrf52.cpu on 3333
  133. Info : Listening on port 3333 for gdb connections
  134. Info : accepting 'gdb' connection on tcp/3333
  135. Error: No symbols for NuttX
  136. Info : nRF52832-QFAA(build code: B0) 512kB Flash, 64kB RAM
  137. undefined debug reason 8 - target needs reset
  138. Warn : Prefer GDB command "target extended-remote 3333" instead of "target remote 3333"
  139. Info : pid_offset: 12
  140. Info : xcpreg_offset: 132
  141. Info : state_offset: 26
  142. Info : name_offset: 208
  143. Info : name_size: 32
  144. target halted due to debug-request, current mode: Thread
  145. xPSR: 0x01000000 pc: 0x000000dc msp: 0x20000cf0
  146. target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x000000dc msp: 0x20000cf0
  147. .. note:: You will probably see the ``Error: No symbols for NuttX`` error appear once at startup. This is OK
  148. unless you see it every time you step the debugger. In this case, it would mean you did not enable debug symbols.
  149. Now, You can now inspect threads:
  150. .. code-block::
  151. (gdb) info threads
  152. Id Target Id Frame
  153. * 1 Remote target nx_start_application () at init/nx_bringup.c:261
  154. (gdb) info registers
  155. r0 0x0 0
  156. r1 0x2f 47
  157. r2 0x0 0
  158. r3 0x0 0
  159. r4 0x0 0
  160. r5 0x0 0
  161. r6 0x0 0
  162. r7 0x20000ca0 536874144
  163. r8 0x0 0
  164. r9 0x0 0
  165. r10 0x0 0
  166. r11 0x0 0
  167. r12 0x9 9
  168. sp 0x20000c98 0x20000c98
  169. lr 0x19c5 6597
  170. pc 0x1996 0x1996 <nx_start_application+10>
  171. xPSR 0x41000000 1090519040
  172. fpscr 0x0 0
  173. msp 0x20000c98 0x20000c98
  174. psp 0x0 0x0 <_vectors>
  175. primask 0x0 0
  176. basepri 0xe0 -32
  177. faultmask 0x0 0
  178. control 0x0 0
  179. With gdb
  180. ~~~~~~~~
  181. You can also do NuttX aware debugging using ``gdb`` scripting support.
  182. The benefit is that it works also for the sim build where ``openocd`` is
  183. not applicable. For this to work, you will need to enable PROC filesystem support
  184. which will expose required task information (``CONFIG_FS_PROCFS=y``).
  185. To use this approach, you can load the ``nuttx/tools/nuttx-gdbinit`` file. An
  186. easy way to do this is to create a symbolic link:
  187. .. code-block:: console
  188. $ cd $HOME
  189. $ ln -s nuttx/tools/nuttx-gdbinit .gdbinit
  190. This way whenever gdb is started it will run the appropriate commands. To inspect
  191. the threads you can now use the following ``gdb`` command:
  192. .. code-block::
  193. (gdb) info_nxthreads
  194. target examined
  195. _target_arch.name=armv7e-m
  196. $_target_has_fpu : 0
  197. $_target_has_smp : 0
  198. saved current_tcb (pid=0)
  199. * 0 Thread 0x20000308 (Name: Idle Task, State: Running, Priority: 0) 0xdc in __start()
  200. 1 Thread 0x20001480 (Name: init, State: Waiting,Semaphore, Priority: 100) 0x7e08 in arm_switchcontext()