Written August 2025
Walkthrough #1 involved a target program that was already running before the debug session was started. In some cases that might not be practical; for example, if the issue you want to debug occurs before the program stops for user input. Or you just want to debug a program without having to manually launch a separate task to run it first.
The context for this walkthrough then is that we want to debug the program EXLIB:FOREACH[908,53] starting from the command prompt.
.LOG EXLIB:908,53
.ADB FOREACH.RUN
ADB version 1.0(106) A-Shell DeBugger
Launching task ADB2 ...
Message sent to ADB2 on job 3 (JACKX1:3C)
Waiting for ACK .... [ACK]
Waiting for target to connect [^C to abort] ...
Connection Accepted!
Cmd/Rep: INIT/ACK Status: MON TIW / Running
Msg: Init Debugging
Loading LSX info ... 14 labels
Loading SYM info ... 32 variables
Resolving local variable scope ... 11
Debugging
ADB >
Note that we started the session by logging to the location where the both the RUN and LSX files were and thus there was no need for an explicit directory for the RUN file or an /LSXDIR switch. Other things to note about the above which differ from Walkthough #1 are that because there was no /TARGETJOB specified, ADB launched its own slave job ("ADB2" in this example) and logged in into our current directory. The FOREACH.LSX file has been loaded, providing a context for subsequent commands, but FOREACH.RUN is not yet running.
We can tell it is not yet running a program as there is no Location (Loc) information in the indented status. We can still set a breakpoint in the desired target program by specifying its name explicitly as shown below.The Status "MON" indicates "monitor level", aka "at the command prompt", and "Running" indicates that it is currently running in the sense that it has not been stopped by ADB via a breakpoint.
ADB > BREAK
Set Breakpoint at next instruction: FOREACH.RUN:000024
Breakpoint set - use INFO BREAK to list breakpoints
ADB > INFO BREAK
[Breakpoint list:]
1) FOREACH.RUN:000024
[End of breakpoint list]
ADB >
Note that the BREAK command with no arguments defaults to the currently loaded program (FOREACH.RUN, even though it's not actually running yet), and to the next instruction after the current position. If we really wanted to set a breakpoint at the very first instruction, we'd need to use BREAK 0.)
We can use the LIST command (again, without any arguments for the current location) to see just where our breakpoint is:
ADB > LIST
FOREACH.RUN ...
000000
000000 ++include ashinc:ashell.def
! SOS70:ASHELL.DEF[907,16] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <1_1>
000000
000000
000000 ++ifnmap VERSYS_ASHELL_DEF
000000
000000 map1 VERSYS_ASHELL_DEF,s,40,">>@VERSYS(1)->>ashell.def[317]"
000024
000024 map1 CR_LF$,s,2,chr(13)+chr(10) ! [251]
000031
000031 define FS_DRV = 1 ! MX_FSPEC flags (1)
ADB >
Note that LIST normally shows the statement at the current location—i.e. the next statement to execute, in bold. But in a case where there are multiple source lines for the same location, they all show bold as seen above.
Now we can start the program running using the RUN command:
ADB > RUN
Breakpoint @ FOREACH.RUN:000024
000024 map1 CR_LF$,s,2,chr(13)+chr(10) ! [251]
ADB >
Cmd/Rep: INFO/ACK Status: RUN / At Break
Loc: FOREACH.RUN:000024 Level: 1
ADB >
Note that RUN assumes we are talking about the currently loaded program (FOREACH.RUN). If you wanted to start with a different program, perhaps one that would eventually CHAIN to or XCALL the program we are debugging, we would use FORCE with an explicit command line. You can however add command line arguments to the RUN command if applicable (e.g. RUN ARG1 /SWITCH2).
The response to the RUN command shows that we've hit the breakpoint, displaying the next instruction. (MAP statements with initializers are effectively a combination of a variable definition and an assignment statement.) We can then use a series of NEXT commands (first one explicit, the others implicit, i.e. just hitting ENTER) to step through the MAP statements and ++included functions until we get to a point of interest:
ADB > NEXT
000031 map1 AG_TERM,S,1,chr(127) ! [201] terminator
ADB >
000039 private dimx test(5), x, 1
ADB >
000045 private dimx $capitals,ordmap(varstr;varstr)
ADB >
000051 Procedure Init'Module'Scope'Collection()
ADB >
0001b4 Procedure Test'Module'Scope'Collection()
ADB >
0002cd Procedure Test'Static'Local'Collection(country$ as s0,cap$ as s0)
ADB >
000529 Procedure Clear'Module'Scope'Collection()
ADB >
0006bc ? tab(-1,0);"Test iteration and scope for collections"
ADB >
...
ADB >
0008af dimx $capitals,ordmap(varstr;varstr)
ADB >
0008bb $capitals("California") = "Sacramento"
ADB >
Note that when stepping through MAP statements, the only ones that you’ll see are those that have some kind of runtime action such as an initial value. DIMX statements will also show up because there is a runtime action, initializing the array or collection. Procedure and Function definitions will also show up, since the runtime interpreter has to acknowledge and skip over them when they appear in-line.
The complications in locating the logical start of the program could all have been bypassed if there was a standard label (e.g. START: or BEGIN: or MAIN: ) marking the logical beginning of the main program, in which case we could have specified that in the BREAK command (e.g. BREAK FORACH.RUN,MAIN: )..
Now that the target program is running and under ADB control, we can proceed as we would in the case covered in the first walkthrough. To wrap this example up, let’s illustrate another PRINT command:
ADB > PRINT $capitals("California")
Cmd/Rep: PRINT/ACK
Vartyp: S(),DIMX-AUTOEX (&h00a0e1)
Size: 10
Value: Sacramento
The PRINT command works for simple scalar variables as well as arrays and collections, but only if the subscripts are literal. So PRINT ARY(3) works, but PRINT ARY(var) would not. Variables with multiple instances (i.e. local variables) will be selected based on the current location. Some complex variables, like iterators ($$i) or MLIST tokens are not supported by the PRINT.
When done debugging, use the QUIT command to terminate the session. Unlike the case in Walkthough #1 where the target job was already running before we started debugging, in this case, since the target slave job was launched by ADB, it will be shut down by the QUIT command.