RISC OS: Using the Acorn / ROOL Desktop Debugging Tool DDT (part 1)


This is the first part of an introductory tutorial to one of the first RISC OS Desktop Debugging Tool (DDT) available in the original Acorn Desktop Development Environment suite (DDE) and now on the RISC OS Open DDE.

Disclaimer

  • This series of articles is not exhaustive to all the features offered by the DDE DDT. It should be considered only as an introduction or as a tutorial for new users to learn how to use the debugger.
  • The ROOL / Acorn DDE DDT is NOT the ARM DDT (Although if they are both built for the ARM CPU and have similar names, they are two different products).
  • This series of articles only describe how to use the Acorn / RISC OS Open DDT.
  • If you’re using ROOL DDE then before reading this article please make sure you have correctly installed your ROOL DDE, here I added a full installation tutorial for your convenience and with all the details on how to make DDE work fine on all RISC OS releases, please check it out.

Introduction

Here is another development tool that I had to learn when I was a teenager by “hacking” it, because, for some reasons I do not recall, when I received my first copy of the Acorn DDE (back in the early 90s) there was no documentation accompanying it. The Acorn Desktop Debugging Tool was one of the first of its kind, way before GDB was even a thing, when debugging was just an art mostly forged in the source code by adding all sorts of code tracking messages and tricks. The aim of the tool was to help application developers to debug their single and multi-tasking applications on RISC OS, so it’s not really a tool to debug device drivers and/or Kernel modules.

DDT is an ARM AIF image debugger, so it cannot debug ELF executables. Acorn C/C++, Acorn DDE, ROOL DDE, Beebug Easy C and Beebug Easy C++ can be used to generate AIF executables. Modern GCC for RISC OS generates ELF executables ( however an ELF executable can be converted into AIF if needed ) while IIRC old GCC 2.x.y and 3.x.y could generate Executable AIF.

DDT components

Originally developed at Acorn Ltd for their Acorn Desktop Development Environment (Acorn DDE) as successor of their Acorn Symbolic Debugger, DDT is available nowadays as part of the RISC OS Open Desktop Development Environment (ROOL DDE) and it’s composed principally by 2 components:

  • The !DDT Front End, a RISC OS multi-task application that controls and uses the DDT Module.
  • The DDT Module, a RISC OS single-task relocable module which is stored in the !System modules container and that gets loaded in memory when the user loads the !DDT application. The DDT Module controls the debugging of our program.

However DDT also uses other SWIs (SoftWare Interrupts, an old way to call ARM System Service Calls or SVC) provided mostly by RISC OS itself and few other Modules.

DDT quirkiness

One DDT thing that seems to confuse many new users is that by having a WIMP Front End and having Desktop word in its name it may sounds like DDT is a full multi-tasking tool (or true multi-tasking to use the original term from Acorn), but it is not fully multi-task and there are historical reasons for that: DDT had to be able to halt RISC OS  at any point in order to be able to do the single stepping and to handle breakpoints a user may have set in the source code while debugging it.

Basically when it halts our code (due a step in or a breakpoint) DDT has to freeze RISC OS itself, but when our code execution resumes (for example when we press ^C) then DDT re-enable RISC OS multi-tasking (and so also other applications running at the same time will resume as well). The reason some people believe it’s a single task tool only is because debugging step-by-step (aka opcode-by-opcode) disassembled code doesn’t give enough time to actually observe any multi-tasking activity in the background (for example having another app sending messages) and in that specific case it really behaves like a single-task tool.

Compiling code to be debugged in DDT

Before we even try to use DDT we MUST compile our code with debugging info otherwise DDT won’t be able to perform a source level debug process.

Compiler parameters

When compiling C code with Acorn C/C++, Acorn DDE and/or ROOL DDE, to have DDT performing Source-Level debugging we should make sure the cc compiler has the option -g (which asks the compiler to add the AIF High-Level debug info to the object file and set the flag at 0x24 in the AIF header to 2). Also we should make sure that the -g option is added as one of the last options, this to avoid potential conflicting options.

– If you are compiling your code using the !CC desktop application then:

Just select the option Debug on the !CC main window after you’ve dragged your C source on !CC icon on the iconbar.

DDT-CC-Options

Fig a1

– If your are compiling your code using a Makefile, scripts and/or command line then:

Add the option -g to the line where you are calling the cc compiler, something like:

cc list-of-my-options -g -o mycode

ObjAsm Assembler parameters

If you need to debug ARM assembly code and you want to have a better debugging experience with DDT, then you may want to pass the options -g --keep to ObASM Assembler. These options ask ObjAsm to add debug info (-g) and to keep local labels in the symbol table of the object file (–keep) and those info will be used by DDT during the debugging session (-g in ObjAsm works similarly to -g for CC on the AIF header).

– If you are using !ObjAsm desktop application to assemble your ARM source code then:

Just select the option Debug from the main window after you carried your asm source on the !ObjAsm icon on the iconbar.

Please Note: If you use the Desktop application !ObjAsm and check debug option it will only add -g option, JFYI.

– If you are using Makefiles and/or other scripts to assemble your code then:

Pass the options -g --keep to the line where you call objasm command. For example:

objasm s.hellow -o test -g --keep

Compiling code using ROOL Makefiles

ROOL DDE comes with some useful AMU Makefile libraries which kinda help with bigger projects, but that also add “new” rules to the game.

If your MakeFile is including or using ROOL AMU Makefile libraries (basically if you added something like include CApp to your amu Makefile for example) then, instead of using the info above, all you have to do is call amu passing the debug goal, like:

amu debug THROWBACK=-throwback

Another useful tips when using the ROOL shared makefiles is to clear (or “unset”) C_NO_FNAMES  in your Makefile (after you’ve included CApp shared makefile). This because the ROOL Makefiles library by default compile C code without the embedded functions name. This helps to keep the executable small and so faster to be loaded from slow devices like SD cards, but it can cause issues when we need to debug our code. To unset C_NO_FNAMES simply add the following line to your Makefile AFTER you included a ROOL shared Makefile:

C_NO_FNAMES :=

In certain cases you may want to customise the debug build and in such cases you can set some special AMU variables in your Makefile before you include the ROOL amu Makefiles library.

For example, if you are using include CApp in your amu Makefile then all you have to do is add the following line to your Makefile BEFORE you include CApp to it:

DBG_TARGET = MyAppDebug

And if you want to also specify which debugging Object file to link (for example to have more debugging info in your final debugging executable AIF) then add also:

DBG_OBJS   = MyObj1 MyObj2 ...

Obviously replace MyAppDebug with the name of your program and myObj1, MyObj2 etc. (in case you’ve got distracted, the 3 dots means a list of object, not something you have to type) with your object files that contains debug info (usually that means just copy what you already have written in the OBJS variable basically).

I would recommend to use the ROOL amu Makefiles libraries because they add more, they also include C:o.DDTLib to your object code when activating debugging, which helps.

Compiling code with other compilers

ROOL DDE suite comes also with the !ABC compiler, which compiles BBC BASIC into a sort of executable AIF (not a standard AIF thought). RISC OS also has other compilers like Beebug Easy C and C++, Acorn ISO Pascal (that compile ISO Pascal into an Executable AIF) as well as other Assemblers etc. If I have time I’ll try to add articles for each specific of these other compilers, because some of them don’t always adhere perfectly to what DDT expect, others are still only 26bit capable or because their differences may require some extra space to be described.

Linker parameters

For the link command, if you are using a Makefile and/or scripts/command line to link your code then you should make sure to add the -Debug option as follow:

link list-of-my-options -Debug list-of-my-object-files-to-link

If, instead you are linking your code using the !Link desktop application, make sure you select the Debug option from the main window after you’ve carried your object file on !Link icon on the iconbar.

AFAIR The linker -debug should add the low-level debugging info to the AIF file and make sure that the value of &24 in the AIF header file is either set to 1 if it was zero or to 3 if it was set to 2.

Please Note (1): As far as I remember If you do not wish to use Source Code level debugging you can avoid using -g for the C compiler and ObjAsm ( and also avoid –keep for the ObjAsm ), however to be able to debug your code correctly the -Debug option for the linker is a must have.

Please Note (2): If you are using ROOL amu Makefiles library then do not worry about the linker because the amu libraries will take care of it and in the correct way, just follow the instructions on the “Compiling Code using ROOL Makefiles” paragraph.

Correct executable location on the file system

You should also make sure to place your generated executable AIF in the directory that contains the C sources (.c), the C headers (.h) and/or the ASM source (.s) subdirectories, for example if your source tree looks like the following:

!MyApp
   |
   +- src
   |   |
   |   +- c
   |   |  |
   |   |  +- mycode
   |   |
   |   +- h
   |      |
   |      +- mycode
   |

Then you should place your executable in src.

Here is a visual example:

DDT-ExecAIF-location

Fig b1

This because DDT uses Run$Path variable to get the absolute path to the source and then it takes the source file names from the debugging info which would be similar to mycode.c which on RISC OS becomes c.mycode, hence the full path to the source becomes: <Run$Path>.c.mycode

Please Note (1): If you do not want to place your executable in the directory that contains the c,h,o and s subdirectories you can do so, but then you’ll have to provide the path to the sources manually from the DDT application menu and on some past releases of DDT it did give me some issues, so now I always place my executable in the directory containing my source to avoid any issue. To select the source path from the DDT Application menu, when you have loaded your executable in DDT, before starting to debug it click on the mouse Menu button (on RISC OS this is the middle button by default) and select the option Options -> Source. In the Source field type the absolute path to the directory containing the c,h,o and s subdirectories.

Please Note (2): If you are using ROOL amu MakeFiles library then it should already place your executable in the right place.

If you do not follow all the rules above, then, when you’ll start your debugging session, DDT will show you a warning message on the lower window:

No source level debugging information

If you have forgotten to pass -Debug in the linker then DDT will display also the following warning message:

No debugging information available

The linker -Debug option is important because it allows DDT to access a lot of important linking symbols which may help you to debug your code or when your code calls functions in 3rd parties libraries or in the SharedCLibrary of RISC OS.

Starting a Debug Session

Useful trick: before you start your debug session with DDT open your .c (or .s if you are coding in ASM) directory containing all your source files and put it on your right side of the screen, it will be useful later on during the debug session to find all the correct file-names to load the sources in the debugger to look at functions and code you want to create a breakpoint to. Given that DDT will halt your desktop, during the debugging to access source files  you’ll need to use DDT itself and tell it which file you want to open, so having a file list ready available will result very handy and will make your life easier 🙂

To start a debug session load !DDT frontend application and then carry your executable icon on the !DDT icon on the iconbar. If you have followed the instructions on how to compile your code for DDT your executable icon will look different than when you compile and link it without debugging options. If it does look a “debuggable executable” icon then, to start a debugging session, just double click on it.

As soon as !DDT loads your AIF executable it will open a couple of windows like in the picture below:

DDT-MainWindows

Fig c1

Sometimes, when loading your executable, DDT may show a warning message in the Status Window:

Can't set breakpoint on procedure main

This message simply mean that DDT has tried to find the C main function in your executable and couldn’t find it. This can happen because you did not compile your C code with the debug info or because:

  • The AIF image is not a compiled C code
  • The AIF image is a BBC BASIC compiled code using ABC compiler
  • The AIF image was generated from an ASM source
  • The source was indeed C, but it’s a library (or a plugin) program and so doesn’t contain the function main

If this message gets displayed to you and your source was C and it did contain the main function then please review the steps above on how to compile code for DDT otherwise ignore the message. If your code is compiled from other languages or does not contain the function main you’ll need to set the initial breakpoint manually. Read the “Debugging your code” section to know how to do that.

DDT Workspace

The first thing you will notice at this point is that all your applications running on RISC OS will freeze after the two windows above are being displayed and that your mouse pointer will change to a red “forbidden access” icon if you move it outside of the two DDT windows, this to indicate that you cannot interact with other applications while running a DDT debugging session.

Status Window

The DDT window on the lower side is called Status Window and is used to output messages and display variables values etc. during the debugging session.

When you start your session, if your executable contains debug info or if your executable has been compiled with !ABC compiler, DDT will always display the message:

RO area limit not on page boundary, last page not protected

This message means that Memory Protection is enabled (this is so by default on RISC OS) and that the last part of the code or read only area are not page aligned. This means basically that the last page of the read only area cannot be protected against accidental writes. The origin of this is in the linker and how it adds debugging info to the executable for example. So when caused by the debug info then it’s ok and can be ignored. Acorn promised to fix this in future versions of the linker back in the 90s, but I saw it’s still happening on latest ROOL DDE (29c at the time of writing this). In the case of !ABC compiled code it’s not because it contains debug info (ABC does not add that unfortunately), it seems to be because ABC creates an executable that DDT struggles to understand.

Main Window (or Context Window)

The window on the top side is called Context Window (but at the time I have got familiar with DDT I had no manuals so I always called it Main Window or Code Window) and it usually shows either source code or disassembled code.

The -> symbol on your left on the Main Window identify where in the source or binary code we are (for the binary code this also correspond to address in the PC register). As soon as DDT start debugging a user program you’ll always see:

  • That binary disassembled code in Fig c1 which is the Header of the AIF (this is also called symbolic disassembly of the run-time system initialization code, a full description of this here). If you configured your code to have source debugging do not worry, this area always appears as a disassembly because it’s actually not your code (your code still hasn’t been started yet), it’s the AIF object format header and the code you see is the system run-time initialisation code and when it has completed its task then it’ll start your code (for example for C compiled programs that means that the Executable AIF will initialise the SharedCLibrary and then the SharedCLibrary will jump into your code main function).
  • Debugging first location is always 0x0008000, this is a standard base location for Executable AIF on RISC OS.
  • For more info on the AIF header and the system run-time initialisation code please check this article.

You can use the Main Window also to display other files content and to set breakpoints in a visual fashion.

The output of the Main Window, when it’s a binary disassembly, looks like a typical disassembler output (nothing fancy):

  • 1st column from your left represent the memory location
  • 2nd column from your left represent the value stored at that memory location
  • 3rd column from your left is the ASM mnemonic that DDT interpreted from the 2nd column value
  • 4th column is the parameters list for the instruction/mnemonic  of column 3
  • sometimes on 5th column you’ll see some comments which represent the value of variables and labels that may appear in the parameters list column. For example look at location 0x0000800c, you’ll notice the bl instruction (ARM Branch with Link, aka jump to subroutine)  followed by Stub$$Code which is a label that points at location 0x0000817c.

Debugging code

As already said above, the first output you’ll see is always a symbolic disassembly of the entry point of the entire AIF executable. This is not the beginning of your code, AIF are statically linked executables so there is quite a lot of code before you get into your compiled code, this code will also call RISC OS SharedCLibrary to be initialised, however, do not worry DDT in most cases will easily find your executable main function (if you wrote it in C or C++) and so the next action for you generally is very simple and straight forward:

With the mouse button on one of the 2 DDT windows press the menu button (in RISC OS such button is the middle mouse button, on modern mouses this correspond often to the scroll wheel).

A local menu will open like in the picture below:

DDT-MainMenu

Click on the option called “Single step ^S”, that will open a new window like the one below:

DDT-SingleStep

If DDT understood the debugging symbols and the extra info contained in your executable correctly it will automatically show the option “Step by source statement” selected. All you have to do is click on “OK” button to jump to the entry-point of your main function in your code and so, skip all the SharedCLib initialisation steps.

DDT-MainSource

Please note: the -> just before a C code block start symbol { means DDT is NOT yet inside the code block, hence you cannot yet set watchpoints for variables and pointers defined inside the code block, to do that you’ll need to “enter” the code block otherwise you’ll get an error:

Procedure not currently active

To avoid that just do a step by source and that will be enough to activate the procedure or function

Ok this concludes the first part of this introductory tutorial, I hope you’ve found useful information here.

If you enjoyed this post, please don’t forget to support my blog by:

  • Visiting my on-line hacking and engineering merchandise shop on redbubble.com by clicking here
  • Or you can also make a donation with the PayPal link in the column on your right
  • Or share this article

If you like my articles and want to keep getting informed on new ones you can follow me on on of those 21st Century thingies called FacebookTwitterInstagram or Pinterest

And as always if you have any questions please feel free to use the comments section below.

Thank you! 🙂

What next?

If you are interested in coding on RISC OS:

4 thoughts on “RISC OS: Using the Acorn / ROOL Desktop Debugging Tool DDT (part 1)

  1. Pingback: RISC OS: Using the Acorn / ROOL Desktop Debugging Tool DDT (part 2) | Paolo Fabio Zaino's Blog

  2. Pingback: RISC OS: Installing ROOL Desktop Development Environment (DDE) tutorial | Paolo Fabio Zaino's Blog

Leave a Reply or Ask a Question

This site uses Akismet to reduce spam. Learn how your comment data is processed.