Added SegTracker in FS-UAE’s Debugger

For most classic Amiga developers Michael Sinz’ Enforcer is a valuable tool for debugging. Especially the contained tools SegTracker and FindHit are very helpful when analyzing bugs in your compiled code: SegTracker patches AmigaDOS’ functions for loading and unloading binary files and then tracks where the (code/data/bss) segments of each binary are located in memory. If a crash occurs then you can locate which binary caused it. To get more detailed information then FindHit comes into play: If the segment associated with a crash location is identified then FindHit loads the debugging info stored in an executable and then can match these infos to your location and gives you the source code file and line that was used to generate the faulty code…

I do most of my Amiga development now in a cross-dev environment on my Mac and then the FS-UAE emulator is the runtime environment to test and debug code. While it is possible to use the same Enforcer setup inside FS-UAE I really like the built-in debugger of the emulator: It allows to freeze the whole Amiga and inspect the full state. Furthermore, memory watchpoints and breakpoints are available, too. The only thing that was missing: a SegTracker feature that tells me where my application/driver code is loaded and a FindHit feature to get detailed infos on the associated source.

Thanks to open source of both FS-UAE and Enforcer I was able to add both features without too many effort: In the following I present you an extended FS-UAE that adds SegTracker and FindHit right inside the built-in debugger!

1. Build the extended FS-UAE

Currently, the SegTracker extension is only available on my own FS-UAE branch chris-devel on my GitHub Repository. Just clone the source from there and build a fresh FS-UAE. See the build docs of FS-UAE for more details. I tested the extension both on Mac OS X and Linux. I haven’t tried Windows and I suppose the code might need some adjustments before it runs there… Patches are always welcome here :)

2. Run FS-UAE

You’ll need the built-in debugger to use the new features. Therefore, you have to ensure that the debugger is enabled in your .fs-uae configuration file. My Host.fs-uae optimized for development looks like this:

fullscreen = 0 # I want an emulator window
floppy_drive_volume = 0 # No click sounds
joystick_port_1 = nothing # Don't block cursor keys

# give me a backslash key on my MacBook Pro:
# use Fn+Return
keyboard_key_kp_enter = action_key_backslash

automatic_input_grab = 0 # keep the mouse free
uae_cachesize = 8192 # use JIT
console_debugger = 1 # <--- enable the debugger
parallel_port = raw:/tmp/vpar # setup a virtual parallel port
serial_port = /tmp/vser # setup a virtual serial port

Note the console_debugger entry!

Make sure to run FS-UAE from a console otherwise you won’t see the debugger :) On Mac OS X you use and launch FS-UAE like this:

> fs-uae-2.3.0b1-macosx/ cfgs/os31cwb.fs-uae

The last argument gives the configuration file to use.

On Linux it works similarly: Use a terminal to launch the fs-uae binary.

If you press F11+D now in the FS-UAE window then the debugger is launched in the console:

  D0 00000001   D1 0000F90A   D2 00000000   D3 0000003F
  D4 00005000   D5 0000000B   D6 000006EF   D7 00000006
  A0 07B12B91   A1 07B14239   A2 07B14235   A3 07B14924
  A4 079D1428   A5 07B0F6E4   A6 07B13E62   A7 07B02A8E
USP  07B02A8E ISP  07802270 SFC  00000001 DFC  00000001
CACR 80008000 TC   00008000 ITT0 00000000 ITT1 00000000
DTT0 00000000 DTT1 00000000 VBR  07825C3C MSP  00000000
MMUS 00000003 URP  07820A00 SRP  07820A00
T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=0 STP=0
FP0: 0 FP1: 0 FP2: 0 FP3: 0
FP4: 0 FP5: 0 FP6: 0 FP7: 0
FPSR: 0000 FPCR: 00000000 FPIAR: 00f81622 N=0 Z=0 I=0 NAN=0
079D6BF0 6a0c                     BPL.B #$0000000c == $079D6BFE (T)
Next PC: 079d6bf2

Enter x + Return to leave the debugger and this reanimates your Amiga emulation in the FS-UAE Window. While the debugger is active the Amiga is frozen therefore nothing happens there…

3. Enable SegTracker

The SegTracker extension is not enabled by default. You have to enable it if you want to use it.

Start FS-UAE with the WB/Kickstart of your choice (but note that SegTracker will not work on KS 1.x!) and enter the debugger. With the ? command you get a list of available commands and in the patched FS-UAE you will see lots of new Z* commands:

  Z                     print SegmentTracker status.
  Ze [<0-1>]            enable/disable/toggle SegmentTracker
  Zl                    show seglists tracked by SegmentTracker.
  Za <addr>             find segment that contains given address.
  Zs 'name'             search seglist with given name.
  Zf 'hostfile'         load debug info from given executable file.
  Zy 'symbol'           find symbol address.
  Zc 'file' <line>      find source code line address.

We use Ze to enable the SegTracker:

SegmentTracker is enabled

Now it is important to reboot your virtual Amiga because the SegTracker is only installed during start up:

> x          # leave debugger
F11+R        # Reset Amiga
# wait a bit for reboot
F11+D        # re-enter debugger

If everything went well then you can already see the seglists that were loaded during startup: Use the Zl command to see a complete list:

> Zl
'LIBS:render.library' @079f58d4
  #00 [079f58d8,0000cb84,07a0245c]
'Scalos:Plugins/OOP/title_clock.plugin' @07a0ec3c
  #00 [07a0ec40,00000850,07a0f490]
  #01 [079df7d0,00000010,079df7e0]
  #02 [07a0f498,00000190,07a0f628]
'Scalos:Plugins/OOP/volumegauge.plugin' @07b0396c
  #00 [07b03970,00000fc8,07b04938]
  #01 [07b04940,000001fc,07b04b3c]
  #02 [07b04b48,00000094,07b04bdc]
'Mount' @07b082b4
  #00 [07b082b8,000018ac,07b09b64]
  #01 [079415c0,00000198,07941758]
found 151 seglists.
> x

This is an OS 3.1 startup with Classic Workbench installed.

For each loaded binary you see all loaded segments and for each segment the start address, size, and end address.

4. Load your Code

Its time to debug your own code: I use the plipbbox.device SANA-II device driver of my plipbox project here as an example.

I launch my driver by first copying it into the DEVS:Networks directory and then the TCP/IP Stack is started with this driver. I use Roadshow here as it has a very nice command line interface for handling things (and developers _love_ cli :):

CLI> addnetinterface plipbox

Now lets have a look in the FS-UAE’s debugger if my binary is already tracked. You can use either the Zl command to see the whole list or use the Zs command to search seglists by name:

> Zl 'plip'
Searching seglists matching 'plip'
'DEVS:Networks/plipbox.device' @07b41efc
  #00 [07b41f00,00001fd8,07b43ed8]
  #01 [07b185e0,00000124,07b18704]
found 1 seglists.

Ah, here is my code! This information is already very helpful if you want to start disassembling or setting breakpoints. But the info is still a bit coarse and therefore I added support for debug infos:

5. Add Debug Info

Now lets add debugging info to this seglist. For this you’ll need the exact same binary you use in your Amiga emulation somewhere located on your host file system. As I use cross-builds its usually the other way round and no big issue: I create the binary on my host and transfer it (via shared folder) to the Amiga. Furthermore, you’ll have to compile your binary with debugging information included (on SAS/C compiler its the DEBUG=LINE switch).

Use the Zf command to load and attach debug infos from the binary file to the tracked seglist found in the current system:

> Zf 'plipbox.device'
Loading debug info for seglist 'DEVS:Networks/plipbox.device' from hunk file 'plipbox.device'
file 'plipbox.device': 2 segments
  segment #00: CODE [00001fd8]   14 symbols,   3 src files
    000000f4  _DevInit
    00000234  _DevOpen
    00000428  _DevClose
    000004a2  _DevExpunge
    0000059c  _DevTermIO
    000005c8  _DevBeginIO
    00000974  _DevAbortIO
    0000178e  _ServerTask
    00001962  _addtracktype
    000019d2  _remtracktype
    00001a28  _dotracktype
    00001a8a  _gettrackrec
    00001ada  _freetracktypes
    00001f30  _NewList
    base:src/device.c: #289
    base:src/server.c: #404
    base:src/track.c: #58
  segment #01: DATA [00000124]    0 symbols,   0 src files

The given name is first searched to find a seglist in the system with the given name. Then the name is used to load a hunk executable directly from the current directory in the host file system (i.e. my Mac here).

Currently, the location of the binary in the host file system is a limitation, but that may be removed in further releases without too much work…

The segments of the file are loaded and the debug information is extracted. If the segment layout (size and number) of the loaded seglist matches the one found on the emulated Amiga then the debug info is attached otherwise an error is given.

Use the Zl or Zs command again to see the attached debug info:

> Zs 'plip'
Searching seglists matching 'plip'
'DEVS:Networks/plipbox.device' @07b41efc
  #00 [07b41f00,00001fd8,07b43ed8]   14 symbols,    3 src files
    07b41ff4  _DevInit
    07b42134  _DevOpen
    07b42328  _DevClose
    07b423a2  _DevExpunge
    07b4249c  _DevTermIO
    07b424c8  _DevBeginIO
    07b42874  _DevAbortIO
    07b4368e  _ServerTask
    07b43862  _addtracktype
    07b438d2  _remtracktype
    07b43928  _dotracktype
    07b4398a  _gettrackrec
    07b439da  _freetracktypes
    07b43e30  _NewList
  #01 [07b185e0,00000124,07b18704]    0 symbols,    0 src files
found 1 seglists.

Ok, now everything is in place for debugging.

Note that the Zs command already maps the symbols to the loaded locations. Therefore, you can directly set breakpoints on the corresponding addresses.

6. Use Debug Infos

The Za command is the main tool during debugging: It allows you to map an arbitrary address to seglist and debug info if its available:

> Za 0
00000000: not found in any segments.
> Za 7b41ff4
07b41ff4: 'DEVS:Networks/plipbox.device' #00 [07b41f00,00001fd8,07b43ed8] +000000f4
    07b41ff4 +00000000  _DevInit
    07b41ff4 +00000000  base:src/device.c:159
> Za 7b42000
07b42000: 'DEVS:Networks/plipbox.device' #00 [07b41f00,00001fd8,07b43ed8] +00000100
    07b41ff4 +0000000c  _DevInit
    07b41ff4 +0000000c  base:src/device.c:159

Note the offset in the second column of the debug info (+0/+c): Its the distant of the current address to the debug information.

You can also perform look ups the other way round: Give a symbol name or part of it and you will see the matching memory locations:

> Zy 'dev'
Searching symbols matching 'dev'
    07b41ff4:  _DevInit
    07b42134:  _DevOpen
    07b42328:  _DevClose
    07b423a2:  _DevExpunge
    07b4249c:  _DevTermIO
    07b424c8:  _DevBeginIO
    07b42874:  _DevAbortIO

Or you give a source file name and a line number and you’ll get the address of the generated code:

> Zc 'dev' 159
Searching code line matching dev:159
    07b41ff4:  base:src/device.c:159

7. Summary

With these new tools the built-in debugger in FS-UAE is now a very poweful tool for application and driver debugging on the Amiga. While the current feature set is still basic it is quite useful. I’ll keep adding new features if I need them during debugging :) E.g. adding the debug info to the disassemble command might be a nice extension…

Have Fun and I hope you find these tools useful for your own projects, too!


2 comments to Added SegTracker in FS-UAE’s Debugger

Leave a Reply