Debugging TADS3 on Linux

Howdy,
I downloaded and built frobtads on debian, compile TADS3 projects using t3make and use gargoyle-free to run my apps (as frob does not support german character set out of the box).
Does anyone have experience on how to debug a TADS3 app on linux? Is there a native debugger that can be built from source? What other strategies do people use?

I am having issues I can only understand (and hopefully fix) while debugging I fear. (Un)fortunately, I don’t have a Windows machine at home so I am a bit lost here :confused:

Happy to hear from you, best - fx

2 Likes

A suboptimal solution I found is that the TADS 3 workbench works pretty well via Wine. There are a bunch of caveats: if you’re like me and compile TADS 3 via Makefiles, importing into workbench will mess everything up.

For Hand Me Down I had a debug make target that copied the source directory to a debug area, and run workbench in Wine from there with custom debug build environment.

3 Likes

I use a set of debug routines, some I have shared in this forum (e.g. a “scroll of knowledge” when read, prints the current values of the variables & flags investigated)

Also I use “Imp’s gates” for quickly reaching far points in the map; in general, I don’t feel the need of debuggers when I can create adhoc debug commands/items.

Best regards from Italy,
dott. Piergiorgio.

3 Likes

A while back I wrote a simple interactive debugger for TADS3/adv3 (there’s also an adv3lite version which I think works the same but I don’t use adv3lite so ymmv). It’s “just” TADS3 code itself, so it’s not a true debugger; it just uses the builtin reflection services and exception handlers to drop execution into a very simple bespoke debugging command parser and expression evaluator. It’s not much, but it does let you set breakpoints and/or drop into the debugger to look at the contents of the stack when the game barfs.

I do my TADS3 coding mostly on linux as well, and my debugging process is mostly a combination of using that and simple debug-by-printf()-ish stuff.

I’ve also written a very simple linter module for implementing linters, but that’s more for commemorating rules for static analysis that you yourself (as the game designer) come up with than doing “generic” debugging.

4 Likes

(Also a linux dev) If you haven’t tumbled onto it yet, add -source reflect to your debug builds. This gives you access to VERY enhanced stack trace info, as well as access to the reflectionServices.valToSymbol() which dumps symbol information as printable strings (instead of needing to suss out string properties of an unknown object). Then yeah, lots of debug prints. I crafted a bare bones debug ‘module’ to give me a consolidated space to put that stuff, though inevitably some debugs require in-method print statements anyway.

#charset "us-ascii"

/*   Debug Printer...
 *
 *   Include the main header for the standard TADS 3 adventure library.
 *   Also include the US English definitions, since this game is written
 *   in English.  
 */
#include <adv3.h>
#include <en_us.h>

// some convenience debug macros.  need to define in any source
// file that wants to use them, though only v2s() likely useful
//
#define gDebug (debugMgr.debugEnabled)
#define gQuiet (debugMgr.quietEnabled)
#define v2s(Symbol) reflectionServices.valToSymbol(##Symbol)

//  QUIET function, mainly used to shut off output when
//  'FF' to debug areas deep in gamestate
// ie..  >QUIET
//       >REPLAY DEBUG.TXT
//       >QUIET
//
DefineSystemAction(Quiet)
    execSystemAction() {
		gQuiet = (gQuiet ? nil : true);  // toggle value
        if (gQuiet) {
            "##QUIET MODE ENABLED\n";
            mainOutputStream.disable();
        } else {
            mainOutputStream.enable();
            "##QUIET MODE DISABLED\n";
        }
    }
;
VerbRule(Quiet)
	('quiet') : QuietAction
	verbPhrase = 'quiet/quieting'
;
modify mainOutputStream
    outputOn = true
    enable() { outputOn = true; }
    disable() {outputOn = nil; }
    writeFromStream(txt) {
        /* if an input event was interrupted, cancel the event */
        inputManager.inputEventEnd();

        /* write the text to the console */
        if (outputOn) aioSay(txt);
    }
;

//  DEBUG function, enables every turn print of desired values
//
modify DebugAction
	execAction() {
		gDebug = (gDebug ? nil : true);
        "##DEBUG MESSAGES <<gDebug ? 'ENABLED' : 'DISABLED'>>";
        if (gDebug) new Daemon(debugMgr, &debugPrint, 1);
        else eventManager.removeMatchingEvents(debugMgr, &debugPrint);

        /* ORIG:  if the debugger is present, break into it,
         * never played with this, sorry
         * 
        if (t3DebugTrace(T3DebugCheck))
            t3DebugTrace(T3DebugBreak);
        else
            "Debugger not present. "; */
	}
;

debugMgr : Thing
    debugEnabled = nil
    quietEnabled = nil
    debugPrint() {
        // debug prints go here

        "DEBUG:  bigSword.location = <<v2s(bigSword.location)>>\n";
    }
;

Would also recommend this thread for stack trace chasing hints…

6 Likes

Yeah, for “just” debug-by-printf() stuff I also wrote the syslog module, which defines a Syslog class you can use as a mixin.

It provides a _debug() method. The simplest usage is a single argument, a text literal. It’s output only if the game is compiled with -D SYSLOG.

You can also provide a second optional argument as a logging tag/ID. Logging tags can be turned on and off via syslog.enable(id) and syslog.disable(id).

All instances of Syslog can also optionally define a syslogID property. If defined, it will be prepended onto each line of debugging output.

3 Likes

This looks promising. After some first testing I got a little bit of a grasp here… I had to define a verb rule for “debug”, which then toggles debugging as expected, but the debug messages only get printed ONCE after I toggle debugging on (and not after every action the player performs). This is fixed by removing the comment in the DebugAction that starts with ORIG: …
This is a great start to built on top of. I will look closer into reflections and the debugMgr in the near future. You would not have any idea how to set a breakpoint and step into executed lines of code one after the other, would you? :slight_smile:
Thank you for the example code !

2 Likes

That is helpful, and I will look into it, thank you

1 Like

Sorry, no, I have not tried that. Good luck though, and welcome!

1 Like