Keywords: sdccman

# 5. Debugging

There are several approaches to debugging your code. This chapter is meant to show your options and to give detail on some of them:
When writing your code:

- write your code with debugging in mind (avoid duplicating code, put conceptually similar variables into structs, use structured code, have strategic points within your code where all variables are consistent, ...)
- run a syntax-checking tool like splint (see —more-pedantic 3.3.4) over the code.
- for the high level code use a C-compiler (like f.e. GCC) to compile run and debug the code on your host. See (see —more-pedantic 3.3.4) on how to handle syntax extensions like __xdata, __at(), ...
- use another C-compiler to compile code for your target. Always an option but not recommended:) And not very likely to help you. If you seriously consider walking this path you should at least occasionally check portability of your code. Most commercial compiler vendors will offer an evaluation version so you can test compile your code or snippets of your code.

Debugging on a simulator:

- there is a separate section about SDCDB (section 5.1) below.
- or (8051 specific) use a free open source/commercial simulator which interfaces to the AOMF file (see 3.2.1) optionally generated by SDCC.

Debugging On-target:

- use a MCU port pin to serially output debug data to the RS232 port of your host. You'll probably want some level shifting device typically involving a MAX232 or similar IC. If the hardware serial port of the MCU is not available search for 'Software UART' in your favourite search machine.
- use an on-target monitor. In this context a monitor is a small program which usually accepts commands via a serial line and allows to set program counter, to single step through a program and read/write memory locations. For the 8051 good examples of monitors are paulmon and cmon51 (see section 6.5).
- toggle MCU port pins at strategic points within your code and use an oscilloscope. A digital oscilloscope with deep trace memory is really helpful especially if you have to debug a realtime application. If you need to monitor more pins than your oscilloscope provides you can sometimes get away with a small R-2R network. On a single channel oscilloscope you could for example monitor 2 push-pull driven pins by connecting one via a 10 k resistor and the other one by a 5 k resistor to the oscilloscope probe (check output drive capability of the pins you want to monitor). If you need to monitor many more pins a logic analyzer will be handy.
- use an ICE (in circuit emulator). Usually very expensive. And very nice to have too. And usually locks you (for years...) to the devices the ICE can emulate.
- use a remote debugger. In most 8-bit systems the symbol information is not available on the target, and a complete debugger is too bulky for the target system. Therefore usually a debugger on the host system connects to an on-target debugging stub which accepts only primitive commands.
  Terms to enter into your favourite search engine could be 'remote debugging', 'gdb stub' or 'inferior debugger'. (is there one?)
- use an on target hardware debugger. Some of the more modern MCUs include hardware support for setting break points and monitoring/changing variables by using dedicated hardware pins. This facility doesn't require additional code to run on the target and usually doesn't affect runtime behaviour until a breakpoint is hit. For the mcs51 most hardware debuggers use the AOMF file (see 3.2.1) as input file.

Last not least:

- if you are not familiar with any of the following terms you're likely to run into problems rather sooner than later: volatile, atomic, memory map, overlay. As an embedded programmer you have to know them so why not look them up before you have problems?)
- tell someone else about your problem (actually this is a surprisingly effective means to hunt down the bug even if the listener is not familiar with your environment). As 'failure to communicate' is probably one of the job-induced deformations of an embedded programmer this is highly encouraged.

Subsections

- 5.1 Debugging with SDCDB
  - 5.1.1 Compiling for Debugging
  - 5.1.2 How the Debugger Works
  - 5.1.3 Starting the Debugger SDCDB
  - 5.1.4 SDCDB Command Line Options
  - 5.1.5 SDCDB Debugger Commands
    - break [line | file:line | function | file:function]
    - clear [line | file:line | function | file:function ]
    - continue
    - finish
    - delete [n]
    - info [break | stack | frame | registers ]
    - step
    - next
    - run
    - ptype variable
    - print variable
    - file filename
    - frame
    - set srcmode
    - ! simulator command
    - quit
  - 5.1.6 Interfacing SDCDB with DDD
  - 5.1.7 Interfacing SDCDB with XEmacs
- 5.2 Debugging with other debuggers (e.g. GDB): ELF / DWARF