\cfg{chapter}{Section}

\cfg{text-filename}{ldebug.txt}
\cfg{text-chapter-numeric}{true}
\cfg{text-indent-preamble}{false}
\cfg{text-quotes}{"}{"}
\cfg{text-indent}{4}
\cfg{text-width}{72}

\cfg{html-chapter-numeric}{true}
\cfg{html-suppress-address}{true}
\cfg{html-single-filename}{ldebug.htm}
\cfg{html-leaf-level}{0}
\cfg{html-template-fragment}{%k}{%b}
\cfg{html-head-end}{<meta name="viewport" content="width=device-width, initial-scale=1.0">}
\cfg{html-leaf-contains-contents}{true}
\cfg{html-heading-hashtag-links}{true}

\cfg{pdf-filename}{ldebug.pdf}

\cfg{ps-filename}{ldebug.ps}

\cfg{info-filename}{ldebug.info}

\cfg{chm-filename}{ldebug.chm}

\cfg{winhelp-filename}{ldebug.hlp}

\cfg{man-filename}{ldebug.7}
\cfg{man-identity}{ldebug}{7}{2025}{}{E. C. Masloch}

\title lDebug manual

\copyright 2020--2025 by E. C. Masloch.
Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

This document has been compiled on \date{%Y-%m-%d}.


\C{overview} Overview and highlights

lDebug is a 86-DOS debugger based on the MS-DOS Debug clone FreeDOS Debug.
It features DPMI client support for 32-bit and 16-bit segments,
a 686-level assembler and disassembler, an expression evaluator,
an InDOS and a bootloaded mode, script file reading, serial port I/O,
permanent breakpoints, conditional tracing, buffered tracing,
auto-repetition of some commands,
and a number of extensions.
There is also a symbolic debugging option being developed.


\H{quickstart} Quick start for reading this manual

\b The interface reference (\k{interface}) explains the basics of the debugger's interface
and lists some common commands.

\b The parameter reference (\k{parref}) lists the types of parameters
used by the available commands.

\b The command reference (\k{cmdref}) describes most commands in detail.

\b The expression reference (\k{exprref}) details how numeric parameters
are parsed by the expression evaluator.

\b The variable reference (\k{varref}) lists a subset of the debugger's variables
and what they can be used for.

\b The assembler reference (\k{asmref}) describes the assembly language
used by the debugger's assembler and disassembler some.

\b The interrupt reference (\k{intref}) lists what interrupt hooks the debugger sets up.

\b The service reference (\k{serviceref}) lists what services are called by the debugger,
which may be useful for developers of the debugger,
or of kernels, ROM-BIOSes, or DPMI hosts.

\b The Extensions for lDebug reference (\k{eld})
describes ELDs in some detail.

\b The online help pages (\k{helptopics}) provide some additional descriptions
not found elsewhere in the manual,
as well as overviews of many different topics.

\b The command help (\k{cmdhelp}) lists most of the switches and parameters
accepted by the debugger and the instsect program.

\b The news (\k{news}) lists an overview of changes since prior releases of lDebug.

\b Invoking the debugger (\k{invoking}) states how to start the debugger,
either bootloaded, as a device driver, as an application,
or through the test suite.

\b Building the debugger (\k{building}) lists components, build options,
and instructions on how to build.

\b Debugging the debugger itself (\k{debugging}) lists some considerations
for working with CDebug or DDebug as a debuggee.

\b The test reference (\k{testref}) describes the tests that are
implemented in the test suite.

\b The additional usage conditions section (\k{additionalusageconditions}) lists
attribution and licenses for the various depackers
that can be used for the compressed debugger executable.

\b Source Control Revision ID gives the Mercurial hash
of the manual's source revision,
and links to that revision in ecm's repository.

For a tour, definitely start with the interface reference (\k{interface}).
To help invoke the debugger read the section on
\q{Invoking the debugger as an application} (\k{invoking-app}).
It may help to read the manual while testing the debugger on another terminal.
Use the main page of the online help (\k{helpmain})
as a reference to what is possible,
then check the command reference (\k{cmdref}) for details.
To explain what parameter types are used
refer to the parameter reference (\k{parref}).
For how to calculate refer to the expression reference (\k{exprref}).

Reconfiguring the debugger can be done using variables,
including the \cw{Debugger Assembler Options} (DAO) and
the \cw{Debugger Common Options} (DCO) 1 to 7.
Use the variable reference (\k{varref})
and the online help pages on the options (\k{helpoptions}) for those.
Change variables using the R commands,
such as \cq{r dco or= 800} or \cq{r ior := #50}.
Some configuration can be done using the \cw{INSTALL} command,
refer to \k{cmdinstall}.


\H{tips} Some tips for using the debugger


\b At a \cq{[more]} prompt for pagination,
entering Ctrl-C aborts the current command and returns
to the debugger command line.

\b Use the \cw{GT} or \cw{GNT} commands to skip past conditionals

\b Use \cw{G ABO} to skip past calls or loops if \cw{P} would not work

\b T, P, G, U, and D commands have autorepeat
to repeat the same command if an empty line (only blanks) is entered
after they return control to the debugger prompt

\b The \cw{POINTER} type expression allows
using a 32-bit number as a 16:16 segmented address
whereever an address parameter is parsed

\b The assembler can access the expression evaluator
by surrounding an expression with parentheses \cq{(...)}

\b The A, E, D, and U commands write to the AAO, AEO, ADO, and AUO variables
to point past the end of their last read or write

\b The ABO variable points past the last instruction
disassembled by an R command

\b Permanent breakpoints can be set up using the B commands,
including as pass points or conditionally

\b The G command can repeat the prior list
by specifying the \cw{AGAIN} keyword as the first breakpoint,
and can save to the list without actually executing the debuggee
by ending the breakpoint list with a \cw{REMEMBER} keyword

\b T, P, and G commands can change either the instruction pointer only
or also the code segment using
an equals-sign-prefixed address as the first prameter.
The TTEST command will change the CS:IP without actually executing anything.

\b The machine type can be viewed or changed with an M command.
Assembly and disassembly will note if a required machine level
is absent according to the machine type.

\b DCO option 800 or \cw{INSTALL GETINPUT}
enables the line editor and input history
even when using DOS for input

\b DCO6 option 200 or \cw{INSTALL BIOSOUTPUT}
will use the ROM-BIOS for output instead of DOS,
including for register change highlighting

\b DCO option 8 or \cw{INSTALL INDOS}
will act as if the debugger is
always running with the InDOS flag set,
avoiding DOS calls from the debugger itself

\b The \cw{INSTALL AMIS} and \cw{INSTALL TIMER} commands
can be used to provide the debugger's AMIS interface
and hook the timer interrupt

\b The \cw{DW ss:csp} command is useful
to view the current stack formatted as words

\b The debugger is largely capitalisation-insensitive

\b The LFSR variable allows to generate a stream of pseudo-random numbers

\b The DIM command shows MCB names of blocks pointed to by interrupt vectors,
while DIL (or DIML) will query AMIS multiplexers
for their interrupt entrypoints to find hidden chains

\b Long output of many commands is paged by default,
displaying a \cq{[more]} prompt that
pauses the output until a keypress is received

\b The VALUE IN construct allows to match one numeric value or range
against many match values or match ranges

\b A breakpoint can be set up on an interrupt handler
by issuing for example \cq{BP NEW ptr ri2Dp},
if the interrupt handler is writeable

\b If given a single expression the H command
displays the result as hexadecimal and as decimal

\b Decimal numbers can be entered with a \cw{#} prefix,
and binary with \cw{2#}.
Character codes can be used as numbers with \cw{#"..."}

\b Script files can be run with the Y command

\b A program can be traced until it tries
to modify interrupts 1 or 3 using
\cq{tp FFFFF while ! value from linear 0:1*4 length 3*4 in writing silent}.
Add a conditional breakpoint
like \cq{bp new ptr ri21p when value ax in 2501, 2503} beforehand
to intercept DOS calls to change these interrupts.
(lCDebug or lDDebug require \cw{INSTALL INDOS} to write a breakpoint
on the int 21h handler.)

\b If at its entrypoint and you want to return from a 16-bit near function,
use \cq{g word [ss:sp]}.
For a 16-bit far or interrupt function use \cq{g ptr [ss:sp]}

\b In a loop with several exit conditions,
trace with T or P and accumulate exits
with \cq{G AGAIN address REMEMBER}
(insert an offset or \cw{(NOT)TAKEN} keywords for the address),
then finally run \cq{G AGAIN}

\b The L and W commands for reading and writing sectors
accept drive letters for their second parameter,
specified with a trailing colon

\b The RV, RVM, RVP, and RVD commands will show some information
on modes, memory segment locations, processes, and device headers

\b RX toggles the 32-bit register view for the R command

\b The RE buffer can contain many different commands,
which are run on RE commands or when T, P, or G initiate a register dump

\b The DCO options are described in the full \cw{?O} help page
as well as individual pages like \cw{?O6} for DCO6

\b Not sure what version of lDebug is running?
The command \cw{?BUILD} displays the description
and source control revision IDs.
The description includes a build date or release number.

\b Setting a breakpoint at the current instruction pointer with the G command
will trace past this instruction once
then write the breakpoint and run at full speed

\b There's a TSR mode converting the application-mode debugger
into a resident program, allowing to debug the debugger's parent process

\b The symbolic F register for the R command
allows dumping and modifying the flags using the abbreviated flag states.
Use the \cw{?F} command to list the meanings of the flag states.

\b The R command can modify variables
using binary operators suffixed by an equal sign,
both on the command line of the R command
as well as after the R variable prompt

\b By adding a trailing dot after a variable name for the R command,
a variable's value can be inspected
without bringing up a variable prompt
that requires submitting a second input line

\b A single dot input can exit any special prompt,
such as the interactive enter mode,
the assembler,
or the R command variable prompt


\C{news} News

\H{news-r10} Release 10 (future)

\b Support 3byte register pairs like \cw{dlax} and \cw{al00}.
Also, document them and compound with zero low word
32-bit register pairs like \cw{cs00}.

\b Use \cw{lzexedat -4} for online help compression and
\cw{lzexedat -4 -l} for extpak.eld compression.
This compresses better than heatshrink and depacks faster,
heathshrink needs about 1.5 times the time.

\b Change DCO1 200h to be used to disable use of HLT instruction
in Real/Virtual 86 Mode only,
and add DCO2 8000_0000h to disable it in Protected Mode.
Drop DIF1 flag to do the same as the latter,
as there was no way to clear it.

\b Add several S MCB types for lDOS

\b Allow kernel command line in \cw{BOOT PROTOCOL=} command
to start with a semicolon after the second name

\b Open DOS file handles used by the debugger
with the no-inherit flag
so they aren't leaked to the debuggee

\b Add hooks for the errfix Extension for lDebug,
to keep track of the error carat display position

\b Fix a minor init bug if application doesn't relocate environment

\b Add application switch /TV to not relocate
the debugger's environment block to within the main program allocation
(will leave the space reserved for this unused, sorry)

\b In instsect's FAT32 loader do proper LBA check,
including workaround for
\W{https://www.bttr-software.de/forum/forum_entry.php?id=21275}{the Xi8088 bug}

\H{news-r9} Release 9 (2024-12-21)

\b Enable immediate assembler by default.
Implies using dual code segments for the lDebugX builds.

\b Enable heatshrink compression of help pages,
and move the depack buffer that it uses into the message segment.
Costs about 300 bytes of code space but saves several KiB
of total resident space.

\b Introduce DCO7 option 2000h to forbid flat binary file loading
if debugger is resident
(after application mode TSR command
or initially when started in device mode).
Loading .EXE and .COM executables as programs while resident
was already forbidden in release 8.

\b Update the lDOS boot32 loader embedded into instsect.com
to use new FSIBOOT5 revision of the loader

\b Add two patch areas for use by tsc.eld

\b Exclude ELD houdinis (conditional breakpoints) at build time by default

\b Add DCO7 flag 1000h to not recreate an empty process
in the command loop once an attached process has terminated.

\b Add /R switch to application mode, to reserve memory,
and reserve.eld to work with reserved memory

\b Fix DX command AXO variable

\b Disable DX command by default,
as the code segment ran out of space in the lCDebugX build.
The command can still be used as an Extension for lDebug.

\b Add ELD1TAIL trailer header support,
so that an ELD may be appended to another file
and the ELD loader will find it by seeking from the EOF

\b Add test reference to manual

\b Fix, do not eat comma after length number
if no length keyword follows

\b Add boot load setting DRDOS (same as IBMDOS with \cw{maxpara=-1})

\b Allow to boot kernel of up to 29 KiB to linear 00700h
by shrinking the stack reservation below the BPB to 256 Bytes
(or 512 Bytes if passing a command line)

\b Work around Book8088 / Xi8088 BIOS bug
when trying to detect LBA support in bootloaded debugger

\b Fix, allow to run installed ELD commands in the THEN clause
of IF commands

\b Fix to not corrupt device driver's loader PSP

\b Bugfix, correctly parse device driver command line ending in LF

\b Add assembler reference chapter to manual

\b In assembler disable optimisation from index with scale times 1
to base, now acting like NASM with \cw{nosplit} keyword

\b Display scale times 1 explicitly in disassembler

\b Fix in assembler to always allow blanks after scale

\b Add DAO flag 2_0000h to disassemble in NASM style
using ECX or CX as second operand
to \cw{loop} instructions if ASIZE prefix is present,
rather than D or W suffix

\b Add DAO flag 1_0000h to hide \cw{MODRM} keywords

\b Match NASM and NDISASM order of operands for \cw{xchg} with a ModR/M,
in both the assembler and disassembler

\b Assemble and disassemble \cw{MODRM} keyword
to select or indicate non-default forms of instructions

\b Reject \cw{movzx} to 32-bit register with memory source
lacking a size keyword

\b Allow to assemble displacement size keyword within brackets

\b In many cases disassemble immediates with a size keyword
if they are encoded in a longer form than needed

\b Allow to assemble \cw{JMP FAR imm} with a single immediate,
which becomes the offset that is combined with the AAS as a segment

\b Allow to specify \cw{BYTE 1} to assembler
to use an imm8 shift/rotate count (the 186+ form) similar to NASM,
and disassemble this with the \cw{BYTE} keyword as well

\b Optimise to sign-extended 8-bit immediate/displacement
when an appropriate 16-bit value is specified to the assembler
(eg \cq{adc dx, FFFF}, \cq{imul dx, dx, FFFF},
\cq{push FFFF}, \cq{mov dx, [bx + FFFF]})

\b In assembler allow \cq{push [100]} or \cq{pop [100]}
without a size specified,
defaulting to word size (in 86 Mode or a 16-bit CS),
or to dword size (in a 32-bit CS for lDebugX).
Disassembler however always shows the size.

\b Fix, allow comma between number and length keyword

\b lDebugX: Fix BL (breakpoint list) segment output
in PM when not matching current CS

\b Fix: Parsing a linear address starting with
\cq{@(} required two closing parens

\b On too long lines of assembler directive DD
(using numeric or string data)
do not actually overflow the buffer,
rather detect the overflow before the write

\b lDebugX: Fix non-terminate PM to 86M switch with the selector
in a seg/sel variable (eg ADS) not on a segment boundary

\b lDebugX: Fix PM int 21h function 4Ch on 32-bit stacks


\H{news-r8} Release 8 (2024-03-08)

\b Fix bootloaded Y :label command

\b Add new tools patchqry and patchpro
to patch default values in the iniload query patch site
and in the inicomp lCFG block to select a progress display choice
(shipping in separate repo patchini, also provided as current build)

\b Added progress displays to compressed executable depackers,
set DOS environment variable \cw{LDEBUGPROGRESS} to
a number: 1 (dots), 2 (percentage), 3 (bar), 4 (bar and percentage)

\b Exomizer on server updated to current git commit,
inicomp depacker updated to handle P & 32 flag

\b Fix: Correct drive unlocked after W sector-writing command,
and on MS-DOS v7.00 drive will be locked at all
even though int 21h function 7305h is not used

\b Fix: Passing a debuggee pathname to the device mode debugger,
which is invalid, will no longer crash the machine
and display an error instead

\b Added a rel.sh script which will automate the release build.
It configures the ELD mak scripts to not create the XLDs nor eldcomp.eld,
and deletes all listing files and many of the temporary files.

\b Moved packlib output files into tmp directory rather than bin

\b Fix: AMIS description is padded so as to
keep most offsets identical between release builds and daily builds


\H{news-r7} Release 7 (2024-02-16)

\b Fix bug when specifying BOOT PROTOCOL=
with the second file (add file) in a subdirectory

\b Allow to resize history buffer segment
in init using the /H= switch

\b ELD data blocks can be resized
in init using the /Y= switch

\b In path search (init or path.eld) skip directories

\b Fix boot EXT/Y/BOOT DIR reads when FAT12 entry
that straddles a sector boundary is read

\b Support comma separator before program load name

\b Add \cw{::empty::} keyword to skip
automatic scripts path search in EXT and Y commands

\b Enable _EXTENSIONS by default

\b Disable _EMS, _RN, and _RM by default

\b Optimise application/device init memory use,
requires a second init relocation for large buffers

\b Allocate a separate environment block
of size 2 KiB for the debugger

\b Allow unquoted comma to separate Y and EXT filenames

\b Support \cw{::scripts::} and \cw{::config::} prefixes
in boot Y and EXT commands, as well as the BOOT DIR command

\b Enable new NASM warnings
to avoid section-crossing near and short branches

\b Fix boot file read ending on both a cluster boundary
and the End Of File

\b Fix int 21h calls with DS != SS.

\b Add Extension for lDebug loading
and basic interface for linking.
Still default disabled at build time.
If enabled, an /X=MAX switch enlarges the ext segment buffer.

\b Fix, truncate areas addresses for non-bootloaded mode.

\b Fix a bug in /A switch relocation of code section
(if layout 2 in use and _PM _DUALCODE enabled).

\b Add /T switch to relocate debugger during init.

\b Add a fractional digit to bytes size formatting.

\b Fix: In DIL check for valid appearing int 2Dh
before calling it.

\b Fix: Do not allow DI with two parameters
where the second is below the first.

\b Add INSTALL TOGGLE command.

\b Fix INSTALL command with AREAS keyword followed by
another keyword.

\b Fix: DIL command was broken since addition of the /A switch
(enlarge auxiliary buffer) due to using wrong segment.

\b A single list parameter can be specified with different sizes,
switching back and forth using \cq{AS size} keywords.


\H{news-r6} Release 6 (2023-08-26)

\b Add length keywords PAGES, KiB, MiB, GiB

\b Call DOS_HELPER_PRESTROKES_START dosemu2 helper service

\b Add byte length variables
DENTRYLEN, DSTACKLEN, DMESSAGELEN,
DCODE1LEN, DCODE2LEN, DAUXBUFLEN, DHISBUFLEN.
Also DALLOCSEG and paragraph size DALLOCSIZE.

\b Emit warning on unknown filename extension in INIT.
Can be disabled with /PW- switch.

\b /P switch to guess filename extension and do path search in INIT.
/PS for path search only, /PE for guessing extension only.

\b Make interrupt 0Dh, 0Ch hooks a run time option.
Add INSTALL noun \cw{INTFAULTS} to enable these hooks.

\b Add CLEAR command.

\b Serial I/O is controlled by an internal variable
rather than directly by the DCO option.
Fixes some bugs, such as running \cw{INSTALL SERIAL, TIMER, AMIS}.

\b In S command result data dump list displacements
after the result address to indicate that the data dumped
is \e{after} the match and does not include the match data itself.

\b Add ::SCRIPTS:: path keyword for DOS I/O Y command.
Also used if a Script for lDebug file is not found.

\b Add H AS SIZE modes to display result
using the decimal bytes size display (from DM command).

\b Introduce /A= switch for larger auxiliary buffer
in application mode or device mode.

\b IOK variable added.
Both IOI and IOK will force reading from a terminal now.

\b lDebugX fix: In PM, if a segment is limited to 64 KiB,
do not attempt to dump S command result data beyond the limit.

\b Introduce the WHILE buffer,
and use it also for G command.
Also used for S command and RC./RE.REPLACE,
unless it is in use in which case these commands
can still use the auxiliary buffer (if it isn't in use).

\b Add RH mode and RH command (none, one, two, or IN parameters).
This mode uses the auxiliary buffer,
disabling other commands that use it.
Add RHCOUNT variable too.

\b lDebugX fix: Do not corrupt buffered commands
when running DX command.

\b Fix, set error code if BOOT command attempts to read
from 33-bit space using CHS addressing.

\b Add \cw{COUNT} command and variable.
S command also sets the variable.

\b Add TOP keyword for D, DB, DW, DD, and DX commands.

\b Add DCO2 40_0000h for unconditional linebreak before R dump,
changed DCO6 8000_0000h to be conditional on int 10h being used
and the current column being nonzero.

\b Add DCO2 20_0000h for underscores in 32-bit R variable display.

\b Add \cq{?VERSION} help page.

\b Add \cq{END} keyword to range parameter parsing.

\b Add new \cw{INSTALL} command keywords
to aid reconfiguring the debugger.

\b Application and device mode will now detect a startup
Script for lDebug file, intended for configuration.
The /IN switch disables this detection.

\b Bugfix: Y command may have failed due to a line overflow.

\b Improve detection of invalid DD commands that may be valid
when interpreted as D commands.

\b Display H command remainder if the last operation is a division.

\b In \cw{getinput} allow Ctrl-A (like Home) and Ctrl-E (like End).

\b DT command (ASCII table if empty, else text of specified byte values).
Additionally, DTT command (dump text table top half).

\b lDebugX bugfix: If dumping for example 8 bytes at 1FFF0h
in a large segment the debugger would loop infinitely.

\b AS SIZE keywords for E, F, S strings.

\b Added DAO option 400h for MSDebug style opcode field width
in disassembly.

\b Added DCO2 10_0000h to do some R command variable prompts
in MSDebug style.

\b Added DCO2 option 8_0000h to display additional blanks
in R command register dump for MSDebug style.

\b Added DCO2 option 40000h to treat explicit length 0
as 64 KiB, except U treats it as length 1,
to improve MSDebug compatibility.

\b Bugfix: In F RANGE command forbid large destination lengths
if the source range is specified in a 16-bit (limit <= 64 KiB) segment
without a length specified.
Would truncate the source to up to offset 0FFFFh.

\b Quotemarks added as expression separators
to improve MSDebug compatibility.

\b Add lDebug ad section to manual (in \k{ldebug-ad}),
comparing lDebug to MSDebug and original MS-DOS Debug.

\b Allow to read .HEX files. Only record type 00h and 04h used.
Can read files larger than 64 KiB, unlike MS Debug.

\b Add K command (same as our default N command),
and DCO2 options for MS Debug compatible N command.

\b Add RC.ABORT command to allow a Script for lDebug file
called from the RC command line buffer
to modify the RC buffer itself.

\b Add DCO6 options for style 2 and style 3 alternative flag state dump.

\b Add DCO6 option to display a linebreak before R dump.

\b New _EXPRDUALCODE build option to save some
5 kB in the first code segment.
Disabled by default.

\b Fix: Device mode debugger should not retain an open handle
for FDCONFIG.SYS.

\b Trying to open the \cw{LDEBUG$$} device
will now cause a critical error.

\b Some code in the run exit and entrypoints
can be moved into entry segment,
saving about 250 bytes in the first code segment.

\b DPMI exception entrypoint handlers can be moved
into entry segment,
saving nearly 300 bytes in the first code segment.

\b Fix: When a symbol table is allocated in DOS memory
and the debugger quits with a QD command,
the table would stay allocated.

\b Add ATTACH command to attach to a PSP,
can be used while application mode or device mode
debugger is resident.
(Opposite of TSR command.)

\b MMX register support in expression evaluator
optimised to take up less run time of other expression terms

\b mktables program extended, allowing for builds of the debugger
that do not contain table entries above specified machine level.

\b Non-boot-loaded modes now discard the ?BOOT help page,
saving 2.7 kB of resident memory use.

\b Refactor to store long help messages in another segment,
reducing the pressure of the data entry segment by 22 kB.

\b Fix QC command if not last in container,
would corrupt MCB chain

\b Application and device driver mode now
discard most of the boot loaded mode code,
saving about 9 kB of resident memory use.

\b Fix an lDebugX D command bug on non-386 machines

\b Add build option _APPLICATION,
to create special-purpose builds if disabled.
(Not provided pre-built as yet.)
\cw{$RESULTEXT} variable for mak.sh can set a filename extension
other than \cq{.com}.

\b getinput redraw optimised, fewer complete redraws

\b Add DCO3 option 0100_0000h to
highlight prefix/suffix in getinput if text parts are not visible

\b Improve handling of very narrow displays

\b RE.LIST and RC.LIST use the IOCLINE setting now


\H{news-r5} Release 5 (2023-03-08)

\b Client PSP is now stored internally as a segment,
even when lDebugX is in Protected Mode.
DM command now shows this segment rather than a selector.
(The PSPSEL variable can be read for a selector instead.)

\b RM command now accepts an optional size keyword

\b \cq{IF EXISTS R variable THEN} command added

\b MMX support of the machine is re-detected after lDebugX switched modes

\b Fix: RM command and MMxy variable read and R MMxy variable write work now

\b Fix: In \cw{/E+} mode a zero word is now pushed to the initial stack

\b dosemu2 \cw{-dumb} mode now detected specifically when
needed for register change highlighting to ROM-BIOS interrupt 10h

\b Fix: Bootloaded init could have corrupted part of its image
during second relocation, if needed.
(This case cannot occur during normal load at 200h:0
on a machine with 512 KiB or more of available LMA.)

\b Fix: Creating a process resets the DTA to PSP:80h

\b Fix: \cq{R VD} accesses VD variable, rather than run \cq{RVD} command

\b Improvements to support NEC V20 machine

\b Add CIP and CSP variables, use CIP for EXECUTING keyword

\b Fix error handling if S command search area is shorter than search mask

\b IOCLINE variable added to support display on the HP 95LX's narrow screen

\b Fix: Stack access variables set wrongly for interrupt instructions

\b Fix: In DPMI protected mode QA or Q command sometimes would not work

\b Immediate assembler merged.
Currently defaults to disabled at build time.

\b Bootable lDebug: Allow to access small FAT32 file system
(less than 64 Ki clusters)

\b Add timer configuration variables and default
the SDELTALIMIT variable to 5 to improve wait performance

\b Serial I/O: Add option to always do EOI after calling
downlink for IRQ sharing. Autodetect in KEEP prompt
if this option must be used or if IRQ sharing must not be used.

\b Query patch support for ldosboot iniload can be used
to set the BOOTUNITFLx variable for the debugger load unit

\b Change: DCO6 option 200h only makes output go to ROM-BIOS,
new DCO6 option 0100_0000h makes all Input/Output use ROM-BIOS.
(The 200h flag still allows to read script files from DOS.)

\b lDebugX: Fix, allow to use TSR command in PM
(expected a segment where a selector was read)

\b lDebugX: Fix PSP variables and TSR command
expecting higher limit in PM
(getsegmented now sets limit 0)

\b lDebugX: Fix getexpression not preserving the scratch selector

\b Add FL.xF variables to read flag status in expressions,
eg FL.CF which reads as 1 if CY and 0 if NC

\b When creating an empty process (eg after QA command)
also write the current command line tail to it
(instead of the debugger's internal N buffers)

\b Display amount of ancestors for
the symsnip revision ID

\b A pair of 32-bit E command fixes

\b Write AES:AEO (e_addr) in E command and
allow E command without an address

\b lDebugX: Add DESCTYPE keyword in expressions

\b lDebugX: Add descriptor modification commands
and DARESULT variable, refer to \k{cmddesc}

\b Add XARESULT variable for XA command

\b Allow to share the serial IRQ so eg two lDebug instances
can be connected to two serial ports that use the same IRQ,
like COM2 and COM4 (both use IRQ #3 by default)

\b Do not simulate repeated string scan/compare instructions
when disassembling them using the U command
(only do so for R command disassembly)

\b Disassembler handles o32/o16 OSIZE prefixes
as belonging to push and pop with segregs,
instead of displaying the prefix as \cq{unused}.

\b If simulation of repeated string scan/compare instructions
is disabled in DAO then the access variables will now be set up
assuming a count of 1, rather than the maximum possible count.

\b Add convenience entrypoints for debuggable mode
at CODE:1, CODE2:0, and CODE2:1.
The offset 0 entrypoints will return to the main command loop,
called \cq{cmd3}.
The offset 1 entrypoints will additionally display a linebreak.

\b Allow switching lCDebugX to debuggable mode upon putrunint
and allow running a breakpoint early in putrunint.

\b Add AMIS private function 33h, provided by lDebugX by default
and can be used by lDDebugX/lCDebugX by default

\b Add INSTALL and UNINSTALL commands

\b Allow to specify length of D command with LINES keyword

\b Add DEFAULTDLEN, DEFAULTDLINES, DEFAULTULEN, and DEFAULTULINES
variables to modify default sizes of D and U commands

\b Display long numeric constants with underscore separators
for readability in online help pages and documentation

\b Allow to disable disassembler memory access
for referenced memory and repeated string instruction simulation,
using four new DAO flags

\b Change HP 95LX 40-column friendly mode support
in the disassembler to use two DAO flags
rather than two DCO6 flags (one of which was shared)

\b Allow to specify variable RIxP/S/O/L with
x as a single-digit hexadecimal number

\b Bugfix: Allow operators between ?? and ::
in a ternary operator expression for H command

\b Allow to specify \cw{SILENT} keyword
followed by a number before the S command's range or list,
display only up to a certain amount of results

\b Add CLR operator, bitwise AND with the bitwise NOT
of the right hand operand. Precedence above bitwise AND.

\b Bugfix: Absolute value operator \cw{?} should always
give its result an unsigned type

\b Allow switching lCDebugX to debuggable mode upon debugger exception
and allow running a breakpoint early or late in debugger exception.

\b Add debugger exception areas to display the cause
of a memory access which may fault in the debugger.
Also adds a linebreak for eg referenced memory reads
to work in tandem with the partial disassembler output.
(Idea from FreeDOS Debug/X, though there it
only does a linebreak and implements it differently.)

\b Bugfix: Disassemble mov with segreg and memory operand
always with m16, ignoring the operand size selected.
In assembler never emit an osize prefix
and reject an explicit \cw{dword} size keyword.

\b In disassembler display instruction and referenced memory address
before accessing memory, so partial output is displayed
in case a fault occurs in the debugger (FreeDOS Debug/X pick)

\b Document side effects of expression evaluator

\b Bugfix, allow all valid address parameter formats
for the source address of an M move memory command
(suggested by FreeDOS Debug/X)

\b Add AMIS private function 31h to instruct lDebugX to try to
install its DPMI hook, make use of this in lDDebugX and lCDebugX

\b Add descriptions of BOOT commands to manual

\b Fix HIDDEN= keyword for BOOT READ/WRITE with partition specified,
add HIDDENADD= keyword to modify rather than replace hidden sectors

\b Fix a bug in BOOT PROTOCOL= command that could disallow
use of ENTRY and BPB parameters
if running a non-DPMI build on a 386+ machine

\b Avoid faults in the debugger if a code selector
with a low limit gets used for writing, eg by A or E commands

\b Fix bug setting wrong debuggee CS limit if _DUALCODE build

\b Add variables DSTACKSEG/SEL, DENTRYSEG/SEL, DCODE1/2SEG/SEL,
DAUXBUFSEG/SEL, DHISBUFSEG/SEL, DSCRATCHSEL, DSYM1/2SEL
(selector variables only for lDebugX,
symsels only for symbolic lDebugX)

\b RVM command shows second code segment if _DUALCODE build

\b In C, E, and A commands in PM display original selector,
not the scratch selector as replacement.
Variable AAS is also affected by this.

\b Fix a bug with different selectors for lDebugX C and M commands
(picked from FreeDOS Debug/X version 2.00)

\b Add taken keywords to address parsing, refer to \k{paraddress}.
(This effectively adds the \cw{GT} and \cw{GNT} commands,
as well as \cw{TTEST=TAKEN} and \cw{TTEST=NOTTAKEN} to change \cw{(e)ip}.)

\b Bugfix: Allow entering double-slash to disable second file search
for the BOOT PROTOCOL= command even if no command line follows

\b Application /C= switch and kernel command line will now
skip leading blanks following a semicolon that is converted to a linebreak

\b Modify serial interrupt handler to pass on interrupt call
if the PIC does not indicate an interrupt in the In-Service Register (ISR)

\b Add /M switch and interrupt 7, 0Ch, 0Dh hooks (for R86M exceptions),
though build options for all of them are disabled by default

\b Add force BPB CHS geometry (4) and force LBA access (2) flags
to the \cw{BOOTUNITFLx} flag variables

\b Add switches /F and /E

\b Allow zero as parenthetical partition specification,
allow to access partition \cw{u(bootldpunit).(bootldppart)}
if LDP is equal to FDA

\b Bugfix: Reading with BOOT command that crossed 64 KiB DMA boundary
would copy too much or too little from the sector segment to target

\b Start of HP 95LX support (NEC disassembly repeat rules,
narrower R/U/D command output, do not intercept interrupt 6)

\b Bugfix: Command \cw{r f .} no longer displays garbage

\b Use test_high_limit to check segment limits,
to determine whether to use 32-bit offsets in several spots

\b Disable calling XMS by Protected Mode far call by default

\b Add dual code segment support to allow code size beyond 64 KiB

\b Introduce dash prefix to commands to disable
symbolic debugging features (no-op if not symbolic build)

\b Introduce U address LENGTH length LINES keyword
to disassemble a number of lines rather than bytes

\b Add BS command for swapping permanent breakpoint indices

\b Document doubled delimiter quote mark for lists and string literals

\b Add string literal escaping of delimiter quote mark
by doubling the delimiter quote mark

\b Add \cw{/2} switch to use alternative video adapter for
debugger output if available (pick from FreeDOS Debug)

\b Add \cw{?OPTIONS} help page and specific pages
for DCO1, DCO2, DCO3, DCO4, DCO6, DIF, and DAO

\b Set new \cw{INICOMP_WINNER} build variable so as to use lzsa2
compression for current releases

\b Add \cw{_DEBUG_COND} build option to allow toggling
debug mode on and off at run time

\b Add \cw{INT8CTRL} variable which contains number of ticks
to wait for Control pressed entrypoint; set to zero to disable

\b Fix: Control-C also aborts RC command buffer execution

\b Fix: Default operand for \cw{AAM} and \cw{AAD} instructions
is omitted in disassembler

\b Enhancement: If at the end of a stdin-redirected file
the debugger cannot quit it will now enable InDOS mode
and allow the user to control the debugger afterwards

\b Fix: Do not crash or loop infinitely upon
encountering the end of a stdin-redirected file

\b Extract more source files from debug.asm

\b Allow appending \cw{00} to a 16-bit register name
to get a 32-bit value with the register value in the high word

\b Do not cause error from empty \cw{/C=''} switch

\b Use ampersand prompt to display commands run from RC buffer

\b When loading a .BIN file set the process's command line buffer
the same way as if loading a .COM file

\b Add heading hash links to every heading
in the ldebug.htm manual (requires patched Halibut)

\b Add LFSR and LFSRTAP variables

\b Run unix2dos on ldebug.txt manual

\b Add QD (quit from device initialisation) and
QC (quit from device in container MCB) commands

\b Add RVD command to display device header address and allocation size,
as well as DEVICEHEADER and DEVICESIZE variables to read same

\b Bugfix, on pass or non-pass permanent breakpoint hit
while running with T/TP/P command do not check WHILE condition

\b Add \cw{PARAS} keyword to range length parsing,
to multiply a count by 16 (size of a paragraph)

\b Bugfix, should allow to run if int 2Fh is invalid

\b Add device-driver mode to allow loading the debugger in CONFIG.SYS

\b Fix, do not crash if no UMCB but int 21.5803 works

\b Add V commands and /V command-line switch (video screen swapping)

\b Add \cw{RIxxP} variables to read IVT entries
in a way suitable to be used as \cw{POINTER} type expressions

\b Work around FreeDOS kernel bug prior to 2022 May
so as to fail on loading an empty executable

\b Fix, also use SDA manipulation to change current PSP
when lDebugX is in Protected Mode

\b Add TERMCODE variable to read int 21.4D return
after debuggee process terminated

\b Add QB command (run breakpoint late in debugger quit)

\b Add RVP command to display debugger mode
and current debuggee and debugger process addresses

\b Add (D)PSP|PARENT|PRA|PSPSEL variables

\b Do not try to proceed past a call near immediate
if the called functions consists of a \cw{retf} instruction.
(This supports a method for relocation,
used for example by the debugger itself.)

\b Add command-line switch /B to run a breakpoint early

\b Add RC commands to view, change, and run RC buffer commands,
re-using the command line buffer

\b Add \cw{MACHX86} and \cw{MACHX87} variables to read machine type

\b Allow M machine type command to parse
an expression for the machine level number to set

\b Add QA command (try to terminate attached process)

\b Fix int 19h and debuggee termination handling.
Int 19h in a DOS application mode now sets up
registers to terminate the current process
when running the debuggee again.

\b Add an lDebugX option DCO3 20_0000 to break on entering PM

\b Add an lDebugX option DCO3 10_0000 to use a 32-bit stack segment
for the debugger itself (can help compatibility)

\b Fix so that semicolon is allowed as End Of Line in getrange

\b Fix \cw{R size [mem] := val} causing a fault
in the debugger if value ends in FFFFh

\b Implement \cw{POINTER} types for handling
a 32-bit expression as a 16:16 far pointer

\b Implement basic handling of expression types
(signed/unsigned)

\b Revision IDs in \cw{?BUILD} command list
the amount of ancestors to help to compare revisions

\b Fix a segment addressing bug when switching modes
(eg have a breakpoint in a DPMI allocation
while the client is running in 86 Mode)

\b Fix some cases of detecting 32-bit offsets incorrectly


\H{news-r4} Release 4 (2022-03-08)

\b Recognise LF as linebreak in serial input

\b E interactive mode fixes:

\lcont{

\b Support LF to exit interactive mode
(that is, accept Linux style linebreaks)

\b Support DEL sent by serial terminal

\b In lDebugX correctly handle 32-bit offsets

\b Also write new value when minus is entered

\b Honour blank for continue to next byte,
CR or dot for exit interactive mode

\b Always correctly read value
even if blank is entered afterwards

\b Improve E interactive mode compatibility
across different input sources
(like stdin file, script file, serial terminal)

\b Display linebreak upon new address displayed

}

\b Fix: Register variable \cq{CH} would be misparsed as
\cq{CHAR} type instead of the expected variable

\b Allow DI command to receive an IN value list
similar to the y in a VALUE x IN y construct

\b Fix: Allow to set a breakpoint on an interrupt 21h handler
and do not crash or corrupt state if the debuggee then terminates.
(That is, do not call service 4Dh before restoring breakpoints.)

\b Fix: Too long N command could crash the debugger

\b Fix: DDebug TSR quit would not work correctly
due to overflowing a rel8 \cw{jmp}

\b Add R, M, and L key letters to DI command
(always 86 Mode, show MCB names, follow AMIS interrupt lists)

\b Fix: \cw{R WORD [memory]} prompt would not consider the size keyword
as part of the input line prompt

\b Add AMIS private function 30h - Update IISP Header

\b In DI command in 86 Mode follow IISP headers

\b Add \cw{QQCODE} variable

\b Add \cw{BOOT[L|Y|S][UNIT|PART]} variables, \cw{BOOTUNITFL(x)} variables

\b Add bzpack compression method

\b Drop DPS variable when building without DPMI support

\b Fix PSP variables in Protected Mode:
PSP is always a 86 Mode segment,
PSPS is a segment or selector,
and PPR and PPI work

\b Add \cw{HHRESULT} variable


\H{news-r3} Release 3 (2021-08-15)

\b Add workaround with extra int 23h and int 22h handlers
and raw mode-switching
to use interrupt 21h service 0Ah in PM.
DCO2 flag 800h clear by default.

\b Add TRYAMISNUM variable to try a specific AMIS multiplex number first

\b Add DCO4 flag 2 to allow disabling lDebugX's int 2Fh hook

\b Build option \cw{_MEMREF_AMOUNT} enabled by default

\b mktables switches \cw{direction} and \cw{stackhinting}
enabled by default

\b Fix DOS application script file reading
to honour InDOS status

\b Fix H BASE= command with GROUP=
sometimes displaying trailing garbage

\b Fix DDebugX hooking random PM interrupts

\b Fix trailing blanks in DI command

\b Added a number of automated acceptance tests

\b Add variable \cw{AMISNUM} to read the multiplex number

\b Fix an old bug in the assembler that happened to make
instructions like \cq{mov ax, 0} fail to assemble now

\b Made interrupt 8 hook optional, default-off

\b Added optional, default-off interrupt 2Dh hook

\b Properly unhook interrupts utilising IISP header chains,
if the debugger's interrupt handlers are reachable.
Added DCO4 flags (upper 16 bits) to force unhooking
if a handler is unreachable.
If a handler is both unreachable and not forcibly unhooked
then it stays hooked. The Q command fails in that case.

\b Fix to allow \cq{$} prefix to segments in DebugX
while in Real/Virtual 86 Mode

\b Debugger's 86 Mode entrypoints now use
the IBM Interrupt Sharing Protocol header.
(However, it is still assumed that the debugger
\e{owns} the interrupt entrypoints.)

\b Add \cw{WIDTH=} keyword handling to \cw{H BASE=}

\b Introduce variables IOL and IOF to control
how many levels of execution are cancelled by Control-C

\b Scripts with CR LF linebreaks
at the end or after calling another script
no longer cause superfluous empty lines to be processed

\b Control-C aborts script file reading that is in progress

\b Bugfix, when calling three nested levels of Y script files
while bootloaded then
the outermost script's already buffered content
would not rewind properly

\b Fix so that Control-C from ROM-BIOS keypress buffer
is consumed properly while reading script file,
instead of looping forever

\b Check for Control-C in ROM-BIOS's circular keypress buffer,
add variables IOS and IOE

\b Extend Control-C handling so RE buffer execution is aborted by it

\b Add a simple \cw{BOOT DIR} command
(SFN name only, attributes, size (using FAT+), datetime)

\b Add string literals \cw{#"..."} to expression evaluator

\b Add \cw{H BASE=} command

\b Add \cw{merge} and \cw{debug} switches to mktables.
Both are default off for now.
Merging means redundant operand list tails are merged.

\b Bugfix, accessing the variable SRC caused an infinite loop

\b LZMA-lzip depacker fixed to not use \cw{cs xlatb},
as the segment override prefix may be ignored on CPUs below 386

\b Added conditional \cw{?? ::} construct operator

\b Merged branch \cw{uumemref} and made memrefs available in default branch.
The build option \cw{_MEMREF_AMOUNT} must be enabled to use them.

\b Memory access direction and stack hinting
in the assembler and disassembler tables.
Switches named \cw{direction} and \cw{stackhinting} to mktables program.
(Default off for now.)

\b LINEAR term allowed in expressions

\b VALUE IN construct allowed in expressions

\b Commas are only allowed between expressions,
no longer within expressions

\b If DCO2 flag 8000h is set during RE buffer execution
and SILENT 1 was used do actually only display last RE output


\H{news-r2} Release 2 (2021-05-05)

\b Documented SLEEP command

\b Line editing history for raw terminal/serial input
(in a fixed segment of size 8 KiB currently)

\b Fix missing register dump after T/TP/P
which ends up matching a non-pass non-hit breakpoint

\b Fix: Entering a literal as 3#102002022201221111211
or #4294967296
would overflow silently to zero instead of causing an error

\b Reset high words of EIP and ESP when trying to terminate client process

\b Add change highlighting to R register dump

\b Assembler internals: Allow ASM_ESCAPE usage when needed

\b If BL command is given an unused index do not display incorrect WHEN

\b Reset segment registers when trying to terminate client process

\b Handle unusual SIB bytes correctly in P command's disassembly

\b Bugfix, Y script file called by another Y script file would turn quiet

\b Bugfix, if permanent breakpoint WHEN condition was in use
then the wrong index and ID would be displayed in the pass/hit message

\b Acknowledge IRQ to secondary PIC too if applicable
(if using a high IRQ for the serial I/O interrupt)

\b Bugfix, in BOOT commands do not prepend a word to the auxbuff anymore

\b Only create manual in HTML, text, and PDF formats

\b Add files doc/fdbuild.txt and doc/LDEBUG.LSM for FreeDOS packages

\b BOOT: work around qemu bug with \cq{LOOPNZ}

\b BOOT: retry CHS reads up to 16 times

\b Add instsect and lDebug command help to manual

\b Expression evaluator allows \cq{OR=} as synonym for \cq{|=}
(especially useful if shell does not allow specifying pipe symbol for /C)

\b Assembler: Allow specifying \cq{LOOPxx destination, (E)CX}
as in NASM instruction reference to specify address size

\b For assembler allow specifying \cq{INT BYTE 3} to get CDh encoding
and display it this way in disassembler

\b Only adjust offset saved in PSP's SPSAV variable if it points to our stack

\b In assembler do not allow sizeless memory operand
when immediate matches IMMS8 (eg \cq{add [100], 12})


\H{news-r1} Release 1 (2021-02-15) and earlier

\b \cq{G REMEMBER} command to work with the saved temporary breakpoint list

\b WHEN conditions for permanent breakpoints

\b RIxxO/S/L variables (read-only view of IVT entry)

\b 3BYTE type for \cq{R var} and indirection in expression evaluator

\b In disassembler handle unusual SIB byte contents correctly

\b IDs for listing permanent breakpoints

\b In disassembler correctly dump far memory operands,
double memory operands (BOUND), and do a32 addressing

\b Add \cq{S range REVERSE} command

\b Fix corner case of S command:
The commands \cq{f 100 l 10 0} \\ \cq{s 100 l 10 0}
should result in 16 matches

\b SROx and SRC search result variables

\b SLEEP command

\b H command displays decimal numeric value (when given a single expression)

\b In disassembler display WORD keyword when o16 in 32-bit CS

\b Bugfix, in XR do not skip first digit of allocation size

\b G and T/TP/P breakpoints work reliably in DebugX
when the client enters, leaves, or switches from/to Protected Mode

\b F and S command allow accepting \cq{RANGE} specifications for source data

\b Add TTC/TPC/PPC default step counts for T/TP/P commands

\b DW/DD commands to dump memory in words or doublewords

\b Manual added (this document)

\b RE buffer execution to run almost arbitrary commands
when T/TP/P/G intend to dump register contents

\b Conditional control flow with IF and GOTO in a script file

\b /C command line option to pass commands to the debugger on startup

\b In assembler allow specifying SHORT/NEAR/FAR for jumps and calls

\b Script file reading

\b Pass point functionality (inspired by DR-DOS's SID) using counters

\b G LIST command to list the saved temporary breakpoint list

\b Auto-repetition for G command, G AGAIN command

\b DebugX's DPMI entrypoint hooking automatically checked
instead of always avoiding it on MSW and dosemu

\b Serial port I/O, with defaults (for COM2) that
can be reconfigured using debugger variables

\b Permanent breakpoints

\b Buffered tracing using \cq{P/TP/T ... SILENT}
which writes to an internal buffer during the run
then replays the last entries from it upon finishing the run

\b TP command which is like T except it
handles repeated string operations like P

\b DM command lists MCB sizes in decimal Bytes/KiB

\b Conditional tracing using \cq{P/TP/T ... WHILE} conditions

\b L and W commands allow drive letters instead of numbers

\b Bootloaded mode and its BOOT commands

\b NASM style address disassembly, blanks after commas, keywords uncapitalised

\b TSR mode and command to enter it

\b R command allows treating flags (CF, ZF, etc), debugger variables,
registers, and memory variables (byte, word, 3byte, dword) as variables

\b Conditional "jumping" and "not jumping" notices
in register dump's single-line disassembly

\b Options DCO1, DCO2, DCO3, DAO to modify some behaviour

\b Extended online help pages

\b _DEBUG option which swaps the exception handlers and
thus allows debugging most of the debugger itself
(_DEBUG builds are not included in the package
and have to be created by building them specifically)

\b Arbitrary unsigned 32-bit expression evaluator

\b Paging for long command output

\b Usage conditions changed to Fair License
(having asked Paul Vojta and received his confirmation),
prior conditions also allowed as alternatives


\C{building} Building the debugger

Building lDebug is not supported on conventional DOS-like systems.
(DJGPP environments may suffice but are not tested.)
Assembling the main debugger executable may require
up to 1 GiB of memory.


\H{buildingcomponents} Components for building

The following components are required to build with the provided scripts:

\b bash - to run mak* scripts

\b perl - to patch binaries (overwrite unused revision IDs)
and to filter reproduce dt file contents

\b grep - to detect whether boot loading is in use, and to export variables

\b sed - to filter dosemu2 output

\b hg (Mercurial) - to retrieve revision IDs

\b wc - to count amount of ancestors

\b GNU time - when $use_build_time is enabled,
to display main assembler run's memory use and wall time

\b python - to run hg and to run the test suite

\b C compiler - to compile supporting programs

\b dosemu2 - to run build decompression tests (optional)

\b qemu - to run build decompression tests (optional)

\b nasm - to assemble. NASM versions to choose:

\lcont{

\b NASM versions up to 2.07 fail -- \cq{%deftok} is not supported

\b NASM versions prior to 2.09.02 fail -- \cq{%deftok} is implemented wrongly

\b NASM version 2.09.02 works (last tested 2019-11)

\b NASM versions 2.09.03 to 2.09.10 all fail -- \cq{%assign %$foo%[bar] quux} doesn't function right

\b NASM version 2.10.09 works (last tested 2019-11)

\b NASM version 2.14.03 works (last tested 2020-12)

\b NASM version 2.15.03 works (last tested 2020-12)

\b NASM version 2.16 (current git head) fails, due to
\W{https://bugzilla.nasm.us/show_bug.cgi?id=3392732}{a bug with %strcat}
and
\W{https://bugzilla.nasm.us/show_bug.cgi?id=3392733}{a bug with %assign ?%1}
and
\W{https://bugzilla.nasm.us/show_bug.cgi?id=3392803}{a bug with %00}

\b (As of 2022-08-23) Current git head
\W{https://github.com/netwide-assembler/nasm/pull/25#issuecomment-1186217590}{with a patch}
for the %strcat bug and
\W{https://bugzilla.nasm.us/show_bug.cgi?id=3392803}{with a patch}
for the %00 bug works (last tested 2022-08)

\b NASM version 2.16rc10 works (last tested 2022-11)

\b Upcoming NASM version beyond 2.16.01 works (last tested 2023-07),
\W{https://bugzilla.nasm.us/show_bug.cgi?id=3392892}{with a patch}
to fix a major memory leak

}

\b lzexedat.sh - to build compressed extpak.eld and online help pages
(lzexedat can also be used to compress the inicomp stage payload)

\b alternatively: heatshrink - to build compressed extpak.eld and online help pages
(heatshrink can also be used to compress the inicomp stage payload)

\b halibut - to build this manual,
\W{https://github.com/ecm-pushbx/halibut/commit/1ccc3ac}{with a patch}
to include the hash links next to section names

\b supporting programs:

\lcont{

\b mktables (included in debugger source)

\b tellsize (included in separate repo called tellsize)

\b mktmpinc.pl (included in separate repo called mktmpinc,
to create temporary include files, optional)

\b crc16-t/iniload/checksum (included in separate repo called crc16-t,
to add checksumming, optional)

\b a 86-DOS kernel and shell (to run build decompression tests
or the test suite, optional)

}

\b additional sources (must be referenced in cfg.sh or ovr.sh):

\lcont{

\b lmacros (macro collection)

\b scanptab (partition table scanning for bootable debugger)

\b ldosboot (iniload frame for bootable debugger, boot sector loaders,
checkpl if using new style checksumming)

\b instsect (application to install boot sector loaders)

\b bootimg (to run decompression test with qemu
and create boot image for qemu to use for the test suite)

\b inicomp (if to use compression support), also needs one of:

\lcont{

\b brieflz (blzpack)

\b lz4

\b snappy (snzip)

\b exomizer -- recommended as this usually results in the smallest files

\b x-compressor

\b heatshrink

\b lzip -- usually even smaller than Exomizer but takes longer to decompress

\b lzop

\b lzsa -- default choice, one of the fastest depackers

\b apultra

\b bzpack

\b lzexedat (part of ecm's lzexe fork)

}

\b crc16-t/iniload (if to add checksumming)

\b symsnip (only if symbolic option is enabled)

}


\H{buildingprocess} How to build

\n Clone the mercurial repo from
\W{https://hg.pushbx.org/ecm/ldebug}{https://hg.pushbx.org/ecm/ldebug}
or in an existing repo use \cq{hg pull} to update the repo

\n Update the repo with \cq{hg up} or \cq{hg up default}
or any other available commit you want to build

\n Clone the other needed repos from
\W{https://hg.pushbx.org/ecm/}{https://hg.pushbx.org/ecm/}
or in existing repos use \cq{hg fetch}
or the sequence of \cq{hg pull} then \cq{hg up}
to update the repos.
(Usually the additional source repos do not have multiple branches.)

\n Copy the ldebug/source/cfg.sh file to ovr.sh in the same directory

\n Edit ovr.sh to point to the repos

\n Edit \cw{INICOMP_METHOD} in ovr.sh to
select none, one, or several compression methods.
Surround multiple values with quotes and delimit with blanks.
If the value "none" is used no compression will occur.
If several values are given the smallest of the resulting files
will be used as the \cw{ldebug.com} result.
This favours LZMA-lzip (lzd) and Exomizer 3 (exodecr) compression
as they result in the best ratios.
The uncompressed \cw{ldebugu.com} file will always be generated,
you can rename or copy or symlink it to use it as \cw{ldebug.com} if you want.

\n If you have dosemu2 or qemu,
you may enable the \cw{use_build_decomp_test} option
by setting it to a nonzero number.
This insures that the compressed executables
will actually succeed in decompression when entered in EXE mode,
and will lower the required minimum allocation given in the EXE header to
the minimally required value so that decompression will still succeed.
This defaults to using dosemu2, which must have a DOS installed
that allows filesystem redirection.
\cw{DEFAULT_MACHINE} can be used to select qemu instead.
The options \cw{BOOT_KERNEL}, \cw{BOOT_COMMAND}, and \cw{BOOT_PROTOCOL}
must be set up then to allow building a bootable diskette.
(This is needed because qemu does not offer filesystem redirection for DOS.)

\n If \cw{use_build_decomp_test} is enabled,
you may also enable \cw{INICOMP_PROGRESS}
(again by setting it to a nonzero number).
This enables code for a progress display during depacking
of a compressed executable.
The default for application mode and device driver mode
is to not display the progress indicator.
Setting the (DOS) environment variable \cw{LDEBUGPROGRESS}
to a value between 1 and 4 will enable the indicator.
This is now enabled by default in release and current daily builds.

\n Edit \cw{INICOMP_WINNER} to name one method
or the keyword \cq{smallest} or \cq{fastest}.
The latter requires \cw{use_build_decomp_test} to be enabled,
as well as to set the variable \cw{INICOMP_SPEED_TEST} to a nonzero number.
This number specifies how often to decompress the image
during the decompression timing test.
A number of 16 or higher is recommended.

\n The \cw{use_build_revision_id} option is by default on.
It requires that the sources are in hg (Mercurial) repos
and that the hg command is available to run \cq{hg id}.
The resulting revision IDs are embedded into the executable
and will be shown for the ?B (long) and ?BUILD (short) commands.

\n In ovr.sh you can also specify which tools to use.
For example, the variable \cw{$NASM} specifies the nasm executable to use,
with path if needed.

\n If you want to rebuild debugtbl.inc you should compile mktables then run it.
While in the ldebug/source directory,
run \cq{./makec} (or use whatever C compiler to build mktables)
then \cq{./mktables} next.
Note that mktables only needs to be used
if either the source files (instr.*) changed or
the mktables program itself has been altered.
If the assembler and disassembler tables are not to change
then mktables need not be used.

\n Finally, run \cq{./mak.sh} from the ldebug/source directory.
You may pass environment variables to it, such as
\cq{INICOMP_METHOD=exodecr ./mak.sh} to select Exomizer compression.
You may also pass it parameters which will be passed to the main
assembly command, such as \cq{./mak.sh -D_DEBUG4} to enable debugging messages.

The mak.sh script expects that the current working directory
is equal to the directory that it resides in.
So you'll always want to run it as \cq{./mak.sh} from that directory.
The same is true of the make* scripts.

The make* scripts work as follows:

\dt make

\dd calls mak.sh to create debug and debugx

\dt maked

\dd calls mak.sh to create ddebug and ddebugx

\dt maker

\dd calls mak.sh to create only debug

\dt makerd

\dd calls mak.sh to create only ddebug

\dt makex

\dd calls mak.sh to create only debugx

\dt makexd

\dd calls mak.sh to create only ddebugx

ldebug/tmp, ldebug/lst, and ldebug/bin will receive
the files created by the mak script.
The following filenames are for the default when running mak.sh on its own
which is to create debug.
(When ddebug, debugx, or ddebugx are created, the names change accordingly.)
In the ldebug/bin subdirectory, \cw{debug.com}
will be a nonbootable executable (even if the \cw{_BOOTLDR} option is enabled).
This executable can safely be compressed using EXE packers such as the UPX.
(In cfg.sh the option \cw{use_build_shim} now controls whether
\cw{debug.com} is created. It defaults to disable this output file.)
If the \cw{_BOOTLDR} option is enabled,
\cw{ldebug.com} will be a compressed bootable executable
(if any compression method is selected),
whereas \cw{ldebugu.com} will be an uncompressed bootable executable.
These bootable executables must not be compressed using any other programs.
Doing that would render the kernel mode entrypoints unusable.
Incidentally, UPX rejects these files because
their \q{last page size} MZ EXE header field holds an invalid value.

The bootable executables can be used as
MS-DOS 6 protocol \cw{IO.SYS},
MS-DOS 7/8 \cw{IO.SYS},
PC-DOS 6/7 \cw{IBMBIO.COM},
EDR-DOS \cw{DRBIO.SYS},
FreeDOS \cw{KERNEL.SYS},
RxDOS.3 \cw{RXDOS.COM},
or as a Multiboot specification or Multiboot2 specification kernel.
In any kernel load protocol case,
the root FS that is being loaded from should be
a valid FAT12, FAT16, or FAT32 file system
on an unpartitioned (super)floppy diskette (unit number up to 127)
or MBR-partitioned hard disk (unit number above 127).
In addition, the bootable executables also
are valid 86-DOS application programs that can be loaded in EXE mode
either as application or as device driver.
(Internally, all the .com files are MZ executables with a header,
but they are named with a .COM file name extension for compatibility.)

It is valid to append additional data, such as a .ZIP archive,
to any of the executables.
However, if too large this may render loading with
the FreeDOS or EDR-DOS load protocols impossible.
All the other protocols work even in
the presence of arbitrarily large appended data.


\S{buildingmktables} How to build the mktables program and the debugger tables

The mktables tool is a C program that prepares the debugger
assembler/disassembler tables from three input files.
The input files are:

\dt instr.set

\dd Instruction set, mapping mnemonics to opcodes and instruction keys

\dt instr.key

\dd Instruction keys, each one specifying a list of operand types

\dt instr.ord

\dd Instruction orderings, specifying which keys must be preferred
by the assembler


The output files are:

\dt debugtbl.inc

\dd Receives the tables

\dt debugtbl.old

\dd Receives prior output file

\dt debugtbl.tmp

\dd Used during building the tables


As mentioned, mktables only needs to be built and ran
if any of the input files, or mktables itself,
or the mktables options have changed.
The debugger's hg repo carries a copy of the current
full default tables so running mktables is usually not needed.

The following options are available:

\dt \cw{[no]direction}

\dd Enables or disables memory access direction operands.
These operands tell the disassembler whether
a memory operand is a source, a destination, or both.
This option is on by default.

\dt \cw{[no]stackhinting}

\dd Enables or disables stack access hint operands.
These operands tell the disassembler that an instruction
represents a stack push, stack pop, or stack special operation.
This option is on by default.

\dt \cw{[no]merge}

\dd Enables or disables merging redundant tail operand lists.
This is a small optimisation of the operand list tables.
This option is on by default.

\dt \cw{[no]debug}

\dd Enables or disables debugging output.
This option is off by default.

\dt \cw{filename}

\dd Followed by a filename argument.
The indicated file is used as output file
instead of the default \cq{debugtbl.inc}.

\dt \cw{[no]offset}

\dd Enables or disables offset comments in output tables.
Disabling them makes it easier to find changes
between different tables without the noise added by them.
This option is on by default.

\dt \cw{[no]discardunused}

\dd Enables or disables discarding unused operand lists.
Enabling helps optimise the output tables,
particularly when a machine limit is in use.
This option is on by default.

\dt \cw{8086}, \cw{186}, \cw{286}, \cw{386}, \cw{486}, \cw{all}

\dd Limit tables to include only instructions
up to the specified machine type.
Default is \cq{all}.


mktables is built using a C compiler. OpenWatcom and gcc
should both work. An example to build mktables on a DOS host with OpenWatcom is:

\c wcl -ox -3 -d__MSDOS__ mktables.c

An example to build mktables with gcc on a Linux host:

\c gcc -xc MKTABLES.C -o mktables -Wno-write-strings -DOMIT_VOLATILE_VOID


\S{buildinginstsect} How to build the instsect application

\n Clone the mercurial repo from
\W{https://hg.pushbx.org/ecm/ldebug}{https://hg.pushbx.org/ecm/ldebug}
or in an existing repo use \cq{hg pull} to update the repo

\n Update the repo with \cq{hg up} or \cq{hg up default}
or any other available commit you want to build

\n Clone the other needed repos (lmacros, ldosboot, instsect) from
\W{https://hg.pushbx.org/ecm/}{https://hg.pushbx.org/ecm/}
or in existing repos use \cq{hg fetch}
or the sequence of \cq{hg pull} then \cq{hg up}
to update the repos.
(Usually the additional source repos do not have multiple branches.)

\n Copy the ldebug/source/cfg.sh file to ovr.sh in the same directory

\n Edit ovr.sh to point to the repos

\n In ovr.sh you can also specify which tools to use.
For example, the variable \cw{$NASM} specifies the nasm executable to use,
with path if needed.

\n Finally, run \cq{./makinst.sh} from the ldebug/source directory.
You may pass environment variables to it.
You may also pass it parameters which will be passed to the
assembly commands.

The makinst.sh script expects that the current working directory
is equal to the directory that it resides in.
So you'll always want to run it as \cq{./makinst.sh} from that directory.

ldebug/tmp, ldebug/lst, and ldebug/bin will receive
the files created by the makinst script.
ldebug/bin/instsect.com will be the instsect application,
which has boot sector loaders for FAT12, FAT16, and FAT32 embedded.
The default protocol is lDOS and the default kernel name LDEBUG.COM.
Read the instsect help page for instructions on how to use it.
Refer to \k{cmdhelp-instsect} for the instsect help.
The help can also be obtained by running \cw{instsect.com /?} from DOS.
The kernel name can be modified with the \cw{/F=} switch to instsect.
For instance, \cq{instsect.com /f=lddebugu.com a:} installs the loader
onto drive A: with the name set up to load the uncompressed lDDebug.

Current lDOS boot32 uses the FSIBOOT4 protocol for an additional stage.
This is interoperable with the upcoming RxDOS version 7.25's use of
the FSIBOOT4 protocol, as well as with loaders that use
a different sector for their additional stage (like Microsoft's),
or those that do not use an additional stage (like FreeDOS's).


\S{buildingtest} How to prepare the test suite

The test suite (test/test.py) by default uses qemu.
(dosemu2 tends to need more than 5 seconds to start
while qemu manages in 2 seconds or less.)

If the debugger is run as a DOS application
and qemu is used then a boot image containing a DOS kernel,
shell, autoexec.bat, and quit program must be created.
If the build option use_build_qimg is enabled
then calls to mak.sh will create such an image.
The script file makqimg.sh carries out this task.

If the debugger is run as a DOS application
and dosemu2 is used then the DOS installed in dosemu is used.
The -K and -E switches to dosemu2 are used to
mount a host directory and execute the debugger.

If the debugger is bootloaded (in either qemu or dosemu2)
then a boot image with only the debugger executable
and a startup boot script file must be created.
If the build option use_build_bimg is enabled
then calls to mak.sh will create such an image.
The script file makbimg.sh carries out this task.

The test script creates symlinks to bin/ and
tmp/qemutest/ and tmp/bdbgtest/ on its own.
It can be executed from any directory,
as it should find its files based on its own location.
The test suite uses pseudoterminals, qemu or dosemu2, and
the default Python unittest module.

Some tests may require having executed the script file
test/scripts/mak.sh from within the test/scripts directory.
When booting the debugger or using qemu, this must be run
before makbimg.sh or makqimg.sh is run.

The DPMI tests currently require manual setup,
with a directory test/dpmitest/ containing the
dpmitest programs (for dosemu2) or a diskette image
test/dpmi.img containing the programs as well as
the HDPMI host executable (for qemu).


\H{buildingoptions} Build options

\dt _DEBUG

\dd Make the program debuggable.
A \q{D} is usually prepended to the program name.
This means that the program's handlers are only installed
within the function \cw{run},
and are uninstalled within the function \cw{intrtn1_code}
or \cw{intrtn1_entry.code}.
This allows debugging everything except this section.
This is intended to be used with a default build of lDebug
as the outer debugger.
However, there is nothing preventing usage of a different debugger.
To indicate that the debuggable debugger is running,
its default command prompts are prepended by a tilde \cq{~}.

\lcont{

(To debug everything including
the section from \cw{run} to \cw{intrtn1_*},
or the DPMI entry of lDebugX,
a lower-level debugger must be used, such as dosemu's dosdebug
or other debuggers that are integrated into emulators.)

}

\dt _DEBUG_COND

\dd Only takes effect if _DEBUG option is also enabled.
Allow to enable or disable debuggable mode
within the same process.
A \q{C} is usually prepended to the program name.
To indicate that the debuggable mode is enabled,
the debugger's default command prompts are prepended by a tilde \cq{~}.

\lcont{

The command-line switch /D+ can be used to start up
in debuggable mode. /D- instead insures to start up
in non-debuggable mode. The DCO6 flag 100h can be
toggled subsequently to toggle debuggable mode.
This DCO6 flag can also be changed using \cw{INSTALL DEBUG} commands.

lDebug with the _DEBUG option disabled accepts a no-op /D- switch.
lDDebug with _DEBUG enabled but _DEBUG_COND disabled
accepts a no-op /D+ switch.

}

\dt _PM

\dd Make the program DPMI-capable.
An \q{X} is usually appended to the program name.
If possible, the interrupt 2Fh function 1687h is hooked and made to
return lDebugX's entrypoint.
Otherwise, the initial entry into protected mode must be traced.
Upon entry lDebugX will install itself as if it is the actual client,
initialise itself, then set up the original client
as if that had entered protected mode.
The assembler and disassembler will detect and support 32-bit code segments.
Other commands will also use 32-bit addressing to allow using 32-bit segments.
To indicate that the debugger is in protected mode,
its default command prompt changes from the dash \cq{-} to a hash sign \cq{#}.
(lDDebugX or lCDebugX in debuggable mode
prepends its tilde to that resulting in \cq{~#}.)

\dt _APPLICATION

\dd Enabled by default.
Enables to use the executable as a DOS application.
Disabling allows to save a little memory for a special-purpose build.

\dt _DEVICE

\dd Enabled by default.
Enables to use the executable as a DOS device driver.
Disabling allows to save a little memory for a special-purpose build.

\dt _BOOTLDR

\dd Enabled by default.
Makes the program support being bootloaded.
This additionally requires the lDOS iniload stage wrapped
around the MZ .EXE image of the debugger.
The mak.sh script prepends an \q{l} to the base filename
to create the names for the bootable files.
For building debug, this results in \cw{ldebugu.com} and \cw{ldebug.com}.
In bootloaded mode, I/O is never done using DOS,
as if InDOS mode was always on.
The DOS's current PSP is not switched during debugger operation.
The MCB chain can only be displayed using the DM command
by specifying the start segment explicitly.
The BOOT commands are supported, refer to \k{helpboot}.
Disabling this option allows to save a little memory for a special-purpose build.

\dt _HISTORY

\dd Enables the line editing history for getinput
(ROM-BIOS input or serial input, DOS input only if getinput enabled).
Defaults to on.
Size can be specified using _HISTORY_SIZE.
Whether a separate segment is used can be controlled
using the _HISTORY_SEPARATE_FIXED option.
Defaults to an 8 KiB separate segment buffer.
Size of a separate segment can now be modified by the init
using the DOS device or application command line switch /H.

\dt _MEMREF_AMOUNT

\dd Indicates number of memref structures to include.
Default 4 (on).
If enabled without a value, the default (4) is selected.
When enabling this option, you most likely want to first rebuild
the assembler and disassembler tables using the command
\cw{./mktables direction stackhinting}.
(These mktables switches are now default enabled.)
This allows for memrefs to indicate whether an explicit memory operand
is a read or write (\cw{direction}),
as well as for stack accesses
like \cw{push}, \cw{pop}, \cw{call}, \cw{retn}
to be recognised in memrefs (\cw{stackhinting}).
Memrefs are initialised by disassembly.
Memrefs can be accessed using the access variables
like \cw{READADR0}, \cw{READLEN0}, etc. Refer to \k{varaccess}.
The access variables are written
after an R command's register dump and disassembly
(refer to \k{cmdr}).
Access variables can be accessed using special keywords
behind the \cw{IN} of a \cw{VALUE x IN y} construct (refer to \k{exprvaluein}).

\lcont{

Note that memrefs are not always exact.
For instance, accesses by some instructions
are not detected (eg \cw{lgdt}, \cw{sgdt}, \cw{fsave}).
Some instructions' accesses are not always correctly detected,
such as \cw{enter} with non-zero second operand,
string instructions spanning segment boundaries,
or instructions using \cw{ss} after
a write to \cw{ss} that causes disassembly repetition.
Some types of accesses are never detected either,
such as GDT/LDT accesses to load descriptors.
The stack access of software interrupt instructions
is correctly detected only when tracing interrupts
(Trace Mode set to 1, refer to \k{cmdtm});
if the interrupt call is proceeded past then
like any proceeded-past function call it may use more stack space.

}

\dt _SYMBOLIC

\dd Enables the symbolic debugging support.
This currently defaults to off.
Documentation about the symbolic debugging support is still lacking.
This may require the _DUALCODE build option to be enabled.

\dt _IMMASM

\dd Enable the immediate assembler.
Refer to \k{cmdimmasm}.
This currently defaults to off.
This may require the _DUALCODE build option to be enabled.

\dt _DUALCODE

\dd Enable the second code segment of the debugger.
Most of the symbolic and immediate assembler code will be put
into the second code segment if it is enabled.
Currently defaults to on if both _PM and _SYMBOLIC are enabled.

\dt _BOOTLDR_DISCARD

\dd Discard boot loaded mode specific code when installing
the debugger as a DOS application or DOS device driver.
This saves about 9 kB of resident memory use.
Enabled by default.

\dt _BOOTLDR_DISCARD_HELP

\dd Discard boot loaded mode ?BOOT help page when installing
the debugger as a DOS application or DOS device driver.
This saves about 2.7 kB of resident memory use.
Enabled by default.
Only takes effect if option _MESSAGESEGMENT is enabled.

\dt _MESSAGESEGMENT

\dd Adds an additional segment for storing long messages
like the help pages.
This moves about 20 kB out of the data entry segment.
Enabled by default.

\dt _EXPRDUALCODE

\dd Moves most code of the expression evaluator into
the second code segment, if _DUALCODE is also enabled.
This moves 5 kB out of the first code segment.
Performance may suffer from this option.
Disabled by default.

\dt _SYMBOLASMDUALCODE

\dd Moves most code of the symbols.asm file into
the second code segment, if _DUALCODE is also enabled.
Disabled by default.

\dt _CHECKSECTION

\dd Sets default value for the following three options.
Disabled by default.

\dt _CHECKCALLSECTION

\dt _CHECKJMPSECTION

\dt _CHECKJCCSECTION

\dd These options enable detection of invalid cross-section branches.
Enabling all of these options makes the build take a long time,
possibly in excess of two and a half minutes (versus 30 seconds).
Further, memory use of the assembler may as much as triple easily.
(166 MiB seen, versus 66 MiB.)
The \W{https://bugzilla.nasm.us/show_bug.cgi?id=3392892}{patch for the %rep leak}
for NASM versions beyond 2.16.01 is a must for enabling any of these options.
These options are not useful if the _DUALCODE option is not enabled.

\dt _EXTENSIONS

\dd Reserves memory for Extension for lDebug loading
and adds the EXT command to load.
(DOS must be available for application mode or device mode.
Auxiliary buffer must be available for bootloaded mode.)
The /X= switch to the application mode or device mode debugger
can be used to set the size of the ELD instance code segment.
Likewise, the /Y= switch can be used to set the size
of the ELD data area.
Enabled by default.


\C{gettingstartedrelease} Getting started with the release

The stand-alone and FreeDOS release packages contain
the following files:

In the \cw{bin} or \cw{BIN} directory:

\dt \cw{ldebug.com}

\dd Compressed bootable debugger, build without DPMI support

\dt \cw{ldebugx.com}

\dd Compressed bootable debugger, build with DPMI support

\dt \cw{instsect.com}

\dd Application to install boot sector loaders,
with lDOS loaders that default to load \cw{LDEBUG.COM}
from a FAT12, FAT16, or FAT32 file system

\dt \cw{*.eld}

\dd Extensions for lDebug


Only in the stand-alone package, \cw{bin} also contains:

\dt \cw{ldebugu.com}

\dd Uncompressed bootable debugger, build without DPMI support

\dt \cw{ldebugxu.com}

\dd Uncompressed bootable debugger, build with DPMI support


In the FreeDOS package, \cw{SOURCE/LDEBUG/ldebug/bin} contains
all the same files as \cw{bin} in the stand-alone package.
(All files in \cw{BIN} are duplicated from this \cw{bin} directory.)
Likewise, the stand-alone package's \cw{tmp}, \cw{doc}, and \cw{lst}
are carried over into the FreeDOS package's source tree.

Unlike the stand-alone package, the FreeDOS package contains all sources
needed to build the debugger from scratch, except for the build toolchain.
The following repos' most recent tip revisions are copied into
the \cw{SOURCE/LDEBUG} source tree:

\dt inicomp

\dd Depacker stages for compressed triple-mode executables

\dt instsect

\dd Install boot sector loaders to drives or file system images

\dt ldosboot

\dd Boot sector loaders and initial loader stage for kernels
(triple-mode executables supported)

\dt lmacros

\dd lDOS assembly macro collection

\dt scanptab

\dd Allow initial loader or bootloaded debugger to scan for partitions

\dt tellsize

\dd Display the allocation size needed by a .big style application image 


The \cw{tmp} or \cw{SOURCE/LDEBUG/ldebug/tmp} directory
contains subdirectories for each used compression method.
For example, there is a subdirectory named \cw{lz4}.
These subdirectories contain the compressed executables
\cw{ldebug.com} and \cw{ldebugx.com} built
with the corresponding compression method.

NB: The default choice of compression method (lzsa2)
is chosen based on the executable size and depacker performance.
Other compression method choices may be desired.
The uncompressed executables may be used,
or those compressed with another method
(as found in the \cw{tmp} subdirectories).


In the \cw{doc} directory, or \cw{DOC/LDEBUG}:

\dt \cw{ldebug.htm}

\dd This manual in HTML, preferred form

\dt \cw{ldebug.txt}

\dd Manual in plain text (with CR LF line endings)

\dt \cw{ldebug.pdf}

\dd Manual in PDF (only in stand-alone package or source tree)

\dt \cw{fdbuild.txt}

\dd FreeDOS package build instructions

\dt \cw{LDEBUG.LSM}

\dd LSM file for lDebug FreeDOS package


In the root directory, or also \cw{DOC/LDEBUG}:

\dt \cw{license.txt}

\dd Full license texts for lDebug


In the \cw{APPINFO} directory, only for FreeDOS package:

\dt \cw{LDEBUG.LSM}

\dd LSM file for lDebug FreeDOS package


In the \cw{lst} or \cw{SOURCE/LDEBUG/ldebug/lst} directory:

\dt \cw{debug.map}

\dd Assembly map corresponding to \cw{ldebug.com} and \cw{ldebugu.com}

\dt \cw{debugx.map}

\dd Assembly map corresponding to \cw{ldebugx.com} and \cw{ldebugxu.com}

\dt \cw{instsect.map}

\dd Assembly map corresponding to \cw{instsect.com}

\dt \cw{boot12.map}, \cw{boot16.map}, \cw{boot32.map}

\dd Assembly maps corresponding to the loaders
that are embedded into \cw{instsect.com}


Listing files are no longer shipped with release builds
(as of release 8),
neither in the stand-alone package nor the FreeDOS package.
To obtain a listing file that will match the binaries of
a release build, one may obtain the daily current build of the same day
as the release build.
The only differences should be in the debugger version strings,
which are filled to the same size
to avoid changing the offsets of everything.

Alternatively, in the \cw{source} directory
\cq{./make reproduce} may be run on a host system
to recreate all artefacts of the build of the main debugger.
(Exact identicalised output may require the same toolchain
as originally used.)
Likewise, in the \cw{source} directory \cq{./makinst.sh} may be run
to recreate the instsect artefacts
and in the \cw{source/eld} directory \cq{./mak.sh} to create the ELDs.


\C{invoking} Invoking the debugger

\H{invoking-boot} Invoking the debugger in boot loaded mode

The debugger can be loaded as a variety of kernel formats.

The Multiboot1 and Multiboot2 entrypoints
will expect that a kernel command line is provided.
The EDR-DOS, FreeDOS, RxDOS.3, and lDOS load protocols allow specifying
a kernel command line, but it is optional.

If a kernel command line is detected then its contents
are entered into the command line buffer.
Unescaped semicolons are translated into Carriage Returns.
Semicolons and backslashes may be escaped with backslashes.

If no kernel command line is given, the debugger assumes
a default. It is equivalent to checking for a file and label using
the IF command (\k{cmdif}), then if found to execute that script file.
The IF condition is like \c{if exists y ldp/LDEBUG.SLD :bootstartup then}
and the subsequent script command is \c{y ldp/LDEBUG.SLD :bootstartup}
(\k{cmdy}).
The filename is however \c{LDDEBUG.SLD} for DDebug builds,
and \c{LCDEBUG.SLD} for CDebug builds.

Executing the \cw{Q} command (\k{cmdq}) makes the debugger
uninstall itself then continue running whatever code
the debuggee is in.
Executing the \cw{BOOT QUIT} command (\k{helpboot})
makes the debugger attempt to shut down the machine.
First it will try to call a dosemu-specific callback.
Next it will attempt shutting down with APM.
(This works in qemu.)
Finally it will give up if no attempt worked.


\H{invoking-app} Invoking the debugger as an application

The debugger is internally an MZ .EXE style application.
It may need MS-DOS version 3 level features.
A few switches are supported:

\dt \cw{/?}

\dd Show the command help page about invoking the debugger.
Refer to \k{cmdhelp-ldebug} for a copy of that help.

\dt \cw{/C}

\dd Put the text following this switch into the command line buffer.
Unquoted unescaped blanks indicate the end of the text.
Parts may be quoted using single quote marks or double quote marks.
Unescaped semicolons are translated into Carriage Returns.
Semicolons, backslashes, quote marks, and blanks
may be escaped with backslashes.

\dt \cw{/IN}

\dd Clear the command line buffer.
This switch can be used to discard the default commands
placed into the command line buffer.
They are intended to load a start up configuration from
a Script for lDebug file, either in the directory
specified by the \cw{%LDEBUGCONFIG%} variable or in
the debugger executable's directory.

\dt \cw{/A}

\dd Specify auxiliary buffer size.
The size may be specified as the keywords \cw{MIN}, \cw{MAX},
a hexadecimal number, or a hash sign \cw{#} followed by a decimal number.
If a blank follows directly behind \cw{/A} this is parsed like \cw{/A=MAX}.
Minimum size is 8208 Bytes, maximum size is by default 24576 Bytes.
The auxiliary buffer currently cannot be resized
by the resident debugger.
This switch is processed by the debugger's init.

\dt \cw{/S}

\dd This switch is only used if the symbolic option is enabled.
It can be used to set the size of the symbol tables early,
before loading a debuggee application.
Refer to \k{cmdzswitchs}.

\dt \cw{/B}

\dd Run a breakpoint within the debugger's initialisation.

\dt \cw{/F}

\dd Enable/disable treating file as a flat binary.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
This controls the DCO6 option 400h.
If enabled, .EXE and .COM files will be loaded as flat binaries
even if they contain an MZ executable header.
.HEX files will also be loaded as flat binaries
rather than being interpreted to load the described contents.
Writing the files back as flat binaries is also enabled by this.
(Note that the file has to fit into memory for this.)
/F implies /E+, but /F+ and /F- do not imply anything about /E.

\dt \cw{/E}

\dd Enable/disable setting Stack Segment != PSP for loading flat binaries.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
This controls the DCO6 option 800h.
If enabled then loading a flat binary file
(with filename extensions such as \cw{.BIN}
or using the /F switch)
will set up a Stack Segment at the end of the process memory block.
That is, in a different segment than the process segment.
If disabled, then flat binaries always get SS = PSP even if
that leaves the stack pointing into the binary image.
/F implies /E+.

\dt \cw{/V}

\dd Enable/disable video screen swapping.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
Refer to \k{cmdv}.

\dt \cw{/2}

\dd Enable/disable using a second display for debugger output.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
This option is disabled by default.
If no second display is detected by the debugger,
trying to enable this mode causes an error message.
This option can only be enabled by the debugger's init.
Therefore there is no Debugger Common Options flag for this mode.

\dt \cw{/P}

\dd Enable/disable path search and guessing filename extension.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
This option is disabled by default.
When enabled, the debugger's init will try to expand
the filename passed after the switches.
(This only works during initially loading the debugger.
Subsequent N or K commands will not observe /P+ mode.
Therefore there is no Debugger Common Options flag for this mode.)

\lcont{

If the last component of the filename
(after the right-most forward slash, backslash, or colon)
does not yet contain a dot,
the debugger will first try to load from the filename as given.
Then it will try to append three different filename extensions
in order: \cw{.COM}, \cw{.EXE}, and \cw{.BIN}.

If the filename does not contain any path components
(indicated by forward slashes, backslashes, or colons)
and no match is found in the current directory,
the debugger will read the \cw{%PATH%} variable if any.
It will then attempt to find a match in every path element
in order. (If the filename does not contain a dot,
then for every path element, it is searched for
the filename as-is and then
with each of the three extensions added.
If all four attempts fail, the next path element is tried.)

\dt \cw{/PE}

\dd Enable/disable guessing filename extension, only.

\dt \cw{/PS}

\dd Enable/disable path search, only.

}

\dt \cw{/PW}

\dd Enable/disable warning for unknown filename extension.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
This option is enabled by default.
When enabled, the debugger's init will match
the filename passed after the switches
to a list of known extensions.
(This only works during initially loading the debugger.
Subsequent N or K commands will not observe /PW+ mode.
Therefore there is no Debugger Common Options flag for this mode.)

\lcont{

If the filename is not empty, and if the last component of the filename
(after the right-most forward slash, backslash, or colon)
does contain a dot,
and the last four text bytes do not match a known extension,
then the warning is displayed by init.
The known filename extensions
are: \cw{.HEX}, \cw{.ROM}, \cw{.COM}, \cw{.EXE}, and \cw{.BIN}.

}

\dt \cw{/D}

\dd This switch is only used for a conditionally debuggable build (lCDebug).
Enable/disable debuggable mode.
Enable if a blank or plus sign follows this switch.
Disable if a minus sign follows this switch.
This controls the DCO6 option 100h.
By default, debuggable mode is enabled.
For lDebug or lDDebug builds (not lCDebug),
a no-op /D switch is accepted but a switch
that disagrees with the debuggability of the build is rejected.


After the switches a filename may follow.
After the filename, command line contents for the process
to be debugged may follow.
These are both passed to the N command.
Then, an L command for loading an application is run.

Executing the \cw{Q} command (\k{cmdq}) makes the debugger
try to terminate the debuggee application
and to then terminate itself.
The debugger returns to whatever application called it.

If the TSR command (\k{cmdtsr}) is used, the debugger
patches the parent of the currently running application
to be the debugger's parent.
A subsequent \cw{Q} command will then behave much like
it does in boot loaded mode:
The debugger uninstalls itself and continues execution
in the current debuggee context.

The debugger detects its configuration directory as follows:

\n If the environment variable \cw{LDEBUGCONFIG} is set, read it.

\n Else, if the path to the debugger's executable can be determined,
use that.

\n Else, the current directory on the current drive is used.

The command line buffer receives a command that uses the
configuration directory.
This command is written before any /C= switch contents.

It is equivalent to checking for a file and label using
the IF command (\k{cmdif}), then if found to execute that script file.
The IF condition is like
\c{if exists y ::config::LDEBUG.SLD :applicationstartup then}
and the subsequent script command is
\c{y ::config::LDEBUG.SLD :applicationstartup}
(\k{cmdy}).
The filename is however \c{LDDEBUG.SLD} for DDebug builds,
and \c{LCDEBUG.SLD} for CDebug builds.
This default command can be disabled using the /IN switch.


\H{invoking-device} Invoking the debugger as a device driver

The debugger's MZ .EXE style executable can also
be loaded as a device driver.
Loading as a device driver requires an MS-DOS version 5 level feature.
Namely, the loader has to initialise and pass the pointer
to the end of memory available to the device driver.
(The debugger attempts to detect whether this pointer
is passed and indicates enough memory,
but it is unclear how well that works.)

Device drivers can be loaded from CONFIG.SYS using a
\cw{DEVICE=} directive.
Other loaders such as DEVLOAD may work too.
(DEVLOAD 3.25 specifically needs a patch to fix some problems
keeping track of memory and to allow DEVLOAD
to report more than 64 KiB of memory available to the device driver.)

DOS device loaders generally convert the device driver's command line
to allcaps.
To work around this, the debugger will interpret
the exclamation mark in a special way:
An exclamation mark indicates to convert the next letter
to a small letter, if it is a capital letter.
To pass a literal exclamation mark, double it.

All command line switches of the application mode
are also accepted by the device mode debugger.
(The /T switch is the exception,
it is only valid to the application mode.)
In particular, \cw{/C=} can be used to pass commands to execute.
The configuration Script for lDebug file is detected
in the same way as for application mode,
except the label used is \cw{:devicestartup}.

The debugger will start up with debuggee client registers
set up from the way they were passed by the device loader.
CS:IP will point to a far return instruction in
the debugger's entry segment.
The stack will be preserved from what the device loader passed, too.
That means running the debuggee allows to return control
to DOS and have it finish installation of the debugger as a device.
Subsequently, DOS and other device drivers and applications
can be debugged, just like when resident in TSR mode.

The device mode debugger can terminate in two different modes.
Both require a specific command letter appended
to the Q command.

QD may be used if control
did not return to the device loader yet.
The debugger checks this condition by stashing away
a copy of all regular registers to compare to their current values.
This includes all GPRs, all segment registers, EIP, and EFL.
Also, the debugger's device header fields for
pointing to the next device header are compared to FFFFh.
If both match, it is assumed that we can still modify
the request header passed by the device loader.
This allows to report an error and set up an empty memory block
to keep, so that the loader will know to discard the device.

QC may be used if control has returned to the device loader already
and the debugger device has been installed into the system.
It requires locating the device header in the chain of devices
that starts with the NUL device in the DOS data segment.
It also requires to find the memory block containing the debugger.
It must be either a PSP-alike MCB (self-owned regular MCB
containing exactly the debugger allocation)
or an \cq{SD} (System Data) container MCB with one or more sub-MCBs
(one of which contains exactly the debugger allocation).
If these conditions are met, the debugger can be quit.
It re-uses parts of the TSR application mode termination.

\s{NOTE:} Using QC currently assumes that no system file handles
are left allocated to the placeholder character device
that the debugger installs to keep itself resident.
This device is currently called \cq{LDEBUG$$}.
If this rule is not followed the system might crash.


\H{invoking-test} Invoking the test suite

Use the test.py script in the test subdirectory.
Use the -v switch to do verbose output.
Specify test name patterns to use with -k,
or omit to run all tests.
(Refer to the Test Reference in \k{testref}
for a list of all tests.)

The script uses the following environment variables:

\dt build_name

\dd Build name to use.
Either debug (default), debugx, ddebug, ddebugx, cdebug, or cdebugx.

\dt test_booting

\dd If set to a nonzero number, boot into the debugger.
Otherwise, a DOS is loaded and
the debugger is run as an application.
Some tests are booting only,
some other tests are non-booting only.
The unsupported tests are skipped automatically.

\dt test_initialise_commands

\dd Commands to be executed by the test set up method
right after establishing serial I/O.
Semicolons are replaced by Carriage Returns.
This should include the command \cq{r dco6 clr= 100}
or \cq{uninstall debug}
if testing lCDebug to disable its debuggable mode.

\dt test_sleepduration

\dd Floating point number which defines the default
sleep duration, in seconds, for read calls that do not override it.
This defaults to 0.05.

\dt test_addsleepduration

\dd Floating point number which defines a duration, in seconds,
to add to the duration of overridden read calls.
This defaults to 0.0.

\dt DEFAULT_MACHINE

\dd \cq{qemu} or \cq{dosemu} (default is \cq{qemu})

\dt DOSEMU

\dd dosemu executable to use

\dt QEMU

\dd qemu executable to use

\dt DEBUG

\dd If set to a nonzero number, dump all serial I/O
and all debugging messages.

The most common reason for random failures is timing.
If this is suspected to be the case, the duration variables
allow increasing the time spent waiting on debugger output.
They were added to replace the workflow
of editing durations manually in the test script.


\C{interface} Interface Reference


\H{interface-output} Interface Output

The debugger provides a line-based text interface.
The interface is written to DOS standard output by default.
If InDOS mode is entered,
\cw{INSTALL BIOSOUTPUT} has been used,
or the debugger is bootloaded
then the interface is written to the terminal using interrupt 10h.
Serial I/O can be enabled to write the interface to the serial port.


\H{interface-input} Interface Input

The default command prompt indicates that a command may be entered.
It is a dash \cq{-} by default,
or a hash sign \cq{#} when DebugX is in Protected Mode.
An exclamation point \cq{!} is prepended
by a DOS application or device mode debugger (not bootloaded)
while DOS's InDOS flag is set.
(This check always uses the actual InDOS flag,
ignoring the "force InDOS" mode of the debugger.)
A tilde \cq{~} is prepended for DDebug,
or CDebug while in debuggable mode.

If DOS command line input is done using \cw{getinput}
(eg if DCO option 800h is set or \cw{INSTALL GETINPUT} was run)
or the input is from a raw (ROM-BIOS) terminal,
or from a serial port, then the line editing history is enabled.
Prior commands may be recalled using the Up arrow key.
The Down arrow key may also be used to reverse the recall.
As soon as any prior or new line is edited
the history recall is disabled.
To discard the current line and re-enable history recall,
Control-C may be entered.

Long command output may be paged.
In that case, once a screenful has been displayed,
a \cq{[more]} prompt is displayed to pause the output.
After pressing any key the output is continued.
If Control-C is pressed, the current command is aborted.


\H{interface-serial} Enabling serial I/O

Refer to \k{varserial} for the serial configuration variables.
Setting the DCO flag 4000h enables serial I/O.
This flag can also be set using the \cw{INSTALL SERIAL} command.
Upon enabling serial I/O a prompt is sent to the serial port.
This prompt looks like the following example:

\c lDebug connected to serial port. Enter KEEP to confirm.
\c =

(The name of the debugger is modified to
indicate DebugX, DDebug, DDebugX, CDebug, or CDebugX.
The prompt indicator is \cq{~= } for DDebug
or CDebug while in debuggable mode.)
If the keep prompt is successfully displayed
by the serial terminal and is responded to
with the requested \cq{KEEP} keyword
then serial I/O is established.

If the confirmation does not occur after a timeout
then serial I/O is disabled again.
The timeout defaults to about 15 seconds.
In this case the debugger itself clears the DCO flag 4000h.

If the DCO flag 4000h is cleared then serial I/O is disabled.
The flag can also be cleared using the \cw{UNINSTALL SERIAL} command.


\H{interface-rdump} Register dumping

The R command (refer to \k{cmdr}) without any parameters
dumps the current register values.
Then it disassembles a single instruction,
or occasionally more than one.
The register dump looks like this by default:

\c -r
\c AX=0000 BX=0001 CX=58A0 DX=0000 SP=0800 BP=0000 SI=0000 DI=0000
\c DS=1BEC ES=1BEC SS=35A9 CS=1BEC IP=0140 NV UP EI PL ZR NA PE NC
\c 1BEC:0140 8CC8              mov     ax, cs
\c -

If the \cq{RX} command was used
to switch on 32-bit register dumping,
then the register dump looks like this:

\c -r
\c EAX=00000000 EBX=00000001 ECX=000058A0 EDX=00000000 ESP=00000800 EBP=00000000
\c ESI=00000000 EDI=00000000 NV UP EI PL ZR NA PE NC
\c DS=1BEC ES=1BEC SS=35A9 CS=1BEC FS=0000 GS=0000 EIP=00000140
\c 1BEC:0140 8CC8              mov     ax, cs
\c -

The RE command (\k{cmdre}) runs the RE buffer commands.
The default RE buffer content is a single \cq{@R} command.
After running the program being debugged,
usually the RE buffer commands are also being run.
This includes a step with the T, TP, or P commands.
(\K{cmdt}, \k{cmdtp}, \k{cmdp}.)
It also includes a run with the G command. (\K{cmdg}.)
Further, a permanent breakpoint
which is configured as a pass point being passed
also runs the RE buffer commands. (\K{cmdb}.)

Setting the flags 1_0000 or 4_0000 in the DCO3 variable
enables register change highlighting.
(The command \cw{INSTALL RHIGHLIGHT} sets DCO3 4_0000.)
When output is written to DOS standard output
or to a serial port
then ANSI escape sequences are used to highlight.
Specifically, \cq{\\x1B[7m} is used to reverse video
and then \cq{\\x1B[m} to reset the colours.

For DOS standard output it may be needed to install
an ANSI escape sequence parser.

For serial I/O the terminal connected to the debugger
is expected to handle the escape sequences.

If the output is to a terminal using interrupt 10h
and DCO3 flag 2_0000 is clear and the terminal is
detected as functional then highlighting is
done using interrupt 10h video attributes.

The functionality check is done by calling
interrupt 10h service 03h.
If the indicated current column is nonzero
then the terminal is considered functional.
(Recent dosemu2 in \cw{-dumb} terminal mode
is detected as not being functional.
Current dosemu2 is queried for \cw{-dumb} mode directly,
and considered not functional if in this mode.)

If this check fails or the DCO3 flag 2_0000 is set
then escape sequences are written using interrupt 10h.


\H{interface-mdump} Memory dumping

Another basic command is the D command (\k{cmdd}).
It is used to dump memory contents.
For example, to dump part of a program:

\c -d
\c 1BEC:0140  8C C8 31 DB 05 70 14 50-53 CB 70 03 91 67 BC 45 ..1..p.PS.p..g.E
\c 1BEC:0150  3F 10 C1 6F F9 70 BA 22-7C 71 C3 72 0A 81 0A 81 ?..o.p."|q.r....
\c 1BEC:0160  47 74 68 76 6C 77 32 72-A7 2F BD 78 4B 16 9F 7B Gthvlw2r./.xK..{
\c 1BEC:0170  C9 2B 09 37 0A 81 81 7D-E2 7E AC A0 00 00 00 00 .+.7...}.~......
\c 1BEC:0180  10 49 00 00 0F 00 00 00-00 00 00 00 10 49 00 00 .I...........I..
\c 1BEC:0190  0F 00 00 00 F8 30 80 00-00 00 00 00 80 00 00 00 .....0..........
\c 1BEC:01A0  07 00 00 00 07 00 00 00-00 00 00 00 00 00 00 00 ................
\c 1BEC:01B0  00 00 00 00 97 65 00 00-00 00 00 00 00 00 00 00 .....e..........
\c -

Or, to dump the stack as words:

\c -dw ss:sp
\c header     0    2    4    6    8    A    C    E    0123456789ABCDEF
\c 35A9:0800  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0810  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0820  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0830  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0840  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0850  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0860  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c 35A9:0870  0000 0000 0000 0000-0000 0000 0000 0000 ................
\c -


\H{interface-disasm} Disassembly

The U command is used to disassemble one or several instructions.
Example:

\c -u
\c 305C:0000 8CD0              mov     ax, ss
\c 305C:0002 8CDA              mov     dx, ds
\c 305C:0004 29D0              sub     ax, dx
\c 305C:0006 31D2              xor     dx, dx
\c 305C:0008 B90400            mov     cx, 0004
\c 305C:000B D1E0              shl     ax, 1
\c 305C:000D D1D2              rcl     dx, 1
\c 305C:000F E2FA              loop    000B
\c 305C:0011 50                push    ax
\c 305C:0012 01E0              add     ax, sp
\c 305C:0014 83D200            adc     dx, +00
\c 305C:0017 83C00F            add     ax, +0F
\c 305C:001A 83D200            adc     dx, +00
\c 305C:001D 24F0              and     al, F0
\c 305C:001F 83FA01            cmp     dx, +01
\c -


\H{interface-load} Loading the debuggee

A program to examine can be loaded using the N and L commands.
If the debugger is loaded as a DOS application
with a filename specified in its command line,
it will run the N and L commands on its own.

The N command sets up some buffers internal to the debugger.
One of those specifies the pathname of the executable file to load.
The pathname must include the filename extension, if any.
The pathname must be relative to the current directories
at the time the L command runs, or it must be absolute.
This is not true of the pathname initially specified
on the debugger command line tail if the debugger switch /P is used.
The path Extension for lDebug (refer to \k{eld-path})
can be loaded to provide
extension guessing and path search for later N or K commands
after the debugger has been loaded properly.

The tail of the N command after the pathname is used
as the command line tail for a new debuggee process.

The L command without any parameters attempts
to load the program specified to the last N command
into a new process.
If the L command does not display any messages this indicates success.


\H{interface-run} Running the debuggee

Once a program is loaded into the debugger it can be run
in several ways:

\dt G command

\dd Runs at full speed until a breakpoint is encountered.
Temporary breakpoints can be specified to the G command.
Refer to \k{cmdg}.

\dt T command

\dd Traces a single instruction,
except for software interrupts which are by default
run at full speed with a breakpoint after them.
Refer to \k{cmdt}.

\dt P command

\dd Either runs at full speed with a breakpoint
behind the current instruction,
or traces a single instruction.
Software interrupts, call instructions,
repeated string instructions, and loop instructions
are proceeded past by using a breakpoint.
Refer to \k{cmdp}.

\dt TP command

\dd Like the T command except that repeated string instructions
are proceeded past like the P command would.
Refer to \k{cmdtp}.

All run commands support auto-repeat:
Submitting an empty line to the debugger (blanks allowed but no comment)
will make the debugger run the last command again.
For the G command auto-repeat, the specified temporary breakpoints
will be used again.
Refer to \k{cmdautorepeat}.

Permanent breakpoints can be set up and changed using
the B commands.
They can be configured to behave as pass points as well.
Refer to \k{cmdb}.

The ?RUN help page in \k{helprun} lists some additional features
of the T, P, and TP commands.


\H{interface-help} Help

The online help can be accessed using the \cq{?} command.
Refer to \k{helptopics} for copies of the online help.


\C{debugging} Debugging the debugger itself

There are debuggable builds of the debugger,
called lDDebug (unconditionally debuggable)
and lCDebug (conditionally debuggable).

The debuggable mode works by installing the mandatory
interrupt handlers of the debuggable debugger
only within the \cq{run} function,
so as to return the control flow to this instance
when it runs its debuggee code.
On return into this instance,
it uninstalls its mandatory handlers again.
This mechanism allows to debug most of the debugger
using a different instance of lDebug
(or potentially another debugger).

In debuggable mode, an additional command is supported,
the BU command (which stands for "Break Upwards").
It will run a breakpoint within the debugger's
code segment which will break into the other debugger.
Its code was updated so it will break at the
command dispatcher after the label cmd4.
This means if the outer debugger is also an lDebug
then it can be instructed to skip to the next command
being dispatched by entering the command \cq{G ip}.

lDDebugX (or lCDebugX) can also install its exception areas
into the other lDebugX instance. For this, the other
debugger needs to have run an \cq{INSTALL AMIS} command.
Then the debuggable debugger can run its \cq{INSTALL AREAS}.
Afterwards, faults in the debuggable debugger
will make the other lDebugX indicate the area of the fault.

After lDebugX has caught a fault in the CODE or CODE2 segment,
it can be instructed to resume the lDDebugX (or lCDebugX)
command input loop (cmd3) by running a \cq{G=0} command.
If \cq{G=1} is used instead, an additional linebreak will
be displayed by the debuggable debugger
before it starts prompting for input.
This is useful if the fault occurred
with some partial output currently displayed.
The offset 0 and offset 1 entries are also supported
by non-DPMI builds and can of course be used
at any point in time other than after a fault, too.

There are some DCO6 flags to control breakpoints and
entering lCDebug's debuggable mode in the functions
debuggerexception and putrunint. They can be displayed
using a \cq{?O6} command.

Other than for the most trivial sessions it is recommended
to control the outer debugger by serial I/O,
separately from the I/O of the debuggable debugger.
If the latter also should be controlled by serial I/O
then two different ports can be used.
The terminal connected to the outer debugger
can also be set up for TracList,
the lDebug companion application which traces a listing file.
For instance, if lDDebugX is to be traced,
TracList should be run with the ldebug/lst/ddebugx.lst
listing file.


\H{debugging-init} Initialising the debuggable debugger

To allow the debuggable debugger to relocate and initialise
its code sections,
the outer debugger should generally start running
the debuggable debugger with a plain \cq{G} command.
The debuggable debugger can then return control
to the outer debugger using its \cq{BU} command.

If the initialisation of the debuggable debugger
is to be debugged, the \cq{/B} switch may be of use.
Otherwise, note that the NEC V20/V30 and 486 CPU detections
may fail when traced using an outer lDebug.

The NEC detection may lock the machine up
if its specially encoded \cq{pop cx} is traced
or run with a breakpoint directly behind it.
To allow to continue tracing after it,
a breakpoint must be set up at the \cq{jcxz} instruction or later.
There must not be a breakpoint on the \cq{mov sp, ax} instruction.
The \cq{pop cx} instruction must not be traced with the Trace Flag set.
Failure to honour these requirements may lock up the NEC CPUs,
for example the one used in the HP 95LX,
which then may require resetting the system with Ctrl-Shift-On.
This also resets the system date and time.

The 486 detection may wrongly detect a 386 instead of a 486+
when traced on some systems, such as some revisions of dosemu(2).


\H{debugging-sectioning} Sectioning overview

The sections of the debugger are declared in debug.asm:

\c   org 100h
\c   addsection lDEBUG_DATA_ENTRY, align=16 start=100h
\c data_entry_start:
\c %define DATASECTIONFIXUP -data_entry_start+100h
\c _CURRENT_SECTION %+ _start:
\c %xdefine %[_CURRENT_SECTION %+ FIXUP] - _CURRENT_SECTION %+ _start+100h
\c
\c   addsection ASMTABLE1, align=16 follows=lDEBUG_DATA_ENTRY
\c   addsection ASMTABLE2, align=16 follows=ASMTABLE1
\c   addsection MESSAGESEGMENT, align=16 follows=ASMTABLE2 vstart=0
\c messagesegment_start:
\c   addsection lDEBUG_CODE, align=16 follows=MESSAGESEGMENT vstart=0
\c code_start:
\c %define CODESECTIONFIXUP -code_start+0
\c _CURRENT_SECTION %+ _start:
\c %xdefine %[_CURRENT_SECTION %+ FIXUP] - _CURRENT_SECTION %+ _start+0
\c   addsection lDEBUG_CODE2, align=16 follows=lDEBUG_CODE vstart=0
\c code2_start:
\c %define CODE2SECTIONFIXUP -code2_start+0
\c _CURRENT_SECTION %+ _start:
\c %xdefine %[_CURRENT_SECTION %+ FIXUP] - _CURRENT_SECTION %+ _start+0
\c
\c   addsection DATASTACK, align=16 follows=ASMTABLE2 nobits
\c   addsection INIT, align=16 follows=lDEBUG_CODE2 vstart=0
\c %if _DEVICE
\c   addsection DEVICESHIM, align=16 follows=INIT vstart=0
\c %endif
\c   addsection RELOCATEDZERO, vstart=0 nobits
\c relocatedzero:

These are the sections:

\dt lDEBUG_DATA_ENTRY

\dd Data entry section. Used for data, most messages, and
code entrypoints into the debugger.
Addressed with the same segment as the debugger's PSP.
This segment is usually addressed using SS, often DS also,
and sometimes ES too.
Not relocated, except if application /T switch used.

\dt ASMTABLE1, ASMTABLE2

\dd Assembler/disassembler tables.
Addressed with the same segment as the debugger's PSP
and the data entry section.
Not relocated, except if application /T switch used.

\dt MESSAGESEGMENT

\dd Used to store some long messages,
as well as the ELD link info tables.
Addressed with a vstart of zero using its own segment.
Relocated to behind the data stack section
when the init sets up the debugger.
May be truncated to drop \cw{?BOOT} help page
when not in bootloaded mode.

\dt lDEBUG_CODE

\dd First and main code section.
Addressed with a vstart of zero using its own segment.
This segment is addressed using CS most of the time.
Relocated to behind the message segment or
behind the auxiliary buffer.
May be truncated to drop boot code
when not in bootloaded mode.

\dt lDEBUG_CODE2

\dd Second code section.
Only used (not empty) if _DUALCODE is enabled.
Addressed with a vstart of zero.
Relocated to behind the first code section.

\dt DATASTACK

\dd Nobits. Uninitialised data and stack section.
Addressed using the same segment
as the data entry section.
This contains the ELD data blocks,
the size of which can be changed
using the \cw{/Y=} switch to the application or device driver init.
The maximum ELD data size will expand this section up to offset 65_520.

\dt INIT

\dd Debugger init.
Addressed using a vstart of zero.
In device mode and application mode,
this section is relocated at least once.
A second relocation will be attempted if
_INIT_MAX=0 and the chosen sizes of the auxiliary buffer,
the ELD code segment, the history buffer,
and the ELD data blocks are too large to fit into
the initial allocation.
Discarded after init is done.

\dt DEVICESHIM

\dd This section is eventually installed at the beginning
of the debugger allocation for the device mode debugger,
before the debugger's pseudo-MCB and PSP created by the init.
It contains the header and resident code of the device driver
that the debugger installs to stay resident.

\dt RELOCATEDZERO

\dd Nobits. A label in
this section is used in far call (dualcall with _PM=0)
instructions for the segment immediate.
Its use is to emit a relocation into the listing file,
helping these instructions to be matched by TracList.


There are some additional segments that do not correspond
to sections in the debugger's sources.
All of these segments are allocated at init time.

\dt Auxiliary buffer

\dd Used for various needs.
Default size is 8 KiB + 16 Bytes,
can grow up to 24 KiB using \cw{/A=} switch to non-boot init.

\dt History segment

\dd Used to hold line editor history.
Default size is 8 KiB,
can grow up to nearly 64 KiB using \cw{/H=} switch to non-boot init.
Can shrink to nearly 260 Bytes as well.

\dt Environment block

\dd Holds the debugger's environment.
Size is 2 KiB.

\dt ELD code segment

\dd Provides space for loading ELD code instances.
Default size is 16 KiB, can grow up to 65_520 Bytes
or shrink all the way to zero bytes
using the \cw{/X=} switch to non-boot init.


Some additional memory allocations show up as gaps in
the memory map of the debugger:

\dt Device driver header and code

\dd This is initialised from the DEVICESHIM section.

\dt Device driver trailer paragraph

\dd This is reserved to support the QC command,
in case the debugger is stored in an SD sub-MCB.

\dt Layout 3 gap

\dd When the debugger init determines that the auxiliary buffer
cannot be placed as desired in one of the first two layouts,
then a gap of about 8 KiB is allocated additionally.

\dt Boot image ident

\dd This paragraph contains a signature that spells \cq{NDEB}
and size information on the allocation of the debugger.

\dt Boot alignment gap

\dd The boot allocation is done using the int 12h memory size.
This size is specified in an amount of kilo binary bytes.
Therefore, the debugger may need to allocate up to 1008 Bytes
more than it needs to align its allocation to a KiB boundary.


\H{debugging-eld} Debugging ELDs

The ELD code segment has a different convenience entrypoint
that returns the control flow to the \cw{cmd3} loop.
Due to the structure of ELD instances, there can be no code at
offset 0.
Instead, there is an entry at offset 79h.
Therefore, when the inner debugger is running code
in the ELD code segment, a \cq{G=79} command can be used
to cancel the currently running ELD.
(At most points in an ELD, to cancel the currently running ELD
should be safe.
In particular, any calls to debugger code that may do I/O
or that may invoke the error handler must be safely cancellable.)


\S{debugging-eld-offset-hint} Using the offset hint to debug ELDs

ELDs can be loaded at arbitrary offsets in the ELD code segment.
The first ELD is always loaded at offset 80h,
but subsequent ELDs may be loaded at higher offsets.
The only certainty is that the offset is paragraph-aligned.

To help in using TracList to debug an ELD,
a special handshake is provided to communicate an ELD's offset.

The outer debugger should \cq{install amis} and install
the AMIS message ELD by running \cq{ext amismsg.eld install}.
When the ELD linker runs in the inner debugger,
it will send a hint message to the outer debugger's
AMIS function 40h (refer to \k{int2Dfunc40}).
The hint is received by the AMIS message ELD
of the outer debugger and displayed to the outer debugger's
terminal before processing the next command in the \cw{cmd3} loop.

The hint line looks like this example:

\c TracList-add-offset=ldmem.lst::0080h

When the hint line is received by tractest, it will hand it over
into the line file and hint file, both read by TracList.
TracList will then parse the offset provided by the hint.
In the current use case this hint is always
used to add a file-scoped offset.


\S2{debugging-eld-offset-hint-eld} Using the hint ELDs

There are additional ELDs, hint.eld and hintoth.eld.
Both will enumerate listing hints for all currently loaded ELDs.

The first, hint.eld, will send a string containing all the hints
to the AMIS message service of another debugger instance.

The second, hintoth.eld, will display the hints of an other link debugger
to the terminal of the debugger instance that runs the hintoth.eld.
This requires the other debugger instance to have installed its
AMIS interface and loaded the amisoth.eld to provide the other link.


\S{debugging-eld-houdini} Using houdinis to debug ELDs

Houdinis are conditional breakpoints.
They run an \cw{int3} instruction only if three conditions are met:

\n Houdinis are enabled in the ELD's build

\n The debugger is in debuggable mode (for lCDebug)
or it is an unconditionally debuggable build (lDDebug)

\n Houdinis have been enabled in the DCO7
using eg \cq{install houdini}


\S{eld-examples} ELD examples

\dt ldmem - Command hook

\dd Depicts how to install and uninstall a resident ELD
with a command hook.

\dt ldmem - Nouns

\dd Dispatches to subfunctions using a table of nouns
that can be entered on the command line,
defaulting to \cw{ALL} if no nouns are specified.

\dt ldmemoth - Other linker use

\dd Uses the other link info to access data structures
of a different instance of lDebug running on the system.
(Almost all of the sources are shared with ldmem.)

\dt amismsg - AMIS handler

\dd Implements two TSR-private AMIS services, functions 40h and 41h,
by using the AMIS handler hook.

\dt amisoth - Export link info

\dd Exports the link info and data/entry/stack segment and selector
of the debugger on the AMIS interface, to be read by ldmemoth.

\dt aformat - Iterate a table of handlers

\dd This ELD hooks into a record 4 handler chains exposed
by the debugger. To handle all of them,
the install and uninstall code iterates over a table
that points to the handlers and the hooks
in which they are referenced.

\dt list - Find files with wildcard pattern

\dd The list ELD finds and opens files specified by a pathname pattern.
It can use DOS LFN find, DOS SFN find, or a bespoke boot directory scan
to match filenames.

\dt list - Use eldstrict mode with annotated relocations

\dd This mode utilises the recent NASM's reloc warnings to
enforce relocations being marked by the reloc or reloc2 mmacros.

\dt rn - Do 386-related patches upon loading the ELD

\dd The RN ELD implements patching based on whether it is running
on a 386+ machine or not. It re-uses the debugger's patch
and table writing macros.

\dt amount - Install an ELD variable

\dd This installs ELDAMOUNT as a variable that can be read
by the debugger's expression evaluator.

\dt eldcomp - Modify output in the puts handler

\dd When detecting a difference, eldcomp will rerun the ELD
under test and allocate buffers to copy the ELD's allocation.
Then it will run a debugger C command to highlight differences.
To relate the C command output to the ELD's listing file offsets,
eldcomp hooks into the puts handler and writes the in-section
offset before and after the C command output.

\dt eldcomp - Inject debugger commands

\dd To run its test commands, eldcomp installs itself as a resident ELD
and hooks into the debugger's command injection handler.
It then injects up to 17 commands to be run by the debugger.

\dt ifext - Add an IF command

\dd When installed as a resident ELD, ifext will provide the
\cw{IF [NOT] EXT extensionname THEN command} construct.

\dt x - Add a help page to the ? command

\dd The EMS commands ELD will add its help page using
either of two commands: \cw{X?} or \cw{?X}.

\dt set - Redirect output in a puts handler

\dd When run with the /E switch, the set ELD will inject a command
with a puts handler installed.
This handler will save one line of output
and cause none of the output to actually be displayed.

\dt withhdr - Provide prefix commands

\dd The WITH HEADER and WITH TRAILER commands are prefixes
that modify the workings of a subsequent command.

\dt variable - Preprocess command text

\dd This ELD installs a preprocess handler to expand
DOS environment variables in commands.

\dt dpb - Get an address that is always a 86 Mode segmented address

\dd Uses \cw{getaddrX} to get an 86 Mode segmented address,
even in Protected Mode.
This happens to work.
The address is read if the DPB command is used
with the \cw{LIST AT} keywords.

\dt dosspace - Big number arithmetic

\dd Uses 48-bit byte size display and 64-bit numerics
to display total and free space on a DOS drive.

\dt errfix - Provide an interface variable

\dd This ELD fills an indirect (pointer) variable in the debugger.
Other ELDs can use the contents of this variable
as part of an interface, to access an array variable
that lives within the errfix.eld data block.


\C{parref} Parameter Reference

\H{parnumber} Number

Plain numbers are evaluated as expressions.
Refer to \k{exprref}.
Expressions consist of any number of the following:

\b Unary operators

\b Binary operators

\b Operands

Plain number parsing for an expression continues for as long as
a valid expression is continued.
For example, in the command \cq{D 100 + 20 L 10} the starting address
(its offset to be specific) is calculated as \q{100 + 20}.
Then the expression evaluator encounters the \cq{L},
which is not a valid binary operator.
Plain number expression parameters are used by a lot of commands.
Sometimes, the plain number parameter type
is called \q{count} or \q{value}.


\H{paraddress} Address

An address parameter is calculated with a default segment.
First, a plain number is parsed.
If it is followed by a colon, the first number is taken as segment,
and then another number is parsed for the offset.
If the first number is specified as a pointer type
using the type keyword \cq{POINTER}
then its upper 16 bits are taken as segment
and its lower 16 bits are taken as the offset.
Otherwise, the first number is used as the offset.
Offsets may be 16 bits or 32 bits wide,
though 32-bit offsets are only valid for DebugX and only in 32-bit segments.

If a segment or pointer type expression are prefixed
by a dollar sign \cq{$} then the specified segment
is always taken as a Real/Virtual 86 Mode segment,
even if DebugX is in Protected Mode.
Otherwise, in Protected Mode a segmented address
refers to a selector.

Instead of an address, the address parameter may consist of the
taken keywords: \cw{TAKEN} or \cw{T} for taken,
and \cw{NOTTAKEN} or \cw{NT} for not taken.
This is only valid if the current \cw{cs:(e)ip} points
at a conditional branch instruction,
and will cause a parsing error otherwise.
The taken keywords will evaluate to a segmented address
pointing at the target of the conditional branch.
The not taken keywords will evaluate to a segmented address
pointing to behind the conditional branch instruction.

Address parameters are used by a lot of commands.


\H{parrange} Range

A range parameter may have a default length,
or it may be disallowed to omit a length.
Parsing a range starts with parsing an address.
Then, if the end of the line is not yet reached,
an end for the range may be specified.
The end may be a plain number,
which is taken as the offset of the last byte to include in the range.
The address of the last byte to include must be equal or above
the address of the first byte that is included in the range.

The end may instead be specified with an \cq{L} or \cq{LENGTH} keyword.
In that case, the keyword is followed by a plain number
and an optional item size keyword.
A length of zero is not valid.
The item size keyword may be \cq{BYTES}, \cq{WORDS}, \cq{DWORDS}, \cq{QWORDS},
\cq{PARAS}, \cq{PARAGRAPHS}, \cq{PAGES}, \cq{KiB}, \cq{MiB}, or \cq{GiB}.
Except for the first, the plain number will be shifted
as for the specified unit size
(multiplying by 2, 4, 8, 16, 512, 1024, 1_048_576, or 1_073_741_824).
It is an error if the shifting overflows the debugger's 32-bit arithmetic.
The \cq{BYTES} keyword is only provided for symmetry;
currently all commands taking ranges default to byte size
for the \cq{LENGTH} number.

For example, the command \cq{DD 100 LENGTH 4 DWORDS} will
dump memory from address 0100h (in the current data segment)
in dword units, for a length of 4*4 = 16 bytes.
The item size keywords were introduced
primarily for the \cq{DW} and \cq{DD} commands
(refer to \k{cmdd}),
but they can be used for any command that accepts a range.

There is a new keyword called \cq{END}.
This keyword may appear where the \cq{L} or \cq{LENGTH} keyword
would be expected. After the \cq{END} keyword
the end offset is parsed.
This is the same behaviour as if no keyword was present
but crucially it allows an end offset starting with the text
\cq{L}, which would otherwise be misparsed as an \cq{L} keyword.

If the default length is used (the line ends after the start address)
then a start address near the end of a segment (1_0000h or 1_0000_0000h)
will shorten the length if it would otherwise overflow the segment.

Range parameters are used by a lot of commands.


\H{parrangelines} Range with \cw{LINES} keyword allowed

This type of parameter is an extension of the range parameter type.
Both the default length and the explicit length
may be specified as a number of lines instead of an address length.

An explicit \cq{LINES} length is specified
by prepending an \cq{L} or \cq{LENGTH} keyword
(like an address length)
but then specifying a unit as \cq{LINES} instead.
The number of lines specified must be nonzero and below 8000h.

The exact details of how a lines length is used
depend on the command in question.
A range with lines length is allowed
for the U command (\k{cmdu})
and the D/DB/DW/DD commands (\k{cmdd}).


\H{parlist} List

A list is made up of a sequence of items.
Each item is either a plain number or a quoted string.
List parsing continues until the end of the line.
Each plain number represents a single byte.
Quoted strings represent as many bytes as there are quoted.
A quoted string can be delimited
by single quotes \cw{'} or double quotes \cw{"}.
If the used delimiter quote mark occurs twice back to back
while reading the quoted string,
this is taken as an escape to include the delimiter mark itself
as a byte of the string.
List parameters are used by the E, F, and S commands.
Refer to \k{cmde}, \k{cmdf}, and \k{cmds}.

A list may have its type changed with an \cw{AS} keyword,
followed by a size keyword \cw{BYTES}, \cw{WORDS}, or \cw{DWORDS}.
When a larger size is selected,
each subsequent number expression and each byte of quoted text
are written to a full word or a full dword instead of to a byte.
Text bytes are zero-extended.
Numbers can calculate to any value fitting the specified size.
A list's type may be changed multiple times within the list.


\H{parlistorrange} List or range

A list or range can be specified for this parameter.
The range is identified by a leading \cq{RANGE} keyword.
Otherwise, a list is parsed.
A list or range parameter is as yet used by
the S command and the F command, refer to \k{cmds} and \k{cmdf}.


\H{parkeyword} Keyword

A keyword is checked insensitive to capitalisation.
Keywords depend on each command.
Only the keywords used to specify a range's length are shared
by all commands that parse ranges.


\H{parindex} Index

An index is a plain number that specifies a breakpoint index.
It allows operating on one specific breakpoint.
The index parameter type is used by the B commands,
refer to \k{cmdb}.


\H{parsegment} Segment

A segment is a plain number for parsing purposes.
The segment parameter type is used by the DM command
and some BOOT commands,
refer to \k{cmddm} and \k{helpboot}.


\H{parbreakpoints} Breakpoint

Each breakpoint is a single address, which defaults to the code segment.
The address may instead be specified starting with an AT sign \cq{@},
followed by a blank or an opening parenthesis.
In that case, the following plain number
specifies the non-segmented linear address to use.
The breakpoint parameter type is used by the B and G commands,
refer to \k{cmdb} and \k{cmdg}.


\H{parlabel} Label

A label is a (not quoted) string keyword.
A label can be used by the GOTO and Y commands,
refer to \k{cmdgoto} and \k{cmdy}.
For the Y commands a label must start with a colon.
For the GOTO command the colon may be specified but it is optional.


\H{parport} Port

A port is a plain number for parsing purposes.
The port parameter type is used by the I and O commands,
refer to \k{cmdi} and \k{cmdo}.


\H{pardrive} Drive

A drive may be either an alphabetic letter followed by a colon,
or a plain number. The number zero corresponds to drive A: then.
The drive parameter type is used by the L and W sector commands,
refer to \k{cmdls} and \k{cmdws}.
The EXT, N, and Y commands (\k{cmdext}, \k{cmdn}, and \k{cmdy})
also accept drive parameters, but only as part of their filenames.
These must be in the drive letter followed by colon format.


\H{parsector} Sector

A sector is a plain number, which can be equal to any 32-bit value.
The sector parameter type is used by the L and W sector commands,
refer to \k{cmdls} and \k{cmdws}.
Some BOOT commands also use sector numbers, refer to \k{helpboot}.


\H{parcond} Condition

A condition is a plain number.
It is evaluated either to nonzero (true) or zero (false).
The condition parameter type is used by the IF command,
as well as the P, TP, and T commands
when specified with a \cq{WHILE} keyword.
The BW and BP (with a \cq{WHEN} keyword) commands also use conditions.
Refer to \k{cmdif}, \k{cmdp}, \k{cmdt}, \k{cmdbw}, \k{cmdbp}.
The length of a condition for B commands is
limited by how much space is left
in the permanent breakpoint conditions buffer.
This buffer currently defaults to 1024 bytes.
It is shared for all conditions of all permanent breakpoints.


\H{parregister} Register

A register specifies an internal variable of the debugger.
Most prominently these include the debuggee's registers
as stored by the debugger in its data segment.
A register or variable may be an operand in a plain number's expression.
However, several forms of the R command also use register parameters.
These allow reading and writing the register values.
Refer to \k{cmdr}.


\H{parcommand} Command

Command is a special parameter type that is used only by
the RE.APPEND, RE.REPLACE, RC.APPEND, and RC.REPLACE commands
(\k{cmdredot} and \k{cmdrcdot}).
It is read verbatim and entered into the RE or RC command buffer.
Semicolons within a command parameter are not parsed as
end of line comment markers.
Instead, they are converted to CR (13) codes in the buffer.
This delimits the parts of the parameter into several commands.
A semicolon may be prefixed by a backslash to escape it and thus
enter a literal semicolon into the buffer.


\H{parid} ID

ID is a special parameter type that is used only by
the BP and BI commands (\k{cmdbp} and \k{cmdbi}).
Leading and trailing whitespace is ignored.
An ID can be empty, or contain up to 63 bytes of data.
The length of an ID is also limited by how much space
is left in the permanent breakpoint ID buffer.
This buffer currently defaults to 384 bytes.
It is shared for all IDs of all permanent breakpoints.


\H{parfilename} Filename or pathname

This parameter type is used by EXT, N, K, and Y commands,
as well as some BOOT commands.
EXT and Y commands allow to use double quote marks.
When using DOS, EXT and Y commands can access files using Long File Names (LFNs).
When using DOS, all available commands parsing filenames
may specify drive letters.
EXT and Y commands when bootloaded, and some BOOT commands,
may specify partitions at the beginning of filenames.


\H{parcmdlinetail} Command line tail

Command line tails are parsed by EXT, N, and K commands.
They always are located behind a filename parameter.
A command line tail may be empty.
The N and K commands will store the command line tail
for use by the L program-loading command.
The EXT command passes its command line tail
to the Extension for lDebug that it loads.
The ELD may parse its command line tail
in whatever way is desired,
which may involve parsing other parameter types.


\C{exprref} Expression Reference

\H{exprliteral} Literals

Literals consist of one or more digits.
A literal must start with a digit or hash sign \cq{#}.
Embedded underscores \cq{_} are skipped.
Literals must not overflow 4 giga binary minus 1, that is FFFF_FFFFh.

The default base for literals is sixteen (hexadecimal).
A hash sign \cq{#} indicates a base change.
If nothing preceeds the hash sign the base is changed to ten (decimal).
Otherwise, the number before the hash sign is read in the prior base
and taken as the base to change to.
The base must be between 2 and 36, inclusive.
Multiple hash signs are allowed in the same literal.


\H{exprstringliteral} String literals

String literals consist of up to 4 bytes.
The bytes are specified starting with a hash sign \cq{#}
followed by a single-quote mark \cw{'} or double-quote mark \cw{"}.
The same quote mark is used to end the string literal.
If the delimiter quote mark occurs twice back to back
while reading the string literal, that is handled
as an escape to include the delimiter mark itself as a byte.
Strings are read in a little-endian order, same as NASM does.
That is, the first byte of a multi-byte string
is read into the lowest byte of the numeric value.
This matches the order obtained by writing the string to memory
and reading it as a word, 3byte, or dword.


\H{exprvariable} Variables

A variable consists of a variable name,
possibly followed by parentheses with an index expression.
Variable names are capitalisation insensitive.
Variables differ in size, there are variables
consisting of 8, 16, 24, or 32 bits.
Variables can be written to using the R command.
Some variables are read-only.
A few variables allow writing some but not all bits.


\H{exprindirection} Indirection

Indirection is indicated by square brackets.
Within the brackets an address is parsed,
defaulting to \cw{ds} as the segment.
The size of the indirect access can be specified
with a type specifier before the brackets.
The usual types are
\cw{BYTE}, \cw{WORD}, \cw{3BYTE}, and \cw{DWORD}.
Like variables, indirection terms can be written to using the R command.


\H{exprparens} Parentheses

Parentheses can be used to force a different order of operations.


\H{exprlinear} \cw{LINEAR} keyword

A keyword reading \cw{LINEAR} introduces an address to parse.
The address defaults to \cw{ds} as the segment.
The address may be separated from subsequent text with a comma.
If the expression is to be separated from a subsequent element
using a comma after a \cw{LINEAR} address then two commas are needed.
Depending on the segmentation scheme of the current mode
the segmented address is converted into a linear address.
If DebugX is in Protected Mode and the segment base cannot
be determined the expression is rejected as an error.


\H{exprdesctype} \cw{DESCTYPE} keyword

This keyword introduces a descriptor type read.
The following expression is taken to be a selector specification.
This keyword is only valid for (DPMI-enabled) lDebugX builds,
and only while in Protected Mode.

The value is read from a \cq{lar} instruction on
the following expression, and shifted to the right by 8.
If the instruction indicates that the selector does not
refer to a valid descriptor then the result of this keyword
is zero.


\H{exprvaluein} \cw{VALUE IN} construct

A keyword reading \cw{VALUE} starts a \cw{VALUE IN} construct.
Between the \cw{VALUE} and subsequent \cw{IN} keyword
there is a single value expression,
or a range of the form
\cw{FROM expression TO expression} or
\cw{FROM expression LENGTH expression}.
Next follows the \cw{IN} keyword.
After this, there is a list of match ranges.
A match range is either a single value expression,
or a range of the form
\cw{FROM expression TO expression} or
\cw{FROM expression LENGTH expression}.
After each match range a comma indicates another match range follows.

In a \cw{FROM TO} specification the first expression
has to evaluate to unsigned below-or-equal the second expression.
In a \cw{FROM LENGTH} specification the length
must be nonzero.
If these conditions are not met
then the value or match range in question
is always considered as not matching.

The entire \cw{VALUE IN} construct evaluates to how many
of the match ranges match the value range.
The construct only evaluates to zero if no matches occurred.
A nonzero value indicates that at least one match occurred.


\S{exprvaluein-keywords} \cw{VALUE IN} construct keywords

Instead of a value or match range as specified here,
the keyword \cw{EXECUTING} may be specified.
This expands to the following input:

\c FROM LINEAR cs:cip LENGTH abo - cip

If the \cw{_MEMREF_AMOUNT} build option is enabled
and paired with the \cw{direction} and \cw{stackhinting} switches to mktables
then additional keywords are available for \cw{VALUE IN} match ranges.
That is, these keywords must be specified behind the \cw{IN} and
cannot be specified between the \cw{VALUE} and \cw{IN}.

These keywords are as follows:

\dt \cw{READING}

\dd Expands to a comma-separated list of \cw{FROM readadr0 LENGTH readlen0}
constructs, for every read access variable pair (refer to \k{varaccess}).

\dt \cw{WRITING}

\dd Expands to a comma-separated list of \cw{FROM writadr0 LENGTH writlen0}
constructs, for every write access variable pair (refer to \k{varaccess}).

\dt \cw{ACCESSING}

\dd Expands to \cw{READING, WRITING, EXECUTING}.


\H{exprconditional} Conditional \cw{?? ::} construct

The ternary conditional operator takes three operands.
It is the only ternary operator.

The first operand, the condition, is specified before the \cw{??} keyword.
Note that the \cw{??} keyword must be terminated by a blank
or an opening square bracket or round parenthesis.

The second operand is specified between the \cw{??} keyword
and the \cw{::} keyword.
Its value is used as the construct's return value if the condition is true.

The third operand is specified after the \cw{::} keyword.
Its value is used as the construct's return value if the condition is false.

The conditional operator can be nested freely.
The conditional operator must not be combined into
the R command's assignment operator as in \cw{??:=}.
The third operand may be separated from subsequent text with a comma.
If the expression is to be separated from a subsequent element
using a comma after a conditional's third operand then two commas are needed.

Any side effects that may happen from parsing and reading
the second operand or the third operand will always happen,
even if the operand in question
is not selected as the result by the construct.


\H{exprsideeffects} Expression side effects

Some uses of the expression evaluator may have side effects.
These side effects may happen even if the parsing of an expression
or a command
ultimately fails.
As a special case, side effects may occur up to twice
if a machine mode command (\k{cmdmc}) is parsed.

The ternary \cw{?? ::} operator and the \cw{VALUE IN} construct
will both always evaluate every operand that they're given,
even if that operand is not selected as the result or
does not contribute to the match count.

Possible side effects include:

\b LFSR and RLFSR variables will be stepped once each time they're read.

\b Indirection can read access arbitrary memory in the current mode,
making it possible to affect memory-mapped I/O
if such memory is visible to the debugger.
Other variables may also read memory, but not as arbitrary as indirection.

\b If an address parsed within an address parameter
or in indirection or in a \cw{LINEAR} construct
includes a dollar sign prefixed segment or pointer type expression,
then lDebugX may request a selector from the DPMI host.

\b If the symbolic build option is enabled,
symbol table access in XMS or 86 Mode memory may occur.


\C{cmdref} Command Reference


\H{cmdautorepeat} Empty command - Autorepeat

Entering an empty command at an interactive prompt results in autorepeat.
Empty means no content except for blanks.
A line starting with a semicolon comment is not considered empty.
Interactive prompts for this purpose include:

\b the debugger as a DOS application (\cw{int 21h})

\b the debugger in InDOS mode or as a bootloaded program
(\cw{int 16h}/\cw{int 10h})

\b the debugger across a serial port (port I/O)

Input that does not count as an interactive prompt includes:

\b reading from a file redirected as stdin using DOS (\cw{int 21h})

\b reading from a Y script file using DOS (\cw{int 21h})

\b reading from a Y script file while bootloaded (\cw{int 13h})

\b reading from the command line buffer

\b reading from the RE buffer

Autorepeat is not supported by all commands.
The following commands support autorepeat:

\dt D/DB/DW/DD

\dd Continues memory dump behind the last prior dumped position.
Continues with the same element size as the prior dump.
As for if the command is executed with an address lacking a length,
the default length is used. (It defaults to 128 bytes, refer to \k{varlengths}.)

\dt DZ/D$/D#/DW#

\dd Continues string dump behind the last prior dumped string.
Continues with the same type of string as the prior dump.

\dt DX

\dd Continues memory dump.

\dt G

\dd Repeats a step running the debuggee.
An equals address given to the prior Go command is not used again.
The same G breakpoints as used by the prior Go command are used
(same as G AGAIN).
The exception is that wherever a breakpoint matches the
\cw{CS:(E)IP} at the start of the command's execution, it is skipped once.

\dt P

\dd Repeats a step running the debuggee.
An equals address given to the prior Proceed command is not used again.
A count given to the prior Proceed command is not used again,
autorepeat always runs as if not given a count.
(That means the PPC variable is used as the effective count.
Refer to \k{varcounts}.)

\dt T

\dd Repeats a step running the debuggee.
An equals address given to the prior Trace command is not used again.
A count given to the prior Trace command is not used again,
autorepeat always runs as if not given a count.
(That means the TTC variable is used as the effective count.
Refer to \k{varcounts}.)

\dt TP

\dd Repeats a step running the debuggee.
An equals address given to the prior Trace/Proceed command is not used again.
A count given to the prior Trace/Proceed command is not used again,
autorepeat always runs as if not given a count.
(That means the TPC variable is used as the effective count.
Refer to \k{varcounts}.)

\dt U

\dd Repeats disassembly behind the last prior disassembled instruction.
As for if the command is executed with an address lacking a length,
the default length is used. (It defaults to 32 bytes, refer to \k{varlengths}.)


\H{cmdquestionmark} ? command

\c Online help    ?

The question mark command (?) lists the main online help screen.


\S{cmdhelptopics}

There are additional help topics that can be listed by using
the question mark command with an additional letter or keyword.
These keywords are as follows:

\c Registers      ?R
\c Flags          ?F
\c Conditionals   ?C
\c Expressions    ?E
\c Variables      ?V
\c R Extended     ?RE
\c Run keywords   ?RUN
\c Options pages  ?OPTIONS
\c Options        ?O
\c Boot loading   ?BOOT
\c lDebug build   ?BUILD
\c lDebug build   ?B
\c lDebug sources ?SOURCE
\c lDebug license ?L

The full help pages are listed in \k{helptopics}.


\H{cmdcolon} : prefix - GOTO label

A leading colon indicates a destination label for GOTO, see \k{cmdgoto}.


\H{cmdimmasm} . (dot) command - Immediate assembler

A dot command can be used to invoke the immediate assembler.
This is only available if the _IMMASM build option was enabled.
Following the dot, an instruction is parsed which is assembled.
If successful, then the assembled instruction is immediately run.

Branches and instructions involving CS as a prefix or operand
are handled specifically to do something equivalent to
the assembled instruction, by a combination of
special detection and modification or as-if handling.
This includes jmp far/near/short, jcc, loop, call far/near,
retf/retn/iret, mov to ds, mov from ds or cs, push cs,
push ds, pop ds, lds, and all memory operands with cs prefix.
(The instructions involving ds are handled specifically
because a cs prefix is replaced by a ds prefix and
ds is temporarily replaced by the cs value then.)

Interrupt calls are always proceeded past, even if TM is set.
The int instruction is run from a buffer internal to the debugger.
Interrrupts which depend on the CS or (E)IP they're called from
may not work as expected.
Calls are usually traced, but can be proceeded past by including
a comma after the dot command.

Warning: It is generally not safe to modify SS or SP
to relocate the stack with the immediate assembler.
This will fail because the immediate assembler traces
most of the instructions assembled with it, which uses
the stack both before and after running the instruction.
LSS SP or LSS ESP are okay if the stack
is valid immediately after the instruction is traced.
To relocate the stack otherwise you may
use the R command to modify the SS and (E)SP debugger variables.
This does not trace anything in between modifying the two variables.


\H{cmda} A command - Assemble

\c assemble        A [address]

Starts assembly at the indicated address (which defaults to CS segment),
or if no address is specified, at the "a_addr" (AAS:AAO variables).

Assembly mode has its own prompt.
Entering a single dot (\cw{.}) or an empty line terminates assembly mode.
Comments can be given with a prefixed semicolon.
In assembly mode, whereever an immediate number occurs
an expression can be given surrounded by parentheses \cw{(} and \cw{)}.
In such expressions, register names like AX are evaluated
to the values held by the registers at assembly time.
To refer to a register as an assembly operand, it must occur
outside parentheses.


\H{cmdattach} ATTACH command - Attach to process (Leave TSR mode)

\c attach process  ATTACH psp

While in resident mode, the ATTACH command can be used
to attach the debugger to a process.
This is the opposite operation to the TSR command (see \k{cmdtsr}).
The device driver mode starts out as detached
while the application mode starts out as attached.

The provided parameter must be a segment value,
even if lDebugX is in Protected Mode.
It refers to the PSP to attach to.
This PSP must not be self-owned.

To attach to a process, the debugger stores away
the current PRA and parent of the process,
and modifies both to point to the debugger instead.

When attached to a process, commands like QA and the
process-loading L command can be used sensibly.
The Q command will also try to terminate the attached process.

When detached, the Q command will continue to run
the current debuggee context after the debugger
has been uninstalled.

The usual parameter to the attach command consists
of the \cq{PSP} variable, which will have the command
try to attach to the current debuggee process.
Other choices like \cw{ATTACH PARENT} are also valid.


\H{cmdb} B commands - Permanent breakpoints

There are a fixed number of permanent breakpoints provided by the debugger.
The default is to provide 16 permanent breakpoints.
They are specified by indices ranging from 00 to 0F.
A breakpoint can be unused, used while enabled, or used while disabled.
A breakpoint that is in use has a specific linear address.
It is allowed, though not advised,
for several breakpoints to be set to the same address.

When running the debuggee with the commands G, T, TP, or P,
hitting a permanent breakpoint stops execution,
and indicates in a message "Hit permanent breakpoint XX"
where XX is replaced by the hexadecimal byte index of the breakpoint.
If the breakpoint counter is not equal to 8000h when the breakpoint is hit,
then the "Hit" message is followed by a "counter=YYYY" indicator.
If the breakpoint ID is not empty, then
the ID is shown with an "ID: " prefix.
The ID is shown either on the same line as the "Hit" message,
or on the next line if the ID exceeds 28 bytes.
After that message a register dump occurs,
same as for default breaking for the Run commands.


The exceptions are as follows:

\b If the CS:(E)IP at the first step of a G command matches any breakpoints,
then G does a TP-like step with all breakpoints other than
the "cseip"-breakpoint written,
while the "cseip"-breakpoint is not written.
After that, the "cseip"-breakpoint is written
and execution resumes as normal for G.

\b If T.NB or TP.NB or P.NB is used,
no permanent breakpoints are written at all.

\b If T.SB or TP.SB or P.SB is used,
then during the first step no permanent breakpoints are written.
If a counter higher than 1 is given, then during subsequent steps
permanent breakpoints are written.


Each breakpoint has a breakpoint counter,
which defaults to 8000h if not set explicitly by the BP or BN commands.
The breakpoint counter behaves as follows:

\b If (counter & 3FFFh) equals zero then the counter
is considered to be at a terminal state.

\b If the point breaks while the counter is not at a terminal state,
then the counter is decremented.

\b If the counter is decremented to 0 or 4000h, then the point is hit.

\b If the counter is decremented to 8000h or C000h,
or was already at either count without being decremented,
then the point is hit.

\b If the point is not hit but the bit (counter & 4000h) is set,
then the point is passed.


Example counter values:

\dt 8000h (default)

\dd Always break

\dt 4000h

\dd Always pass

\dt 8003h

\dd Break on third time the breakpoint is reached, then break always

\dt 0003h

\dd Break on third time the breakpoint is reached, but do not break again

\dt C006h

\dd Pass for five times, then on the sixth time the breakpoint is reached
break on it, then break always


The point being passed means that during running the debuggee
with a Run command, execution is not stopped, but a message indicating
"Passed permanent breakpoint XX, counter=YYYY" is displayed.
As for the "Hit" message the ID, if any, is also shown.
After that message, a register dump occurs.
Then execution is continued in accordance with
the command that is running debuggee code.

Each breakpoint can have a breakpoint condition.
If the condition expression evaluates to false when
the point breaks, then the point is not considered hit or passed.
The breakpoint counter is not stepped then either.


\S{cmdbp} BP command - Set breakpoint

\c set breakpoint  BP index|AT|NEW address
\c                   [[NUMBER=]number] [WHEN=cond] [ID=id]

BP initialises the breakpoint with the given index.
It must be a yet unused breakpoint.
If the index is specified as the keyword NEW,
the lowest unused breakpoint (if any) is selected.
If there is the keyword AT instead of an index or a keyword NEW,
then an existing breakpoint at the same linear address, if any, is reset
(unlike the NEW keyword),
or a new one is added (same as if given the NEW keyword).

The address can be given in a segmented format,
which defaults to CS, and which in DebugX
is subject to either PM or 86M segmentation semantics
depending on which mode the debugger is in.
The address can also be given with an @ specifier
(followed by an opening parenthesis or whitespace)
in which case it is specified as the 32-bit linear address.
Debug without DPMI support limits breakpoints to 24-bit addresses,
of which 21 bits are usable.

The optional number, which defaults to 8000h,
sets the breakpoint counter to that number.

The optional WHEN keyword introduces a breakpoint condition.
If the breakpoint is reached then the condition, if specified,
is checked before stepping the counters.
If the condition is false at that point the point is not
considered hit or passed and its counter is not stepped.

There is an optional OFFSET keyword (not shown in the example)
which allows overriding the breakpoint's preferred offset.
Refer to \k{cmdbo} for details.

The optional ID keyword allows setting the breakpoint ID.
The ID is displayed by BL and when a breakpoint is hit or passed.
The default ID is an empty ID.
Note that the ID extends for the remainder of the line.
There cannot be a breakpoint counter number
nor WHEN condition nor OFFSET after the ID keyword.


\S{cmdbi} BI command - Set breakpoint ID

\c  set ID         BI index|AT address [ID=]id

BI sets the breakpoint ID of the specified breakpoint.
The ID is displayed by BL and when a breakpoint is hit or passed.
The ID may be specified as empty.


\S{cmdbw} BW command - Set breakpoint condition

\c  set condition  BW index|AT address [WHEN=]cond

The BW command sets the breakpoint condition.
If the WHEN keyword and the condition are absent
then the condition is reset.
That means the point is no longer conditional.


\S{cmdbo} BO command - Set breakpoint preferred offset

\c  set offset     BO index|AT address [OFFSET=]number

The BO command sets the breakpoint preferred offset.
The preferred offset is used only by the BL command.
It is used to determine the segmented address to display.
The offset is a word variable for Debug and a dword variable for DebugX.
If the OFFSET keyword and the number are absent
then the offset is disabled,
as if the breakpoint was specified with a linear address.
(Internally this is done by setting the offset to all 1 bits.
The offset can be explicitly set to FFFFh (Debug) or FFFF_FFFFh (DebugX)
for the same effect.)


\S{cmdbn} BN command - Set breakpoint number

\c  set number     BN index|AT address|ALL number

BN sets the breakpoint counter of
the specified breakpoint with the given index,
or all used breakpoints when given the keyword ALL,
or the first breakpoint with a matching linear address
when given the AT keyword.
The number defaults to 8000h.


\S{cmdbc} BC command - Clear breakpoint

\c  clear          BC index|AT address|ALL

BC clears the specified breakpoint with the given index,
or all breakpoints when given the keyword ALL,
or the first breakpoint with a matching linear address
when given the AT keyword.
This returns the specified breakpoint (or all of them) to the unused state.
Any associated ID or condition is deleted by BC too.


\S{cmdbd} BD command - Disable breakpoint

\c  disable        BD index|AT address|ALL

Given an index or the keyword ALL or the keyword AT (like BC),
BD disables breakpoints that are in use.
A disabled breakpoint's address is retained and BP
will not allow initialising it anew (except with AT),
but it is otherwise skipped in breakpoint handling.


\S{cmdbe} BE command - Enable breakpoint

\c  enable         BE index|AT address|ALL

Like BD, but enables breakpoints.


\S{cmdbt} BT command - Toggle breakpoint

\c  toggle         BT index|AT address|ALL

Like BE and BD, but toggles breakpoints:
A disabled breakpoint is enabled, while an enabled breakpoint is disabled.


\S{cmdbs} BS command - Swap breakpoint

\c  swap           BS index1 index2

This command is provided to allow re-ordering existing breakpoints.
It takes two indices both of which must refer to valid breakpoints.
However, it is allowed to specify the index of an unused breakpoint
for either of the parameters (or even both).
All data associated with the two breakpoints is swapped.


\S{cmdbl} BL command - List breakpoints

\c  list           BL [index|AT address|ALL]

BL lists a specific breakpoint given by its index,
or all used breakpoints if given the keyword ALL
or given neither an index nor the keyword.
When given the AT keyword,
all breakpoints with a matching linear address are listed.
(This differs from all other B commands,
which only select the first matching breakpoint when the AT keyword is given.)

When listing all breakpoints
only used breakpoints are displayed.

The output format for unused breakpoints is as follows:

\b "BP"

\b The byte index given as two hexadecimal digits

\b "Unused"


The output format for used breakpoints is as follows:

\b "BP"

\b The byte index given as two hexadecimal digits

\b A plus sign if the breakpoint is enabled, a minus sign if it is disabled.

\b "Lin=" followed by the linear address of this breakpoint.

\b The segmented address of this breakpoint.
Only displayed if the breakpoint was initially
specified with a segmented address, or
it had a preferred offset specified with the BP OFFSET= keyword
or to the BO command.

\b The breakpoint content byte given in parentheses (generally "CC").

\b "Counter=" followed by the breakpoint counter.

\b "ID: " followed by the breakpoint ID, if any.
Depending on the length the ID is shown on the first line
or on a second line.

\b "WHEN " followed by the breakpoint condition, if any.
This is always written to a line on its own.

Example output of BL:

\c -bp at 100 id = start
\c -bp at 103 counter = 4000
\c -bp at 105 when al == 7
\c -bl
\c BP 00 + Lin=01_BB70  1BA7:0100 (CC) Counter=8000, ID: start
\c BP 01 + Lin=01_BB73  1BA7:0103 (CC) Counter=4000
\c BP 02 + Lin=01_BB75  1BA7:0105 (CC) Counter=8000
\c  WHEN al == 7
\c -


\H{cmdbu} BU command - Break Upwards

\c break upwards   BU

This command, which is only supported by Debuggable builds (DDebug)
or Conditionally Debuggable builds (CDebug),
causes the debugger to execute an int3 instruction in its own code segment
(lDEBUG_CODE).
This breaks to the next debugger that was installed prior to DDebug or CDebug.
Prior to the breakpoint, the message "Breaking to next instance." is displayed.
The breakpoint is in the \cw{cmd4} dispatcher.
When the next instance is another lDebug then
running the command \cq{G ip} in it can be used to run
the debuggable debugger until the next command is dispatched.
(This does not work if an Extension for lDebug command handler
processes a command instead of passing it on to the debugger.)

In non-debuggable lDebug builds, the following error message
is displayed instead:

\c -bu
\c Already in topmost instance. (This is no debugging build of lDebug.)
\c -

In conditionally debuggable builds, the following message is displayed instead
if CDebug is currently not in debuggable mode:

\c -bu
\c Debuggable mode is disabled.
\c Enable with this command: r DCO6 or= 0100
\c -


\H{cmdboot} BOOT commands - Boot loading support

The BOOT commands are only available if the debugger
is running in boot loaded mode.

\S{cmdbootprotocol} BOOT PROTOCOL= command

\c BOOT PROTOCOL=proto [parameters] [partition] [pathnames [cmdline]]

This command is used to load a boot sector or kernel
using the loaders implemented by the debugger.
These loaders attempt to be highly compatible to the original loaders
whose load protocols they simulate.

\S2{cmdbootprotocolprotocol} Specify protocol

Using the keyword \cw{PROTOCOL}, the load protocol to use as a base
can be specified.
This keyword is required, unless the special protocol named \cw{SECTOR}
is to be used.

\S2{cmdbootprotocolaltering} Altering protocol parameters

When specifying a protocol other than the special \cw{SECTOR} protocol,
the protocol parameters can be altered.
Each protocol will set up defaults for all of those parameters.
Each protocol can be completely described by a combination of parameters
and default filenames.
Every parameter is indicated by a keyword
followed by a numeric expression,
or in some cases followed by a segmented address.

The following parameters are available:

\dt MINPARA

\dd Specify minimum amount of paragraphs to load from the first file.
It is an error if a file is shorter than that.

\dt MAXPARA

\dd Specify maximum amount of paragraphs to load from the first file.
It is valid for the file to be shorter or longer than this.
If nonzero then it is an error if the file is so long that
there is not enough memory to hold this amount of paragraphs.
If zero, then as much of the file is loaded as fits.

\dt SEGMENT

\dd Specify load address of the data from the first file.
The number specified is taken to be the segment of an address within memory.

\dt ENTRY

\dd Specify entrypoint to set up in the CS:IP registers.
If a single numeric expression, it is taken as the offset (for IP)
and the segment value is assumed as zero.
That is, CS will be set up to equal the SEGMENT parameter in use.
If a segmented address, the offset is used for IP
and the segment is used as a relative adjustment to the SEGMENT that is in use
to obtain the value for CS.
It is valid for the segment value to be positive or negative.

\dt BPB

\dd Specify where to load the boot sector with (E)BPB.
If a single numeric expression, it is taken as the offset
in segment zero.
If the segment is specified as 0FFFFh or -1,
then the "auto-BPB" feature is used and the boot sector and stack is
located at a high address that is not otherwise used.
The offset is still set to the offset part in this case.

\dt CHECKOFFSET

\dd Specify offset of word value to check.
Must not possibly cross a sector boundary.
(This is checked by testing that the offset modulo 32 is not equal to 31.)
May not be higher than 0FFFEh.

\dt CHECKVALUE

\dd Specify value of word to check.
If zero, no check occurs.
It is an error if this value is nonzero and the check does not match.


The following boolean parameters are available.
Like the other parameters they read a numeric expression,
but this is only checked to be true (non-zero) or false (zero).

\dt SET_DL_UNIT

\dd If true, set up the DL register with the load unit.
This is used by several protocols.

\dt SET_BL_UNIT

\dd If true, set up the BL register with the load unit.
This is used by the FreeDOS and EDR-DOS protocols.

\dt SET_SIDI_CLUSTER

\dd If true, initialise the DI (FAT12/FAT16) or SI:DI (FAT32) registers
to hold the number of the first cluster of the first file.
This is used by the MS-DOS v7 protocol.

\dt SET_DSSI_DPT

\dd If true, initialise DS:SI registers to point to the DPT.
(Set equal to the interrupt 1Eh vector.)
This may be used by the MS-DOS v6 and IBMDOS protocols.

\dt PUSH_DPT

\dd If true, initialise stack to hold a segmented (16:16) pointer
to the interrupt 1Eh vector (always 0:78h)
and then the DPT address (equal to the interrupt 1Eh vector).
This may be used by the MS-DOS v6 and IBMDOS protocols,
and is used by the MS-DOS v7 protocol.

\dt DATASTART_HIDDEN

\dd If true, modify the data start variable at \cw{dword [ss:bp - 4]}
to include the number of hidden sectors.
(The hidden sectors are the partition's start offset in its unit.)
This is used by the MS-DOS (v6/v7) and IBMDOS protocols.

\dt SET_AXBX_DATASTART

\dd If true, set the AX:BX register pair to the data start variable.
If DATASTART_HIDDEN is also set, the registers will receive the value
of the data start variable that includes the hidden sectors.
This is used by the MS-DOS v6 and IBMDOS protocols.

\dt SET_DSBP_BPB

\dd If true, set up the DS register to equal SS.
This makes DS:BP point to the boot sector with the (E)BPB.
This is used by the EDR-DOS protocol.

\dt LBA_SET_TYPE

\dd If true, change the third byte of the boot sector
to indicate the use of LBA access functions
in the manner expected by the MS-DOS v7 load protocol.
That means a 90h (nop instruction) is written if to use CHS access,
a 0Eh is written if the FAT type is not FAT32 and to use LBA access,
and a 0Ch is written if the FAT type is FAT32 and to use LBA access.

\dt MESSAGE_TABLE

\dd If true, include the message table used by the MS-DOS v7 load protocol.

\dt SET_AXBX_ROOT_HIDDEN

\dd If true, pass the sector number of the root directory start
including hidden sectors in the AX:BX register pair.
This is used by the RxDOS.0 and RxDOS.1 protocols.

\dt NO_BPB

\dd If true, do not load the boot sector with BPB.
This is used by the CHAIN protocol.

\dt SET_DSSI_PARTINFO

\dd If true, load sector with partition table to address 00600h
and point DS:SI and DS:BP to the active partition table entry
within the partition table.
This is used by the CHAIN protocol.

\dt CMDLINE

\dd If true, allow a command line to be specified after the filenames.
This is used by the RxDOS.2, RxDOS.3, and lDOS protocols.
As an extension it may be enabled for the EDR-DOS or FreeDOS protocols, too.


\S2{cmdbootprotocolpartition} Specifying protocol partition

After the parameters, the debugger will try to parse a partition specification.
Partition specifications are capitalisation-insensitive.
A partition may be specified in the following ways:

\dt FDA

\dd Diskette-style (unpartitioned) file system on unit 00h

\dt FDB

\dd Diskette-style (unpartitioned) file system on unit 01h

\dt HDA1

\dd MBR-style (partitioned) file system on unit 80h, first primary partition

\dt HDA2

\dd MBR-style (partitioned) file system on unit 80h, second primary partition

\dt HDA5

\dd MBR-style (partitioned) file system on unit 80h, first logical partition

\dt HDA6

\dd MBR-style (partitioned) file system on unit 80h, second logical partition

\dt HDA(partnumber)

\dd MBR-style (partitioned) file system on unit 80h,
with partition specified by partnumber.

\dt HDB1

\dd MBR-style (partitioned) file system on unit 81h, first primary partition

\dt LDP

\dd File system that the debugger loaded from

\dt YDP

\dd File system that the most recent Y command loaded from

\dt SDP

\dd Last used file system

\dt U00.

\dd Diskette-style (unpartitioned) file system on unit 00h

\dt U80.1

\dd MBR-style (partitioned) file system on unit 80h, first primary partition

\dt U(unitnumber).(partnumber)

\dd Unit specified by unitnumber with partition specified by partnumber.
The specified partnumber may be specified as an expression in parentheses
or as a literal number without parentheses.
If it is an expression equal to zero in parentheses
then that means unpartitioned.

\dt LD(partnumber)

\dd Unit that the debugger loaded from,
with partition specified by partnumber.

\dt YD(partnumber)

\dd Unit that the most recent Y command loaded from,
with partition specified by partnumber.

\dt SD(partnumber)

\dd Last used unit,
with partition specified by partnumber.


If no partition can be parsed, SDP is assumed.
Note that partition numbers are parsed as decimal numbers,
except if the partition number is specified as an expression with parentheses,
in which case the default expression base is used (hexadecimal).


\S2{cmdbootprotocolnames} Specifying protocol filenames

One or two pathnames may be specified to load,
after the parameters or the partition specification.
Both will have a default specified by the protocol.
The default for the second name may be empty.
If the second name is empty, no additional file is searched for.
If two names are specified, they must be separated by one or more blanks.

Each pathname may include subdirectory names,
indicated by trailing slashes.
If a pathname ends in a slash,
the default filename is searched in the directory indicated by the pathname.
The second pathname may be specified as two slashes to indicate no second file.
If the second name defaults to empty,
a lone dot may be used to indicate no second file.
If the second name defaults to not empty,
a lone dot may be used to indicate searching the default name
in the same directory as the first file.
If either pathname is specified as only one slash,
then the corresponding default name is searched for in the root directory.

If the second name is not specified at all,
or is specified as a lone dot,
the default additional filename is searched for in the same directory
as the first file.
If the second name is specified but does not start with a slash,
then it is assumed to be a pathname relative to the directory
of the first file.
Otherwise, if the second name is specified and starts with a slash,
the second name is searched
in the directory of the specified pathname
which is interpreted as being relative to the root directory.

The 32-byte directory entry of the first file is loaded to 00500h.
The 32-byte directory entry of the second file is loaded to 00520h.
These entries are used by the MS-DOS v6 and IBMDOS protocols.
If no second file is searched for, the 32 bytes at 00520h
are filled with zeroes.

The blank-padded FCB filenames of the two files
are stored within the pseudo boot sector with (E)BPB
that the loader sets up for the kernel.
This supports kernels scanning the boot sector for informational filenames.


\S2{cmdbootprotocolcmdline} Specifying protocol command line

If the CMDLINE boolean parameter is enabled,
then after the two pathnames specifying filenames
a command line is parsed.
The command line should be separated from the second filename specification
with one or more blanks.
This command line is passed to the loaded kernel
as specified for the lDOS load protocol.
(The FreeDOS kernel was extended to also use a command line passed this way.)

If the CMDLINE parameter is enabled but no command line content is specified,
then an empty command line is passed.
Note that this differs from passing no command line.
To pass no command line, the CMDLINE parameter must be disabled.

As a special case, semicolons are allowed within the specified command line
and do not indicate comments.


\S2{cmdbootprotocolcompat} Boot load protocol compatibilities

The following notes are from lDOS boot.asm,
in a comment titled \q{Notes about partial load compatibilities}:

\S3{ldosbootcompatfd} FreeDOS

\b Relocates to an address other than 27A00h (1FE0h:7C00h)

This is true of the lDebug BOOT command as well. However,
the original FreeDOS loader relocation can be emulated by
specifying a \cw{BPB=1FE0:7C00} parameter.

\b A lot of options between _USE_PART_INFO, _QUERY_GEOMETRY, _CHS, _LBA,
   and/or _RPL need to be disabled to make the loader fit

This is not a problem to the lDebug BOOT command.


\S3{ldosbootcompatdr} DR-DOS

\b Must enable _MEMORY_CONTINUE to load off file systems with cluster
   sizes > 1 KiB (depending on file size) or >= 32 KiB (certainly)

\b Will not load whole file if _MEMORY_CONTINUE is enabled and file
   data exceeds 29 KiB, without erroring out. The new option called
   _LOAD_CHECK_MAX_SIZE has been added to address this. However, it
   won't fit without disabling some other options such as _LBA, _CHS,
   _USE_PART_INFO, or _QUERY_GEOMETRY.

This is not a problem to the lDebug BOOT command.
The full 29 KiB can be loaded regardless of cluster size,
given a sector size of 1 KiB or below.

\b Disables DPT, data start, and directory entry to 00500h options by
   default so loading a faithful IBMDOS v4+ kernel will fail as msload
   or lDOS iniload need these options to operate

This is not a problem to the lDebug BOOT command.
In fact the DRDOS protocol in lDebug exactly matches the IBMDOS protocol
except that it defaults to a \cw{MAXPARA=-1} parameter.
Therefore a small enough IBMBIO.COM file can be loaded
with the DRDOS protocol even if it expects any of the bits and bobs
provided by the IBMDOS protocol.


\S3{ldosbootcompatibmms6} IBMDOS and MS-DOS 6

\b Does not actually relocate DPT, just provide its address

Applicable to lDebug as well. The table can be relocated
and modified by the user however, if need be.
This should be done after running a BOOT PROTOCOL command
so as to pass the original DPT address to the kernel.

\b A lot of options between _USE_PART_INFO, _QUERY_GEOMETRY, _CHS,
   and/or _LBA need to be disabled to make the loader fit

This is not a problem to the lDebug BOOT command.


\S3{ldosbootcompatms7} MS-DOS 7

\b Does not actually relocate DPT, just provide its address

Applicable to lDebug as well. The table can be relocated
and modified by the user however, if need be.
This should be done after running a BOOT PROTOCOL command
so as to pass the original DPT address to the kernel.

\b Does not contain message table used by loader

The message table is provided by the lDebug BOOT command
if enabled using the MESSAGE_TABLE parameter.
This is default enabled for the MSDOS7 protocol.


\S2{cmdbootprotocolcompatadd} Boot load protocol compatibilities additions

\S3{bootcompataddfd} FreeDOS

The original FreeDOS loaders may misbehave trying to load a file
that is larger than 128 KiB,
when rounded up to a full cluster boundary.
The lDebug loader is impacted by this problem less.


\S3{bootcompatadddr} DR-DOS

The DR-DOS and the original Enhanced DR-DOS load
(prior to lDOS single-file EDR-DOS load in 2024)
are similar.
They depend on the BIO file to be fully loaded.
The BIO file is limited to 29 KiB for DR-DOS load.
(For original EDR-DOS load the BIO file has limits
similar to the kernel file for FreeDOS load.)

These loads do not use any directory entries
nor file start clusters passed anywhere.
Consequently, they have to scan the root directory
for their DOS files, named \cw{IBMDOS.COM}
or \cw{DRDOS.SYS}.
That means these files and their filenames
cannot be overridden by the debugger.

DR-DOS load presumably uses only the load unit
passed in the DL register to find the file system
that it wants to load its DOS file off.
Original EDR-DOS load also used the hidden sectors
in the BPB pointed to by DS:BP to identify the correct file system.


\S3{bootcompataddibmms6} IBMDOS and MS-DOS 6

Although the initial loader originally introduced for MS-DOS v4.00
is called the "Non-Contiguous IBMBIO Loader (MSLOAD)"
it does still depend on the first cluster of the BIO file
being cluster 2, the first data cluster of the file system.
This was fixed as of MS-DOS v5.00 however.

Original loaders expect the BIO file as the first entry
in the root directory
and the DOS file as the second entry.
They also arrange for these entries to be loaded to
linear 00500h and 00520h.
The debugger will allow any file in the file system
to be used and will load the directory entries
to the expected locations,
which may enable booting differently named
or located files.

There is a problem with the DOS file loader:
It may select a drive to load from using only
the load unit, but read the start cluster
from the DOS file directory entry
and use the data start sector passed from the prior loader.


\S{cmdbootlist} BOOT LIST command

\c BOOT LIST [unit|partition]

This command is used to list partitions on an MBR-style partitioned unit.


\S{cmdbootdir} BOOT DIR command

\c BOOT DIR [partition] [pathname]

This command is used to list files within a directory
of a FAT12, FAT16, or FAT32 file system.
A partition specification may be included.
A pathname may be included;
if it refers to a directory then the contents are listed,
otherwise the specified file is listed.



\S{cmdbootreadwrite} BOOT READ and BOOT WRITE commands

\c BOOT READ|WRITE [unit|partition] segment [[HIDDEN=sector] sector [count]]

These commands are used to read or write sectors from disks.
After the command keyword, a partition specification may be listed.
Then, a segment must follow. This specifies the buffer to use.

After the segment, an optional HIDDEN= keyword can be specified
to specify a 32-bit sector number base.
This is useful to implement 33-bit LBA access,
but note it will overwrite the partition offset if a partition is specified.
Instead of the HIDDEN= keyword, a HIDDENADD= keyword can be specified.
It also reads a 32-bit sector number base.
However, as opposed to HIDDEN=, HIDDENADD= will add to the hidden value of
a specified partition, instead of replacing it.
If a whole unit without a partition is specified then
HIDDEN= and HIDDENADD= will result in the same offset being used.

After the segment and optional hidden keywords,
a 32-bit sector number may be specified. It defaults to zero.
After the sector number, a 16-bit count may be specified. It defaults to one.

Note that sectors are read or written one sector at a time.
If the interrupt 13h function used returns an error 9 (boundary error),
the debugger will attempt to use its auxiliary buffer
to carry out the read or write, copying data as appropriate.
The auxiliary buffer is aligned so as not to cross a 64 KiB boundary in memory.
(Error 9 is usually returned if trying to access too many sectors at once
or when diskette ISA DMA would cross a 64 KiB boundary.)


\S{cmdbootquit} BOOT QUIT command

\c BOOT QUIT

This attempts to shut down the machine.
A dosemu-specific callout will be attempted first,
if dosemu is detected.
Using APM will be attempted next, which works on qemu.
If neither works, the debugger gives up.


\H{cmdc} C command - Compare memory

\c compare         C range address

Given a range, the address of which defaults to DS,
and another address that also defaults to DS,
this command compares strings of bytes,
and lists the bytes that differ.


\H{cmdcount} COUNT command - Count list length

\c count length    COUNT [RANGE range|list]

This command parses a range or list parameter.
The resulting pattern's length is displayed in hexadecimal and decimal.
The \cw{COUNT} variable is also set to the length count number.
If a range is given then the length has to fit into the segment.


\H{cmdd} D command - Dump memory

\c dump            D [range]
\c dump bytes      DB [range]
\c dump words      DW [range]
\c dump dwords     DD [range]

Given a range, the address of which defaults to DS,
this command dumps memory in hexadecimal and as ASCII characters.
The range may be specified with a lines length
(refer to \k{parrangelines}).
The default length if none is specified defaults to the number of lines
specified in the variable \cw{DEFAULTDLINES} if it is nonzero,
or else the number of bytes specified in the variable \cw{DEFAULTDLEN}.

If a lines length is used, that many lines are dumped.
The count of lines does not include the header or trailer
if they're used.
The count of lines will be inaccurate if the symbolic build is used
and the dump lists symbols that point into the dumped data.
(The amount of data in this case will match what it should be
to produce the requested count of lines if no symbols were listed.)
The count of lines will be accurate if either
the 40-column friendly mode is enabled or not.
If enabled, roughly half as much data is dumped
for a given amount of lines, as the 40-column mode
dumps up to 8 bytes per line as opposed to the 80-column mode
which dumps up to 16 bytes per line.

If the DCO option 4 is set, text with the high bit set
(80h to FFh, the top half of the 8-bit encoding space)
is displayed as-is in the text dump.
If a \cw{TOP} keyword is used before the range,
then top half text is displayed as-is as well.
Otherwise, it will be treated like nonprintable text,
which means it is replaced by dots in the text dump.

The variable \cw{DDTEXTAND} is used as a mask to modify
the text code before display. It defaults to 0FFh.
Setting this to 7Fh will mimic MS-DOS Debug's display
of text in its data dump, masking off the high bit.
In this case the \cw{TOP} setting has no effect.

If no range is specified, the D command continues dumping at "d_addr"
(ADS:ADO),
which is updated by each D command to point after the last shown byte.
The default length is determined in the same way as for
if a range without a length is specified.
If autorepeat is used it behaves the same way as a D command
without a range.

The default is for D to dump bytes.
After a DW or DD command,
the autorepeat and plain D (without a range) default to the last-used size.
If the default range should be used but the size should be reset to bytes,
the DB command can be used.
The D command with a range always acts the same as DB.


\H{cmddi} DI command - Dump Interrupts

\c dump interrupts DI[R][M][L] interrupt [count]

The DI command dumps interrupt vectors from the IVT (86M) or IDT (PM).
In PM, for the vectors 00h to 1Fh, the exception handlers are also dumped.
In 86 Mode, an interrupt chain is displayed
if more than one entrypoint is reachable from the topmost handler.
To make the next handler reachable, a handler
must match one of several header / entry formats:

\b IBM Interrupt Sharing Protocol (IISP) header (fully standard,
with 10EBh entrypoint and EBh jump to hardware reset
- this matches what Ralf Brown's AMIS programs recognise)

\b Non-standard IISP header

\b iHPFS-style uninstalled IISP header (EA90h entrypoint)

\b FreeDOS kernel relocation (near call followed by far jump immediate)

\b Just a far jump immediate


If the R is specified (directly after DI)
then 86 Mode handlers are dumped even if in PM.

If the M is specified
then MCB names are displayed.

If the L is specified
then AMIS interrupt lists are queried for
the interrupt number being dumped.
This is so that the involved multiplex numbers
and interrupt list indices can be displayed,
and also so that hidden chains can be dumped.
This means chains that are not reachable
from the topmost IVT handler, but are found through
the AMIS "Determine Chained Interrupts" call
(either 03h pointer or 04h list return).
The list index is displayed as FFFFh if
the handler was found with 03h pointer return.
Otherwise it indicates how many list entries
precede the found handler's entry.
For example, \cq{list:0000h} means that
the first list entry matched, and
\cq{list:0001h} means that the second list entry matched.

Specifying the L makes the debugger use
its auxiliary buffer.
That means the DIL command cannot be used
from the RE buffer if
the T/TP/P silent buffer is used,
or if RH mode is enabled.
In addition, note that with the default
buffer size, no more than about a 1000
handlers can be handled.
(The actual limit may be as low as 500 handlers
if a lot of hidden chains occur.)
If the limit is exceeded then the DIL command
will display an error.
The same error can also occur if the chain
loops, or references a single handler from
more than one other handler, or
a single handler is listed
by more than one multiplexer.


\H{cmddm} DM command - Dump MCBs

\c dump MCB chain  DM [segment]

The DM command dumps an MCB chain.
If not given a start MCB segment,
and the debugger is running as an 86-DOS application or device driver,
the start of DOS's MCB chain is used.
If given a start MCB segment, this is used as the starting MCB.
(Note: In current RxDOS builds, the start MCB is always at segment 60h.)

The DM command initially lists the debuggee's PSP.
This is only valid when the debugger is running as an 86-DOS application
or device driver.

The MCB chain dump is continued until an MCB is encountered that
has neither an M nor a Z signature letter,
or the MCB address wraps around the 1 MiB boundary.
In particular, this means that a disabled UMB link MCB
(usually pointing to the MCB at segment 9FFFh
if there is no EBDA nor any pre-boot-loaded programs)
will not end the dump.

There is an Extension for lDebug (ELD)
that also implements the DM command, known as dm.eld.
It adds some additional features.
Refer to \k{eld-dm}.


Example output:

\c -dm
\c PSP: 2ACA
\c 02B4 4D 0008 0018     384 B SD
\c 02CD 4D 0000 0013     304 B
\c 02E1 4D 02E2 00A8   2.6 KiB COMMAND
\c 038A 4D 038B 00A8   2.6 KiB COMMAND
\c 0433 4D 0434 2695   154 KiB LDEBUG
\c 2AC9 5A 2ACA 7535   468 KiB DEBUGGEE
\c 9FFF 4D 0008 2100   132 KiB SC
\c C100 4D 0008 0144   5.0 KiB SD
\c C245 4D 0000 0006      96 B
\c C24C 4D C24D 00A8   2.6 KiB COMMAND
\c C2F5 4D 0000 1D09   116 KiB
\c DFFF 4D 0008 1000  64.0 KiB SC
\c F000 4D F001 0019     400 B SEEKEXT
\c F01A 4D 0000 07F3  31.7 KiB
\c F80E 4D 0000 0090   2.2 KiB
\c F89F 4D 038B 001E     480 B COMMAND
\c F8BE 4D 02E2 0040    1024 B COMMAND
\c F8FF 5A C24D 0100   4.0 KiB COMMAND
\c -

The columns are as follows:

\n Segment address of MCB in hexadecimal.
Always one less than the segment of the memory block contents.

\n Signature letter in hexadecimal.
Usually 4D (\cq{M}) for linking MCB and 5A (\cq{Z}) otherwise.

\n Owner of the MCB in hexadecimal.
Values below 50h are special system values.
0 indicates an unused MCB.
8 is the usual \cw{SC}/\cw{SD}/\cw{S} system MCB owner.
Higher values are generally process segments.
A process segment is usually a memory block that is
preceded by an MCB, which is owned by that block itself.

\n Size in paragraphs of the MCB in hexadecimal.
A value of zero is valid and indicates an MCB
with an empty corresponding memory block.

\n Size in bytes or kibibytes, in decimal.
This is a number of up to 4 digits,
which may have a fractional part,
and a unit of \cw{B} (Bytes) or \cw{KiB} (Kilo binary Bytes).

\n Name of the owner of this MCB.
Free MCBs do not have a name.
System MCBs have a name that is up to two letters long.
Otherwise, the name is read from the MCB owner's own MCB.
In this case the name is up to 8 letters long.


\H{cmddstring} DZ/D$/D#/DW# commands - Dump strings

\c display strings DZ/D$/D[W]# [address]

The D string commands each dump a string at a specified address,
which defaults to DS as the segment.

\b DZ displays an ASCIZ string, terminated by a byte with the value 0.

\b D$ displays a CP/M-style string, terminated by a dollar sign character \cw{$}.

\b D# displays a Pascal-style string with a length count in the first byte.

\b DW# displays a string with a length count in the first word.


\H{cmddesc} D.A/D.D/D.B/D.L/D.T commands - Descriptor modification

These commands are only available in lDebugX (DPMI-enabled) builds.
They can only be used in Protected Mode.
RC is set to 800h when attempting to use any of these commands
while not in Protected Mode.

\c Descriptor modification commands:
\c  (only valid in Protected Mode)
\c   Allocate      D.A
\c   Deallocate    D.D selector
\c   Set base      D.B selector base
\c   Set limit     D.L selector limit
\c   Set type      D.T selector type


\S{cmddescalloc} D.A command - Allocate descriptor

\c   Allocate      D.A

Allocates an LDT descriptor from the DPMI host.
Sets the variable DARESULT to the selector if successful,
else FFFFh.
Sets RC to 801h or a DPMI error code (>= 8000h) on failure.


\S{cmddescdealloc} D.D command - Deallocate descriptor

\c   Deallocate    D.D selector

Deallocates an LDT descriptor.
Sets RC to 802h or a DPMI error code (>= 8000h) on failure.


\S{cmddescbase} D.B command - Set descriptor base

\c   Set base      D.B selector base

Sets the base of an LDT descriptor.
A useful shorthand is to use a construct like
\cq{LINEAR cs:0} to get the base of a descriptor
referenced by another selector.
Sets RC to 803h or a DPMI error code (>= 8000h) on failure.


\S{cmddesclimit} D.L command - Set descriptor limit

\c   Set limit     D.L selector limit

Sets the limit of an LDT descriptor.
Limits beyond FFFFFh must be 4 KiB aligned (low 12 bits set).
Sets RC to 804h or a DPMI error code (>= 8000h) on failure.


\S{cmddesctype} D.T command - Set descriptor type

\c   Set type      D.T selector type

Sets the type of an LDT descriptor.
00FAh is a 16-bit code segment,
4000h is the D/B bit (Default size / Big),
so 40FAh is a 32-bit code segment.
00F2h is a 16-bit data segment.
8000h is the G bit (Granularity); modifying it may change the limit.
The DESCTYPE keyword can be used in an expression
to read the current type of a descriptor, refer to \k{exprdesctype}.
Sets RC to 805h or a DPMI error code (>= 8000h) on failure.


\H{cmddt} DT command - Dump text table

\c dump text table DT [T] [number]

Without a number parameter and without the T specifier,
an ASCII table (codepoints 00h to 7Fh) is listed with short names
for unprintable ASCII but the text itself for printable ASCII.
The table lists the decimal and hexadecimal numbers.
Without a number parameter but with the T specifier,
a similar table depicting
the top half of the 8-bit codepoint space is listed
(values 80h to FFh).

With a parameter, each byte of the specified number is
displayed in decimal, hexadecimal, and the short name or
the text itself (quoted).
If the T specifier is present,
top half text (value >= 80h) is displayed quoted,
otherwise it instead displays as \cq{top}.
The command will loop starting with the least-significant byte
of the number, then continue with subsequent bytes until all
remaining bytes are equal to zero.
All up to four bytes are listed on the same line.

Note that without the T specifier,
no codepage dependent text is displayed.
The T stands for \cq{top}.


\H{cmde} E command - Enter memory

\c enter           E [address [list]]

The E command is used to enter values into memory.
If the list is specified, its contents are written
to the address specified.
Otherwise, the interactive enter mode starts at the address specified.
If no address is specified then interactive enter mode
starts at the last used address.
This is behind the last byte written by a prior E command,
or at the last byte displayed in interactive enter mode.

In the interactive enter mode, the segmented address is displayed,
and then the current byte value (2 hexadecimal digits)
found at that address yet.
Following the value a dot is displayed.
For example:

\c -e 100
\c 1FFE:0100  C3.

At this point the debugger accepts several different inputs:

\b One or two hexadecimal digits:
To enter a new value to be written at this address

\b A blank:
To write the new value (if any) and proceed to the next byte

\b A minus:
To write the new value (if any) and proceed to the prior byte

\b Carriage Return, Line Feed, or a period:
To write the new value (if any) and quit interactive enter mode

\b Backspace:
To delete the most recently entered digit of a candidate new value

\b All other inputs are ignored

After entering a blank, the debugger will either display
the next byte's current value in the same line or
start a new line with the current segmented address and
then the current byte value.
A new line is started if the current offset is divisible by 8.
For example, after entering 8 blanks:

\c -e 100
\c 1FFE:0100  C3.     CC.     CC.     CC.     CC.     CC.     CC.     CC.
\c 1FFE:0108  CC.

After entering a minus, the minus is displayed on the current line
and then (always) a new line is started to display
the new segmented address (with its offset decremented).
For example, entering a new value (\cq{A0}), then a blank,
then a minus, and then another new value (\cq{A1}), then a CR:

\c -e 100
\c 1FFE:0100  C3.A0   CC.-
\c 1FFE:0100  A0.A1
\c -


\H{cmdext} EXT command - Load and run an Extension for lDebug

\c run extension   EXT [partition/][extensionfile] [parameters]

The EXT command is used to run an Extension for lDebug (ELD) file.

This command and the infrastructure needed for it,
including two buffers of usually several dozen KiB together,
are only included when the debugger is built with
the _EXTENSIONS option enabled.
(This is now the default.)

The ELD must be in a special executable format
defined by the debugger.
The current ELD format starts with the magic bytes
\cq{ELD1} at offset zero in the file.
An ELD file typically has a filename extension
\cw{.ELD} or \cw{.XLD} though this is not required.
(If the \cw{extname.eld} is installed it will check for
either of the two known extensions, and
if none is specified
it will guess the same two extensions in order.)

To load ELDs in the application mode or device mode debugger,
the DOS file system is used.
That means DOS must be available for loading ELDs then.
To load ELDs in the boot loaded mode debugger,
the auxiliary buffer must be available
and int 13h is used to access a FAT file system.

Like the Y command (refer to \k{cmdypathnames}),
the EXT command pathname can be specified with one of the
debugger configuration path keywords.
Also, if an EXT command doesn't find a file
specified without a configuration path keyword,
the debugger will retry the file open
with the \cw{::scripts::} path prepended.

Unlike Script for lDebug files opened with the Y command,
Extensions for lDebug may be run with parameters
specified after the ELD filename.
The ELD receives the parameters as free form string data
which it is free to interpret as it wishes.
A semicolon may or may not be interpreted
as a comment indicator by an ELD.
The ELD can expect that within 256 bytes a Carriage Return occurs.

Some ELDs can install themselves as resident Extensions
to the debugger, hooking into the command dispatch
to run their own command rather than the debugger's default.
All resident ELDs provide a command hook,
at least for their respective uninstall commands.
Some resident ELDs may hook into other parts of the
debugger as well.


\S{cmdext-elds} Current ELDs

The ELDs are described in detail in \k{eld}.
The following ELDs are provided currently:

\dt LDMEM

\dd Displays information on memory use of the debugger.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{LDMEM} command,
and uninstalled with an \cw{LDMEM UNINSTALL} command.

\dt HISTORY

\dd Lists the command history of the debugger, or clears it.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{HISTORY} command,
and uninstalled with a \cw{HISTORY UNINSTALL} command.

\dt DI

\dd Re-creation of the DI and DIL commands of the debugger.
This allows to use the DI commands when the debugger
is built with the \cw{_INT=0} build option.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DI} command,
and uninstalled with a \cw{DI UNINSTALL} command.

\dt DM

\dd Re-creation of the DM command of the debugger.
This allows to use the DM command when the debugger
is built with the \cw{_MCB=0} build option.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DM} command,
and uninstalled with a \cw{DM UNINSTALL} command.

\dt RN

\dd Re-creation of the RN command of the debugger.
This allows to use the RN command when the debugger
is built with the \cw{_RN=0} build option
(as is the default now).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{RN} command,
and uninstalled with an \cw{RN UNINSTALL} command.

\dt RM

\dd Re-creation of the RM command of the debugger.
This allows to use the RM command when the debugger
is built with the \cw{_RM=0} build option
(as is the default now).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{RM} command,
and uninstalled with an \cw{RM UNINSTALL} command.

\dt X

\dd Re-creation of the X commands of the debugger.
This allows to use the X commands when the debugger
is built with the \cw{_EMS=0} build option
(as is the default now).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{X} commands,
and uninstalled with an \cw{X UNINSTALL} command.

\dt DX

\dd Re-creation of the DX command of the debugger.
This allows to use the DX command when the debugger
is built with the \cw{_DX=0} build option
(which is the default as of release 9).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DX} command,
and uninstalled with an \cw{DX UNINSTALL} command.
This ELD requires a 386+ machine.

\dt INSTNOUN

\dd Displays information on install flags of the debugger.
These are the nouns accepted by the \cw{INSTALL} and
\cw{UNINSTALL} commands.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{INSTNOUN} command,
and uninstalled with an \cw{INSTNOUN UNINSTALL} command.

\dt RECLAIM

\dd Transient utility to reclaim unused space
in the ELD code buffer and the ELD data blocks buffer.
This is no longer needed because the debugger now
includes the implementation of this tool
and automatically reclaims memory before loading an ELD.

\dt ELDCOMP

\dd A tool to compare an ELD with its XLD counterpart.
XLD is the filename extension typically used
to hold a build of an ELD with some linker optimisations.
ELDCOMP allows to compare the two,
helping to identify and locate relocation errors
in the ELD to be tested.

\dt AFORMAT

\dd Once installed, this ELD hooks into the assembler.
After a line is submitted to the assembler, the AFORMAT ELD
will dump in hexadecimal the bytes written by the assembler.

\dt AMISMSG

\dd This ELD hooks into the debugger's AMIS interface.
It provides the AMIS functions 40h and 41h to send
messages to the debugger terminal.
A message may consist of up to 383 bytes of text.
The message is displayed either on the next command
being read in the \cw{cmd3} command input loop
using a command injection handler,
or when the command \cq{AMISMSG DISPLAY} is run.

\dt AMOUNT

\dd This ELD once installed provides the \cw{ELDAMOUNT} variable.
This variable can be read to obtain the amount of installed ELDs.

\dt BASES

\dd A converter for different numeric bases.
Can accept a numeric parameter to be evaluated by the expression evaluator.
Using a \cw{BASE=} specifier or the name of a base
(\cw{HEXADECIMAL}, \cw{DECIMAL}, \cw{BINARY}, \cw{OCTAL})
the input number may be specified as a literal,
which accepts unsigned numbers of up to 64 bits.
Output is in the four known bases, formatted
to resemble the expression evaluator's literal input format.
Output can be in one arbitrary base using a trailing \cw{OUTPUT} keyword,
followed by \cw{BASE=}, \cw{GROUP=}, and \cw{WIDTH=} specifiers.
The BASES ELD can be installed residently using
an \cw{INSTALL} parameter to provide the resident \cw{BASES} command.

\dt CO

\dd Installs the \cw{COPYOUTPUT} commands.
Once a file is specified with \cq{COPYOUTPUT NAME filename}
the debugger opens the file to append to it.
While not InDOS all output to the debugger terminal
is written to the opened file.

\dt CONFIG

\dd Allows to show or set the debugger config paths.

\dt DTADISP

\dd Displays the current DOS Disk Transfer Address.

\dt IFEXT

\dd Allows to run another command conditionally,
using a command of the form \cw{IF [NOT] EXT "extension name" THEN command}.
May be used as a transient ELD or installed residently
using an \cw{INSTALL} command to provide the \cw{IF EXT} commands.

\dt KDISPLAY

\dd Displays the current K/N command buffers' content.

\dt LIST

\dd Displays the description lines for ELD files
that are specified with a single pathname pattern.
The pattern may contain wildcards in the last component.
After the pathname, several keywords may be specified:
\cw{VERBOSE} to display technical details,
\cw{HELP} to display the help,
and \cw{SFN} to force use of the DOS SFN find interface
instead of trying the DOS LFN find interface.

\dt PRINTF

\dd Allows to print formatted output.
Can be installed residently or used as a transient tool.

\dt SET

\dd Allows to access the environment block to
read or write variables.
Can install a resident \cw{SET} command using an \cw{INSTALL} parameter,
or run transiently using a \cw{RUN} parameter.

\dt USEPARAT

\dd Installs an output hook into the debugger
to display an underscore line after disassembling near or far jumps
or near, far, or interrupt return instructions.

\dt VARIABLE

\dd Installs a command preprocessor hook
to expand \cq{%VARIABLE%} specifications in commands.

\dt WITHHDR

\dd Installs a prefix command called \cw{WITH}.
This can be used as \cw{WITH HEADER} or \cw{WITH TRAILER}
to temporarily set DCO flags to enable D command headers or trailers.
Command injection is used to reset the flags afterwards.

\dt AMISCMD

\dd This ELD hooks into the debugger's AMIS interface.
It provides the AMIS function 43h
to inject commands into the debugger.

\dt AMISOTH

\dd This ELD hooks into the debugger's AMIS interface.
It provides the AMIS function 42h
to export the debugger's link info as an "other link".

\dt AMITSRS

\dd Port of Ralf Brown's AMIS TSR lister.

\dt BOOTDIR

\dd List directory entries in bootloaded mode.

\dt DBITMAP

\dd Dump 8-bit-wide graphics from memory.

\dt DOSCD

\dd Change DOS current directory or drive.

\dt DOSDIR

\dd List directory entries using DOS.

\dt DOSDRIVE

\dd Get or set a DOS drive.

\dt DOSPWD

\dd Display DOS current directory.

\dt EXTNAME

\dd Installs residently to guess EXT and Y command filename extensions.

\dt INJECT

\dd Injects commands into other debugger instance
using the other's AMIS function 43h.
(This function is provided by the AMISCMD ELD.)

\dt INSTNOTH

\dd INSTNOUN variant that operates on another debugger instance.
This requires the other instance to have installed the AMISOTH ELD
and its AMIS handler to provide the AMIS function 42h.

\dt LDMEMOTH

\dd LDMEM variant that operates on another debugger instance.
This requires the other instance to have installed the AMISOTH ELD
and its AMIS handler to provide the AMIS function 42h.

\dt LINFO

\dd Installs residently to display status of program-loading L command.

\dt PATH

\dd Provides path search and filename extension guessing
for the K and N commands.

\dt EXTLIB

\dd Library of ELDs to be used instead of single files.

\dt EXTPAK

\dd Compressed library of ELDs.

\dt QUIT

\dd Quits the machine. Can be installed residently.

\dt DOSSEEK

\dd Get or set the DOS 32-bit seek of a process handle.

\dt ALIAS

\dd Define simple aliases that are replaced in a command preprocess handler.

\dt DPB

\dd Display a DOS drive's DPB (MS-DOS v4 to v6 layout,
optionally with FreeDOS, MS-DOS v7.10, or EDR-DOS FAT32 extensions).

\dt RDumpIdx

\dd Dump text bytes pointed to by DS:SI and ES:DI in R register dump.

\dt RDumpStr

\dd Dump text pointed to by DS:DX in R register dump.

\dt CHECKSUM

\dd Calculate checksum over a memory range,
as a transient command or installed residently.

\dt HINT

\dd Display TracList listing offset hints for all installed ELDs,
writing to the terminal of another debugger instance (using its AMISMSG service).
Can be used as a transient command or installed residently.

\dt HINTOTH

\dd Display TracList listing offset hints for all installed ELDs
of the other link debugger instance (using its AMISOTH service).
Can be used as a transient command or installed residently.

\dt CHSTOOL

\dd Utilities to work with int 13h unit partitions and geometry.
Can be used as a transient command or installed residently.

\dt S

\dd Replaces the S command (\k{cmds}) with additional support
for WILD and CAPS keywords.

\dt DOSSPACE

\dd Display DOS drive total and free space

\dt DOSSTRAT

\dd Display DOS memory allocation strategy and UMB link status

\dt DHM

\dd Dump HMA Memory Control Block chain

\dt ERRFIX

\dd Fix error message display

\dt RCEXEC

\dd Add RC.EXECUTE command to fill RC buffer then immediately run it

\dt DEVICES

\dd List device driver headers and DPBs

\dt SBRANCH

\dd Search for short or near direct branches to a target


\H{cmdf} F command - Fill memory

\c fill            F range [RANGE range|list]

The F command fills memory with a byte pattern.
The first parameter is the range to fill.
The next parameter can be a list, in which case
it provides the pattern with which to fill.
If the RANGE keyword is provided then the pattern
is read from memory as indicated by
the range parameter that follows the keyword.
The pattern is repeated so as to fill the destination.
If the RANGE keyword is used, then the length of the
pattern address range is optional.
If the length is absent, it is assumed to equal that
of the destination range.


\H{cmdg} G command - Go

\c go              G [=address] [breakpts]

The G command runs the debuggee.
It can be given a start address (the segment of which defaults to CS),
prefixed by an equals sign,
in which case CS:EIP is set to that start address upon running.
Note that if there is an error parsing the command line,
CS:EIP is not changed.
Further, if a breakpoint fails to be written initially,
CS:EIP also is not changed.

The G command allows specifying breakpoints,
which are either segmented addresses
(86M or PM addresses depending on DebugX's mode)
or linear addresses prefixed by an "@ " or "@(",
similar to how the BP command allows a breakpoint specification.
G breakpoints are identified by their position in the command line,
as the 1st, 2nd, 3rd, etc.
The build option \cw{_NUM_G_BP} specifies
how many G breakpoints are supported.
By default, 16 G breakpoints are supported.

The G AGAIN command re-uses the breakpoints given
to the last (successfully parsed) G command.
It also allows an equals-sign-prefixed start address like the plain G command,
in front of the AGAIN keyword.
After the AGAIN keyword, additional breakpoints may be specified.

If the command repetition of G is used,
it is handled as if "G AGAIN" was entered,
that is it re-uses the same breakpoints as those given to the prior G command.

A G command that fails to parse will not modify the stored G breakpoint list.
If an error occurs during writing breakpoints,
the list will have been modified already however.

The G LIST command lists the breakpoints given
to the last (successfully parsed) G command.

The "content" byte in G LIST is usually CCh (the int3 instruction opcode),
but retains its original value
if a failure occurs during breakpoint byte restoration.

Example output of G LIST:

\c -g 100 103 105
\c AX=3000 BX=0000 CX=0200 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
\c DS=1BA7 ES=1BA7 SS=1BA7 CS=1BA7 IP=0103 NV UP EI PL ZR NA PE NC
\c 1BA7:0103 CD21              int     21
\c -g list
\c    1st G breakpoint, linear 0001_BB70  1BA7:0100, content CC
\c    2nd G breakpoint, linear 0001_BB73  1BA7:0103, content CC (is at CS:IP)
\c    3rd G breakpoint, linear 0001_BB75  1BA7:0105, content CC
\c -

The output is as follows:

\b The 1-based index ordinal of the point.

\b The linear address of the point.
(21-bit for Debug, 32-bit for DebugX.)

\b The segmented address of the point.
Only listed if the point was specified in a segmented form.
That is, if the point was specified with a "@ " or "@(" prefix
then no segmented address is saved along with it.
(Internally, the word or dword "preferred offset" variable
is set to all 1 bits then.)
In Protected Mode, the segment is specified as \cq{CS:} if
the code segment's base matches the preferred offset.
Otherwise, an R86M segment is shown with a dollar sign \cq{$} prefix
if the preferred offset matches any R86M segment.
Failing that the offset is shown with a prefix reading \cq{????:}.

\b The content byte. This is usually CCh.
However, if a breakpoint failed to be restored
then the original value is displayed here.

\b Indicator that this point matches the current CS:IP or CS:EIP.
This is only displayed if such a match is applicable.
Running G AGAIN when this is applicable will
step one time to bypass the corresponding point.

There is another G command:
After any equals sign, AGAIN keyword, and/or specified breakpoints,
the line can be ended with a REMEMBER keyword.
This saves the specified G breakpoint list
and then returns control to the user.
(The equals address, if any, is discarded.)
It allows preparing a G breakpoint list ahead of its use.
Auto-repeat, if enabled, will run like G AGAIN and
actually run the debuggee after a G REMEMBER command.


\H{cmdgoto} GOTO command - Control flow branch

\c goto            GOTO :label

The GOTO command can only be used when executing from a script file,
the command line buffer, or the RE buffer.
It lets execution continue at a different point in the file or buffer.
Labels are identified by lines that start with a colon,
followed by the alphanumeric label name,
and optionally followed by a trailing colon.
The destination label of the GOTO command may be specified
with or without the leading colon.

There are several special cases:

\b If the destination label is :SOF (Start Of File) then
the file or buffer completely rewinds to its start.

\b If the destination label is :EOF (End Of File) then
the file or buffer is closed.

\b If the destination label is not found then
the file or buffer is closed, along with an error message.


\H{cmdh} H command - Hexadecimal add/subtract values

\c hex add/sub     H value1 [value2 [...]]
\c base display    H BASE=number [GROUP=number] [WIDTH=number] value

The H command performs calculation and displays the result.
If a single expression is given then its value is displayed,
in hexadecimal and then in decimal.
If more than one expression is given then
two results are displayed, in hexadecimal only.
The first result is that which is calculated by adding all expressions.
The second result is calculated by subtracting all subsequent
expressions from the first expression's value.

If a value is above or equal to 8000_0000h then
along each display of that value, the value interpreted
as a negative two's complement number is listed in parentheses.

If the form with the \cw{BASE} keyword is given
then only one number is displayed.
The specified base may be between 2 and 36, inclusive.
If the \cw{GROUP} keyword is also used then digits are grouped.
The group separator is the underscore, \cq{_}.
The grouping number must be below or equal 32 (20h).
The default grouping is none, same as \cw{GROUP=0}.
If the \cw{WIDTH} keyword is also used then
at least that many digits are displayed.
The width must be below or equal 32 (20h).
The default width is one digit, same as \cw{WIDTH=0} or \cw{WIDTH=1}.

Examples:

\c -h 1
\c 0001  decimal: 1
\c -h 1 1
\c 0002  0000
\c -h 1 1 1
\c 0003  FFFFFFFF (-0001)
\c -h 1 + 2 * 3
\c 0007  decimal: 7
\c -h cs * 10
\c 0001A730  decimal: 108336
\c -h -26
\c FFFFFFDA (-0026)  decimal: 4294967258 (-38)
\c -h base=2 group=8 AA55
\c 10101010_01010101
\c -h base=2 group=4 width=#16 #1234
\c 0000_0100_1101_0010
\c -h base=#10 group=3 400*400
\c 1_048_576
\c -h base=3 group=3 FFFF_FFFF
\c 102_002_022_201_221_111_210
\c -


\H{cmdi} I command - Input from port

\c input           I[W|D] port

The I commands input from an x86 port.
The port can be any number between 0 and FFFFh.
Plain I inputs a byte from the specified port.
The IW and ID commands input a word or dword respectively.


\H{cmdif} IF command - Control flow conditional

\c if numeric      IF [NOT] (cond) THEN cmd
\c if script file  IF [NOT] EXISTS Y file [:label] THEN cmd
\c if variable     IF [NOT] EXISTS R variablename THEN cmd

The IF command allows specifying a conditionally executed command.
This is especially useful for creating conditional control flow branches
with the GOTO command (see \k{cmdgoto}).

For the first form, the condition is a numeric expression.
If it evaluates to non-zero it is considered true.
If the NOT keyword is absent then a true condition expression
leads to executing the THEN command.
With the NOT keyword present the logic is reversed.
Note that if an error occurs in parsing,
the THEN command is not executed,
regardless of whether the NOT keyword is present.

The second form specifies a script file
in the same format as accepted by the Y command (refer to \k{cmdy}).
A label may be specified behind the filename, as for the Y command.
If the file is found, and contains the specified label if any,
then the EXISTS clause is considered true.
Depending on the presence of the NOT keyword
the THEN command is executed next, or skipped.
Note that if an error occurs in parsing,
the THEN command is not executed,
regardless of whether the NOT keyword is present.

Likewise, if an unanticipated error occurs during access
then the THEN command is not executed.
Anticipated errors include:

\n The drive or ROM-BIOS unit cannot be accessed at all.
(Determined by sector 0 being unreadable.)

\n The specified partition is not found.

\n A specified directory is not found.

\n The file is not found.

\n A DOS error occurs opening the file.

\n The file is empty.

\n A specified label is not found.


The third form checks for a variable name
being recognised like for the R variable access command.
If the variable name is recognised the condition
is considered true.
Otherwise, the candidate name is skipped by scanning
for the first blank or comma,
except for parenthetical index expressions which
are parsed as expressions.
The condition is considered false
if no variable is recognised.


\H{cmdinstall} INSTALL command - Install optional features

This command can be used to enable certain optional features.
The parameters are a list of comma-separated keywords.
First the entire list will be parsed.
Upon successful parsing of all keywords
the command will then start to handle the keywords.

The first keyword to the \cw{INSTALL} command may be
the \cw{TOGGLE} keyword.
In this case the subsequently specified keywords
are toggled rather than enabled.

Save for the \cq{AREAS} keyword, these features can be
accessed by using the corresponding DCO flags as well.
The allowed keywords are:

\dt INT2F

\dt DPMIHOOK

\dd (lDebugX-only) Enable installing debugger's interrupt 2Fh hook
to intercept the DPMI entrypoint function call.
The interrupt hook will actually occur upon running
any debuggee code in Real/Virtual 86 Mode.
If the debugger is unable to hook the DPMI entrypoint then
a message is displayed and the DCO4 flag is cleared.
This is expected on MSWindows 4 and old dosemu versions.
This hook is enabled by default.
This keyword controls DCO4 flag 0002h.

\dt FAULTS

\dt INTFAULTS

\dd Install debugger's interrupt 0Dh and 0Ch hook.
These interrupts may be called by the machine in Real 86 Mode,
or by a VMM like dosemu2 in Virtual 86 Mode,
to indicate faults occurred.
Interrupt 0Dh indicates a General Protection Fault,
while interrupt 0Ch indicates a Stack Fault.
(If an address faults with the SS segment it is considered a Stack Fault.)
Both of these interrupt handlers are usually
called for IRQs as well, however.
The debugger's handlers will check
whether the corresponding IRQ is being serviced.
If it is, the call is chained to the debugger's downlink.
Only if the IRQ is not being serviced,
the debugger will handle the call as a fault.
(This heuristic is not perfect, but it works most of the time.)
This keyword controls DCO4 flag 0010h.

\dt INT08

\dt INT8

\dt TIMER

\dd Install debugger's interrupt 8 hook for the timer tick IRQ.
This enables the Interrupt 8 Control pressed detection
depending on the INT8CTRL variable (refer to \k{varint8ctrl})
as well as the double Control-C via serial I/O detection.
This keyword controls DCO4 flag 0004h.

\dt INT2D

\dt AMIS

\dd Install debugger's AMIS interface on interrupt 2Dh.
A free multiplex number must be available
and the existing interrupt vector must be valid for this to succeed.
This keyword controls DCO4 flag 0008h.

\dt AREAS

\dd (lDDebugX-/lCDebugX-only) Install this debugger's exception areas
into another debugger. The other debugger must have its AMIS interface
installed at the point in time that this command is run.
This keyword does not correspond to any DCO flags.

\dt SERIAL

\dd Install serial I/O for the debugger interface.
Configuration must be ready, refer to \k{varserial}.
This keyword controls DCO flag 4000h.

\dt INDOS

\dd Enter force InDOS mode.
The debugger will avoid calling DOS in this mode,
helping in debugging DOS or the interrupt 21h or 2Fh handlers.
This keyword controls DCO flag 0008h.

\dt GETINPUT

\dd Enter the use DOS getinput mode.
When DOS is available and used for I/O,
this mode enables use of the debugger's \cw{getinput} function
rather than using the DOS interrupt 21h service 0Ah line editor
to read from standard input.
The debugger's line editor includes proper line editing,
allows overlong input with a horizontally scrolling view of the buffer,
and enables history recall.
This keyword controls DCO flag 0800h.

\dt RHIGHLIGHT

\dd Enable R command register change highlighting.
This keyword controls DCO3 flag 04_0000h.

\dt AUTOREPEAT

\dd Enable autorepeat while reading from a terminal.
This feature is enabled by default.
This keyword controls DCO3 flag 1000_0000h (in reverse).

\dt BIOSOUTPUT

\dd Prefer to output to video ROM-BIOS terminal
using interrupt 10h services
instead of to the DOS interrupt 21h.
This keyword controls DCO6 flag 0200h.

\dt FLATBINARY

\dt FSWITCH

\dd Enable flat binary read mode, in which MZ .EXE files
and .HEX files
are read and written as if they were flat binaries.
This feature is also controlled by the /F+ or /F- switches.
This keyword controls DCO6 flag 0400h.

\dt BIGSTACK

\dt ESWITCH

\dd Enable .BIG style stack mode, in which flat binaries
are loaded with the stack set up in a separate segment.
This allows to execute .BIG style flat format executables
like used in the build process of the debugger itself.
This feature is also controlled by the /E+ or /E- switches.
This keyword controls DCO6 flag 0800h.

\dt RH

\dd Enable RH mode.
In RH (Register dump History) mode, a number of the last
R, RE, T, TP, P, or G outputs are buffered in the auxiliary buffer.
(The auxiliary buffer is about 8 KiB large by default.)
The RH command can then be used to display
all or some of the steps of the buffered contents.
Other commands that use the auxiliary buffer, like RN and RM,
cannot run when this mode is enabled.
Enabling RH mode will clear the RH/silent buffer.
This keyword controls DCO6 flag 10_0000h.

\dt DEBUG

\dd (lCDebug-only) Enable debuggable mode.
The conditionally debuggable debugger
defaults to start up in debuggable mode.
This feature is also controlled by the /D+ or /D- switches.
This keyword controls DCO6 flag 0100h.

\dt PAGING

\dd Enable paging.
This feature is enabled by default.
This keyword controls the DCO1 flag 10h (in reverse).

\dt PAGINGRC

\dd Enable paging when running RC buffer commands.
This keyword controls the DCO3 flag 1000h.

\dt PAGINGY

\dt PAGINGSCRIPT

\dd Enable paging when running Script for lDebug commands.
This keyword controls the DCO3 flag 2000h.

\dt PAGINGRE

\dd Enable paging when running RE buffer commands.
This keyword controls the DCO3 flag 4000h.

\dt RX

\dt REGS386

\dd Enable 32-bit and 386 registers display.
This keyword controls the DCO1 flag 1.
This flag is also toggled by the \cw{RX} command, \k{cmdrx}.

\dt TM

\dt TRACEINTS

\dd Enables tracing into software interrupt handlers.
This keyword controls the DCO1 flag 2.
This flag is also accessed by the \cw{TM} command, \k{cmdtm}.

\dt HOUDINI

\dd Enables breaking on houdini breakpoints in Extensions for lDebug.
This only takes effect in lDDebug,
or in lCDebug with debuggable mode enabled.
This keyword controls the DCO7 flag 100h.

\dt DEBUGOPTLINK

\dd Enables debugging output of missing optional links
in Extension for lDebug linker.
This keyword controls the DCO7 flag 2.

\dt QUIETINSTALL

\dd Enables suppressing Extension for lDebug installation messages.
This keyword controls the DCO7 flag 4.

\dt QUICKRUN

\dd Enables quickly running Extensions for lDebug.
This keyword controls the DCO7 flag 8.
Only quit.eld is affected by this yet.


\H{cmdlp} L command - Load Program

\c load program    L [address]


\H{cmdls} L command - Load Sectors

\c load sectors    L address drive sector count

Loads sectors from a local DOS drive.
The count specifies how many sectors to load.
The sector number specifies where on the drive to load from.
The drive specifies the drive to access,
and is specified either as an expression
or a drive letter with trailing colon (\k{pardrive}).
The address is a segmented address indicating
where to write the sector data.

The reverse is the Write Sectors command, \k{cmdws}.


\H{cmdm} M command - Move memory

\c move            M range address

This command copies data from one memory range
to another range.
The source range is specified as the first parameter.
The destination is specified as the second parameter,
which only accepts an address.
The length of the destination is equal
to the length of the source.

If the source and destination overlap,
the data movement is insured to be done in the direction
which will end up with the original source data
found intact at the destination.
If the source and destination do not overlap
then the movement may be done forwards or backwards.


\H{cmdmc} M command - Set Machine mode

\c 80x86/x87 mode  M [0..6|C|NC|C2|?]

An M command without parameters,
with a single \cq{?} parameter,
with an \cq{NC} parameter,
or a single expression parameter
is a get or set machine mode command.

The machine mode is used by the assembler and disassembler
to show machine requirements exceeding the current machine.

A plain \cq{M} or \cq{M ?} command displays the current machine.

An \cq{M NC} or \cq{M C0} command sets the current coprocessor
to absent.

An \cq{M C} command sets the current coprocessor to present.
It is set to the coprocessor type
corresponding to the current machine.

An \cq{M C2} command sets the current coprocessor to present,
and the coprocessor type to 287.
This command is only valid if the current machine is a 386.

An M command with an expression evaluating to 0 to 6
sets the current machine to the specified numeric value.
It also sets the current coprocessor type
corresponding to the specified numeric value.
Coprocessor presence is not modified by this command however.

Note that all machine mode commands that parse a
numeric expression (not \cq{M}, \cq{M ?}, nor \cq{M NC})
will actually parse the expression twice due to
the internal dispatching between the machine mode commands
and the move memory command.
If the expression has side-effects then these side-effects
will also occur twice.
(An example of a side effect is reading the LFSR variable,
which will step the LFSR.)


\H{cmdn} N command - Set program Name

\c set name        N [[drive:][path]progname.ext [parameters]]

This command sets up the filename and parameters to use when setting up
a new process using the L (Load program) command.
If the filename ends in \cw{.COM} or \cw{.EXE} it will be loaded
as a DOS program using the interrupt 21h service 4B01h.
If the filename ends in \cw{.HEX} it will be interpreted
by the debugger to load the contained data as a binary image.
Otherwise the file is loaded as a flat binary
by the debugger itself.
In any case, the PSP of the process created by the L command
will receive the command line tail,
which starts after the filename.

Unlike Microsoft's Debug the executable filename
is not included in the command line tail,
and an existing process won't be modified by the N command.
It only sets the filename and tail for L to use.


\H{cmdo} O command - Output to port

\c output          O[W|D] port value

The O commands output to an x86 port.
The port can be any number between 0 and FFFFh.
Plain O outputs a byte to the specified port.
The OW and OD commands output a word or dword respectively.
The value to write is specified by the second expression.


\H{cmdp} P command - Proceed

\c proceed         P [=address] [count [WHILE cond] [SILENT [count]]]

The P command causes debuggee to run a proceed step.
This is the same as tracing (T command) for most instructions,
but behaves differently for \cq{call}, \cq{loop},
and repeated string instructions.
For these, a proceed breakpoint is written behind the instruction
(similarly to how the G command writes breakpoints),
and the debuggee is run without the Trace Flag set.

As an exception, if a near immediate \cq{call} (opcode E8h)
is to be executed and its callee is a \cq{retf} or \cq{iret} instruction,
then the \cq{call} instruction is traced and not proceeded past.
(This supports some relocation sequences.)

Like for the G command, a start address can be given to P
prefixed by an equals sign.
Next, a count may be specified,
which causes the command to execute as many P steps as the count indicates.

After a count, a WHILE keyword may be specified,
which must be followed by a conditional expression.
Execution will only continue if the WHILE expression evaluates to true.

After a count (when no WHILE is given) or after a WHILE condition,
a SILENT keyword and optional count may be given.
In this case, the debugger buffers the register dump and
disassembly output of the executed steps,
until control returns to the debugger command line.
Then, the last dumps stored in the buffer are displayed.
If a non-zero count is given, at most that many register dumps are displayed.


\H{cmdq} Q command - Quit

\c quit            Q

This command attempts to quit the debugger.
It may fail if the currently attached process (if any)
does not return into the debugger's Parent Return Address
upon running an interrupt 21h function 4C00h
in the debuggee context.
It may also fail if any of the hooked interrupts
cannot be restored. In this case, setting
the corresponding DCO4 flags can force unhooking upon a retry.

For quitting a device driver mode debugger,
the QC and/or QD flags to the quit command must be used.
Refer to \k{invoking-device} for a description of them.

If the debugger was attached to a DOS process
the quit command will try to terminate the process.
If the quit command succeeds,
the debugger will return to its own parent process.

If not attached to a DOS process the quit command acts differently.
This is always true of the bootloaded debugger,
is true of the device driver mode debugger by default
(absent any ATTACH commands),
and is true of the application mode debugger
after a successful TSR command (absent subsequent ATTACH commands).
In this case, a quit command that succeeds
will continue to run the current debuggee code
in the exact state it was left in last.

The bootloaded debugger offers the BOOT QUIT command
which will try to quit the currently running (virtual) machine
rather than quitting the debugger.
It is described in \k{cmdbootquit}.

The quit Extension for lDebug (\k{eld-quit})
acts like the BOOT QUIT command
but can be loaded as an ELD even when in a DOS mode.

If the QB flag to the quit command is used,
then the debugger will run a breakpoint in its quit handler,
if the quit command succeeds.
This breakpoint runs after the debugger has uninstalled
its interrupt handlers.
Refer to \k{cmdqb}.


\H{cmdqa} QA command - Quit attached process

\c quit process    QA

The QA command tries to quit an attached process.
It does this by resetting the current cs:eip, ss:esp, efl, and
(only for DebugX) all segment registers.
Then it runs interrupt 21h service 4C00h in the context
of the current debuggee.
Afterwards it reports on how the debugger regained control
and whether the attached process terminated.

(If between the current debuggee's process and the debugger's process
there is any process that is self-parented,
or a breakpoint interrupt or trace interrupt is caused
by the current process having terminated,
then the attached process may be considered not terminated.)

The same underlying function is used by
the program-loading L command
and the default Q command
(except if the debugger is running in TSR mode or bootloaded).


\H{cmdqb} QB command - Quit and break

\c quit and break  QB

The QB command is composed of a Q command with a B flag.
It indicates to the debugger to quit as usual, but to then
run a breakpoint just before the debugger
returns the control flow to either the OS,
the application that executed the debugger,
or (when resident as TSR, device driver, or bootloaded)
the current debuggee.

When successful, this instance of the debugger
has already uninstalled all its interrupt hooks,
so the breakpoint will run the interrupt 3 handler
that was installed prior to the debugger having been installed.


\H{cmdr} R command - Display and set Register values

\c register        R [register [value]]

The R command without any register specified dumps the current registers,
either displayed as 16-bit or 32-bit values (depending on the RX option),
and disassembles the instruction at the current CS:(E)IP location.
If the instruction is a conditional jump
then the R command disassembly will include a trailing notice
that reads \cq{jumping} or \cq{not jumping} depending
on the current status.

R with a register, named debugger variable, or memory variable
(of the form \cw{BYTE/WORD/3BYTE/DWORD [segment:offset]})
displays the current value
of the specified variable.
It then displays a prompt, allowing the user to
enter a new value for that variable.
Entering a dot (.) or an empty line returns to the default debugger command line.

R with a variable, followed by a dot (.),
only displays the current value of that variable.

R with a variable, followed by an optional equals sign,
and followed by an expression,
evaluates the expression and assigns its resulting value to the variable.
The equals sign may instead be a binary operator with a trailing
equals sign, which is handled as an assignment operator.

Examples:

\c -r ax .
\c AX 0000
\c -r ax
\c AX 0000  :1
\c -r ax
\c AX 0001  :.
\c -r ax += 4
\c -r ax
\c AX 0005  :
\c -r word [cs:0]
\c WORD [1867:0000] 20CD  :
\c -r dif .
\c DIF 0100B00B
\c -


R with the special register name \cw{F} accesses
the flags register using the symbolic flag states.
Like for regular registers,
this will display all the current states
then prompt for new ones,
except if a dot or at least one new flag state
is specified trailing after the \cw{R F} command.
Multiple flags' states can be entered on the same line.

The table in \k{helpf} lists the flag states that are recognised,
in the third and fourth column.

It is valid to set two or more states for the same flag,
with the last one winning.
The new flag state input line is parsed in two passes.
An error that
is detected during a subsequent parameter
will have the debugger not already having applied the earlier parameters.
Only when the entire line has been parsed successfully,
the flag changes take effect.


\S{cmdre} RE command - Run register dump Extended

\c Run R extended  RE

The RE command runs the RE buffer commands. Refer to \k{helpre}.
The RE buffer has the highest priority
among all buffered commands.
(The RC buffer and Y command Script for lDebug files
have a lower priority than the RE buffer.)

RE buffer commands are displayed with a prompt
consisting of a percent sign \cw{%} or,
for DDebug or for CDebug while in debuggable mode,
a tilde followed by a percent sign \cw{~%}.

\S{cmdredot} RE buffer commands

\c RE commands     RE.LIST|APPEND|REPLACE [commands]

RE.LIST lists the RE buffer contents in a way that can be re-used
as input to RE.REPLACE.

RE.APPEND appends the following commands to the RE buffer.
This command can overflow the RE buffer,
in which case the command aborts with an error.
In this case the command has no effect on the RE buffer contents.

RE.REPLACE replaces the RE buffer with the following commands.
This command generally cannot overflow the RE buffer.

The RE buffer usage is described in the ?RE help page (\k{helpre}).


\S{cmdrc} RC command - Run Command line buffer

\c Run Commandline RC

The RC command runs the command line buffer commands.
This is similar to the RE command,
except it uses a different buffer.
Further, the RC buffer contents have the lowest priority
among all buffered commands.
(The RE buffer and Y command Script for lDebug files
have a higher priority than the RC buffer.)
Upon initialisation of the debugger
the RC buffer is filled.

In case the debugger is loaded as a DOS application or DOS device driver,
the RC buffer first gets the configuration command.
Then the debugger's init appends
the content of the \cw{/C} switch (if any).
If an \cw{/IN} switch is specified,
the RC buffer is cleared.

In case the debugger is bootloaded,
the RC buffer receives the contents of the kernel command line (if any)
or the default kernel command line contents.

If the RC buffer is not empty,
the equivalent to an RC command is run
on startup of the debugger.
(This running happens after the initial N and L commands.)

Command line buffer commands are displayed with a prompt
consisting of an ampersand \cw{&} or,
for DDebug or for CDebug while in debuggable mode,
a tilde followed by an ampersand \cw{~&}.
When both RE and RC are running out of their respective buffers,
the RE buffer contents take precedence.


\S{cmdrcdot} RC buffer commands

\c RC commands     RC.LIST|APPEND|REPLACE [commands]

RC.LIST lists the command line buffer contents in a way that can be re-used
as input to RC.REPLACE.

RC.APPEND appends the following commands to the command line buffer.
Like RE.APPEND this will cause an error if the buffer overflows.

RC.REPLACE replaces the command line buffer with the following commands.


\H{cmdrh} RH command - Display Register dump History steps

\c regdump history RH [IN value, value, ...|value]

The RH command displays steps from the RH/silent buffer
while RH mode is enabled.
RH mode can be enabled using the \cw{INSTALL RH} command.
(Refer to \k{cmdinstall}.)
The parameter to the RH command can be the keyword IN,
followed by one or more comma-separated match ranges,
or by a single number,
or no parameter at all.

The no parameter form displays all steps still saved in the RH buffer.

The one parameter form displays a single step from the RH buffer.
The number 0 refers to the most-recent saved step.
The number 1 refers to the second most-recent saved step.
And so on.

The \cw{RH IN} form accepts one or more match ranges.
A match range can be:

\b A single number.
(Must be below 1_0000h.)

\b The keyword \cw{FROM} followed by a number
followed by the keyword \cw{TO} followed by a number.
(The second number must be above-or-equal the first number.
Both must be below 1_0000h.)

\b The keyword \cw{FROM} followed by a number
followed by the keyword \cw{LENGTH} followed by a number.
(The length number plus the first number
must be below-or-equal 1_0000h.
A zero-length is valid, and will produce no output.)

The \cw{RH IN} command will treat each match range by displaying
the corresponding steps from the RH buffer,
but in chronological order.
For instance, the following two commands are equivalent:

\c rh in from 2 length 4

\c rh in 5,4,3,2

When parameters specify a number that is above the oldest still saved step
in the RH buffer, the behaviour is not certain and may yet change.
(For now, each older step will display nothing.
This still may be subject to change.)

The RH command defaults to page its output, if paging is enabled.
Paging can be disabled for the RH command
using the silent buffer output paging control.
(This will, of course, also affect the silent buffer output.)
The command \cw{r dco3 = dco3 clr 200 or 100} will instruct
the RH command to not page its output.

As an exception, if the RH buffer is empty then
any valid RH command will produce no output at all.

If RH mode is not enabled then the RH command may display
stale or corrupted output, except when run
directly after a silent-buffered T/TP/P command.
In the latter case, the RH command will operate on the contents
stored by the last run command.


\H{cmdrm} RM command - Display MMX Registers

\c MMX register    RM [BYTES|WORDS|DWORDS|QWORDS]

This command dumps all 8 MMX registers.
It is only available if MMX is supported by the machine.
The optional size keyword specifies an item size,
which defaults to BYTES.
The BYTES size will match memory order of the byte values,
displaying the least significant byte's value first.
A size keyword of WORD will display the least significant word
first, and so on.

MMX support is redetected when lDebugX
enters or leaves Protected Mode.
(dosemu2 may support MMX in its Protected Mode
while not supporting it in 86 Mode.)

This command is no longer included in the default build
as of release 7.
To use it, either enable the build time _RM define
or run \cq{ext rm.eld install} to install it
as an Extension for lDebug.


\H{cmdrn} RN command - Display FPU Registers

\c FPU register    RN

This command is no longer included in the default build
as of release 7.
To use it, either enable the build time _RN define
or run \cq{ext rn.eld install} to install it
as an Extension for lDebug.


\H{cmdrx} RX command - Toggle 386 Register Extensions display

\c toggle 386 regs RX

This command toggles the DCO flag 0001h.
The same flag can be set using the command \cw{INSTALL RX}
or cleared using the command \cw{UNINSTALL RX}.
This command is not valid on a non-386 machine.


\H{cmdrv} RV command - Show sundry variables

This command shows the first 16 user-defined variables (refer to \k{varv}),
the current options variables DCO (that is DCO1), DCS, DAO, DAS,
the internal flags DIF (that is DIF1),
as well as the debugger process segment (DPR),
the debugger parent return address (DPI),
and the debugger parent process (DPP).
lDebugX also shows the debugger process selector (DPS),
which is zero in 86 Mode and a selector value in Protected Mode.
(All of these variables can be queried manually,
the RV command lists them merely for convenience.)

Additionally, in the last line the RV command
displays the current debuggee's mode.
This is either Real 86 Mode, Virtual 86 Mode,
or (lDebugX only) Protected Mode with either a 16-bit CS or a 32-bit CS.


\H{cmdrvv} RVV command - Show nonzero user-defined variables

This command shows all user-defined variables (refer to \k{varv})
that are not currently zero.
Variables are always shown four to a line,
so a single non-zero variable will additionally show
up to 3 variables that are currently zero.


\H{cmdrvm} RVM command - Show debugger segments

This command shows various segments (and, in Protected Mode, selectors)
used by the debugger. It currently shows the following:

\b Code segment

\b Code2 segment (only if _DUALCODE build)

\b Data segment

\b Entry segment (same as data segment but with a code selector in PM)

\b Message segment

\b Auxbuff segment

\b History segment


A more detailed list of the debugger's segments,
including their sizes,
can be obtained using the ldmem Extension for lDebug
(\k{eld-ldmem}).


\H{cmdrvp} RVP command - Show process information

This command shows the debugger's mode
as well as some client and debugger process addresses.
The mode is one of:

\b Boot loaded

\b Device driver

\b Application

\b Application installed as TSR


The process addresses include:

\dt PSP

\dd Process Segment Prefix (always a 86M segment value)

\dt Parent

\dd Parent of the PSP (for the debugger the would-be parent for termination,
however note that during normal operation the debugger is self-parented)

\dt Parent Return Address

\dd 16:16 far pointer (a segmented 86M far address) of the process's
interrupt 22h value, the entrypoint to return to the parent
(again for the debugger this is the would-be PRA for termination,
during normal operation the debugger sets up its actual PRA
to return control to the debugger itself)

\dt PSP Selector (only displayed for lDebugX)

\dd A selector or segment value, appropriate for the current mode,
to address the PSP


The process addresses can all be accessed individually too,
using the following variables:

\dt PSP

\dd PSP (client), DPSP (debugger)

\dt Parent

\dd PARENT (client), DPARENT (debugger)

\dt Parent Return Address

\dd PRA (client), DPRA (debugger)

\dt PSP Selector (always a segment if not lDebugX)

\dd PSPSEL (client), DPSPSEL (debugger)


The DPARENT and DPRA variables read as all zeros when the debugger is
loaded in bootloaded, device driver, or resident application (TSR) mode.


\H{cmdrvd} RVD command - Show device information

This command shows the device header (segmented 86M) far address
as well as the size of the device's allocation, in paragraphs.
If the debugger is not loaded in device mode then instead
a message indicating this is displayed.

The two variables can be accessed individually, too.
These are the DEVICEHEADER and DEVICESIZE variables.
Both of them read as all zeros when the debugger is not loaded in device mode.


\H{cmds} S command - Search memory

\c search          S range [REVERSE] [SILENT number] [RANGE range|list]

The S command searches memory for a byte string.
The first range specifies the search space.
By default, searching will begin at the bottom of the search space
and move upwards.
If a REVERSE keyword is specified after the range then searching
will begin at the top of the search space moving downwards.
The search string is specified either with the RANGE keyword
followed by another range, or as a list of byte values.

If the SILENT keyword is specified, a silent number must be parsed
before the list or range parameter.
The number specifies how many result lines are displayed at most.
It is a 32-bit unsigned number that may take any value
in the range, including zero.
If the number is zero, only the amount of matches is displayed.

The read-only variable SRC (Search Result Count) will receive
the 32-bit value that is the amount of matched occurrences.
The variable SRS0 receives the first Search Result Segment.
Likewise SRO0 receives the first Search Result Offset.
SRO1 to SROF hold subsequent Search Result Offsets.
SRO is an alias to SRO0. SRO variables are 32-bit in
the _PM build lDebugX, 16-bit otherwise.
Unused SRO variables are zeroed out by a successful search.
The COUNT variable is set to the length of the search string.

The display of search results is as follows:

\b First, the result's segmented address.

\b Then, the displacement of the following dump.
This is displayed with a leading plus sign and
some amount of hexadecimal digits (2, 4, 6, or 8 digits).
The number is the length of the search pattern
(which is also written to the COUNT variable).

\b Then, a hexadeximal dump of the up to 16 bytes that
follow the search string match at this point.

\b Finally, the ASCII character dump of these up to 16 bytes.

There is an option to disable the data dump so as to
only display the match addresses.
If the bit 80_0000h is set in the DCO variable then
the data dump is suppressed.


\H{cmdsleep} SLEEP command

\c sleep           SLEEP count [SECONDS|TICKS]

The SLEEP command sleeps for the indicated length.
The duration defaults to seconds.
If the TICKS keyword is specified then the duration
is taken to mean timer ticks.
(A timer tick is about 1/18 seconds.)
If the input is from DOS or serial I/O
then Control-C from the input terminal
may be used to cancel the sleep.


\H{cmdt} T command - Trace

\c trace           T [=address] [count [WHILE cond] [SILENT [count]]]

The T command is similar to the P command.
However, T traces most instructions.
Depending on the TM option (\k{cmdtm}), interrupt instructions
are also traced (into the interrupt handler) or proceeded past.

\S{cmdtp} TP command - Trace/Proceed past string ops

\c trace (exc str) TP [=address] [count [WHILE cond] [SILENT [count]]]

The TP command is alike the T command, but
proceeds past repeated string instructions like the P command would.


\H{cmdtm} TM command - Show or set Trace Mode

\c trace mode      TM [0|1]

This instruction accesses the DCO flag 2.
If run without an expression then the current status is displayed.
Otherwise tracing into interrupts (for the T and TP commands)
is enabled (nonzero expression) or disabled (zero expression).


\H{cmdtsr} TSR command - Enter TSR mode (Detach from process)

\c enter TSR mode  TSR

This command tries to find the PSP to which the debugger is attached.
It starts the search at the current PSP and walks up
the parent processes until finding the debugger.
If a self-owned process is encountered the search is aborted.

Once found, the attached PSP is patched
with the PRA and parent process noted down for the debugger itself.
That is, the debugger's would-be parent is made the parent
of the attached process.
The debugger's fields for original PRA and parent are cleared.
Thus the TSR command, if it succeeds, switches the debugger
into resident mode.

The reverse operation is performed by the ATTACH command
(see \k{cmdattach}).
The TSR command can be used right away in application mode,
or can be used in device driver mode after the debugger
has been attached to a process using the ATTACH command.
The default state of the device driver mode debugger
is resident mode.

The TSR command and the ATTACH command
are not usable in bootloaded mode.


\H{cmdu} U command - Disassemble

\c unassemble      U [range]

Given a range, the address of which defaults to CS,
this command disassembles instructions from memory.
The range may be specified with a lines length
(refer to \k{parrangelines}).
The default length if none is specified defaults to the number of lines
specified in the variable \cw{DEFAULTULINES} if it is nonzero,
or else the number of bytes specified in the variable \cw{DEFAULTULEN}.

If a lines length is used, that many lines are disassembled.
However, if a single instruction does not fit within one line
due to a too long string of machine code,
then the lines used for this instruction
will count as one line as concerns the lines length.
If an address length is specified,
all instructions that are contained within or start within
the specified range are disassembled.

If no range is specified, the U command continues
disassembling at "u_addr" (AUS:AUO),
which is updated by each U command to point
after the last disassembled byte.
The R command sets "u_addr" to equal the current CS:(E)IP,
including if the register dump is called by a run command.
The default length is determined in the same way as for
if a range without a length is specified.
If autorepeat is used it behaves the same way as a U command
without a range.


\H{cmduninstall} UNINSTALL command - Uninstall optional features

This command can be used to disable certain optional features.
The parameters are a list of comma-separated keywords.
First the entire list will be parsed.
Upon successful parsing of all keywords
the command will then start to handle the keywords.

The available keywords are documented for the INSTALL command,
refer to \k{cmdinstall}.


\H{cmdv} V command - Video screen swapping

\c view screen     V [ON|OFF [KEEP|NOKEEP]]

The V commands allow to enable or disable video screen swapping.
When enabled, the debugger takes care that screen output of
debuggee and debugger are strictly separated.
This is useful to debug fullscreen text mode programs.

The screen will be swapped whenever the debuggee is run
with a run command (T/TP/P/G),
or when the plain V command is used.
The plain V command is provided
to watch the debuggee screen while the debugger is active.
It ends upon the user entering any key to the debugger terminal.

Video screen swapping currently requires an XMS driver,
and the debugger will allocate an XMS memory block of 32 KiB.

V OFF KEEP will disable video screen swapping
but keep the current debugger screen contents.
V OFF NOKEEP
(and the default for V OFF if the keep flag has not been set)
will instead return to the debuggee screen contents.
When the Q command succeeds, it executes the equivalent of V OFF.
That is it will use the current keep flag.


\H{cmdwp} W command - Write Program

\c write program   W [address]


\H{cmdws} W command - Write Sectors

\c write sectors   W address drive sector count

Writes sectors to a local DOS drive.
The count specifies how many sectors to write.
The sector number specifies where on the drive to write to.
The drive specifies the drive to access,
and is specified either as an expression
or a drive letter with trailing colon (\k{pardrive}).
The address is a segmented address indicating
where to read the sector data.

The reverse is the Load Sectors command, \k{cmdls}.

Note that on MS-DOS v7 this command will lock and unlock
the specified drive to insure it is locked when writing.
As there is no way to query the lock status,
this will unconditionally unlock the drive after writing.

\e{Warning:} You should know what you are doing if you use this command.
Misuse may corrupt any data stored on this drive.


\H{cmdx} X commands - Expanded Memory (EMS) commands

\c expanded mem    XA/XD/XM/XR/XS, X? for help

These commands are no longer included in the default build
as of release 7.
To use them, either enable the build time _EMS define
or run \cq{ext x.eld install} to install them
as an Extension for lDebug.


\H{cmdy} Y command - Run script file

\c run script      Y [partition/][scriptfile] [:label]

The Y command runs a Script for lDebug file.


\S{cmdypathnames} Y command pathnames

The script file is specified in two different ways,
depending on whether the debugger is running as an 86-DOS application
or device driver,
or rather as a boot-loaded kernel replacement.

\b If running as an application or device driver,
the script name is a regular pathname.
It may be quoted with doublequotes if the pathname includes blanks,
semicolons, or commas.
If the indicated drive supports long filenames (LFNs) then
the debugger will first try to open the pathname as an LFN.

\b Otherwise, the script name may start with a partition specification to use.
(Refer to the ?BOOT help page in \k{helpboot} for partition specifications.)
Then, the pathname relative to that partition's root directory follows.
Long filenames are not supported.
Note that it is not valid to run an empty script file when boot-loaded.

In both cases, commas are parsed as separators that end a pathname,
except if they occur within doublequotes.
The same is true of semicolons.
Semicolons may be parsed as end-of-line markers as well.


\S2{cmdyconfigpathes} Y command configuration pathes

A pathname may start with one of two special keywords to
use one of the debugger configuration pathes:

\dt \cw{::config::}

\dd Access the debugger configuration directory

\dt \cw{::scripts::}

\dd Access the debugger scripts directory

The pathname should not include a path separator
(backslash or forward slash) directly after the keyword.


The default path for the debugger configuration directory is
detected as follows:

\n If the debugger is bootloaded, the configuration directory
is set to \cw{ldp/}.

\n If the environment variable \cw{LDEBUGCONFIG} is set, read it.

\n Else, if the path to the debugger's executable can be determined,
use that.

\n Else, the current directory on the current drive is used.


The default path for the debugger scripts directory is
detected as follows:

\n If the debugger is bootloaded, the scripts directory
is set to \cw{ldp/}.

\n If the environment variable \cw{LDEBUGSCRIPTS} is set, read it.

\n Else, if the path to the debugger's executable can be determined,
use that.

\n Else, the current directory on the current drive is used.


The configuration pathes can be shown or modified
using the \cq{config} Extension for lDebug.


\S2{cmdydefaultscripts} Y command default scripts path

If a Y command filename is not found,
and no config path keyword was used,
the debugger will retry the file open
with the \cw{::scripts::} path prepended to the specified filename.
If this is not desired,
an explicit \cw{::empty::} path keyword may be used.


\S{cmdylabels} Y command labels

A label may be specified after a pathname to cause execution to start at that
label instead of at the start of the file.
This is equivalent to placing a \cq{GOTO :label} command
at the start of the script file.
The colon to indicate a label is required.

If execution already is within a script file,
then the Y command may be run with only a label
(again with the colon required).
In that case, the current script file is opened in a subsequent level
(handle or boot-loaded script file context) and execution starts at that label.


\S{cmdyindos} Y command InDOS interaction

Opening a script file as DOS application or device driver only works
while DOS is available (InDOS not set).
Additionally, if during script file execution
DOS becomes unavailable (InDOS is set)
then the script file execution is paused.
It is resumed once DOS becomes available again.
(Control-C with a non-zero IOL variable may still
be used to cancel script file execution.
DOS is called to close affected handles only if DOS is available.)


\H{cmdz} Z commands - Symbolic debugging support

These commands are only supported if
the _SYMBOLIC build option is enabled.

\S{cmdzswitchs} Z /S=size - Allocate, resize, or free symbol tables

The /S switch allows to change the symbol table allocation.
The symbol tables may take up
up to 256 KiB of 86 Mode memory (below 1024 KiB)
or up to 2 MiB of XMS memory.
XMS use implies an additional 65 KiB is allocated for
padding and a transfer buffer.

XMS use can be forced by using a letter X behind the /S.
86 Mode memory use can be forced by using a letter R instead.
The prior selection can be undone using an asterisk *,
returning to the default behaviour.
That means allocate XMS if available,
and fall back to 86 Mode memory otherwise.

After the equals sign a size is to be specified.
The size can be an immediate number or an expression,
or the keyword MAX to use the maximum size.
An expression must be surrounded by round parentheses.
The size specifies the amount of kibibytes to allocate.
The size may be zero, which signals to free all symbol tables.
This deletes all symbols yet defined.
Otherwise, new symbol tables are allocated.
Existing symbols will be transferred from the old symbol tables,
if there are any.
It is an error to specify a symbol table size that
is not large enough to hold all currently defined symbols,
except for specifying a zero size.

Multiple /S switches can be specified within the same Z command.
They are processed one by one, that is
an error during parsing or execution of a subsequent switch
will not make it so a prior switch is skipped.


\S{cmdzstat} Z STAT - Show symbol table statistics

This command shows statistics on the current symbol table sizes,
including the amount of total, used, and free units.
Each of the symbol main array,
symbol hash array,
and symbol string heap are listed.


\S{cmdzadd} Z ADD - Add a symbol

This command is used to add a new symbol.
It can be followed by several parameters.
These are:

\dt SYMBOL= or S=

\dd Name of the symbol, may be quoted

\dt OFFSET= or O=

\dd Offset of the symbol

\dt LINEAR= or L=

\dd Linear address of the symbol

\dt FLAGS= or F=

\dd Flags of the symbol

\dt No keyword

\dd Segmented address of the symbol
to specify the linear address and offset


\S{cmdzdel} Z DEL - Delete a symbol

This command deletes a symbol.
It can be followed by the symbol name to delete,
or a RANGE keyword and an address range parameter,
or an UNREFSTRING keyword.
The latter is to clean up the symbol string heap
by deleting entries that are no longer used.


\S{cmdzcommit} Z COMMIT - Commit temporary symbols

Z ADD will batch up new symbols as temporary symbols.
They are committed into the symbol tables upon
several conditions, such as no more space for temporary symbols
or execution of a command other than Z ADD or Z ABORT.
The Z COMMIT command is for forcing the temporary symbols
be committed.
This should not usually be required.


\S{cmdzabort} Z ABORT - Discard temporary symbols

This command discards all temporary symbols batched by
prior Z ADD commands if they were not yet committed.
If the debugger responds to every command with the
error message "Invalid symbol table data!" then
something went wrong with the committing of
temporary symbols.
In this case the Z ABORT command may help
to return the debugger to a usable state.


\S{cmdzlist} Z LIST - List symbols

\S{cmdzmatch} Z MATCH - Match symbols

\S{cmdzreloc} Z RELOC - Relocate symbols


\C{asmref} Assembler Reference

The assembler is accessed by running the A command (\k{cmda}).
The prompt for the assembler consists of a segmented address,
with a 16-bit segment/selector and a 16-bit or 32-bit offset.
Entering an empty line (whitespace only)
or a single dot to the assembler exits back to the debugger prompt.
Trailing comments may be added using semicolons.


\H{asmref-msdebug} Assembler comparison to MSDebug

Differences from MSDebug's assembler include:

\b 386 level 32-bit operands and addresses are supported.
The call, jmp, push, and pop instructions with memory operands
will assume a default WORD or DWORD size depending on
the D bit of the current CS being assembled into

\b Immediate operand and displacement sizes
(BYTE, WORD, DWORD)
can be specified to force longer encodings

\b Disassembly defaults to NASM address syntax,
lowercase output (except numeric digits),
and a blank after any comma

\b Indentation of the first operand can be disabled,
though it defaults to enabled

\b Some NASM style instruction names like \cw{retn}, \cw{int3}, and \cw{xlatb}
are used in the disassembly, and may be used with the assembler

\b Segment overrides may be included in address operands
rather than in a label-like form (on a line of their own
or as a prefix to an instruction, with a trailing colon)

\b Segment overrides do not require a colon
if they are placed before string instructions

\b Segment overrides may be placed in a SEG pseudo-instruction

\b The disassembler always shows a size for push or pop
with a memory operand, although the assembler can assume a default size


\H{asmref-nasm} Assembler comparison to NASM

The assembler generally strives to accept assembly input
matching the syntax of NASM (the Netwide Assembler).
Key differences:

\b Labels are not supported

\b Numeric input defaults to hexadecimal
(while expressions in parentheses can switch base using a \cq{#} prefix)

\b Character constants are not supported directly,
requiring an expression in parentheses which accepts string literals

\b SIB indexing must be done using exact numbers,
multipliers like 9 or 5 are not automatically parsed into valid SIB bytes

\b The NOSPLIT keyword is not supported,
and the assembler never splits indexing expressions

\b The MODRM keyword is added, which allows selecting
non-default instruction encodings (most of which are size pessimisations)

\b LOOP instructions can be suffixed with a size letter \cq{W} or \cq{D}
whereas NASM requires a second operand that reads \cq{CX} or \cq{ECX}.
The NASM form is supported too,
but the disassembler defaults to the suffix form.

\b A STRICT keyword is not accepted,
instead size and distance keywords can be used to force certain forms

\b CALL FAR and JMP FAR will allow a single immediate number operand,
assembling to an imm:imm branch instruction with the segment
equal to the segment currently being assembled into

\b Size and distance keywords can be followed by a \cq{PTR} keyword,
which has no effect


\H{asmref-roundtrip} Assembler roundtrip

The disassembler is supposed to generate output which
is valid input to the assembler.
Ideally, any disassembly would make it through a "roundtrip",
that is assembling the disassembly output should
result in exactly the same machine code bytes.
This is not always true however.

For instance, the SIB long form encoding of a disp32-only
memory address is disassembled just as the non-SIB form,
and the assembler currently lacks a way to force this encoding.
Invalid prefixes may also not roundtrip successfully.
The order of multiple prefixes may also change,
which can be significant in some cases (eg
the dispatchers for the disassembler's repeated string op simulation).
Additionally, the disassembler may display annotations like
\cq{(unused)} and \cq{[needs 386]}. These must be stripped
from the instruction to enter it into the assembler.
The same is true when running an R command (register dump)
and its disassembly shows a memory content annotation
or the \cq{jumping} or \cq{not jumping} notice.


\H{asmref-disasm-fields} Disassembly fields

The disassembly consists of several fields:

\n The segment which is being read, 4 hexadecimal digits

\n The offset of the first machine code byte in this line,
4 or 8 hexadecimal digits

\n The machine code dump, an even number of hexadecimal digits

\n The instruction mnemonic

\n 0 to 3 instruction operands,
depending on the instruction

\n The annotation, optional


\H{asmref-asm-fields} Assembly fields

The assembly input consists of:

\n The segment:offset that the next instruction will be written to,
this forms the prompt for the debugger's line input.
Offset may be 4 or 8 hexadecimal digits.

\n The instruction mnemonic

\n 0 to 3 instruction operands,
depending on the instruction

\n A comment indicated by a semicolon, optional

The assembler may emit an annotation after it accepts a line.
This will be written to the next line, and can read like
\cq{[needs 386]} or \cq{[needs math coprocessor]}
depending on the current machine type (\k{cmdmc}) and
the needed machine type for the instruction.

Additionally, if the AFORMAT Extension for lDebug
(\k{eld-aformat}) is installed
and enabled, each accepted line to the assembler
will reply with a machine code dump in a subsequent line.
This dump looks similar to the disassembler's dump.
It will correspond exactly to what was written by the assembler.
(It checks which address was used for the last prompt
and which address is used for the next prompt.
The ORG directive is handled as a special case.)


\H{asmref-insref-pointer} Assembly instruction reference

It is recommended to keep an instruction reference on hand.
The old NASM instruction reference does nicely for all 386-level
instructions, though it lacks descriptions
of system structures like descriptors, the TSS, and the FSAVE format.
It is hosted on the web at
\W{https://pushbx.org/ecm/doc/insref.htm}{https://pushbx.org/ecm/doc/insref.htm}
with its sources available in the repo at
\W{https://hg.pushbx.org/ecm/insref/}{https://hg.pushbx.org/ecm/insref/}


\S{asmref-insref-mnemonic} Assembler instruction mnemonics

A mnemonic is a keyword that maps to a certain instruction.
Mnemonics are generally matched cap-insensitively.
Some mnemonics allow different forms with optional or required
size suffix letters. If present, such a letter can be either
a \cq{W} or a \cq{D} to indicate a word (16-bit)
or dword (32-bit) size.


\S{asmref-insref-operands} Assembler operand types

Every explicit operand to an assembly language instruction is one of:

\n A register, which includes 8-bit, 16-bit, or 32-bit registers,
most often a GPR (General Purpose Register),
part of a GPR, or a segment register

\n Memory, possibly addressed using none to two registers
and/or a displacement, possibly with a segment override.
A memory operand generally has the address surrounded
by square brackets \cq{[...]}.

\n An immediate, possibly byte, word, or dword sized,
where a byte may be sign-extended for certain instructions


\S{asmref-insref-overview} A quick overview of most 8086 instructions

\dt ALU 2-operand

\dd add, adc, sub, sbb, and, or, xor, cmp, test

\dt ALU 1-operand

\dd neg, not, inc, dec

\dt Multiplication and division

\dd mul, imul, div, idiv

\dt Shifts and rotates

\dd shl, shr, sar, rol, ror, rcl, rcr

\dt Data movement

\dd mov, xchg

\dt Stack

\dd push, pop, pushf, popf

\dt Branch

\dd jmp, jcc, loop, jcxz, call, int, retn, retf, iret

\dt Flags

\dd clc, stc, cmc, cld, std, cli, sti, lahf, sahf

\dt String

\dd lods*, stos*, scas*, cmps*, movs*

\dt Port I/O

\dd in, out

\dt Special: Addresses and segments

\dd lea, les, lds

\dt Special: Prefixes

\dd repe, repne, lock, es, ss, cs, ds

\dt Special: BCD

\dd daa, das, aaa, aas, aam, aad

\dt Special

\dd nop, xlatb, cbw, cwd, hlt


\S{asmref-insref-alu2} ALU 2-operand instructions

\dt add

\dd Add op1 + op2 and store in op1

\dt adc

\dd Add op1 + op2 + CF and store in op1

\dt sub

\dd Subtract op1 - op2 and store in op1

\dt sbb

\dd Subtract op1 - op2 - CF and store in op1

\dt and

\dd Bitwise AND both ops and store in op1

\dt or

\dd Bitwise OR both ops and store in op1

\dt xor

\dd Bitwise XOR both ops and store in op1

\dt cmp

\dd Calculate op1 - op2, affects only flags

\dt test

\dd Calculate bitwise AND, affects only flags


\S{asmref-insref-alu1} ALU 1-operand instructions

\dt neg

\dd Negate operand in two's complement

\dt not

\dd Bitwise NOT the operand

\dt inc

\dd Increment operand, preserves CF

\dt dec

\dd Decrement operand, preserves CF


\S{asmref-insref-muldiv} Multiplication and division

\dt mul

\dd Multiply to doublewidth result

\dt imul

\dd Multiply signed to doublewidth result

\dt div

\dd Divide doublewidth number

\dt idiv

\dd Divide signed doublewidth number


\S{asmref-insref-shiftrot} Shifts and rotates

\dt shl

\dd Shift left

\dt shr

\dd Shift right, fill zeroes

\dt sar

\dd Shift arithmetic right, fill sign bit

\dt rol

\dd Rotate left

\dt ror

\dd Rotate right

\dt rcl

\dd Rotate with Carry left

\dt rcr

\dd Rotate with Carry right


\S{asmref-insref-move} Data movement

\dt mov

\dd Copy data value

\dt xchg

\dd Exchange two data values


\S{asmref-insref-stack} Stack

\dt push

\dd Push from operand

\dt pop

\dd Pop into operand

\dt pushf

\dd Push flags

\dt popf

\dd Pop flags

\S{asmref-insref-branch} Branch

\dt jmp

\dd Unconditional jump

\dt jcc

\dd Conditional short jump

\dt loop

\dd Decrement counter register and jump if nonzero

\dt jcxz

\dd Jump if counter register is zero

\dt call

\dd Push next instruction's address and jump to subroutine

\dt int

\dd Invoke interrupt handler

\dt retn

\dd Return near

\dt retf

\dd Return far

\dt iret

\dd Interrupt return


\S{asmref-insref-flags} Flags

\dt clc

\dd Clear CF (NC)

\dt stc

\dd Set CF (CY)

\dt cmc

\dd Complement CF

\dt cld

\dd Clear DF (UP)

\dt std

\dd Set DF (DN)

\dt cli

\dd Clear IF (DI)

\dt sti

\dd Set IF (EI)

\dt lahf

\dd Load AH from flags

\dt sahf

\dd Store AH to flags


\S{asmref-insref-string} String

\dt lods*

\dd Load from string

\dt stos*

\dd Store to string

\dt scas*

\dd Compare accumulator register to string

\dt cmps*

\dd Compare two strings

\dt movs*

\dd Copy from string to string


\S{asmref-insref-port} Port I/O

\dt in

\dd Input from port

\dt out

\dd Output to port


\S{asmref-insref-address} Special: Addresses and segments

\dt lea

\dd Load Effective Address (calculate offset into register)

\dt les

\dd Load offset and Extra Segment from far pointer in memory

\dt lds

\dd Load offset and Data Segment from far pointer in memory



\S{asmref-insref-prefix} Special: Prefixes

\dt repe

\dd Repeat string instruction (while ZF set)

\dt repne

\dd Repeat string instruction (while ZF clear)

\dt lock

\dd Lock bus for atomic RMW

\dt es

\dd Override with Extra Segment

\dt ss

\dd Override with Stack Segment

\dt cs

\dd Override with Code Segment

\dt ds

\dd Override with Data Segment


\S{asmref-insref-bcd} Special: BCD

\dt daa

\dd Decimal Adjust after Addition

\dt das

\dd Decimal Adjust after Subtraction

\dt aaa

\dd ASCII Adjust after Addition

\dt aas

\dd ASCII Adjust after Subtraction

\dt aam

\dd ASCII Adjust after Multiply

\dt aad

\dd ASCII Adjust before Division


\S{asmref-insref-special} Special

\dt nop

\dd Do nothing

\dt xlatb

\dd Load byte from lookup table

\dt cbw

\dd Convert signed byte to word

\dt cwd

\dd Convert signed word to dword

\dt hlt

\dd Halt until an IRQ arrives


\C{varref} Variable Reference

\H{varregisters} Registers

All debuggee registers can be accessed numerically:

\b \cw{al}, \cw{cl}, \cw{dl}, \cw{bl},
\cw{ah}, \cw{ch}, \cw{dh}, \cw{bh}

\b \cw{ax}, \cw{cx}, \cw{dx}, \cw{bx},
\cw{sp}, \cw{bp}, \cw{si}, \cw{di}

\b \cw{eax}, \cw{ecx}, \cw{edx}, \cw{ebx},
\cw{esp}, \cw{ebp}, \cw{esi}, \cw{edi}

\b \cw{es}, \cw{cs}, \cw{ss}, \cw{ds}, \cw{fs}, \cw{gs}

\b \cw{fl}, \cw{efl}, \cw{ip}, \cw{eip}

Each two 16-bit registers can be used in a 32-bit register pair, such as:

\b \cw{dxax}

\b \cw{bxcx} (used by \cw{L} load program and \cw{W} write program commands)

\b \cw{sidi}

\b \cw{csip}

Every 16-bit register can be accessed with a \cq{00} suffix,
which puts the register's value in the high word and a constant zero
into the low word.
This is useful with the \cw{PTR} 16:16 far pointer type
in particular, using the specified register for the segment part
with an offset of zero.
For instance:

\b \cw{ax00}

\b \cw{cs00}

\b \cw{es00}

Every 8-bit register can be used as the high byte in a 24-bit register pair
with any 16-bit register as the low word. For example:

\b \cw{dlax}

\b \cw{ahcx}

An 8-bit register with the \cq{00} suffix works similarly
to the 16-bit register case.
The register is used for the high byte of a 24-bit (3byte) value
while the low 16 bits are a constant zero.

Writing to a register pair made up of parts of the same register
(eg \cw{axax}, \cw{alax}) is not well defined and should be avoided.



\H{varmmx} MMX registers - MMxy

If MMX is available, the debuggee's MMX registers
can be accessed as variables.
However, as the debugger only supports 32-bit numbers,
only half of a 64-bit MMX register can be accessed.
The \cq{x} is a digit from 0 to 7.
The \cq{y}, if present, is one of the following letters:

\dt L

\dd Access only low 32 bits

\dt H

\dd Access only high 32 bits

\dt Z

\dd Read low 32 bits, write full 64 bits with zero extension to qword

\dt S

\dd Read low 32 bits, write full 64 bits with sign extension to qword

\dt Letter absent

\dd Same as letter Z


\H{varoptions} Options

\S{vardco} DCO - Debugger Common Options

DCO1 (alias DCO) to DCO7. Dword. Writable.

\S{vardcs} DCS - Debugger Common Startup options

DCS1 (alias DCS) to DCS7. Dword. Read-only.

\S{vardif} DIF - Debugger Internal Flags

DIF1 (alias DIF) to DIF7. Dword. Read-only.

\S{vardao} DAO - Debugger Assembly Options

Dword. Writable.

\S{vardas} DAS - Debugger Assembly Startup options

Dword. Read-only.

\S{vardpi} DPI - Debugger Parent Interrupt 22h

Alias DPRA. Dword. Read-only. Always a 86M segmented pointer.
0 if in TSR mode, or loaded as a device driver, or in bootloaded mode.

\S{vardpr} DPR - Debugger PRocess

Alias DPSP. Word. Read-only. Always a 86M segment.

\S{vardpp} DPP - Debugger Parent Process

Alias DPARENT. Word. Read-only. Always a 86M segment.
0 if in TSR mode, or loaded as a device driver, or in bootloaded mode.

\S{vardps} DPS - Debugger Process Selector

0 while in Real or Virtual 8086 Mode, debugger process selector otherwise.
(The process selector addresses DebugX's PSP and DATA ENTRY section.)
This variable does not exist on non-DPMI lDebug builds.

\S{vardpspsel} DPSPSEL - Debugger PSP Segment/Selector

The debugger's PSP segment while in 86 Mode,
a selector pointing to the same base while in Protected Mode.
This variable exists even on non-DPMI builds,
where it is always the same as DPSP.


\H{varcounts} Default step counts

\dt PPC

\dd Proceed command (\k{cmdp}) default step count

\dt TPC

\dd Trace/Proceed command (\k{cmdtp}) default step count

\dt TTC

\dd Trace command (\k{cmdt}) default step count

All of these are doublewords and default to 1.
For the respective commands, these counts specify
the number of steps to take if none is specified explicitly.
This includes when a command is run by autorepeat,
refer to \k{cmdautorepeat}.
If one of these is set to zero then it is an error
to not specify a count explicitly for
the corresponding command.


\H{varlengths} Default lengths

\dt DEFAULTDLEN

\dd Word. Default length of D/DB/DW/DD commands in bytes (\k{cmdd}).
Only used if DEFAULTDLINES is zero.
Default is 128.

\dt DEFAULTDLINES

\dd Word. Default length of D/DB/DW/DD commands in lines (\k{cmdd}).
Not used if zero.
This is a word variable, but setting it to a value
higher than 7FFFh is invalid.
Default is zero.

\dt DEFAULTULEN

\dd Word. Default length of U command in bytes (\k{cmdu}).
Only used if DEFAULTULINES is zero.
Default is 32.

\dt DEFAULTULINES

\dd Word. Default length of U command in lines (\k{cmdu}).
Not used if zero.
This is a word variable, but setting it to a value
higher than 7FFFh is invalid.
Default is zero.


\H{varlimits} Limits

\S{varrelimit} RELIMIT - RE buffer execution command limit

Doubleword.
Default is 256.
If this many commands are executed from the RE buffer,
the execution is aborted and the command that called RE is continued.

\S{varrecount} RECOUNT - RE buffer execution command count

Doubleword.
This is reset to zero when RE buffer execution starts.
Each time a command is executed from the RE buffer,
this variable is incremented.
If it reaches the value of RELIMIT,
RE buffer execution is aborted.

\S{varrclimit} RCLIMIT - RC buffer execution command limit

Doubleword.
Default is 4096.
If this many commands are executed from the RC buffer,
the execution is aborted.

\S{varrccount} RCCOUNT - RC buffer execution command count

Doubleword.
This is reset to zero when RC buffer execution starts.
Each time a command is executed from the RC buffer,
this variable is incremented.
If it reaches the value of RCLIMIT,
RC buffer execution is aborted.


\H{varreturncodes} Return Codes

\S{varrc} RC - Return Code

Word.
This holds the most recent command's return code.
If the most recent command succeeded, then this is zero.

\S{varerc} ERC - Error Return Code

Word.
This holds the most recent non-zero return code.


\H{varaddresses} Addresses

\S{var_a_addr} A address (AAS:AAO)

AAS: word, AAO: doubleword.
Default address for the assembler.
Updated to point after each assembled instruction.

\S{var_d_addr} D address (ADS:ADO)

Default address for memory dumping.
Updated to point after each dumped memory content.

\S{var_b_addr} Address behind R disassembly (ABS:ABO)

\S{var_u_addr} U address (AUS:AUO)

Default address for the disassembler.

\S{var_e_addr} E address (AES:AEO)

Default address for memory entry.

\S{var_z_addr} DZ address (AZS:AZO)

Default address for DZ command, ASCIZ strings. Terminated by zero byte.

\S{var_c_addr} D$ address (ACS:ACO)

Default address for D$ command, CP/M strings. Terminated by dollar sign \cq{$}.

\S{var_p_addr} D# address (APS:APO)

Default address for D# command, Pascal strings. Prefixed by length count byte.

\S{var_w_addr} DW# address (AWS:AWO)

Default address for DW# command. Prefixed by length count word.

\S{var_x_addr} DX address (AXO)

Default address for DX command. (Only included in DebugX.)


\H{vario} I/O configuration

\S{varior} IOR - I/O Rows

Byte.
Default 1.
Sets the number of rows of the terminal used by DOS or BIOS output.
Setting this to zero disables paging to the DOS or BIOS output.
Setting this to 1 uses the automatic selection.
That means the BIOS Data Area byte at address 484h, plus one, is used.
If using that byte and it is zero, paging is disabled.

\S{varioc} IOC - I/O Columns

Byte.
Default 1.
Sets the number of columns of the terminal used by BIOS input
or DOS input if \cw{getinput} is enabled.
Setting this to zero selects a default (80).
Setting this to 1 uses the automatic selection.
That means the BIOS Data Area word at address 44Ah is used.
This is used by the line input handling
if inputting from the BIOS terminal (int 16h, int 10h),
or if inputting from a DOS terminal when DCO flag 800h is set
(eg by using \cw{INSTALL GETINPUT}).
A value between 2 and 39, inclusive, is not recommended.

\S{variocline} IOCLINE - I/O Columns for splitting lines in \cw{getinput}

Byte.
Default 0.
Sets the number of columns of the terminal at which to split
overlong lines after the user submits an input line
with the \cw{getinput} line editor.
If this is zero, splitting overlong lines is disabled and
it is assumed that the terminal will split lines as desired.
Otherwise, overlong lines (ie those extending past the IOC width)
will be split to have no more than the amount of bytes
specified by the IOCLINE variable.
Makes most sense to set this equal to IOC or DSC, or else to zero.
Any nonzero value is allowed.

\S{varios} IOS - I/O Circular Keypress Buffer Start

Word.
Default 0 or 1Eh.
Indicates where the ROM-BIOS's circular keypress buffer starts.
Value can be nonzero to force a particular offset in segment 40h.
Value can be zero to force using the value at \cw{word [40h:80h]},
using an extension not available on all systems.

On startup the debugger checks whether the extension values are valid.
If they are then the default of the IOS variable is left as zero.
Otherwise, the default is set to 1Eh, which is the default buffer location.

This variable is used to check for Ctrl-C keypresses if the InDOS mode is on
(either InDOS flag set, DCO flag 8 set, or in bootloaded mode)
and serial I/O is not in use
and the flag DCO3 2000_0000h is set.
Setting this variable nonzero and equal to IOE disables Ctrl-C checking.

Modifying this variable should only be done while it is not in use.
That means using DOS for input, using serial I/O for input,
or clearing the DCO3 flag 2000_0000h.
Modifying this variable and the IOE variable should be done together,
so that they are valid together when in use.

\S{varioe} IOE - I/O Circular Keypress Buffer End

Word.
Default 0 or 3Eh.
Indicates where the ROM-BIOS's circular keypress buffer ends.
Value can be nonzero to force a particular offset in segment 40h.
Value can be zero to force using the value at \cw{word [40h:82h]},
using an extension not available on all systems.

Refer to IOS description above.

\S{variol} IOL - I/O Amount of Script Levels to Cancel

Word.
Default 255.
Indicates how many levels of script files and RE buffer execution
to cancel when a Control-C input or critical DOS error
is detected by the debugger.
The effective value will be incremented by one
if IOF flag 1 is set and RE buffer execution is in progress.

Zero indicates to only cancel the current command.
One indicates to cancel the current command,
plus the RE buffer execution if any,
else up to one level of script file execution.
Two indicates to cancel two levels of execution:
either the RE buffer execution
and one level of script file execution,
or up to two levels of script file execution.

The debugger always cancels RE buffer execution first
if it is in progress.
Next, the innermost script file execution is cancelled, if any.

\S{variof} IOF - I/O Flags

Word.
Default 1.
Flags for I/O handling.
Currently defined:

\dt 1

\dd Extra IOL level for RE buffer execution.
If set, RE buffer execution being in progress
increments the effective value of the IOL variable.


\H{var-io-read} I/O reading variables

\dt IOK - Read a keypress

\dd Returns a keypress scancode and/or ASCII text byte.
The keypress is read from the current debugger terminal.
The terminal waits until a keypress arrives,
if none is buffered yet.
The keypress is consumed.
The low byte is an ASCII codepoint or zero.
The high byte is an int 16h scancode or zero.

\dt IOI - Check for input

\dd Returns a nonzero value if input is available
to the current debugger terminal.
The input is not consumed however.
When using DOS, the value 0FFFFh indicates input is available.
When using int 16h, a nonzero return will consist of
a scancode in the high byte and/or an ASCII codepoint in the low byte.
When using serial I/O a nonzero value will be an ASCII codepoint.


\H{varserial} Serial configuration

\S{vardsr} DSR - Debugger Serial Rows

Byte.
Default 24.
Sets the number of rows of the terminal connected via serial port.
Setting this to zero disables paging to the serial port.
Setting this to 1 uses the IOR variable handling.

\S{vardsc} DSC - Debugger Serial Columns

Byte.
Default 80.
Sets the number of columns of the terminal connected via serial port.
Setting this to zero selects a default (80).
Setting this to 1 uses the IOC variable handling.
This is used by the line input handling.
A value between 2 and 39, inclusive, is not recommended.

\S{vardst} DST - Debugger Serial Timeout

Byte.
Default 15.
This gives the number of seconds that
the KEEP prompt upon serial connection waits.
Setting this to zero waits at the prompt forever.

\S{vardsf} DSF - Debugger Serial FIFO size

Byte.
Default 16.
This gives the size of the 16550A's built-in TX FIFO to use.
Set to 15 if using dosemu before revision gc7f5a828 2019-01-22,
see \W{https://github.com/stsp/dosemu2/issues/748}{https://github.com/stsp/dosemu2/issues/748}.

\S{vardspvi} DSPVI - Debugger Serial Port Variable Interrupt number

Byte.
Default 0Bh, corresponding to COM2.
Use 0Ch for COM1.
This specifies the interrupt number to hook
so as to be notified of serial events.
The use of this variable occurs
only when connecting to serial I/O.
The value at that point in time is cached
for as long as the serial connection is in use.

\S{vardspvm} DSPVM - Debugger Serial Port Variable IRQ Mask

Word.
Default 0000_1000b, corresponding to COM2.
Use 0001_0000b for COM1.
This specifies the IRQ mask of which IRQs to enable.
The low 8 bits correspond to IRQ #0 to #7 and
the high 8 bits correspond to IRQ #8 to #15.
If any bit of the high 8 bits is set then generally
the bit 0100b should be set too, to enable the chained PIC.
This circumstance is not automatically detected.
The use of this variable occurs
only when connecting to serial I/O.
The value at that point in time is cached
for as long as the serial connection is in use.

\S{vardspvp} DSPVP - Debugger Serial Port Variable base Port

Word.
Default 02F8h, corresponding to COM2.
Use 03F8h for COM1.
This specifies the I/O port base to address the UART.
The use of this variable occurs
only when connecting to serial I/O.
The value at that point in time is cached
for as long as the serial connection is in use.

\S{vardspvd} DSPVD - Debugger Serial Port Variable Divisor latch

Word.
Default 12, corresponding to 9600 baud.
This specifies the DL value to set during initialisation.
The use of this variable occurs
only when connecting to serial I/O.

\S{vardspvs} DSPVS - Debugger Serial Port Variable Settings

Byte.
Default 0000_0011b, corresponding to 8n1.
(8n1 = 8 data bits, no parity, 1 stop bit.)
This specifies the settings to set up in LCR.
The high bit (80h) generally must be clear.
The use of this variable occurs
only when connecting to serial I/O.

\S{vardspvf} DSPVF - Debugger Serial Port Variable FIFO select

Byte.
Default 0.
This specifies what to write to the FCR.
The low 3 bits (07h) generally must be clear.
The use of this variable occurs
only when connecting to serial I/O.
The value at that point in time is cached
for as long as the serial connection is in use.


\H{vartimer} Timer configuration

These variables control some details of the debugger's timers
used for waiting in a few places.
The affected timers are:

\b SLEEP command

\b KEEP prompt timeout during serial I/O connection

\b Serial output send wait if buffer full

Unaffected timers include:

\b DCO3 flag 0400_0000h (delay for a tick before writing breakpoints),
this only waits until one tick change is observed

\b Interrupt 8 Control pressed check,
this does not count tick changes but rather counts interrupt calls


\S{vargrepidle} GREPIDLE - getc repeat idle count

Byte. Default 0.
If the getc function invokes the idle handling,
it will repeatedly call the idle function
if this variable holds a nonzero value.
The value specifies the amount of repetitions past the first call.
This variable is intended for debugging.


\S{varsrepidle} SREPIDLE - Sleep repeat idle count

Byte. Default 0.
If the SLEEP command invokes the idle handling,
it will repeatedly call the idle function
if this variable holds a nonzero value.
The value specifies the amount of repetitions past the first call.
This variable is intended for debugging.


\S{varsmaxdelta} SMAXDELTA - Maximum encountered delta ticks

Word.
This value is set anew whenever a wait handler
has found a delta ticks larger than the prior value of this variable.
After any wait iteration the variable inevitably will be nonzero.

\S{varsdeltalimit} SDELTALIMIT - Delta ticks limit

Word. Default 5.
This variable specifies the upper limit of the delta between tick low words
accepted as being accurate.

Note that at midnight the tick low word goes from 00AFh or 00B0h to 0000h.
The delta appears to be FF51h or FF50h ticks at that point.
Therefore the limit should be set small enough that the total wait time
is not majorly skewed at midnight.

However, it is possible that the idle handling takes so long
that more than one tick has actually gone by until the wait handling
is run again. For such system setups it can be desirable to
set the limit to more than 1.

A good compromise is to set the limit to between 1 and 6, inclusive.
A limit of 6 ticks only skews for 1/3 of a second at midnight.


\H{vardebug1} _DEBUG1 variables

These variables are not supported by default.
The build option _DEBUG1 must be enabled to include them.
The Test Counter variables work similarly to permanent breakpoint counters:

\b If the counter AND-masked with 7FFFh is zero, it is at a terminal state.

\b If the counter is not yet at a terminal state, it is decremented.

\b If the counter is decremented to zero, it triggers.

\b If the counter is decremented to 8000h or already at 8000h, it triggers.

The default values for all counters and addresses is zero.

\S{vartrx} TRx - Test Readmem variables

If a fault is injected into readmem, it returns the value given in TRV.

\dt TRC - Test Readmem Counter

\dd Word. Each of the TRC0 to TRCF counters
gives one counter for readmem fault injection testing.

\dt TRA - Test Readmem Address

\dd Doubleword. Each of the TRA0 to TRAF counters
gives one linear address for readmem fault injection testing.

\dt TRV - Test Readmem Value

\dd Byte. Default 0.
If a readmem fault is injected, this byte value
is returned by the read instead of the actual memory content.

\S{vartwx} TWx - Test Writemem variables

If a fault is injected into writemem, it returns failure (CY).

\dt TWC - Test Writemem Counter

\dd Word. Each of the TWC0 to TWCF counters
gives one counter for writemem fault injection testing.

\dt TWA - Test Writemem Address

\dd Doubleword. Each of the TWA0 to TWAF counters
gives one linear address for writemem fault injection testing.

\S{vartlx} TLx - Test getLinear variables

If a fault is injected into getlinear, it returns failure (CY).

\dt TLC - Test getLinear Counter

\dd Word. Each of the TLC0 to TLCF counters
gives one counter for getlinear fault injection testing.

\dt TLA - Test getLinear Address

\dd Doubleword. Each of the TLA0 to TLAF counters
gives one linear address for getlinear fault injection testing.

\S{vartsx} TSx - Test getSegmented variables

If a fault is injected into getsegmented, it returns failure (CY).

\dt TSC - Test getSegmented Counter

\dd Word. Each of the TSC0 to TSCF counters
gives one counter for getsegmented fault injection testing.

\dt TSA - Test getSegmented Address

\dd Doubleword. Each of the TSA0 to TSAF counters
gives one linear address for getsegmented fault injection testing.


\H{vardebug3} _DEBUG3 variables

These variables are not supported by default.
The build option _DEBUG3 must be enabled to include them.
These variables are used to test the read-only masking.
Read-only masking makes it so that bits given in the mask are read-only.
Bits that are clear in the mask are writable.

\S{varmt0} MT0 - Mask Test 0

Doubleword. Default 0. Mask AA55_AA55h.

\S{varmt1} MT1 - Mask Test 1

Doubleword. Default 0011_0022h. Mask 00FF_00FFh.


\H{varyy} Y command variables

Y command variables can be used when
the Y command (as application or bootloaded)
has been used to open a script file.
YSx (Y Script) variables are generic and refer to whatever Y file is opened.
YBx (Y Bootloaded script) variables refer to opened Y files while bootloaded.
YHx (Y Handle script) variables refer to opened Y files as application.

\S{varysf} YSF - Y Script Flags

Word. Partially read-write, partially read-only.

Flag 4000h controls whether script file input is displayed or not.
Prepending an AT sign (@) to a line that is read from a script file
will hide the input of that line.
Setting YSF flag 4000h will hide all input lines instead.
The effect is similar to prepending @ to every line.

YSF variables are only available while executing script files.


\H{varv} V variables - Variables with user-defined purpose

Doubleword. Default zero. V0 to VF or V00 to VFF each specify one variable.
It is valid to refer to any V variable using an index expression.
Index expression means that the variable name (\cw{V})
is immediately followed by an opening parenthesis,
followed by a numeric expression which evaluates
to a number below 100h.


\H{varprocess} PSP variables

All of these are read-only.
All of them are zero if in bootloaded mode.

\S{varpsp} PSP - Process Segment Prefix

Word. Always a segment,

\S{varppr} PPR - Process PaRent

Alias PARENT. Word. Always a segment.

\S{varppi} PPI - Process Parent Interrupt 22h

Alias PRA. Dword. Always a 86 Mode segmented address.

\S{varpspsel} PSPSEL - PSP segment or selector

Alias PSPS. Word. Segment or selector according to mode.


\H{varsr} SR variables - Search Results

\S{varsrc} SRC - Search Result Count

Doubleword. Read only. Amount of matches found by last S command.

\S{varsrs} SRS - Search Result Segment

Word. Read only. SRS0 to SRSF each specify one variable.
Search result segments of last S command's matches.

\S{varsro} SRO - Search Result Offset

Word or doubleword (DebugX). Read only.
SRO0 to SROF each specify one variable.
Search result offsets of last S command's matches.
It is valid to refer to any SRO variable using an index expression.
Index expression means that the variable name (\cw{SRO})
is immediately followed by an opening parenthesis,
followed by a numeric expression which evaluates
to a number below 10h.


\H{varaccess} Access variables

These variables can be left out of the build.
The build option \cw{_MEMREF_AMOUNT} must be enabled to include them.

\S{varaccess-readadr} READADR

Doubleword. Read only. READADR0 to READADR3 each specify one variable.
(Amount of READADR variables can be configured at build time
with the option _ACCESS_VARIABLES_AMOUNT, which defaults to 4.)
Linear addresses of string, stack, or explicit memory operand reads.
Initialised by the R command.
Unused variables are reset to zero by the R command.
It is valid to refer to any READADR variable using an index expression.
Index expression means that the variable name (\cw{READADR})
is immediately followed by an opening parenthesis,
followed by a numeric expression which evaluates
to a number below 4.

\S{varaccess-readlen} READLEN

Doubleword. Read only. READLEN0 to READLEN3 each specify one variable.
Length of string, stack, or explicit memory operand reads.
Initialised by the R command.
Unused variables are reset to zero by the R command.
It is valid to refer to any READLEN variable using an index expression.

\S{varaccess-writadr} WRITADR

Doubleword. Read only. WRITADR0 to WRITADR3 each specify one variable.
Linear addresses of string, stack, or explicit memory operand writes.
Initialised by the R command.
Unused variables are reset to zero by the R command.
It is valid to refer to any WRITADR variable using an index expression.

\S{varaccess-writlen} WRITLEN

Doubleword. Read only. WRITLEN0 to WRITLEN3 each specify one variable.
Length of string, stack, or explicit memory operand writes.
Initialised by the R command.
Unused variables are reset to zero by the R command.
It is valid to refer to any WRITLEN variable using an index expression.


\H{varmachine} Machine type variables

\dt MMT - Maximum Machine Type encountered

\dd Set whenever the disassembler encounters
an instruction requiring a machine type
that is higher than this variable's current value.
Writable.

\dt MACHX86 - Machine type for assembler and disassembler

\dd Current machine type to use for assembler and disassembler.
Read-only, use M commands to modify.

\dt MACHX87 - Coprocessor encoded machine type

\dd Contains valid argument to M command:
C0h if no coprocessor,
0Ch if coprocessor matching machine,
C2h if machine is a 386 with a 287 coprocessor.
Read-only, use M commands to modify.


\H{varlfsr} LFSR variables

These variables provide access to a simple LFSR
(Linear Feedback Shift Register).
The default taps are chosen so that a full-range 32-bit LFSR
is in use.
That means there are 4 giga binary steps, minus one, and
all possible 32-bit values are in use except for the all zeros value.
A step of the LFSR is done by shifting the old value to the right once.
If the bit shifted out is a 1, then the new value is obtained by
applying the LFSR taps as a XOR mask to the shift result.
If the bit shifted out is a 0, then the new value is simply the shift result.


\dt LFSR - Forward LFSR variable

\dd Whenever this variable is read, it first executes an LFSR step
from the variable's prior value.
What is actually read is the new value after the step.
This variable is initialised to the constant 2 on startup of the debugger.
That means that with the default taps,
the first read will return 1, the second 8020_0003h, etc.

\dt LFSRTAP - Taps to use for the LFSR

\dd This variable determines the tap bits to use for the LFSR.
The default is 8020_0003h, leading to a full-range 32-bit LFSR.
Different values may be chosen.
The highest bit of the taps value determines
how wide the forward LFSR is.

\dt RLFSR - Reverse LFSR variable

\dd Similar to the forward LFSR variable, except it runs backwards.
This also uses the LFSRTAP variable, however the taps are shifted
to the left once, and the least-significant bit is set to 1.
In addition, the RLFSRTOP variable is used to get the check mask,
by shifting left the constant 1 by RLFSRTOP binary digits places.
The check mask is used to determine whether
to XOR mask with the taps or not.
The check mask also indicates what bit to clear in the taps
in order to create the reverse taps.

\dt RLFSRTOP - Reverse LFSR top bit count

\dd This variable indicates what bit to check in order to
determine whether the reverse LFSR should tap or not.
It also indicates what bit to clear in the creation of the reverse taps.
Its default is 1Fh (31), which lends itself to a 32-bit taps value.
Setting this to a number higher than 1Fh (31) is invalid,
and may be subject to behaviour as yet undetermined.


\H{varri} RIxxy - Real 86 Mode Interrupt vectors

These read-only variables provide access to the 86 Mode
interrupt vectors in a more accessible format.

The xx must be a single or two hexadecimal digits,
or an index expression in parentheses which
evaluates to a number below 256.

The y must be one of the following letters:

\b P - Read vector as a 16:16 segmented pointer (dword),
ready for use as a pointer-type expression.
(Actual use as a pointer-type expression
still requires a \cw{PTR} type keyword.)

\b S - Read vector's segment. (Word.)

\b O - Read vector's offset. (Word.)

\b L - Read vector as a linear address. (3byte.)


\H{varfldot} FL.xF - Flag status

These read-only variables support reading the flag status
of certain flags.

The x must be one letter to form one of the following names:

\dt CF

\dd Carry Flag

\dt PF

\dd Parity Flag

\dt AF

\dd Auxiliary carry Flag

\dt ZF

\dd Zero Flag

\dt SF

\dd Sign Flag

\dt IF

\dd Interrupt Flag

\dt DF

\dd Direction Flag

\dt OF

\dd Overflow Flag

Note that the FL.xF flags are read-only.
To write to a flag with the R command,
it is valid to specify just xF as the variable name,
but this is not valid within expressions to read the flag status.
(It cannot be supported in expressions because
some of the flag names are all hexadecimal digits, such as CF.)


\H{varhhresult} HHRESULT - H command result

Dword. Result of most recent H command.
(If H twofold operation is used then
the addition result is stored in the variable.)


\H{vardaresult} DARESULT - D.A command result

Word. Result of most recent D.A command.
This is set to 0FFFFh by a failed D.A command
and to the allocated selector by a successful D.A command.
This variable is only present in lDebugX.


\H{varxaresult} XARESULT - XA command result

Word. Result of most recent XA command.
This is set to 0FFFFh by a failed XA command
and to the allocated handle by a successful XA command.
This variable is only present if the debugger was built
with the \cw{_EMS} option or the x.eld has been installed.


\H{varint8ctrl} INT8CTRL - Interrupt 8 Control pressed detection time

Word. Number of ticks to wait with Control pressed
until breaking into the debugger.
This variable is only used if the interrupt 8 handler is installed.
If the handler detects that Control is pressed continuously
for this length of time while not in the debugger
then the handler will break into the debugger.
Default is set up for about 5 seconds (5 times 18).
Set to 0 to disable Control pressed detection.


\H{vardevice} Device mode variables

\dt DEVICEHEADER

\dd Dword. Read-only. Gives segmented 16:16 address of device header
installed by the debugger.
Zero if not in device mode.

\dt DEVICESIZE

\dd Word. Read-only. Gives amount of paragraphs allocated to device.
Zero if not in device mode.


\H{varqqcode} QQCODE - Q command termination return code

Byte. Default 0. This variable is used to set the return code
used by the debugger to terminate itself with
interrupt 21h service 4Ch.
This only happens if the debugger is in application mode
and not in TSR mode,
or a device mode debugger has been attached to a process.


\H{vartermcode} TERMCODE - Debuggee termination return code

Word. Debugger sets this value when it is entered
from a debuggee having terminated.
The value is what interrupt 21h service 4Dh returned.


\H{varddtextand} DDTEXTAND - Data dump text AND mask

The variable \cw{DDTEXTAND} is used as a mask to modify
the text code of a data dump before display. It defaults to 0FFh.
Setting this to 7Fh will mimic MS-DOS Debug's display
of text in its data dump, masking off the high bit.
In this case the \cw{TOP} setting of the D command has no effect.


\H{varamis} AMIS variables

\S{vartryamisnum} TRYAMISNUM

The TRYAMISNUM variable is a writable byte variable.
It defaults to 0.
Its content is tried first when searching a free multiplex number.
After that the debugger currently will search
starting from number 0 up to 255.

\S{varamisnum} AMISNUM

The AMISNUM variable is a read-only byte variable.
It contains the actually used multiplex number
while the DIF4 flag 8 is set.
Otherwise its content is not used and is considered stale.

\S{vartrydebugnum} TRYDEBUGNUM

The TRYDEBUGNUM variable is a writable byte variable.
It defaults to 255.
It is similar to TRYAMISNUM, however its content is tried first
to find another debugger instance.
After that the debugger currently will search
starting from number 255 down to 0.
Unused if it matches the debugger's
own currently installed AMIS handler's multiplex number.
This is used by the debugger to find the following services
provided by another debugger instance:

\b Update IISP Header

\b Install DPMI entrypoint hook

\b Install fault areas

None of these services are detected and used
if DCO3 flag 800_0000h is set.
(In the past this flag was wrongly documented
as applying to the Update IISP Header service only.)


TRYDEBUGNUM is as well used by Extensions for lDebug
to find the following services:

\b AMISMSG (one or several listing hints in ELD linker or hint.eld)

\b AMISOTH (ldmemoth.eld, instnoth.eld, hintoth.eld)

\b AMISCMD (inject.eld)

The DCO3 option flags do not affect the ELD use of AMIS services.


\S{vardebugfunc} DEBUGFUNC

The DEBUGFUNC variable is a read-only word variable.
It defaults to 0.
When the Update IISP Header function of the debugger is called
and a search for another debugger happens,
then this variable receives a 0 if no other debugger is found.
It receives a value with the low byte equal to 30h
if another debugger was found.
(The low byte is set up as the AMIS private function number
of the Update IISP Header service.)
The high byte is equal to the detected multiplex number then.


\H{varcount} COUNT - List length count

Dword. Any successfully parsed COUNT or S command will
write the length of the pattern it counted, given in bytes,
to this variable.


\H{varrhcount} RHCOUNT - Count of RH buffer entries

Word. Reads as the current amount of buffered RH mode entries.
May be corrupted if RH mode is not currently enabled.


\H{vareldamount} ELDAMOUNT - Amount of installed ELDs

Word. Reads as the amount of residently installed Extensions for lDebug.
This variable is only supported if the amount.eld has been installed.
Due to the ELD architecture,
this variable will always read as above-or-equal 2.


\H{varcip} CIP - Current CS's EIP or IP

In Protected Mode in lDebugX, this variable is either a word or dword.
Which one it is depends on the D bit of the descriptor
corresponding to the current CS selector.
In Real or Virtual 86 Mode this variable is always a word.
In lDebug without DPMI support this variable is also always a word.


\H{varcsp} CSP - Current SS's ESP or SP

In Protected Mode in lDebugX, this variable is either a word or dword.
Which one it is depends on the B bit of the descriptor
corresponding to the current SS selector.
In Real or Virtual 86 Mode this variable is always a word.
In lDebug without DPMI support this variable is also always a word.


\H{varboot} Boot loading variables

\S{varbootunitfl} BOOTUNITFLxx

The boot unit flags are 256 partially writable byte variables.
Every flag byte corresponds to an int 13h unit.
The following flags are defined:

\b 01h Force CHS access, do not detect LBA support with 13.41

\b 02h Force LBA access, do not detect LBA support with 13.41

\b 04h Force use of BPB's CHS geometry, do not detect with 13.08

The flag 01h takes precedence over 02h if both are set.

These flags match the low flags of the lDOS iniload query patch site.
All the flags are by default pre-initialised to zero,
but this can be overridden in two ways.

The source macro file debug.mac contains the following equates and defines:

\c lufForceCHS:		equ 1
\c lufForceLBA:		equ 2
\c lufForceGeometry:	equ 4
\c luf_mask_writable equ lufForceCHS | lufForceLBA | lufForceGeometry
\c
\c		numdef LUF_DEFAULT_DISKETTE, 0
\c		numdef LUF_DEFAULT_HARDDISK, 0

The first define is the default value used for all diskette units,
that is unit numbers below 80h.
The second define is the default value used for hard disk units,
that is unit numbers above-or-equal 80h.

Further,
\W{https://pushbx.org/ecm/doc/ldosboot.htm#protocol-sector-iniload-patch}{as documented for lDOS boot},
the query patch site of a bootable lDebug executable
can have its default changed during the build
or can be patched later.
If the highest bit of the active patch site byte (80h) is set
then the flags are used to initialise the boot unit flags
of the loaded from unit.

The low two flags exactly match the lDebug boot unit flags.
The flag 04h differs a little, to lDOS iniload it means
to pass along the geometry either detected by
or hardcoded in the prior loader.
To lDebug, the flag means to probe the boot sector
(presumed to be a diskette or superdiskette with a FAT FS BPB).
In both cases, an interrupt 13h service 08h call is avoided.


\C{intref} Interrupt Reference

\H{intmandatory} Mandatory interrupt hooks

\b Interrupt 0 - Divide error

\b Interrupt 1 - Trace

\b Interrupt 3 - Breakpoint

\b Interrupt 6 - Invalid opcode

\b Interrupt 18h - Diskless boot hook

\b Interrupt 19h - Boot load

These interrupts are always hooked by the debugger.
For the non-_DEBUG builds they are
hooked during initialisation and
the debugger attempts to unhook them when quitting.
The highest 8 bits of the dword variable DCO4
control whether they are unhooked
only if reachable (bits in DCO4 zero),
or forcibly so if not reachable (bits in DCO4 ones).
If not forcibly unhooking and an interrupt handler
is not reachable then the Q command fails.

For DDebug, these interrupts are hooked within
the \cw{run} function and unhooked
before the \cw{run} function returns.
This unhooking in DDebug is always forcible;
that is, if not reachable then the interrupts
are unhooked by simply updating
the IVT entries with whatever handlers are
stored as the next vectors in DDebug's entrypoints.

CDebug can run in debuggable mode (like DDebug)
or with debuggable mode disabled.
If the cmd3 loop detects a change in the DCO6 flag 100h
then it will toggle debuggable mode to match the flag.
This will involve hooking the mandatory handlers
or unhooking them (forcibly).

As a special exception, if the debugger detects
that it is running on an HP 95LX,
then interrupt 6 is never hooked.
This supports the different use of this software interrupt
by the software or firmware on this type of device.


\H{intserial} Serial interrupt

This interrupt hook is optional.
Setting the DCO flag 4000h (enable serial I/O)
instructs the debugger
to set up this interrupt hook.
Clearing the flag or using the \cw{Q} command
instructs the debugger to unhook its handler.
The DCO4 flag 1_0000h controls whether the
interrupt unhooking is forcible (flag set)
or not (flag clear).

The exact interrupt number used as serial interrupt
depends on the DSPVI variable
at the point in time at which serial I/O is enabled.
The default is interrupt 0Bh, corresponding to COM2.


\H{int2F} Interrupt 2Fh - Multiplex (DPMI entrypoint)

This interrupt is only hooked by DebugX.
This interrupt hook is optional.
Setting the DCO4 flag 2 instructs the debugger
to set up this interrupt hook.
The debugger tries to hook this interrupt
if it runs application code in Real or Virtual 86 Mode.
Clearing the flag,
entering Protected Mode, or using the \cw{Q} command
instructs the debugger to unhook its handler.
The DCO4 flag 2_0000h controls whether the
interrupt unhooking is forcible (flag set)
or not (flag clear).

This interrupt is hooked to intercept calls to
function 1687h, used to detect the DPMI entrypoint.
DebugX attempts to hook this service to
return its own entrypoint to the caller.
The hook may fail if the DPMI host handles
interrupt 2Fh calls before chaining to the
86 Mode handler chain.
(MS Windows 4.x and older dosemu are reported to do this.)


\H{int8} Interrupt 8 - Timer

This interrupt hook is optional.
Setting the DCO4 flag 4 instructs the debugger
to set up this interrupt hook.
Clearing the flag or using the \cw{Q} command
instructs the debugger to unhook its handler.
The DCO4 flag 4_0000h controls whether the
interrupt unhooking is forcible (flag set)
or not (flag clear).

This interrupt is used to detect
the double Control-C via serial I/O condition.
If the serial I/O handler of the debugger
receives two Control-C keypresses
while the debugger is busy running an application
then the interrupt 8 hook will interrupt the run.

This interrupt is also used to detect
the Control pressed for 5 seconds condition.
Similarly to the serial I/O double Control-C condition,
this will make the debugger interrupt the current run.


\H{int2D} Interrupt 2Dh - Alternate Multiplex Interrupt

This interrupt hook is optional.
Setting the DCO4 flag 8
or running an \cw{INSTALL AMIS} command
instructs the debugger
to set up this interrupt hook.
Clearing the flag
or running \cw{UNINSTALL AMIS}
or using the \cw{Q} command
instructs the debugger to unhook its handler.
The DCO4 flag 8_0000h controls whether the
interrupt unhooking is forcible (flag set)
or not (flag clear).

This interrupt allows other programs to detect
the debugger in the AMIS interface.
The vendor string is \cq{ecm} and the product string \cq{lDebug}.
The description string contains the same display name
and version as the command line help.
There are two real uses of this.
First, the
AMIS function 4, which will return
the list of interrupt entrypoints of the debugger.
Second, lDebug's private AMIS functions 30h, 31h, 33h, 40h, 41h, 42h, and 43h.
They are described in the next sections.

This interrupt hook only succeeds if the current handler is valid.
That is, an offset not equal to FFFFh and a segment not equal to zero.
Another condition is that the debugger needs to detect
an unused AMIS multiplex number to allocate.
This is done automatically when hooking the interrupt.
If either condition fails then a message is displayed
and the debugger clears the DCO4 flag 8 on its own.

The TRYAMISNUM variable is a writable byte variable.
It defaults to 0.
Its content is tried first when searching a free multiplex number.
After that the debugger currently will search
starting from number 0 up to 255.

The AMISNUM variable is a read-only byte variable.
It contains the actually used multiplex number
while the DIF4 flag 8 is set.
Otherwise its content is not used and is considered stale.

Note that the AMIS interface is not AMIS-compliant in a few ways:

\b The uninstall function returns 00h (not implemented).

\b If lDDebug or lCDebug are in debuggable mode,
their mandatory handlers will still be listed
in the AMIS function 4 interrupt list
despite not being installed.
(Their downlink fields will contain FFFFh:FFFFh then.)

\b If the build option _CATCHSYSREQ is enabled then the SysReq
hook will not be listed for AMIS function 5.
The interrupt 8 Control pressed hook is also not listed.


\S{int2Dfunc30} AMIS private function 30h - Update IISP Header

This function is provided for use by our programs
that use AMIS multiplexers and
interrupt handler entrypoints with IISP headers.
All TSRs (including RxANSI, lClock, SEEKEXT, KEEPHOOK,
FDAPM, FreeDOS SHARE) and SHUFHOOK use this function.
(The debugger itself also uses this function,
if it is provided by another resident debugger.)

\c lDebug - Update IISP Header
\c INP:    al = 30h
\c         ds:si -> source IISP header (or pseudo header)
\c         es:di -> destination IISP header
\c OUT:    al = FFh to indicate suppported,
\c          si and di both incremented by 6
\c          destination's ieNext field updated from source
\c         al != FFh if not supported,
\c          si and di unchanged
\c CHG:    -
\c REM:    This function is intended to aid in debugging
\c          handler re-ordering, removal, or insertion.
\c          The 32-bit far pointer needs to be updated
\c          as atomically as possible to avoid using
\c          an incorrect pointer.
\c         Test case: Run a program such as our TSRs'
\c          uninstaller or SHUFHOOK and step through it
\c          with "tp fffff" when operating on something
\c          crucial such as interrupt 21h. Without this
\c          function the machine will crash!
\c         To enable this function to be called, first run
\c          the command "r dco4 or= 8", or "INSTALL AMIS"
\c           (install our AMIS multiplexer handler).
\c         Other workaround: Use SILENT for TP and disable
\c          DCO3 flag 4000_0000 (do not call int 21.0B to
\c          check for Ctrl-C status).
\c         Yet another workaround: Set flag DCO 8 (enable
\c          fake InDOS mode, avoid calling int 21h).
\c REM:    The source may be a pseudo IISP header. In this
\c          case the ieEntry field should hold 0FEEBh
\c          (jmp short $) and the ieSignature field
\c          should indicate the source, eg "VT" for the IVT
\c          or "NH" for inserting a New Handler.


\S{int2Dfunc31} AMIS private function 31h - Install DPMI entrypoint hook

This function is for use by lDDebugX (or lCDebugX).
It instructs lDebugX (or lCDebugX) to install its DPMI entrypoint hook.
It is called by the debuggable debugger right before
it tries to install its own hook.
Non-zero return values in AL indicate the function is supported.
A return value of 0FFh in AL indicates success.
Other non-zero return values indicate that no hook occurred.
Non-DPMI builds of lDebug return zero.
This function should be called only while the InDOS flag is zero.

\c lDebugX - Install DPMI hook
\c INP:    al = 31h
\c OUT:    al = FFh if installed
\c         al = FEh..F0h if not installed but call is supported
\c         al = 00h if not supported
\c CHG:    -
\c STT:    not in DOS


\S{int2Dfunc32} AMIS private function 32h - Reserved for lDebugX

\c lDebugX - Reserved
\c INP:    al = 32h



\S{int2Dfunc33} AMIS private function 33h - Install fault areas

This function is by default provided by lDebugX
(including the variants lCDebugX and lDDebugX)
and is for use by lDDebugX as well as lCDebugX (in debuggable mode).
It is called when the debuggable debugger
is instructed to INSTALL AREAS.

\c lDebugX - Install fault areas
\c INP:    al = 33h
\c         dx:bx -> fault area structure of client
\c OUT:    al = FFh if installed
\c         al = FEh..01h if not installed but call is supported
\c         al = 00h if not supported
\c CHG:    al, bx, cx, dx, si, di, es, ds
\c REM:    The area structure is defined in the lDebug sources'
\c          debug.mac file. The first 32 bytes of the structure
\c          start with a signature word, which is equal to the
\c          word value CBF9h (encoding the instruction sequence
\c          of stc \ retf) if the structure is not currently
\c          installed into any debugger. The remainder of the
\c          32 bytes, as well as the details of how the first
\c          two bytes are used otherwise, are private to the
\c          debugger that provides this service (the server).
\c         The area structure may be far-called in 86 Mode. The
\c          only currently defined function (in al) for this call
\c          is function 00h, which attempts to uninstall the area
\c          structure which is being called. It is valid for
\c          either the server or the client to uninstall an
\c          area structure if they so wish.
\c         The fields of the structure behind the first 32 bytes
\c          point to a number of sub-structures and area function
\c          lists and area lists. All of these structures are
\c          to be accessed using the same segment as the main
\c          area structure. They contain linear start and linear
\c          end addresses, which the client sets up before it
\c          tries to install the areas. The linear start address
\c          is also assumed to point to the segment base address
\c          which is used as the reference for the area functions
\c          and areas. (They do not have to match the offset part
\c          actually used to run the code, but the lists must be
\c          based on the linear start address.)


\S{int2Dfunc40} AMIS private function 40h - Display message

This function is provided by an ELD
hooking into the debugger's AMIS handler.
The ELD is installed by running \cq{ext amismsg.eld install}.
The function provides a way to display a single message,
of up to 384 Bytes,
to the debugger terminal.
(Older revisions only allowed a message size up to 128 Bytes.)
The message is displayed by the ELD's inject handler,
before the next debugger command is read in the \cw{cmd3} command loop.

\c lDebug - AMIS message ELD - Display message to debugger terminal
\c INP:    al = 40h
\c         dx:bx -> ASCIZ message, will be truncated if > 384 Bytes
\c OUT:    al = 00h if not supported
\c         al = FFh if supported and full message stored
\c          (older revisions unconditionally returned al = FFh)
\c         al = FEh if supported and truncated message stored
\c          (truncation may occur at 383 or 384 Bytes of non-NUL text)
\c REM:    Older versions of the ELD only had a buffer of 128 Bytes.

Note that the address in \cw{dx:bx} is a segmented 86 Mode address
as the AMIS interface operates in Real/Virtual 86 Mode.
However, \cw{dx} was chosen to pass the segment
to simplify calling the interface from Protected Mode.
PM code must ensure to fill the register with a segment value,
not a Protected Mode selector.

This function is used by the ELD linker or hint.eld to pass along
offset hints to TracList, refer to \k{debugging-eld-offset-hint}.


\S{int2Dfunc41} AMIS private function 41h - Query message status

This function is provided by the same ELD as function 40h.
It allows to query whether a stored messsage
has been displayed yet.

\c lDebug - AMIS message ELD - Query message status
\c INP:    al = 41h
\c OUT:    al = 00h if not supported
\c         al = 01h if supported and no message is stored
\c         al = 02h if supported and message is still stored (not yet displayed)


\S{int2Dfunc42} AMIS private function 42h - Get other link data

This function is provided by an ELD
hooking into the debugger's AMIS handler.
The ELD is installed by running \cq{ext amisoth.eld install}.
The function exports the debugger's link data
for use by "other link" ELDs running in another debugger instance.

\c lDebug - AMIS other debugger link ELD - Get other link data
\c INP:    al = 42h
\c OUT:    al = 00h if not supported
\c         al = FFh if supported
\c          bx (86M segment) => link tables
\c          cx (selector) => link tables
\c          dx (86M segment) => PSP
\c          si (selector) => PSP
\c          di -> link info in link tables section
\c REM:    If the debugger is without DPMI support or if not in PM,
\c          the selector values may be uninitialised or stale.


\S{int2Dfunc43} AMIS private function 43h - Inject a debugger command

This function is provided by an ELD
hooking into the debugger's AMIS handler.
The ELD is installed by running \cq{ext amiscmd.eld install}.
The function allows to send commands to be injected
into the command loop of the debugger.

Multiple commands can be injected back to back.
They will be injected in the order of the calls to this function.
However, the buffer is of a fixed size.
(Currently, 1024 Bytes.)
If the buffer is full, an error will be returned to the caller.

\c lDebug - AMIS command ELD - Inject a debugger command
\c INP:    al = 43h
\c         cx = flags, all reserved for now (must pass as 0)
\c         dx:bx -> message in byte-counted string,
\c          1 byte length (<= 254)
\c          N bytes text, length matching the value of length byte
\c          1 byte Carriage Return (= 13)
\c OUT:    al = 00h if not supported
\c         al = 01h if supported, but buffer is full
\c         al = 02h if supported, but unknown bit set in cx
\c         al = FFh if successfully stored in buffer


\C{serviceref} Service Reference

These are the services called by the debugger.


\H{service10} Interrupt 10h

Used for output while InDOS, DCO flag 8 set, bootloaded,
when \cq{INSTALL BIOSOUTPUT} was used (DCO6 flag 200h set),
or when DCO6 flag 100_0000h set.

\dt Function 02h

\dd Set cursor position
(only used if highlighting)

\dt Function 03h

\dd Get cursor position
(only used if highlighting,
indicates to highlight to int 10h if supported)

\dt Function 06h

\dd Scroll up window
(used if CLEAR command done while writing to int 10h)

\dt Function 08h

\dd Get video attribute
(only used if highlighting)

\dt Function 09h

\dd Set video attribute
(only used if highlighting)

\dt Function 0Eh

\dd Teletype output

\dt Function 0Fh

\dd Get video mode and page


\H{service16} Interrupt 16h

Used for input while InDOS, DCO flag 8 set, bootloaded,
or DCO6 flag 100_0000h is set.

\dt Function 00h

\dd Read keypress (wait until keypress available, consume it)

\dt Function 01h

\dd Read keypress (return if no keypress available, retain it if any)


\H{service2F} Interrupt 2Fh

\dt Function 1261h

\dd PTS-DOS: Get first UMCB

\dt Function 1680h

\dd Idle (Release timeslice to multitasker)

\dt Function 1687h

\dd Get DPMI entrypoint
(used and hooked by lDebugX)

\dt Function 4300h, 4310h

\dd XMS detection and get entrypoint

\dt Function 4A06h

\dd RPL adjust base memory size
(called by booted debugger if RPL signature present)


\H{service12} Interrupt 12h

Called by booted debugger to determine base memory size.


\H{servicepm31} Protected Mode Interrupt 31h

Used by lDebugX while in Protected Mode.

\dt Function 0000h

\dd Allocate LDT descriptor

\dt Function 0001h

\dd Free LDT descriptor

\dt Function 0002h

\dd Get selector from segment

\dt Function 0003h

\dd Get next selector increment value

\dt Function 0006h

\dd Get segment base

\dt Function 0007h

\dd Set segment base

\dt Function 0008h

\dd Set segment limit

\dt Function 0009h

\dd Set descriptor access rights

\dt Function 000Ah

\dd Create alias descriptor

\dt Function 000Bh

\dd Get descriptor

\dt Function 000Ch

\dd Set descriptor

\dt Function 0200h

\dd Get 86M interrupt vector

\dt Function 0201h

\dd Set 86M interrupt vector

\dt Function 0202h

\dd Get PM exception vector

\dt Function 0203h

\dd Set PM exception vector

\dt Function 0204h

\dd Get PM interrupt vector

\dt Function 0205h

\dd Set PM interrupt vector

\dt Function 0300h

\dd Call Real/Virtual 86 Mode interrupt

\dt Function 0301h

\dd Call Real/Virtual 86 Mode far function

\dt Function 0305h

\dd Get raw mode switch save state addresses

\dt Function 0306h

\dd Get raw mode switch addresses

\dt Function 0900h

\dd Disable Virtual Interrupt Flag

\dt Function 0901h

\dd Enable Virtual Interrupt Flag

\dt Function 0902h

\dd Get Virtual Interrupt Flag


\H{servicepm2F} Protected Mode Interrupt 2Fh

\dt Function 1680h

\dd Idle (Release timeslice to multitasker)

\dt Function 168Ah

\dd Determine whether DOS extender is available.


\H{servicepm21} Protected Mode Interrupt 21h

\dt Function 7305h

\dd Read/write sectors from/to DOS drive.
Used to implement L and W command.

\dt Function 4Ch

\dd Terminate DPMI client and process


\H{servicepm25} Protected Mode Interrupt 25h

Read sectors from DOS drive.
Used to implement L command.


\H{servicepm26} Protected Mode Interrupt 26h

Write sectors to DOS drive.
Used to implement W command.



\H{serviceE6} Interrupt E6h

\dt Function bx = 0, ax = -1

\dd Used by booted debugger to implement BOOT QUIT command
when running in dosemu2.

\dt Function ax = 9

\dd Called early in debugger init
when running in dosemu2.
This call instructs the VM to start its \cw{-input} injection.
It is normally only needed when booting the debugger.


\H{service15} Interrupt 15h

\dt Function 87h

\dd Used by DX command to read memory.

\dt Function 5301h, 530Eh, 5307h

\dd Used by booted debugger to implement BOOT QUIT command
when running in qemu.

\dt Function 4DD4h, bx = 0

\dd Detect HP 95LX


\H{service13} Interrupt 13h

Used by the booted debugger to load scripts, ELDs, or kernel executables.

\dt Function 00h

\dd Reset disk system

\dt Function 02h

\dd Read sector with CHS addressing

\dt Function 03h

\dd Write sector with CHS addressing

\dt Function 08h

\dd Query CHS geometry

\dt Function 41h

\dd Detect LBA extensions support

\dt Function 42h

\dd Read sector with LBA

\dt Function 43h

\dd Write sector with LBA


\H{service19} Interrupt 19h

Boot load. Used if booting the debugger fails.


\H{service2D} Interrupt 2Dh

Used to access Alternate Multiplex Interrupt Specification TSRs.
Can be used while bootloaded too.

\dt Function 00h

\dd Installation check.
Determines whether an AMIS number is in use.

\dt Function 04h

\dd Determine chained interrupts.
Determines interrupt entrypoints.

\dt AMIS private functions 30h, 31h, 33h, 40h, 41h, 42h, 43h of lDebug
(refer to \k{int2D})


\H{service25} Interrupt 25h

Read sectors from DOS drive.
Used to implement L command.
Only used if the debugger is loaded as a DOS application
or DOS device driver.


\H{service26} Interrupt 26h

Write sectors to DOS drive.
Used to implement W command.
Only used if the debugger is loaded as a DOS application
or DOS device driver.


\H{service21} Interrupt 21h

DOS services. Only used while not InDOS.
(Only used if the debugger is loaded as a DOS application
or DOS device driver.)

\dt Function 08h

\dd Get standard input keypress

\dt Function 0Ah

\dd Line buffered standard input

\dt Function 0Bh

\dd Check standard input available / Check Control-C

\dt Function 19h

\dd Get default drive

\dt Function 1Ah

\dd Set DTA (used by list.eld)

\dt Function 25h

\dd Set interrupt vector

\dt Function 29h

\dd Parse filename

\dt Function 2Fh

\dd Get DTA (used by list.eld and dtadisp.eld)

\dt Function 3000h

\dd Get DOS version

\dt Function 3306h

\dd Get true DOS version

\dt Function 34h

\dd Get InDOS flag address

\dt Function 35h

\dd Get interrupt vector

\dt Function 3700h

\dd Get switch character

\dt Function 3Ch

\dd Create file

\dt Function 3Dh

\dd Open file

\dt Function 3Eh

\dd Close file

\dt Function 3Fh

\dd Read from file

\dt Function 40h

\dd Write to file
(Used to write to stdout too)

\dt Function 41h

\dd Delete file

\dt Function 42h

\dd Seek in file

\dt Function 45h

\dd Duplicate file handle

\dt Function 4400h

\dd Used in initialisation
to determine whether handle is to a device

\dt Function 440Dh

\dd Used to lock and unlock drives
by W command

\dt Function 48h

\dd Allocate memory

\dt Function 4Ah

\dd Resize memory

\dt Function 4B01h

\dd Load executable and return to debugger

\dt Function 4Ch

\dd Terminate process

\dt Function 4Dh

\dd Get process return code

\dt Function 4Eh

\dd SFN Find First (used by list.eld)

\dt Function 4Fh

\dd SFN Find Next (used by list.eld)

\dt Function 50h

\dd Set PSP

\dt Function 51h

\dd Get PSP

\dt Function 52h

\dd Get List of Lists

\dt Function 55h

\dd Create child PSP

\dt Function 58h

\dd Get or set memory allocation strategy and UMB link status

\dt Function 5D06h

\dd Get DOS SDA address (used to switch active PSP)

\dt Function 6Ch

\dd Extended open/create

\dt Function 716Ch

\dd Extended open/create with LFN

\dt Function 714Eh

\dd LFN Find First (used by list.eld)

\dt Function 714Fh

\dd LFN Find Next (used by list.eld)

\dt Function 71A0h

\dd Get LFN volume information

\dt Function 71A1h

\dd LFN Find Close (used by list.eld)

\dt Function 7305h

\dd Read/write sectors from/to DOS drive.
Used to implement L and W command.


\H{service67} Interrupt 67h

EMS services. Used by X commands.


\C{eld} Extensions for lDebug reference

Extensions for lDebug (ELDs) can be loaded using the EXT command (\k{cmdext}).
Some ELDs operate in a transient way only;
some memory is allocated to them when they load
and they free this memory again after their run is done.
Other ELDs can be installed residently
and will reserve some of their memory as used beyond their initial run.

\H{eld-ldmem} LDMEM - Dump lDebug memory use.

Displays information on memory use of the debugger.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{LDMEM} command,
and uninstalled with an \cw{LDMEM UNINSTALL} command.

The resident \cw{LDMEM} command as well as the transient ELD
provide a number of keywords to control the output:

\dt MEM

\dd Display memory areas of the debugger,
with their segments, selectors (in Protected Mode only),
and size in Bytes in hexadecimal as well as in KiB.

\dt SEG

\dd Display segments and (in Protected Mode) selectors
in a small overview, without size information on the sections.

\dt HISTORY

\dd Display history utilisation, including how many history entries are used,
how many history buffer bytes are used and how many there are in total,
and the average size per history entry.

\dt STACK

\dd Display stack utilisation, including the total stack size and
how many bytes appear to be used (by a heuristic scan).

\dt ELD

\dd Display ELD code instances and data blocks use.
Each code instance is displayed
either with a code instance name or the indicator \cq{Free space}.
For each code instance, the code start, stop, and size is displayed
in hexadecimal, as well as the size in decimal Bytes/KiB.
For code instances marked as free, the code instance name
is listed behind the size.
This may be stale.
For code instances which have an ELD data block allocated to them,
the data start, stop, and size is displayed on a second line.
Finally,
if the ELD code buffer or the ELD data buffer
have trailing free space,
it is displayed as \cq{Free space} at the end.

\dt ELDVAR

\dd Display ELD variables.
The ext variables format, structure size, amount used, and amount total
are displayed.
For each allocated variable,
its flags, maximum array index, name, and entrypoint into the ELD
are displayed.
The entrypoint display includes the ELD code instance base address
and the ELD code instance name.

\dt COMMANDHANDLER

\dd Display ELD command and preprocess handlers.
Each entrypoint is displayed with its offset,
the offset of its ELD code instance,
and the ELD code instance name.

\dt AMISHANDLER

\dd Display ELD AMIS handlers.
This is alike the command handlers.
(Note that AMIS handlers are always called in Real/Virtual 86 Mode.)

\dt ASMHANDLER

\dd Display ELD assembly handlers.
This is alike the command handlers.

\dt PUTSHANDLER

\dd Display ELD puts-related handlers.
This is alike the command handlers.

\dt INJECTHANDLER

\dd Display ELD inject handlers.
Unlike the command handlers,
inject handlers do not point to a chain of handlers.
Instead, there is only ever none or one single inject handler installed.
That means the display of inject handlers
is not very useful for the LDMEM ELD.
However, the LDMEMOTH ELD may make this display more useful.


Some keywords are expanded to a list of other keywords:

\dt ALL

\dd All output.

\dt ALLNOSEG

\dd All output, except for the SEG output.

\dt ELDALL

\dd All ELD-related output.

\dt ELDHANDLERS

\dd All ELD handlers output.


The keyword \cq{HELP} is handled specifically to display an online help page
when specified to the transient ELD.
It is not valid for the resident ELD's command, however.

If no keywords are specified,
the default keyword is assumed as \cq{ALLNOSEG}.


\H{eld-history} HISTORY - Command history utility.

Lists the command history of the debugger, or clears it.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{HISTORY} command,
and uninstalled with a \cw{HISTORY UNINSTALL} command.

Provides two subcommands:

\dt SHOW

\dd Dump all history entries, in chronological order.

\dt CLEAR

\dd Clear the history, deleting all existing entries.


If the transient ELD is run without a keyword,
then the online help is displayed.


\H{eld-di} DI - Dump Interrupt vectors.

Re-creation of the DI and DIL commands of the debugger.
This allows to use the DI commands when the debugger
is built with the \cw{_INT=0} build option.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DI} command,
and uninstalled with a \cw{DI UNINSTALL} command.

Refer to \k{cmddi}.


\H{eld-dm} DM - Dump MCBs.

Re-creation of the DM command of the debugger.
This allows to use the DM command when the debugger
is built with the \cw{_MCB=0} build option.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DM} command,
and uninstalled with a \cw{DM UNINSTALL} command.

Refer to \k{cmddm}.

The DM ELD by default includes support to dump
the position of each MCB as Bytes or KiB.
Specifying the keyword \cw{POSITION} as the very first parameter
will enable this.

The DM ELD by default includes support to end
the listing past a certain segment address.
Specifying the specifier \cw{LIMIT=} followed
by a numeric expression enables this.
The specifier must be either early
(after \cw{POSITION} if present, before \cw{SKIPSD})
or after the explicit start MCB.

The DM ELD by default includes support to dump SD (System Data)
sub-MCBs. They are displayed indented by one column.
Specifying the keyword \cw{SKIPSD} as a parameter
will skip the SD sub-MCB listing.
(This keyword must be after the \cw{POSITION} keyword
or after the early \cw{LIMIT=} specifier, if present.)

As a special addition, the DM command implemented by the ELD
additionally allows the following parameters:

\dt HEADER

\dd Display a header line first, indicating the meaning of the columns.

\dt TABLE

\dd Similar to HEADER, but expand the columns to a table format
for easier readability.

The \cw{HEADER} or \cw{TABLE} parameter must be after
\cw{POSITION}, an early \cw{LIMIT=}, or \cw{SKIPSD} if present,
but before any explicit start MCB segment expression.


\H{eld-rn} RN - Display FPU registers.

Re-creation of the RN command of the debugger.
This allows to use the RN command when the debugger
is built with the \cw{_RN=0} build option
(as is the default now).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{RN} command,
and uninstalled with an \cw{RN UNINSTALL} command.

Refer to \k{cmdrn}.


\H{eld-rm} RM - Display MMX registers.

Re-creation of the RM command of the debugger.
This allows to use the RM command when the debugger
is built with the \cw{_RM=0} build option
(as is the default now).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{RM} command,
and uninstalled with an \cw{RM UNINSTALL} command.

Refer to \k{cmdrm}.


\H{eld-x} X - EMS commands.

Re-creation of the X commands of the debugger.
This allows to use the X commands when the debugger
is built with the \cw{_EMS=0} build option
(as is the default now).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{X} commands,
and uninstalled with an \cw{X UNINSTALL} command.

Refer to \k{cmdx}.


\H{eld-dx} DX - Dump Extended memory.

Re-creation of the DX command of the debugger.
This allows to use the DX command when the debugger
is built with the \cw{_DX=0} build option
(which is the default as of release 9).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DX} command,
and uninstalled with an \cw{DX UNINSTALL} command.
This ELD requires a 386+ machine.


\H{eld-instnoun} INSTNOUN - Operate on INSTALL flag nouns.

Displays information on install flags of the debugger.
These are the nouns accepted by the \cw{INSTALL} and
\cw{UNINSTALL} commands.
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{INSTNOUN} command,
and uninstalled with an \cw{INSTNOUN UNINSTALL} command.

The operation that can be selected is:

\dt QUIET

\dd Flag for subsequent operation to not display any output.

\dt SET

\dd Enable/install a flag.

\dt CLEAR

\dd Disable/uninstall a flag.

\dt TOGGLE

\dd Toggle a flag.


After the operation, the name of one or more flags must be listed.

If no operation is specified,
all flags are listed. The format is as follows for the first name of a flag:

\b Flag address in debugger entry section. \cq{0000} if a special flag.

\b Flag mask, or the address of the special flag entrypoint.
A mask with more than one bit set indicates a reverse mask.

\b A single symbol representing the state of the flag:
\cq{+} if enabled, \cq{-} if disabled, \cq{?} if a special flag.

\b The name of the flag.

\b The description of the flag.

For subsequent alias names of a flag, only the name is listed.


\H{eld-reclaim} RECLAIM - Reclaim unused ELD memory.

Transient utility to reclaim unused space
in the ELD code buffer and the ELD data blocks buffer.
This is no longer needed because the debugger now
includes the implementation of this tool
and automatically reclaims memory before loading an ELD.

This ELD may still be needed in conjunction with ELDCOMP
to reset the ELD buffers the way ELDCOMP expects them after a run.


\H{eld-eldcomp} ELDCOMP - Compare ELDs with differing linker options.

A tool to compare an ELD with its XLD counterpart.
XLD is the filename extension typically used
to hold a build of an ELD with some linker optimisations.
ELDCOMP allows to compare the two,
helping to identify and locate relocation errors
in the ELD to be tested.

Before running ELDCOMP, you may want to \cw{install nofreeoneshot}
and \cw{uninstall paging} to avoid interfering with the operation of ELDCOMP.
In addition, it may be useful to run the debugger
with the /X switch and particularly the /Y switch
to increase the size of the ELD buffers that may be needed by ELDCOMP.

Up to 8 commands are passed to ELDCOMP, separated by semicolons.
The first and fifth command are typically EXT commands.
The first one loads an XLD, whereas the fifth loads the corresponding ELD
in the same way.
The second and sixth command may invoke a residently installed XLD/ELD,
and are typically the same.
The third and seventh command are used to uninstall a residently installed
XLD/ELD, if any, and are typically the same as well.
The fourth and eighth command should be \cw{ext reclaim.eld}.

The output of the first pass of ELDCOMP is as follows:

\b Output of running the eight commands

\b A line with the data length, data hash, code length, code hash
of the first run

\b A line with the lengths and hashes of the second run

\b The line "Data length mismatch" if applicable

\b The line "Data hash mismatch" if applicable

\b The line "Code length mismatch" if applicable

\b The line "Code hash mismatch" if applicable


If any of the mismatch messages were displayed,
ELDCOMP will attempt to run its second pass.
If the ELD data space doesn't suffice for running the second pass,
the message "Not enough ELD data space left!" is displayed.
You may want to retry with a debugger running with the /Y switch.

The output of the second pass of ELDCOMP
starts out the same as the first pass's.
However, the hashes are expected not to equal those of the first pass
because the ELD data block lives at another offset.
The second pass will additionally display one or both of the following parts:

\b "Comparing data", followed by the left, right, and length numbers.
The output of a C command follows, with the in-ELD offsets prepended
and appended.

\b "Comparing code", in the same way.

The offsets displayed at the beginning and end of each line
of the C commands are offsets
within the ELD data block or the ELD code instance.
They can be referenced in the ELD's listing file
to find the source of the mismatch.


\H{eld-aformat} AFORMAT - Format assembly output.

Once installed, this ELD hooks into the assembler.
After a line is submitted to the assembler, the AFORMAT ELD
will dump in hexadecimal the bytes written by the assembler.


\H{eld-amismsg} AMISMSG - Display message received on AMIS interface.

This ELD hooks into the debugger's AMIS interface.
It provides the AMIS functions 40h and 41h to send
messages to the debugger terminal.
(Refer to \k{int2Dfunc40} and \k{int2Dfunc41}.)
A message may consist of up to 127 bytes of text.
The message is displayed either on the next command
being read in the \cw{cmd3} command input loop
using a command injection handler,
or when the command \cq{AMISMSG DISPLAY} is run.

This ELD is intended to be used in the outer debugger
to receive the TracList offset hints sent by hint.eld
or by the ELD linker
of an ELD being loaded in the inner debugger.


\H{eld-amount} AMOUNT - Provide ELDAMOUNT variable.

This ELD once installed provides the \cw{ELDAMOUNT} variable.
This variable can be read to obtain the amount of installed ELDs.


\H{eld-bases} BASES - Convert between different numeric bases.

A converter for different numeric bases.
Can accept a numeric parameter to be evaluated by the expression evaluator.
Using a \cw{BASE=} specifier or the name of a base
(\cw{HEXADECIMAL}, \cw{DECIMAL}, \cw{BINARY}, \cw{OCTAL})
the input number may be specified as a literal,
which accepts unsigned numbers of up to 64 bits.
Output is in the four known bases, formatted
to resemble the expression evaluator's literal input format.
Output can be in one arbitrary base using a trailing \cw{OUTPUT} keyword,
followed by \cw{BASE=}, \cw{GROUP=}, and \cw{WIDTH=} specifiers.
The BASES ELD can be installed residently using
an \cw{INSTALL} parameter to provide the resident \cw{BASES} command.

\H{eld-co} CO - Copy debugger terminal output to a file.

Installs the \cw{COPYOUTPUT} commands
using the \cw{INSTALL} parameter.
Once a file is specified with \cq{COPYOUTPUT NAME filename}
the debugger opens the file to append to it.
While not InDOS all output to the debugger terminal
is written to the opened file.

Several commands are provided by this ELD:

\dt COPYOUTPUT NAME filename

\dd Set filename and open/create file to append.
An existing file is opened for writing, not truncated.

\dt COPYOUTPUT ON

\dd Enable writing to an opened file. (Default.)

\dt COPYOUTPUT OFF

\dd Disable writing to an opened file.

\dt COPYOUTPUT TOGGLE

\dd Toggle the ON / OFF status.

\dt COPYOUTPUT GETINPUTMODE [ALL|FULLONLY|TOGGLE]

\dd Display or change getinput mode of the COPYOUTPUT ELD.

\dt COPYOUTPUT TRUNCATE

\dd Truncate the currently opened file to zero bytes.

\dt COPYOUTPUT CLOSE

\dd Close the currently opened file.

\dt COPYOUTPUT UNINSTALL

\dd Close a file if any is opened, and uninstall the ELD.


The getinput mode determines how getinput output is written
to the COPYOUTPUT file:

\dt ALL

\dd All getinput output is written,
including Carriage Returns and blanks and printable text
that is used to reposition the cursor or redraw the visible text.

\dt FULLONLY (default)

\dd Only the prompt and the final accepted input line are written.
Repositioning and redrawing output is filtered out and not written.


\H{eld-config} CONFIG - Access debugger config paths.

Allows to show or set the debugger config paths.
This ELD operates as a transient ELD only.
Run as:

\dt SHOW CONFIG

\dd Show debugger config path.

\dt SET CONFIG path

\dd Set debugger config path.

\dt SHOW SCRIPTS

\dd Show debugger scripts path.

\dt SET SCRIPTS path

\dd Set debugger scripts path.


\H{eld-dtadisp} DTADISP - Displays the current DOS Disk Transfer Address.

This ELD runs as a transient ELD only.
It is only valid to run this ELD when DOS is available.


\H{eld-ifext} IFEXT - Conditionally run a command if an ELD is installed.

Allows to run another command conditionally,
using a command of the form \cw{IF [NOT] EXT "extension name" THEN command}.
May be used as a transient ELD or installed residently
using an \cw{INSTALL} command to provide the \cw{IF EXT} commands.

The extension name to provide must match an ELD code instance name
as displayed by a command like \cq{ext ldmem.eld eld}.
An ELD is considered installed if at least one non-free ELD code instance
matches the specified name.
The name is matched insensitive to capitalisation.
The name must be specified with quote marks if it contains a blank.
Names must not be longer than 8 bytes.

For transient use, the \cq{IF [NOT] EXT} construct follows
after the ELD filename.
For instance, \cq{ext ifext.eld if ext "amiscmd" then r} will run
an R command if the AMIS command ELD is installed.


\H{eld-kdisplay} KDISPLAY - Displays the current K/N command buffers' content.

This ELD runs as a transient ELD only.


\H{eld-list} LIST - List ELD/SLD files, description lines, sizes, help.

Displays the description lines for ELD files or SLD files
that are specified with a single pathname pattern.
The pattern may contain wildcards in the last component.
After the pathname, several keywords may be specified:

\b \cw{VERBOSE} to display technical details,

\b \cw{HELP} to display the help,

\b \cw{SFN} to force use of the DOS SFN find interface
instead of trying the DOS LFN find interface,

\b \cw{LIB} to recurse into library ELDs displaying the same infos
for every embedded ELD.

\b \cw{/name} (where the name is a pattern
that can contain question marks or a trailing asterisk)
to filter library ELDs which match the name pattern.
This allows to inspect one or a few of the embedded ELDs
without listing all embedded ELDs.


\H{eld-printf} PRINTF - Print formatted output.

Allows to print formatted output.
Can be installed residently or used as a transient tool.
The first parameter is a quoted string.
Subsequent parameters provide data to format.

Supported escape codes:

\b        \\b      Backslash (8)

\b        \\t      Tab (9)

\b        \\n      Line Feed (10). Usually wanted in a sequence \\r\\n

\b        \\r      Carriage Return (13)

\b        \\s      Blank (32)

\b        \\f      Form Feed (12)

\b        \\xNN    Byte value in one or two hexadecimal digits

Supported format codes:

\b        %%      Literal percent sign

\b        %X, %x  Hexadecimal number (Capitalised, uncapitalised)

\b        %U      Unsigned number

\b        %D, %I  Signed number

\b        %C      Text byte

\b        %S      Text string

\b        %B      Format as Byte/kB/KiB size

Text strings are provided in one of three forms:

\b        START list-parameter END (refer to \k{parlist})

\b        RANGE range-parameter

\b        ASCIZ range-parameter



\H{eld-set} SET - Access environment variables.

Allows to access the environment block to
read or write variables.
Can install a resident \cw{SET} command using an \cw{INSTALL} parameter,
or run transiently using a \cw{RUN} parameter.

Running the command, the following parameters are accepted:

\dt (None)

\dd Display all variables in order of their occurrence.

\dt variable

\dd Display the content of the given variable,
or a message indicating the variable is not set.

\dt variable=

\dd Delete a variable if it exists.

\dt variable=content

\dd Set or modify a variable, if it fits in the environment block.

\dt /E variable=command

\dd Set a variable to the first line of output displayed by the command.
The output is not written to the debugger terminal.

\dt /E /xxx variable=command

\dd Set a variable to a line of output displayed by the command.
The \cq{xxx} indicates which line to choose;
\cq{/0} chooses the first nonempty line, \cq{/1} the second line, etc.


\H{eld-useparat} USEPARAT - Display disassembly separators.

Installs an output hook into the debugger
to display an underscore line after disassembling near or far jumps
or near, far, or interrupt return instructions.
An equals sign line is displayed after disassembly
of a DOS termination call, if it is detected.

Once installed, the command \cq{USEPARAT WIDTH expression}
is provided. It sets the width of the lines to display, between 0 and #80.
The default is #39.


\H{eld-variable} VARIABLE - Expand environment variables.

Installs a command preprocessor hook
to expand \cq{%VARIABLE%} specifications in commands.
This ELD can be used as a transient ELD or as a resident ELD.
Once installed, variable uses in commands are expanded.
Note that the command to uninstall the resident variable.eld is
\cq{VARIABLES UNINSTALL}, not matching the filename of the ELD.

To use the ELD transiently,
a parameter reading either RUN or DISPLAY is to be used.
RUN will run the subsequent command with variable uses expanded.
DISPLAY will instead display the subsequent text with variable uses expanded.


\H{eld-withhdr} WITHHDR - Run commands with temporary DCO flags set.

Installs a prefix command called \cw{WITH}.
This can be used as \cw{WITH HEADER} or \cw{WITH TRAILER}
to temporarily set DCO flags to enable D command headers or trailers.
The ELD can also be used as \cw{WITH NODUMP} to temporarily set a DCO flag
to disable the S command data dump from after S command search results.
Command injection is used to reset the flags afterwards.


\H{eld-amiscmd} AMISCMD - Run commands received on AMIS interface.

This ELD hooks into the debugger's AMIS interface.
It provides the AMIS function 43h
to inject commands into the debugger. (Refer to \k{int2Dfunc43}.)
This requires this debugger to have run \cq{install amis}.

In another debugger instance, inject.eld can be used
to inject commands into this debugger.


\H{eld-amisoth} AMISOTH - Provide other link info on AMIS interface.

This ELD hooks into the debugger's AMIS interface.
It provides the AMIS function 42h
to export the debugger's link info as an "other link".
(Refer to \k{int2Dfunc42}.)
This requires this debugger to have run \cq{install amis}.

In another debugger instance, "other link" ELDs
(ldmemoth.eld and instnoth.eld) can be used
to access this debugger's data.


\H{eld-amitsrs} AMITSRS - List currently installed AMIS multiplexers.

Port of Ralf Brown's AMIS TSR lister.
This ELD can be installed residently or used transiently.
If the parameter is not equal to \cw{INSTALL},
then the following parameters are accepted:

\dt VERBOSE

\dd Display all information for each multiplexer.

\dt MPX

\dd Include the line that indicates the multiplex number.

\dt HOTKEYS

\dt KEYS

\dd Include the display of installed hotkeys.

\dt INT

\dt INTLIST

\dt INTERRUPTS

\dd Include the interrupt list display.

\dt VERSION

\dd Include the line that indicates the version number.

\dt ENTRY

\dd Include the line that indicates the private entrypoint.

\dt DEVICE

\dd Include device response line and display all devices

\dt CHAR

\dd Include device response line and display character devices

\dt BLOCK

\dd Include device response line and display block devices

\dt DPB

\dd Display block devices and their DPBs

If no parameters are specified,
then only one line is displayed per multiplexer,
listing the vendor and product signatures and the description line
of each multiplexer.

The multiplex numbers to process can be changed from the default (all)
to a range using the ONLY= keyword.
After it, a single number parameter
or a \cw{FROM start TO end}
or \cw{FROM start LENGTH length} construct may follow.


\H{eld-bootdir} BOOTDIR - List directory entries.

List directory entries in bootloaded mode.
This ELD runs as a transient ELD only.
The first parameter must be a pathname pattern.
The last component may include wildcards.
The available wildcards are:

\dt Question mark \cq{?}

\dd Matches one byte as a wildcard.

\dt Asterisk \cq{*}

\dd Matches any number of bytes as a wildcard,
up to the end of the current SFN field.

After the pathname pattern, any number of keywords may follow:

\dt WIDE

\dd Display in wide mode, up to 5 names per line.

\dt SORT

\dd Sort filenames.

\dt DATE

\dd Must be specified along with SORT. Sort by date.

\dt SIZE

\dd Must be specified along with SORT. Sort by size.

\dt REVERSE

\dd Reverse the sort order.

\dt DIRFIRST

\dd Sort directories first before any files.

When sorting, the ELD will detect a buffer for storing the filenames
while scanning the directory in the first pass, for sorting the entries.
If this buffer overflows, the ELD cannot succeed.

If the date of a directory entry is zero,
which would be decoded as "1980-00-00",
the date field is blanked out.


\H{eld-dbitmap} DBITMAP - Dump 8-bit-wide graphics from memory.

This ELD can be installed residently or used transiently.

When installed residently, three \cw{DBITMAP} commands are available
in addition to the usual \cw{UNINSTALL} command:

\b \cw{SET0} followed by a list,
to set the default string for 0 bits.
The list must not exceed 10 bytes.

\b \cw{SET1} followed by a list,
to set the default string for 1 bits.
The list must not exceed 10 bytes.

\b Optional \cw{RUN} keyword,
followed by a range,
or by an \cw{INTERNAL} keyword followed by a word,
or by a \cw{STR} keyword followed by a list.
(This command can be used transiently as well.)


After the \cw{RUN} keyword optionally there may be a \cw{SET0} or \cw{SET1} keyword
followed by a list that ends with an \cw{END} keyword.
After any number of such constructs a range
or \cw{INTERNAL} keyword
or \cw{STR} keyword
must follow.
These constructs allow to override the strings for a 0 bit
or for a 1 bit for the duration of a single command.

The three choices for \cw{RUN} commands are handled differently:

\dt Range

\dd Display data in range, 8 bits per line, given length (default: 8 bytes).
Addresses are displayed before each data dump line.

\dt \cw{INTERNAL} followed by a word

\dd Display 8 bytes from the internal font, 8 bits per line,
offset by the specified word.
To address a specific codepoint, multiply its numeric value by 8.
Addresses are displayed before each data dump line.

\dt \cw{STR} followed by a list

\dd Display a graphical string from the internal font.
No addresses are displayed.

The \cw{STR} mode allows processing escape codes indicated by a backslash.
The following escapes are defined:

\dt \cq{\\\\}

\dd Write a single backslash.

\dt \cq{\\M}

\dd Write the next codepoint but with the bits mirrored
(left and right are swapped).

\dt \cq{\\H}

\dd Write a blank, whose width is specified by the next alphanumeric.
\cq{\\H8} is the same as a regular blank,
\cq{\\H4} produces a half-width blank.

Examples:

\c -f 100 l 8 FF
\c -f 108 l 8 00
\c -ext dbitmap.eld run 100
\c 2B03:0100  ********
\c 2B03:0101  ********
\c 2B03:0102  ********
\c 2B03:0103  ********
\c 2B03:0104  ********
\c 2B03:0105  ********
\c 2B03:0106  ********
\c 2B03:0107  ********
\c -ext dbitmap.eld run 108
\c 2B03:0108  ........
\c 2B03:0109  ........
\c 2B03:010A  ........
\c 2B03:010B  ........
\c 2B03:010C  ........
\c 2B03:010D  ........
\c 2B03:010E  ........
\c 2B03:010F  ........
\c -ext dbitmap.eld run set1 '#' end 100 l 2
\c 2B03:0100  ########
\c 2B03:0101  ########
\c -ext dbitmap.eld run internal #'L' * 8
\c 0436:9226  ..**....
\c 0436:9227  ..**....
\c 0436:9228  ..**....
\c 0436:9229  ..**....
\c 0436:922A  ..**....
\c 0436:922B  ..**....
\c 0436:922C  ..******
\c 0436:922D  ........
\c -ext dbitmap.eld run str "\MLDOS"
\c ....**...*****....*****...*****.
\c ....**...**..**..**...**.**...**
\c ....**...**...**.**...**..**....
\c ....**...**...**.**...**...***..
\c ....**...**...**.**...**.....**.
\c ....**...**..**..**...**.**...**
\c ******...*****....*****...*****.
\c ................................
\c -


\H{eld-doscd} DOSCD - Change DOS current directory or drive.

This ELD can only be used transiently.
DOS must be available to run this ELD.

If only a drive letter and colon are specified,
then the current drive is changed to the indicated drive.

If the first parameter is a keyword \cq{BOTH}
then the current drive is changed to the indicated drive
and the current directory on that drive is changed to the indicated path.
It is an error to specify the keyword \cq{BOTH} if no drive letter is given.

If the first parameter is a keyword \cq{IFBOTH}
then if a drive letter is specified, the current drive is changed
to the indicated drive.
Then the current directory is changed to the indicated path.

The current drive is changed by using interrupt 21h function 0Eh,
and checked for success by using interrupt 21h function 19h.
The current directory is changed by using interrupt 21h function 3Bh.


\H{eld-dosdir} DOSDIR - List directory entries.

List directory entries using DOS.
This ELD runs as a transient ELD only.
DOS must be available to run this ELD.

The first parameter must be a pathname pattern.
The last component may include wildcards.
The available wildcards are:

\dt Question mark \cq{?}

\dd Matches one byte as a wildcard.

\dt Asterisk \cq{*}

\dd Matches any number of bytes as a wildcard,
up to the end of the current SFN field.
Semantics may differ for LFNs.

After the pathname pattern, any number of keywords may follow:

\dt SFN

\dd Use DOS SFN search, even if LFN search would be available.

\dt WIDE

\dd Display in wide mode, up to 5 names (SFNs) per line.

\dt SORT

\dd Sort filenames.

\dt SORTSFN

\dd Sort filenames, but sort by SFNs rather than LFNs.

\dt SORTLFN

\dd Sort filenames, but sort by LFNs rather than SFNs.

\dt DATE

\dd Must be specified along with SORT. Sort by date.

\dt SIZE

\dd Must be specified along with SORT. Sort by size.

\dt REVERSE

\dd Reverse the sort order.

\dt DIRFIRST

\dd Sort directories first before any files.

When sorting, the ELD will detect a buffer for storing the filenames
while scanning the directory in the first pass, for sorting the entries.
If this buffer overflows, the ELD cannot succeed.

If the date of a directory entry is zero,
which would be decoded as "1980-00-00",
the date field is blanked out.


\H{eld-dosdrive} DOSDRIVE - Get or set a DOS drive.

This ELD runs as a transient ELD only.
DOS must be available to run this ELD.

If no parameters are specified,
gets the current DOS drive and displays it as the drive letter
followed by a colon.

If the parameter \cq{GET} is specified without a trailing pathname,
act as if no parameters are specified.

If the parameter \cq{GET} is specified with a trailing pathname,
parses the pathname and displays its drive letter if any is specified,
or else the current drive.

If the parameter \cq{SET} is specified with a trailing pathname,
then the pathname must contain a drive letter.
The current drive is changed to the specified drive.

If the parameters \cq{SET QUIET} are specified,
then the trailing pathname and its drive letter specification
are optional.
If no such drive specification is included,
the command silently does nothing.


\H{eld-dospwd} DOSPWD - Display DOS current directory.

This ELD runs as a transient ELD only.
DOS must be available to run this ELD.

If no parameter is specified,
displays the current directory on the current drive.

If a parameter \cq{NUMBER} is specified,
then a trailing plain number parameter is parsed from an expression.
This number must be below 32.
It specifies the drive of which to get the current directory.

Otherwise the parameter must be a drive letter followed by a colon.
It specifies the drive of which to get the current directory.


\H{eld-extname} EXTNAME - Guess EXT and Y command filename extensions.

Installs residently to guess EXT and Y command filename extensions.
Install using the \cw{INSTALL} keyword.

Once installed, running an EXT or Y command without a filename extension
will guess the filename extension.
The EXT command will guess the extension as \cq{.ELD} first
and \cq{.XLD} second.
The Y command will guess the extension as \cq{.SLD}.

The following commands are additionally provided:

\dt EXTNAME WARNEXT

\dd Display status of warning on unknown filename extension.

\dt EXTNAME WARNEXT ON

\dd Enable warning on unknown filename extension.

\dt EXTNAME WARNEXT OFF

\dd Disable warning on unknown filename extension.

\dt EXTNAME WARNEXT TOGGLE

\dd Toggle warning on unknown filename extension.

\dt EXTNAME GUESSEXT

\dd Display status of guessing filename extension.

\dt EXTNAME GUESSEXT ON

\dd Enable guessing filename extension.

\dt EXTNAME GUESSEXT OFF

\dd Disable guessing filename extension.

\dt EXTNAME GUESSEXT TOGGLE

\dd Toggle guessing filename extension.


\H{eld-inject} INJECT - Inject commands into other debugger instance.

Injects commands into other debugger instance
using the other's AMIS function 43h (refer to \k{int2Dfunc43}).
(This function is provided by the AMISCMD ELD, refer to \k{eld-amiscmd}.)


\H{eld-instnoth} INSTNOTH - INSTNOUN which operates on other link debugger.

INSTNOUN variant (refer to \k{eld-instnoun})
that operates on another debugger instance.
This requires the other instance to have installed the AMISOTH ELD
(refer to \k{eld-amisoth})
and its AMIS handler to provide the AMIS function 42h
(refer to \k{int2Dfunc42}).


\H{eld-ldmemoth} LDMEMOTH - LDMEM which operates on other link debugger.

LDMEM variant (refer to \k{eld-ldmem})
that operates on another debugger instance.
This requires the other instance to have installed the AMISOTH ELD
(refer to \k{eld-amisoth})
and its AMIS handler to provide the AMIS function 42h
(refer to \k{int2Dfunc42}).


\H{eld-linfo} LINFO - Display status of L command.

Installs residently to display status of program-loading L command.
Running a program-loading L command will then display some information
on the file being loaded and the process that was created.

Additionally the following commands are provided:

\dt LINFO FILE

\dd Display the program load filename.
This is what an L command will show before the command is processed.

\dt LINFO FILE QUIET

\dd As LINFO FILE, but display nothing if no program load filename specified.

\dt LINFO PROBE

\dd Probe the program load file and current PSP.
This is most of what a successful L command will show
after the command is processed.

\dt LINFO PROBE QUIET

\dd As LINFO PROBE, but display nothing if no program load filename specified.


\H{eld-path} PATH - Path search for K/N commands.

Provides path search and filename extension guessing
for the K and N commands.
This ELD can be installed residently or used transiently.

If used transiently,
the first parameter must be the command letter \cq{K} or \cq{N}.
The path search is done on the program load filename specified to the given
command, and then the command is run with the resulting pathname.
A warning is displayed if the WHILE buffer or DOS are not available,
as path search will not happen in this case.
An error is displayed if the expanded pathname
doesn't fit into the \cw{line_in} buffer.

If used residently,
the K or N commands are intercepted in the command handler.
The path search is done on the program load filename,
and if found the command is modified to receive the resulting pathname.
\e{No warning} is displayed if the WHILE buffer or DOS are not available,
but path search will not happen in this case.
An error is displayed if the expanded pathname
doesn't fit into the \cw{line_in} buffer.


The following commands are additionally provided
when installed residently:

\dt PATH WARNEXT

\dd Display status of warning on unknown filename extension.

\dt PATH WARNEXT ON

\dd Enable warning on unknown filename extension.

\dt PATH WARNEXT OFF

\dd Disable warning on unknown filename extension.

\dt PATH WARNEXT TOGGLE

\dd Toggle warning on unknown filename extension.

\dt PATH GUESSEXT

\dd Display status of guessing filename extension.

\dt PATH GUESSEXT ON

\dd Enable guessing filename extension.

\dt PATH GUESSEXT OFF

\dd Disable guessing filename extension.

\dt PATH GUESSEXT TOGGLE

\dd Toggle guessing filename extension.

\dt PATH PATHSEARCH

\dd Display status of searching path.

\dt PATH PATHSEARCH ON

\dd Enable searching path.

\dt PATH PATHSEARCH OFF

\dd Disable searching path.

\dt PATH PATHSEARCH TOGGLE

\dd Toggle searching path.


\H{eld-extlib} EXTLIB - Library of ELDs.

Library of ELDs to be used instead of single files.
This library contains most other ELDs.
To load an embedded ELD, specify its filename or ELD code instance name
as a parameter to the EXTLIB ELD.
The name may be specified with an \cq{.ELD} or \cq{.XLD} filename extension,
which is ignored.
All trailing parameters after the name are passed to the embedded ELD.

If no ELD name or the name \cq{HELP} is specified,
the EXTLIB ELD's help is displayed instead.
If after the \cq{HELP} keyword one more keyword follows,
the short or long list of embedded ELDs is displayed
along with the EXTLIB help:

\dt WIDE

\dd Display ELD filenames in a wide format, up to 8 ELDs per line.

\dt DESCRIBE

\dd Display ELD filenames along with the corresponding ELD description lines,
one ELD per line.


\H{eld-extpak} EXTPAK - Compressed library of ELDs.

This is used exactly the same as extlib.eld (\k{eld-extlib})
except that the embedded ELDs are compressed
(using heatshrink or lzexedat -4 compression).
This means that operations like the \cw{HELP DESCRIBE} list or
scanning for an ELD code instance name may take longer than with
the uncompressed extlib.eld.


\H{eld-quit} QUIT - Quit the machine.

Quits the machine. Can be installed residently or used transiently.
When run with a parameter \cq{RUN} then this ELD
will attempt to quit (shut down) the currently running machine or VM.
When \cq{install quickrun} has been used,
running this ELD without a parameter will also attempt to quit the machine.


\H{eld-dosseek} DOSSEEK - Get or set the DOS 32-bit seek of a process handle.

This ELD only operates transiently,
and requires DOS to be available.

The first parameter is either \cw{GET} or \cw{SET}.
The second parameter is an expression that evaluates to a process handle number.
This number must refer to a process handle that is opened in the current
debuggee process.

For getting the seek, after the process handle there may follow the
\cw{VAR index} specification.
If it is given, then the specified V variable (\k{varv})
is set to the current 32-bit seek.
Further, a \cw{QUIET} keyword may follow to suppress the output of the command.
If not both a \cw{VAR} and a \cw{QUIET} keyword are specified,
then the output will be like the following example:

\c -ext dosseek.eld get 5
\c Process handle 5 current seek is 0000_1400  #5120   5.0 KiB

For setting the seek, after the process handle another keyword must follow:

\dt ABS

\dd Set absolute seek.

\dt CUR

\dd Set signed offset from current seek.

\dt EOF

\dd Set signed offset from EOF.

After the keyword, an expression follows which gives the 32-bit offset
to seek to.


\H{eld-alias} ALIAS - Define aliases.

Define simple aliases that are replaced in a command preprocess handler.
This ELD must be installed residently.

To add an alias, run as \cq{ALIAS ADD aliasname expansion}.

To delete an alias, run as \cq{ALIAS DEL aliasname}.

To list aliases, run as \cq{ALIAS LIST} or \cq{ALIAS LIST aliasname}.


\H{eld-dpb} DPB - Display a DOS drive's DPB.

Display a DOS drive's DPB (MS-DOS v4 to v6 layout,
optionally with FreeDOS, MS-DOS v7.10, or EDR-DOS FAT32 extensions).
Can be installed residently with \cw{INSTALL} parameter
to provide the \cw{DPB} command,
and uninstalled with a \cw{DPB UNINSTALL} command.

An optional parameter specifies the drive to access.
It defaults to zero.
A drive letter may be specified with a trailing colon.
Otherwise, a number is parsed.
Zero means to access the DOS current drive.
The number one corresponds to drive A:, two to drive B:, and so on.
The DPB is accessed using interrupt 21h function 32h,
which requires DOS to be available.
Enhanced DR-DOS may return DPBs for FAT32 drives on this function
whereas FreeDOS and MS-DOS 7.10 may refuse to do so.

Instead of the drive parameter,
the keyword \cw{ADDRESS} may be specified.
It must be followed by an address parameter.
This address specifies where to read the DPB from.
This address uses a selector in Protected Mode,
except when the parameter is prepended by a dollar sign.

Instead of the drive parameter,
the keyword \cw{LIST} may be specified.
After this keyword, either the keyword \cw{SKIP} or
the keyword \cw{DRIVE} has to follow.

After the keywords \cw{LIST SKIP} a number is parsed.
The list of DPBs is detected from the DOS List of Lists
and a number of DPBs are skipped in the chain until
reaching the target. The number specified after
the keyword indicates how many DPBs to skip.

After the keywords \cw{LIST DRIVE} a drive is parsed.
This may be either a number or a drive letter.
The list of DPBs is detected from the DOS List of Lists
and the DPBs are scanned for one matching the specified drive
in its first field.

Between the \cw{LIST} keyword and the next keyword,
an address for the DOS List of Lists may be inserted.
This starts with an \cw{AT} keyword.
Then an address parameter is parsed.
This address parameter is always a 86 Mode segmented address,
even in Protected Mode.
The address parameter's segment defaults to the DOS data segment
as obtained from reading the 86 Mode interrupt 31h vector's segment.
The address specifies where to find the DOS List of Lists.

Before the \cw{LIST} or \cw{ADDRESS} keywords or the drive specifier,
the keyword \cw{EXTENDED=} may be specified to display an EDPB.
It must be followed by one of the known DOS version keywords.
These are: \cw{FREEDOS}, \cw{MSDOS}, or \cw{EDRDOS}.
The DOS keyword indicates what format of EDPB to display.

Before the \cw{EXTENDED=} keyword,
the keyword \cw{ONLY} may be specified.
If specified, only the EDPB extended fields are displayed,
skipping the base DPB.


As an example, a drive with a typical 1440 KiB diskette file system
will display as follows:


\c -ext dpb.eld A:
\c DOS function 32h call returned al=00h.
\c DOS function returned 86 Mode address=00D9:1E40
\c Drive                       00: 00  0
\c DeviceUnit                  01: 00  0
\c BytesPerSector              02: 0200  512
\c HighestSectorInCluster      04: 00  0
\c SectorsPerClusterShift      05: 00  0
\c ReservedSectors             06: 0001  1
\c AmountFATs                  08: 02  2
\c AmountRootEntries           09: 00E0  224
\c DataStart                   0B: 0021  33
\c MaximumCluster              0D: 0B20  2848
\c SectorsPerFAT               0F: 0009  9
\c RootStart                   11: 0013  19
\c DeviceHeader                13: 0070_0610  7341584
\c MediaID                     17: F0  240
\c Accessed                    18: 00  0
\c Next                        19: 00D9_1E7D  14229117
\c FreeClusterNext             1D: 0000  0
\c AmountFreeClusters          1F: FFFF  65535
\c -

Note that at least the FreeDOS kernel always resets the
\cw{FreeClusterNext} and \cw{AmountFreeClusters} fields
whenever the DPB is obtained using interrupt 21h function 32h.

Invalid drives (including file system redirector drives)
will result in a nonzero return in AL:

\c -ext dpb.eld Z:
\c DOS function 32h call returned al=FFh.
\c -


\H{eld-rdumpidx} RDumpIdx - Dump text bytes pointed to by DS:SI and ES:DI in R register dump.

Once installed, this ELD hooks into the debugger's R command register dump.
If the dump is in 16-bit mode and not configured for 40-column display,
and lDebugX is not in Protected Mode,
this ELD will take effect.
It will display a trailer to the first line
of the register dump,
listing what text bytes are found at the addresses
indicated by DS:SI and ES:DI.

Example:

\c AX=5A20 BX=0000 CX=051C DX=0000 SP=FFFE BP=0000 SI=0082 DI=0000  SI='s' DI=top
\c DS=5A21 ES=5A21 SS=5A21 CS=5A21 IP=04D0 NV UP EI PL ZR NA PE NC
\c 5A21:04D0 AC                lodsb


\H{eld-rdumpstr} RDumpStr - Dump text pointed to by DS:DX in R register dump.

Once installed, this ELD hooks into the debugger's R command register dump.
If the dump is in 16-bit mode and not configured for 40-column display,
and lDebugX is not in Protected Mode,
this ELD will take effect.
It will display a trailer to the second line
of the register dump,
listing what text is found starting at
the address indicated by DS:DX.

Example:

\c AX=0A07 BX=FD2B CX=0000 DX=02BB SP=FFFC BP=0000 SI=0087 DI=0000
\c DS=5A21 ES=5A21 SS=5A21 CS=5A21 IP=03FF NV UP EI PL NZ NA PO NC "Other kernel,"
\c 5A21:03FF 80FFFD            cmp     bh, FD


\H{eld-checksum} CHECKSUM - Calculate checksum over a memory range.

This ELD can be used as a transient command or installed residently.
Install with an \cw{INSTALL} keyword.
The \cw{CHECKSUM} command accepts a range parameter,
with a default length of 512 Bytes.
After the range an optional initial sum can be specified.
This sum defaults to 1.

The checksum is an unsigned 16-bit number.
It is calculated according to the following pseudocode:

\c initial sum = 1
\c for every byte in range:
\c   sum = sum * 31
\c   sum += byte value
\c   sum = sum & 0FFFFh


\H{eld-hint} HINT - Display TracList hints to outer debugger

This ELD can be used as a transient command or installed residently.
Install with an \cw{INSTALL} keyword.
When run, this command displays TracList listing offset hints
for all currently installed ELDs of the debugger running this ELD.
The hints are written to the terminal of another lDebug instance,
assumed to be the outer debugger.
This utilises that outer debugger's AMISMSG service,
so the amismsg.eld and AMIS interface must be installed
in that debugger.

An optional keyword \cw{SKIPSELF} may be specified.
If it is given, then the hint.eld will not write a hint
corresponding to its own ELD code instance.
This is useful for running with eldcomp.eld.


\H{eld-hintoth} HINTOTH - Display TracList hints of the other link debugger

This ELD can be used as a transient command or installed residently.
Install with an \cw{INSTALL} keyword.
When run, this command accesses the other link debugger's installed ELDs.
This utilises the other link debugger's AMISOTH service,
so the amisoth.eld and AMIS interface must be installed
in that debugger.
The HINTOTH command will display TracList listing offset hints
for all currently installed ELDs of the detected other link debugger.


\H{eld-chstool} CHSTOOL - Work with int 13h partitions and geometry.

Utilities to work with int 13h unit partitions and geometry.
Can be used as a transient command or installed residently.
This ELD will not operate in Protected Mode,
as it depends on segment arithmetic and accessing
the ROM-BIOS int 13h interface.

The following commands are supported:

\dt numeric

\dd Read number as a 32-bit encoded CHS tuple.
Lists the decoded CHS tuple.
Using a default unit of 80h,
the resulting LBA sector number is also calculated and displayed,
along with the size of preceding data of this sector number.
The size is displayed using IEC and SI unit prefixes
with the default DCO1 options.
(Actually, the size is displayed once as is,
then once after the DCO1 flag 1000h has been toggled,
then the flag is toggled again to reset it. )

\dd Note that the encoded tuple number can be specified as \cw{cxdx}
when the registers are set up for an int 13h function 02h call,
or by reading the first dword (start) or second dword (end)
of an MBR-style partition table entry.
The low byte is always ignored.

\dt \cw{UNIT=unit} numeric

\dd Same as before, but query ROM-BIOS for the specified unit's geometry
rather than using the default unit of 80h.

\dt \cw{SECTORS=sectors HEADS=heads} numeric

\dd Same as before but specify the geometry manually.
If only one of the two properties is set, the other one
is still detected from the unit, either the default unit 80h
or one specified with the \cw{UNIT=} keyword.

\dt \cw{GEOMETRY} unit

\dd Determine geometry of the specified unit and display it.

\dt \cw{WALK} unit

\dd Walk the partition tables of the specified unit.
After the unit number, a number of keywords may follow:

\lcont{

\dt \cw{EXTENDED}

\dd Also display all nested extended partitions.

\dt \cw{SKIPEXT}

\dd Skip display of all extended partitions,
including outermost extended partitions.

\dt \cw{DUMP}

\dd Dump raw partition table entries as the partition tables are read.
These follow the format: offset in sector, active byte,
CHS start encoded 3byte tuple, partition type byte,
CHS end encoded 3byte tuple, partition start dword, partition size dword.

\dt \cw{DUMPRELOAD}

\dd If \cw{DUMP} is also specified, dump even partition tables
that are certainly rereading the same tables read already.

\dt \cw{LABEL}

\dd For FAT FS partitions, add another line that dumps
the label in the BPB new, as well as the FAT FS ID,
and the unit number and partition number.

\dt \cw{QUIET}

\dd Suppress the lines listing the CHS start and end tuples,
and their LBA sector numbers and byte sizes.

\dt \cw{UPTO=unit}

\dd Specify multi-unit operation. The trailing unit number
should be at least as high as the start unit number.
The scan will process all specified units in order.
If the mode indicates a non-DLA-sort order,
every single pass of the partition table scanner will process
all specified units before control flows to the next pass.
If the mode indicates a DLA-sort order,
then every unit is processed fully (all passes run)
before the next unit is processed.

\dt \cw{MODE=mode}

\dd Change the mode of operation.
Refer to \k{eld-chstool-mode} for the valid modes.

}


\S{eld-chstool-mode} CHSTOOL ELD partition table scanner modes

Modes allow the partition table scanner to emulate most
of the different behaviours of different kernels.
The following mode keywords are recognised to select
a complete configuration:

\dt \cw{LDOS2024}

\dd Old lDOS behaviour. Only a single primary partition per unit,
then a single extended partition per MBR or EPBR of type 5 or type 15,
and a single logical partition per EPBR.
No FAT32 partitions are recognised.

\dt \cw{LDOSNEW}

\dd Proposed new lDOS behaviour. DLA sort (one unit after another
not interleaved in multi-pass scanner),
all primary partitions first
then all logical partitions, using lDebug/lDOS altmbr order,
recognising all extended partitions of types 5, 15, or 85h.
No FAT32 partitions are recognised.

\dt \cw{FREEDOS}

\dd FreeDOS behaviour. Non-DLA sort,
all first active or first primary partitions of each unit first,
then a single extended partition per unit of type 5 or 15,
with multiple logical partitions per EPBR (traditional order) but
only a single nested extended partition per EPBR.
Finally, all remaining primary partitions.

\dt \cw{FREEDOSDLA}

\dd Like FreeDOS with the DLA sort enabled,
so that all drives of one unit are processed
before continuing to the next unit.

\dt \cw{EDRDOS}

\dd Enhanced DR-DOS behaviour.
DLA sort disabled,
all primary partitions first,
then logical partitions (multiple per EPBR, traditional order),
a single extended partition of type 5 or 15 per MBR or EPBR.

\dt \cw{MSDOS5}

\dd MS-DOS v5 behaviour.
DLA sort disabled,
every unit's first active or first primary partition,
then for every unit a single extended partition of type 5,
a single logical partition per EPBR (traditional order),
and a single nested extended partition per EPBR.
Finally, all remaining primary partitions.
No FAT32 or LBA partitions are recognised.

\dt \cw{MSDOS7}

\dd MS-DOS v7 (or more accurately v7.10) behaviour.
Like MS-DOS v5 but FAT32 and LBA partition types
are supported. Further,
the first extended partition per MBR or EPBR
may be of type 15.

The mode can be specified numerically as well.
A leading plus sign \cw{+} means set flag mask,
a leading minus sign \cw{-} means clear flag mask,
and neither means overwrite all flags.
For the numeric meanings,
refer to the source text of the scanptab module.


\H{eld-s} S - Search command with additional support for WILD and CAPS keywords

This ELD provides the same basic command as the S command (\k{cmds}).
However, it allows some extensions as well.
The S ELD can be used transiently or installed residently.
To invoke a resident S ELD the command letter S must be
recognised as a string, that is the search range's first letter or digit
must not immediately follow the \cq{S} letter.

The basic command format is:

\c search          S range [REVERSE] [SILENT number] [RANGE [CAPS] range|list]

The keywords REVERSE, SILENT, and RANGE are all described in \k{cmds}.
The list parameter is based on the debugger's generic list parameter type,
refer to \k{parlist}. However, it adds three new keywords:

\S{eld-s-wild} WILD - Search wildcard

This keyword when encountered in the search pattern list inserts
one wildcard item of the current element size.
As the default item size is byte, a WILD keyword defaults
to inserting a byte-sized wildcard.
After for example AS WORDS, a WILD keyword instead
will insert a word-sized (2-byte) wildcard.

Using wildcards may degrade search performance.

\S{eld-s-caps} CAPS - Search with capitalisation folding

This keyword enables the search to treat every subsequent byte
of the search pattern as requiring capitalisation be folded,
so that small letters and big letters (in the ASCII alphabet)
will match one another.

The CAPS keyword may appear in a search pattern list,
or after the RANGE keyword. In the latter case
capitalisation is folded for the entire search pattern range.

Using the CAPS keyword may degrade search performance.

\S{eld-s-uncaps} UNCAPS - Reset search to do no capitalisation folding

This keyword is only allowed in a search pattern list.
It resets the status set up by the CAPS keyword,
so that byte values are matched exactly again.

\S{eld-s-internals} S ELD internals

The wildcard and caps search modes are implemented using a tag buffer.
Every tag consists of two bits, one of which indicates
that the corresponding byte is a wildcard and
the other one for capitalisation folding.

There are three families of internal functions to handle search
that may involve nonzero tags:

\b Repeated scan byte for a given value

\b Scan a single byte for a given value

\b Compare trailing string after an initial byte match was found


\S2{eld-s-bytescan} S ELD - Byte scan functions

The first function is used to scan for the pattern's first byte
in almost the entire search space. The second function is used
to scan the very last possible match of the first byte.
This distinction is needed because of how the debugger handles
search space length of up to 64 KiB with a 16-bit counter.

Both of these functions must work either with Direction Flag cleared
(UP) or set (DN). Additionally, there is a branch to an a32 variant
of each of these functions to allow searcning in 32-bit segments.

The repeated scan byte functions are implemented by calling
the single byte scan functions in an appropriate loop.

If the tag of the search pattern's first byte is zero,
simple functions that only consist of the a32 dispatching
and a single string operation are used. Tnis is a speed optimisation.


\S2{eld-s-stringcompare} S ELD - Trailing string comparison function

The third function is used after a candidate match is identified
from the first byte scan. If any tags are nonzero in the search pattern,
then complicated functions are used.
These will loop like the single string operation \cq{repe cmpsb} would,
but internally they use the single byte scan functions
to handle tags appropriately.
The tags are iterated through alongside the pattern values.

This function always works with the Direction Flag cleared (UP) although
it would work otherwise as well. As for the other two functions
there is a32 dispatching for searching in 32-bit segments.

If all tags are zero, the trailing string comparison function
is handled by simple functions consisting of a32 dispatching
and a single string operation. If the RANGE CAPS keywords are used
together, medium complex functions are used which always
pass an immediate tag value to the single byte scan function.
Otherwise the full handling of all possible tag combinations is done,
and the loop keeps track of both the current offset, the remaining length,
and the current bit position in the tag buffer.


\H{eld-dosspace} DOSSPACE - Display DOS drive total and free space

This ELD can be installed residently or used transiently.
The DOSSPACE command accepts a drive specification.
If none is given, the DOS default drive is used.
If a drive letter followed by a colon is specified,
that drive is used.
Else, a number is parsed.
The number 0 selects the default drive,
the number 1 selects drive A:, and so on.

Before the drive specification,
the keyword \cw{EXPANDED} may be specified.
This will list more of the interrupt 21h function 7303h fields.

The DOSSPACE command requires DOS to be available.
Once run, it will call interrupt 21h functions 36h and 7303h.

Example output of a FAT12 diskette drive on the lMS-DOS kernel:

\c -ext extlib.eld dosspace
\c DOS function 36h dl=00h call returned ax=0001h, bx=002Eh, cx=0200h, dx=0B1Fh.
\c spc             0001  1
\c free            002E  46
\c bps             0200  512       512 B
\c total           0B1F  2847
\c bpc             0000_0200  512       512 B
\c sfree           0000_002E  46
\c stotal          0000_0B1F  2847
\c bfree           0000_0000_5C00  23552    23.0 KiB
\c btotal          0000_0016_3E00  1457664    1423 KiB
\c DOS function 7303h not supported, error=7300h!
\c -

Example output of a FAT32 hard disk drive on the Enhanced DR-DOS kernel,
with the \cw{EXPANDED} keyword specified:

\c -ext a:extlib.eld dosspace expanded C:
\c DOS function 36h dl=00h call returned ax=0004h, bx=A6B6h, cx=0200h, dx=F614h.
\c spc             0004  4
\c free            A6B6  42678
\c bps             0200  512       512 B
\c total           F614  62996
\c bpc             0000_0800  2048      2048 B
\c sfree           0002_9AD8  170712
\c stotal          0003_D850  251984
\c bfree           0000_0535_B000  87404544    83.3 MiB
\c btotal          0000_07B0_A000  129015808     123 MiB
\c ext.spc         0000_0001  1
\c ext.free        0002_9AD8  170712
\c ext.bps         0000_0200  512       512 B
\c ext.total       0003_D850  251984
\c ext.bpc         0000_0000_0000_0200  512       512 B
\c ext.sfree       0000_0000_0002_9AD8  170712
\c ext.stotal      0000_0000_0003_D850  251984
\c ext.bfree       0000_0000_0535_B000  87404544    83.3 MiB
\c ext.btotal      0000_0000_07B0_A000  129015808     123 MiB
\c ext.physsfree   0002_9AD8  170712
\c ext.physstotal  0003_D850  251984
\c ext.physfree    0002_9AD8  170712
\c ext.phystotal   0003_D850  251984
\c ext.reserved    0000_0000_0000_0000  0
\c -

The fields after \cw{ext.btotal} are only displayed
if the \cw{EXPANDED} keyword is specified.


\H{eld-dosstrat} DOSSTRAT - Display DOS memory allocation strategy and UMB link status

This ELD can be installed residently or used transiently.
It displays the current DOS memory allocation strategy
and UMB link status,
as returned by int 21h functions 5800h and 5802h.
An optional FORCE keyword will run the int 21h calls
even if the debugger is in InDOS mode.


\H{eld-dhm} DHM - Dump HMA Memory Control Block chain

This ELD can be installed residently or used transiently.
The DHM command dumps the chain of HMA MCBs.
These are used by MS-DOS v7 and lDOS to partition the HMA,
if it is managed by DOS.

The following parameters are accepted:

\dt FORCE

\dd Force calling int 2Fh function 4A04h even if InDOS

\dt HEADER

\dd Display header line to the list

\dt TABLE

\dd Display header line and format list as a table

\dt Offset expression

\dd Do not call int 2Fh function 4A04h,
instead use expression result as first HMCB offset
(in segment FFFFh).
It is assumed that A20 is on.
Usually 30h will access the first HMCB.


\H{eld-errfix} ERRFIX - Fix error message display

This ELD cannot be used transiently,
it must be installed residently
using an \cw{INSTALL} keyword.

The purpose of this ELD is to improve the display
of the \cq{^ Error} message (the "error carat")
in the presence of other ELDs.
Integration with errfix.eld has been added
to the following Extensions:

\b EXTNAME

\b ALIAS

\b VARIABLE

\b IFEXT

If ERRFIX has been installed,
modifications to a command made by them
will be reflected in the column
at which the \cq{^ Error} message is written.
ERRFIX now also works to put the message
at the correct position if a Script for lDebug file
contains a tab,
or a tab is entered when getinput mode is disabled.
This assumes that tabs cause the next text
to be aligned to an 8-column tab stop boundary.

The resident ERRFIX command accepts five different commands:

\dt UNINSTALL

\dd Uninstall the ELD

\dt DEBUG

\dd Display debugging output's status (disabled or enabled)

\dt DEBUG ON

\dd Enable debugging output

\dt DEBUG OFF

\dd Disable debugging output

\dt DEBUG TOGGLE

\dd Toggle status of debugging output

The debugging output will dump the command line contents
(at the beginning of the \cw{line_in} buffer)
at the time the error handler is called.

Every text byte takes up three columns in the dump.
Tabs are replaced by the text \cq{\\t},
unexpected Carriage Returns or Line Feeds
are replaced by the texts \cq{cr} or \cq{lf} respectively,
and all other control codes (ASCII code below 32)
are replaced by a single dot.
The end of the buffered text is indicated
by an all-caps \cq{CR}.
Below each text byte,
the expected column is displayed as two hexadecimal digits.
The text and column at which the error message
will be written are both
marked by an asterix \cq{*} prefix
within the dump.

Examples, with ERRFIX and VARIABLE and EXTNAME installed:

\c ~-ext bases.eld
\c  e  x  t     b  a  s  e  s  .  e  l  d *CR
\c  00 01 02 03 04 05 06 07 08 09 0A 0B 0C*0D
\c                ^ Error
\c ~-ext bases
\c  e  x  t     b  a  s  e  s  .  E  L  D *CR
\c  00 01 02 03 04 05 06 07 08 08 08 08 08*09
\c            ^ Error
\c ~-ext set run vldfoo=r ax .
\c ~-%vldfoo% .
\c  r     a  x     .    *.  CR
\c  00 00 00 00 00 00 08*09 0A
\c            ^ Error
\c ~-variable run -h%vldfoo% .
\c  -  h *r     a  x     .     .  CR
\c  0D 0E*0F 0F 0F 0F 0F 0F 17 18 19
\c                  ^ Error
\c ~-variable run %% %vldfoo%
\c *%     r     a  x     .  CR
\c *0D 0F 10 10 10 10 10 10 18
\c                ^ Error
\c ~-


\H{eld-rcexec} RCEXEC - Add RC.EXECUTE command

This ELD cannot be used transiently,
it must be installed residently
using an \cw{INSTALL} keyword.

Running the new \cw{RC.EXECUTE} command that's added by this ELD
is handled by replacing the text \cw{RC.EXECUTE} by \cw{RC.REPLACE},
then injecting an \cw{RC} command to immediately run the RC buffer.
This way a single command can be used to run multiple commands.
This is particularly useful for alias.eld aliases.

Other than the \cw{RC.EXECUTE} command,
this ELD only supports the \cw{RCEXEC UNINSTALL} command
to try uninstalling this ELD.


\H{eld-devices} DEVICES - List device driver headers and DPBs

This ELD can be installed residently or used transiently.
The DEVICES command lists all device driver headers in the system,
or a subset of them.
It currently only operates when not in InDOS mode.

Keywords may be specified to indicate what filter to apply:

\dt CHAR

\dd Display character devices

\dt BLOCK

\dd Display block devices

\dt DPB

\dd Display block devices and their DPBs

If any keyword is specified, only the selected items are displayed.
In the absence of all keywords, everything is displayed.


\H{eld-sbranch} SBRANCH - Search for short or near direct branches to a target

This ELD can be installed residently or used transiently.
Given a 16-bit range and a 16-bit target offset,
this ELD searches for branches within the range segment
that appear to point to the target.
Only near or short immediate, direct branches are found, namely:

\b JMP short

\b JCC short

\b LOOP short

\b JMP near

\b CALL near

Because all of these encode their targets using a relative number,
they can be found even when the exact segment base
as required for proper execution isn't known.

The \cw{SBRANCH} command accepts exactly two parameters:
A range parameter for the search range,
followed by a target offset given as a number.

This ELD is not intended for use on segments larger than 64 KiB
or code segments that default to 32-bit osize/asize.
Size prefixes are also not handled by this ELD.

The output of this ELD is similar to that of the S command (\k{cmds}).
It also writes to the same variables: SRC, SRO, and SRS.


\C{eldformat} Extension for lDebug format

\H{eldexe} ELD executable format

An ELD file may have an "ELD trailer header". If present,
this structure must be located at the very end of the file.
It has the following structure:

\c         struc ELD_TRAILER_HEADER
\c eldthSignature:         resb 8  ; "ELD1TAIL"
\c eldthHeaderOffset:      resd 1  ; negative displacement from eldthSignature,
\c                                 ;  add this dword to the seek offset
\c eldthReserved:          resw 1  ; reserved, must be initialised to zero
\c eldthChecksum:          resw 1  ; sum of all words in trailer header = 0
\c         endstruc
\c         endarea ELD_TRAILER_HEADER, 1

If the trailer header is present, then
the seek offset of eldthSignature plus the value in
\cw{dword [eldthHeaderOffset]} gives the seek offset
of the ELD header.
The ELD header must start before the trailer header,
that is the computed ELD header offset must be below the
offset of the ELD trailer header.
If the ELD trailer header is not present then the ELD header
must be located at seek offset 0,
at the very beginning of the file.

(The eldapend.c tool allows to append an ELD to an existing file
along with the appropriate ELD trailer header.)

The ELD header structure has the following structure:

\c                 ; ELD executable header
\c         struc ELD_HEADER
\c eldhSignature:          resb 4  ; "ELD1"
\c                         resb 3  ; reserved
\c                         resb 1  ; 26 (Ctrl-Z)
\c eldhCodeOffset:         resd 1  ; position displacement from eldSignature
\c eldhCodeImageLength:    resw 1  ; amount bytes, at least 32
\c eldhCodeAllocLength:    resw 1  ; amount bytes, added to prior. sum < 64 KiB
\c eldhDataOffset:         resd 1
\c eldhDataImageLength:    resw 1  ; (zero allowed)
\c eldhDataAllocLength:    resw 1  ; (zero allowed)
\c eldhCodeEntrypoint:     resw 1  ; within code section, used as displacement
\c eldhReserved:           resb 4  ; reserved
\c eldhExtensionSize:      resw 1  ; from eldhSignature, -> past eldhx fields in use
\c         endstruc
\c         endarea ELD_HEADER, 1

The first four bytes and the 8th byte are checked
to match the known format by the debugger.
Extensions should go into the last 6 bytes
which should be zero-initialised for now.
That is, unless a new ELD format is chosen,
which is indicated by changing the signature in the first four bytes.
The header is exactly 32 Bytes long.
The last field, \cw{eldhxExtensionSize}, is the first such extension.
It specifies the size of the extension header, refer to \k{eldexeext}.

The header must be found either using
the ELD trailer header or it must be found
at the very beginning of the ELD file.
The offsets given in the fields
\cw{eldhCodeOffset} and \cw{eldhDataOffset}
are to be interpreted as being displacements
that are added to the base equal to
the position of the start of the ELD header structure.
(This is the position of the \cw{eldhSignature} field.)

The length fields are typically paragraph-aligned
but this is not a requirement.
However, the resulting allocation of code and data space
in memory is always rounded up to a paragraph boundary.
The image and alloc length fields for either
the code space or the data space
must not overflow 16 bits when added.
(Code and data together may exceed 64 KiB however.)
Keep in mind that ELD code space is typically 8 or 16 KiB
(up to 65_520 Bytes maximum) and ELD data space is by default 16 KiB.

Allocation beyond the images is not generally initialised
by the debugger.
If the ELD wishes to initialise it,
this needs to be included in the ELD code.

The entrypoint field is an offset within the code section.
The exact IP value is derived from this by adding
the ELD's instance base offset to the entrypoint field value.
The CS value points to the ELD code segment or a
code selector referencing the same segment.
The entrypoint is entered with the following function protocol:

\c                 ; INP:  es:dx -> loaded initial ELD image
\c                 ;        ELD instance structure filled
\c                 ;       es => ELD code area
\c                 ;       ds:di -> link info
\c                 ;       ss:bx -> loaded initial data
\c                 ;       ss:si -> command line tail
\c                 ;       cs:ip -> entrypoint
\c                 ;       ss:sp -> far return address for current mode
\c                 ; STT:  UP, EI

All other registers (cx, ax, bp, fs, gs, high words) are don't cares.

It is expected that the entrypoint will run a linker,
which uses the link info pointed to by DS:DI to link
the ELD with the exposed interfaces of the debugger.


\S{eldexeext} ELD executable extension header

The \cw{eldhxExtensionSize} field in the ELD executable header
specifies the size of the extension header.
If it is zero, this is a backwards compatible indication
of there not being an extension header.

The extension header is of the following format:

\c         struc ELD_HEADERX
\c eldhxHeader:            resb ELD_HEADER_size
\c eldhxDescriptionOffset: resd 1  ; zero if none, from eldhxHeader. <= 128 Bytes
\c eldhxHelpOffset:        resd 1  ; zero if none, from eldhxHeader
\c eldhxLibTable:          resd 1  ; zero if none, from eldhxHeader
\c eldhxDateTimeOffset:    resd 1  ; zero if none, from eldhxHeader
\c         alignb 16
\c         endstruc

Each currently defined extension field can be zero
to indicate it isn't in use.
Therefore, to make use of a field both the \cw{eldhxExtensionSize} field
must point past it and its content must be nonzero.
The fields are as follows:

\dt \cw{eldhxDescriptionOffset}

\dd Points to an ASCIZ string in the file,
relative to the beginning of the header.
This gives a single line describing the ELD.
The terminating NUL must appear in the first 128 bytes
past the beginning.

\dt \cw{eldhxHelpOffset}

\dd Points to another ASCIZ string.
This gives a help message.
Unlike the description,
it is expected that the help message contains linebreaks.

\dt \cw{eldhxLibTable}

\dd Points to an ELD_LIBTABLE structure, refer to \k{eldexelib}.
The presence of this indicates that this ELD
is a library ELD, containing other ELDs.
This is only used as yet for \cw{extlib.eld}
and its compressed counterpart \cw{extpak.eld}.

\dt \cw{eldhxDateTimeOffset}

\dd Points to an ASCIZ string.
The string is a date time stamp,
currently always in a combined ISO 8601 format,
with seconds precision,
with the time zone indicator \cq{Z}.
For instance, \cw{2025-07-18T18:38:26Z}.

\lcont{

After the date time stamp's terminating NUL,
an extension follows.
This is currently always a zero byte.
If this extension is defined in a future revision,
its use is indicated by a nonzero byte in this position.

}

The help, library table, and date time stamp are usually
all contained within the ELD's data image.
However, this is not required.


\S{eldexelib} ELD library executable format

The library table, if present, is pointed to by
the \cw{eldhxLibTable} field in the extension header.
It should be aligned to a dword boundary,
albeit this is not required at this time.
This is the structure of its beginning:

\c         struc ELD_LIBTABLE
\c eldltFormat:            resw 1
\c         ; 0 = uncompressed
\c         ; 2 = heatshrink compressed
\c         ; 3 = lzexedat -4 compressed
\c         ; 4 = lzexedat -4 -l compressed
\c eldltAmount:            resw 1
\c eldltOffset:            resd 1  ; from eldhxHeader
\c eldltCompressedLength:          ; (dword, only present if format 2, 3, or 4)
\c         endstruc
\c         endarea ELD_LIBTABLE, 1

The \cw{eldltAmount} field indicates how many ELDs are contained
in this library.
It is valid for this field to hold a zero,
albeit this isn't ever the case yet.

The \cw{eldltOffset} field gives the position
of the beginning of the image of contained ELDs,
relative to the beginning of the library's ELD header.
This image is compressed if the library format
equals 2, 3, or 4.
(Format 1 was an earlier format, now unused.)

The field named \cw{eldltCompressedLength} is only present
for the three supported compressed formats.
It gives the length of the compressed image.
It was absent in format 1, which is why format 2 was created.

After either \cw{eldltOffset} or \cw{eldltCompressedLength},
the list of per-ELD table entries starts.
This contains as many entries as indicated by \cw{eldltAmount}.
Every entry is 12 bytes long.

The first dword indicates a displacement
within the image of contained ELDs,
pointing to an ELD's header.
If the image is compressed,
this dword addresses the depacked data,
not the compressed image.

The trailing 8 bytes give the contained ELD's
library entry name.
If it is shorter than 8 bytes it is padded using blanks (ASCII 32).


\H{eldinstance} ELD instance format

Each ELD instance is stored in the ELD code space
with the following format:

\c                 ; ELD instance header
\c         struc ELD_INSTANCE
\c eldiStartCode:          resw 1  ; -> this structure itself (para aligned)
\c eldiEndCode:            resw 1  ; -> behind memory used by instance (para aligned)
\c eldiStartData:          resw 1  ; -> data in data entry section (para aligned), or 0
\c eldiEndData:            resw 1  ; -> behind data (para aligned), or 0
\c eldiIdentifier:         resb 8  ; blank-filled text
\c eldiFlags:              resw 1  ; flags
\c eldiReserved:           resb 14 ; reserved
\c         endstruc
\c                 ; flags for eldiFlags:
\c eldifResident:          equ 1

The first field references its own address.
The second field indicates where the next ELD instance lives,
unless it matches the value of \cw{word [extseg_used]}.
The second field must always be at least the value of the
first field plus 32 (the size of the instance header).
The third and fourth field specify where the ELD data block
associated with this ELD instance lives,
unless both fields are zero indicating no ELD data block.
All of these first four fields are initialised
by the loader (usually the debugger EXT command handler)
upon initialising an ELD.
However, the ELD is free to modify them within the given constraints.
(Note that the ELD buffer fields described in \k{eldbuffers}
must be modified to match the ELD instance fields,
depending on how they are changed.)

The fifth field contains an 8 byte all-printable-ASCII text name
that identifies the ELD.
It should be initialised within the ELD executable.
When shorter than 8 bytes, it should be padded with blanks (value 32).

The flags field indicates whether the ELD instance is resident.
If it is resident, then other commands (including the EXT command
and ELD space reclaim) will not re-use the code or data areas
referenced by this instance.
If it is not resident,
then any re-entry into the debugger's \cw{cmd3} command loop
should be assumed to overwrite this instance's memory.
Note that any DOS I/O and any debugger code that may
branch to the debugger error handlers may become
a point at which the debugger returns to the command loop.

The remaining fields are reserved
and should be initialised to all zeroes.


\H{eldlinkinfo} ELD link info format

The ELD link info table looks like the following structure:

\c                 ; ELD link info header
\c         struc ELD_LINKINFO
\c eldlSignature:          resw 1  ; 0E1D1h
\c eldlReserved:           resw 2
\c eldlUseLinkHash:        resw 1
\c eldlDataAmount:         resw 1
\c eldlDataPrefixes:       resw 1
\c eldlDataEntries:        resw 1
\c eldlDataAddresses:      resw 1
\c eldlCodeAmount:         resw 1
\c eldlCodePrefixes:       resw 1
\c eldlCodeEntries:        resw 1
\c eldlCodeAddresses:      resw 1
\c         endstruc

The \cw{eldlUseLinkHash} field should be 1 to indicate hashes are used,
and 0 to indicate the prefix text is used instead.
Other values are not valid to current ELDs.

It is expected that a linker embedded into an ELD
will use this table to link to the exposed debugger interfaces.
The linker may also be used to resolve internal references
of the ELD to its own code section and data block,
both of which are loaded to dynamically chosen offsets.

The amount fields indicate how many different links
of each type there are. All three arrays of the same type
have as many entries as the amount field of that type indicates.

The prefixes table contains either a 16-bit hash value
per link name, or the first two text bytes of each link name.
The hash value is calculated using the symbolic branch
text hash function, which is implemented as follows:

\c hash = 1
\c for each text value byte:
\c   hash = (hash * 31 + value byte) & 0FFFFh

The entries table contains a word per link that
points to a byte-counted message string
in the same segment as the link info table. This message
starts with a byte giving the remaining length of the message.
If hashes are used, the message is the entire link name.
Otherwise, the message is the link name remaining
after the first two bytes.
(Link names shorter than two bytes are not allowed.
Link names should be at most 64 bytes long.)

The address table for the data links
contains one word per link.
This address is equal to the data link value,
typically but not always an offset in the debugger stack segment.

The address table for the code links
contains two words per link.
The first word is equal to the code link offset value.
This is the address of the code in its respective code section.
The second word indicates which section the link points to.
It must be below 3, and indicates the section as follows:

\dt 0

\dd \cw{lDEBUG_CODE}

\dt 1

\dd \cw{lDEBUG_CODE2} (only used if _DUALCODE build option enabled)

\dt 2

\dd \cw{lDEBUG_ENTRY} (not used yet)


These values must be used with the contents of the
\cw{linkcall_table} to determine the offsets within
the default ELD (\cw{LINKCALL}) which must be called
in order to transfer control to the respective section.
The reference to the link call table must be found
by linking part of the linker itself first,
using the data link to this table.


\H{eldlinkcall} ELD link call table

The link call table contains mappings from section values
in the code links to offsets within the ELD code segment.
These offsets are entries into the builtin default ELD,
called LINKCALL.
This ELD is installed by the debugger's init if possible.
It currently occupies a fixed size of 128 Bytes,
including its own ELD instance header stored
at offset 0 in the ELD code segment.
Thus if no regular ELDs are currently installed residently
then a regular ELD will always be loaded to
offset 0080h in the ELD code segment.
(Thus a \cw{--local-offset 80h} switch to TracList is useful.)

The link call table has the following format:

\dt word .init

\dd Specifies table is initialised and its format. Must be 1.

\dt word Amount

\dd Specifies how many section records follow.
Typically 2 or 3.

\dt dword per Section Record

\dd Each record has the following format:

\lcont{

\dt word Section Index

\dd Match for a section value from a code link.

\dt word Call Offset

\dd Offset to call in ELD code segment.

}


An ELD link call is constructed as follows:

\b Opcode byte for call rel16: 0E8h.

\b Displacement word in rel16 format pointing to appropriate call offset.

\b 2 bytes of code to handle return path, typically a jump short (0EBh).

\b Offset word of code to call in target section.


The ELD linker is responsible for filling in this structure
for every link call that is to be used.
The displacement is calculated from the call offset field
of the link call table entry matching the section value
from the code link.
It must be calculated by subtracting the offset behind
the near call rel16 instruction.
The offset word to call is copied from the code link directly.


\H{eldlinker} ELD linker internals

The ELD linker is composed of three files:

\dt elddata.mac

\dd ELD link data and internal relocations macros

\dt eldcall.mac

\dd ELD link call macros

\dt eldlink.asm

\dd ELD linker code and dump of relocation tables


\S{elddatamac} ELD data macros

The ELD data macros contain the following mmacros for users:

\dt \cw{internalcoderelocation}

\dd Can be used in DATA section or CODE section.
Section type must match \cq{DATA} to indicate a data section.
Links a 16-bit word to the place the ELD code section is loaded.
Parameter specifies offset from current assembly address,
defaulting to \cw{-2} to place the relocation at the end
of the prior instruction.
The relocation must be filled with an address
that uses the code section vstart,
typically a label in the code section.

\dt \cw{internaldatarelocation}

\dd Can be used in DATA section or CODE section.
Section type must match \cq{DATA} to indicate a data section.
Links a 16-bit word to the place the ELD data section is loaded.
Parameter specifies offset from current assembly address,
defaulting to \cw{-2} to place the relocation at the end
of the prior instruction.
The relocation must be filled with an address
that uses the data section vstart,
typically a label in the data section.

\dt \cw{linkdatarelocation}

\dd Can be used in DATA section or CODE section.
Section type must match \cq{DATA} to indicate a data section.
Links a 16-bit word to a data link of the debugger.
First parameter is data link name.
Second parameter specifies offset from current assembly address,
defaulting to \cw{-2} to place the relocation at the end
of the prior instruction.
Third parameter is the keyword \cq{required} (default)
or \cq{optional}.
The relocation must be filled with an address based on
the label \cw{relocateddata}.
The value of this label is subtracted during linking,
and the value of the data link is added.
If the data link is optional,
a missing link will have the linker zero the relocation field.


\S{eldcodemac} ELD code macros

The ELD code macros contain the following mmacros for users:

\dt \cw{houdini}

\dd Emits a conditional int3 breakpoint.
Can be disabled at build time with \cw{_HOUDINI=0} define.
Can be disabled at run time by clearing DCO7 flag 100h
or disabling debuggable mode.

\dt \cw{extcall}

\dd Sets up a 7-byte ELD extension call into the debugger.
This should only be used in the CODE section,
that is a section with type not equal to \cq{DATA}.
An appropriate reference to a code link
is added to the link tables.
There is a second parameter allowed,
defaulting to \cq{required}.
The other options are \cq{optional} and \cq{PM required}.
When the code link for an optional extcall is not found,
the near call instruction is overwritten with three NOP instructions.

\dt \cw{extcallcall}

\dd Sets up a 3-byte call to an 8-byte extension call site,
which will be composed of
a 7-byte ELD call and a \cw{retn} instruction.
This should only be used in the CODE section,
that is a section with type not equal to \cq{DATA}.
Multiple \cw{extcallcall} uses to the same target
will use the same extension call site.
This is the same code size for two calls,
and saves code size for three or more calls.
However, it deoptimises the call stack because
an additional indirection is added.
(The extension call site spends another word
on the near return address
that points back to the \cw{extcallcall} user.)
This macro cannot be used after eldcall_dump_callcall
is used.

\dt \cw{eldcall_dump_callcall}

\dd Must be called like \cq{eldcall_dump_callcall ELDCALL_CALLCALL_LIST}.
Dumps the extension call sites for all prior uses
of the \cw{extcallcall} mmacro.
Also will disable further use of the \cw{extcallcall} mmacro.
This should be used in the CODE section,
before the label to calculate the resident or installed size.
(Resident size is the ELD code size after the linker is discarded.
Installed size is the ELD code size that remains
if the ELD is installed residently.)


\S{eldlinkasm} ELD linker sources

The ELD linker does not define any mmacros.
The assembly source file generally should be included
at the very end of the CODE section,
and must be placed after all uses of the ELD data and code macros.
The only lines after the include directive
should be an alignment directive and the equate
for the code section size.

The linker uses two labels: \cq{linker} is the code entrypoint
into the linker, which should be called like this:

\c                 ; INP:  es:dx -> loaded initial ELD image
\c                 ;        ELD instance structure filled
\c                 ;       es => ELD code area
\c                 ;       ds:di -> link info
\c                 ;       ss:bx -> loaded initial data
\c                 ;       ss:si -> command line tail
\c                 ;       cs:ip -> entrypoint
\c                 ;       ss:sp -> far return address for current mode
\c                 ; STT:  UP, EI

This is typically entered into the ELD executable header's
field named \cw{eldhCodeEntrypoint},
using a directive like \cq{dw linker - code}.

The second label used by the linker is \cq{start},
which the linker will branch to once it
has successfully finished linking.
This is called with the following protocol:

\c                 ; INP:  es => ELD code segment (writable)
\c                 ;       ds:si -> command line tail
\c                 ;       ds:bx -> ELD data block
\c                 ;       ss:sp -> far return address for current mode
\c                 ; STT:  ds = ss, UP, EI

The far return address passed to these two entrypoints
allows to return to the debugger
without the need for a code link to the \cw{cmd3} command loop.
It expects a result code in ax, which it will display
as an error code in case it is above-or-equal 0FF00h.
The linker returns with code 0FFFFh if a required link is missing.
The reclaim ELD returns with code 0FFFDh on errors.


\S{eldtwopasslinker} ELD two-pass linker

The linker will use two passes by default.
The first pass links the linker itself.
The second pass links the ELD application.
If the first pass succeeded,
the second pass may utilise the debugger output interfaces
to display diagnostic messages (warnings or errors).
The second pass will thus emit error messages
indicating exactly which links are missing, if any.


\H{eldinterfaces} ELD interfaces

\S{eldbuffers} ELD code and data buffers

The ELD code section is referenced with the following variables:

\dt \cw{extseg}

\dd ELD code section's segment

\dt \cw{extcssel}

\dd In Protected Mode, code selector to ELD code section (D bit = 0)

\dt \cw{extdssel}

\dd In Protected Mode, data selector to ELD code section (writable)

\dt \cw{extseg_size}

\dd Size of the ELD code section (Bytes), para-aligned, 0 to 65_520

\dt \cw{extseg_used}

\dd Amount of Bytes currently allocated to ELD instances,
para-aligned,
must match \cw{eldiEndCode} of the last ELD instance


The ELD data area is referenced with the following variables.
It always lives in the data/entry/stack section of the debugger.

\dt \cw{extdata}

\dd Offset of ELD data area start, para-aligned.
This must be at least 256.

\dt \cw{extdata_size}

\dd Size of the ELD data area (Bytes), para-aligned

\dt \cw{extdata_used}

\dd Amount of Bytes of the ELD data area
that are currently allocated to ELD instances,
para-aligned

The \cw{extdata_size} and \cw{extdata_used} values have to be added
to the offset base in \cw{extdata} to receive offsets
in the debugger data section.
The \cw{extdata + extdata_size} calculation must not
overflow and may result in up to 65_520.
This maximum is reached if the /Y=MAX switch to init was specified.


\S{eldcommand} ELD command handler

The ELD command handler allows resident ELDs to be called
whenever the \cw{cmd3} command loop of the debugger
has received a command and is about to execute it.
The ELD command handler is called soon after the command loop
has received a command from the \cw{getline} function.
It is valid for the ELD command handler to modify the buffered text,
pass on control to the subsequent command handler without changes,
or completely take over the command.
In the latter case, the ELD should branch back to \cw{cmd3}
once it is done executing the command.

Multiple ELDs can install command handlers.
The command handlers consist of a certain structure which
contains either an extcall to the label \cw{cmd3_not_ext}
(if no further ELD has installed a command handler)
or a downlink made of a rel16 near jump to the next ELD's command handler.
Branching to this downlink or extcall structure allows to pass on a command
(modified or not) to the next ELD,
or finally to the debugger's normal command processing.

The command handler entrypoint is called with the following registers:

\c ; INP:  al = first non-blank byte of command text
\c ;       si -> subsequent command text
\c ;       command text is stored in line_in variable
\c ;       sp = word [savesp]
\c ; STT:  ds = es = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode

The same protocol should generally be followed for passing on
a command to the next command handler or back
to the debugger's command processing.


The command entrypoint must adhere to this structure
for the first ELD installing a command handler:

\b A strict short jump to behind the downlink structure (2 Bytes, 0EBh 08h)

\b An extcall to \cw{cmd3_not_ext}, padded to 8 Bytes size (starts with 0E8h)

If another ELD command handler is already installed,
one of the two ELDs will have its command handler modified as follows:

\b A strict short jump to behind the downlink structure (2 Bytes, 0EBh 08h)

\b A near jump to the next command handler (starts with 0E9h)

\b Padding to 8 Bytes size

The top-most ELD command handler is pointed to by the word variable \cw{ext_command_handler}.
To install or uninstall a command handler,
an ELD should use a data link to this variable.


\S2{eldcommand-install} Procedure for installing ELD command handler

The suggested procedure for installing a command handler is:

\n Adjust sizes of ELD code instance and ELD data block to installed sizes

\n Obtain value of the debugger variable \cw{ext_command_handler}

\n If value is zero, skip to step \k{write_eld_command_handler}

\n If value is nonzero:

\lcont{

\n Overwrite first byte of our ELD's extcall with 0E9h to create a downlink

\n Calculate displacement to write to our downlink to address the value obtained

\n Write the displacement to our structure to finish the downlink

}

\n{write_eld_command_handler} Mark our ELD as resident in the ELD instance flags,
if it isn't yet

\n Write our ELD's command handler address
into the debugger variable \cw{ext_command_handler}


\S2{eldcommand-uninstall} Procedure for uninstalling ELD command handler

The suggested procedure for uninstalling a command handler is:

\n Obtain value of the debugger variable \cw{ext_command_handler}

\n Verify the value is nonzero, or stop the attempt as this is an error condition

\n If value matches our command handler:

\lcont{

\n Check whether our handler does have a downlink structure
(ie it has opcode 0E9h)

\n If yes, calculate the offset referenced by the downlink's displacement
and write this offset to the debugger variable \cw{ext_command_handler}

\n If no, write a zero to the debugger variable \cw{ext_command_handler}

\n Done

}

\n Else:

\lcont{

\n{next_eld_command_handler}
Verify that the current handler has a downlink structure
(ie it has opcode 0E9h), or stop on error condition

\n Remember the current handler in case its downlink matches our handler

\n Calculate the offset of the next handler from the downlink's displacement

\n If the offset doesn't match ours yet go back to step
\k{next_eld_command_handler}

}

\n Copy our downlink or extcall structure to the remembered previous handler,
adjusting the downlink or extcall displacement (same position)
to make it work at the offset of the remembered previous handler
(thus add our base to the displacement then subtract their base)

\n Done


\S{eldinject} ELD command injection

The ELD command injection allows an ELD to run
most of the \cw{cmd3} command loop and then regain the control flow.
At that point,
the ELD may either return to the \cw{cmd3} command loop,
or it may inject a command of its own creation,
or it may continue the last part of the command loop
which calls \cw{getline}.

Installing command injection is done by writing an offset
of a handler within the ELD code section
into the debugger variable \cw{ext_inject_handler}.
Note that this variable is always cleared to zero
when it is read by the \cw{cmd3} command loop.
To do command injection again,
the inject handler needs to write to the variable again.

An inject handler being installed may preserve the prior value
of the \cw{ext_inject_handler} variable
and restore the value upon uninstalling itself.

The inject handler is called with this protocol:

\c ; INP:  sp = word [savesp]
\c ;       line_out -> prompt message
\c ;       di -> behind prompt message
\c ; STT:  ds = es = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode

The inject handler may usually branch to one of three entrypoints:

\b \cw{cmd3} to restart command loop

\b \cw{cmd3_not_inject} to have command loop continue to call \cw{getline00} next
(must pass di -> behind prompt message)

\b \cw{cmd3_injected} to have command loop accept an injected command

In the latter case, the entrypoint is to be branched to with
the following protocol:

\c ; INP:  al = first non-blank byte of command text
\c ;       si -> subsequent command text
\c ;       command text is stored in line_in variable
\c ;       sp = word [savesp]
\c ; STT:  ds = es = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode


\S{eldpreprocess} ELD preprocess handler

The ELD preprocess handler allows resident ELDs to be called
whenever the \cw{cmd3} command loop of the debugger
has received a command and is about to execute it.
The ELD preprocess handler is called directly after the command loop
has received a command from the \cw{getline} function
(or from an inject handler).
It is valid for the ELD preprocess handler to modify the buffered text,
or pass on control to the subsequent handler without changes.

Preprocess handlers should not completely take over commands passed to them.
The purpose of preprocess handlers is to see commands first,
before they are passed to the ELD command handler chain.
That means all installed preprocess handlers will see a command,
even if one of the ELD command handlers will take over the command execution.

Preprocess handlers have the same structure as ELD command handlers,
except they use the debugger variable \cw{ext_preprocess_handler}
to point to the first preprocess handler,
and the last preprocess handler should chain to \cw{cmd3_preprocessed}.
Their installation and uninstallation procedures are the same
except for using the other variable and branch destination.
The protocol comment shown for ELD command handlers
also applies to preprocess handlers.


\S{eldamis} ELD AMIS handler

This handler hooks into the debugger's AMIS interface.
The handler is called early,
after matching the AMIS multiplex number
but before any of the implementations
of debugger functions.

AMIS handlers have a similar downlink structure in their entrypoint
as command handlers and preprocess handlers.
They start with a strict short jump,
but the rel8 displacement is only equal to 3.
A downlink is composed of a strict near jump.
The final AMIS handler contains a far return instruction instead,
and the downlink field is padded to 3 bytes using two NOP instructions.

The handler is called with this protocol:

\c ; INP:  NC
\c ;       ds => entry segment
\c ;       ss:sp -> far return address, ds, dx, cx, bx, ax, iret frame
\c ;       cx destroyed
\c ;       ax, bx, dx, bp, si, di, es, ss = original
\c ;       fs, gs, high words = original
\c ; OUT:  stack frame modified if desired
\c ;       CY to iret after popping frame,
\c ;        should retf (not use downlink)
\c ;       NC to process function as usual (stack al = function),
\c ;        may use downlink
\c ; STT:  Real/Virtual 86 Mode
\c ;       ss != debugger data/entry/stack segment
\c ;       UP
\c ;       DI


\S{eldputs} ELD multi-purpose puts handler

The ELD multi-purpose \cw{puts} handler provides a hook
into the debugger's debug terminal output.
This allows an ELD to filter, store, and/or suppress
output generated by other parts of the debugger or other ELDs.

A multi-purpose \cw{puts} handler is installed by writing an offset
in the ELD code section to the debugger variable \cw{ext_puts_handler}.
If this variable is nonzero,
calls to \cw{puts} (that is, all normal debugger interface output)
will transfer control to the specified handler.
The \cw{puts} handlers now form a chain similar to command handlers,
except that the variable \cw{ext_puts_handler} is used and
the final handler chains back to \cw{puts_ext_done}.
(Prior revisions of the ELDs did not create a chain of handlers.)

If to suppress the message output,
the handler should resume the normal control flow of the debugger
by branching to \cw{puts_ext_done} using an extcall (\e{not} an extcallcall!)
with CY set. The es register should be unchanged but all of
ax, bx, cx, and dx need not be preserved.
386-specific register upper words should be preserved.
If to continue to output the message,
the handler should chain to the next handler with NC
and es unchanged, and es:dx -> the message to display, length ax.
The bx and cx registers never have to be preserved.

Each handler is called with this protocol:

\c ; INP:  es:dx -> message to display
\c ;       ax = length of message
\c ;       NC
\c ; OUT:  CY to not pass on the message for display or write to silent buffer,
\c ;        have to transfer control directly to puts_ext_done (using extcall)
\c ;        ax and dx may be changed
\c ;       NC to pass on the message,
\c ;        may chain to next handler (or transfer to puts_ext_done)
\c ; CHG:  bx, cx, (upon transfer to puts_ext_done with CY: ax, dx)
\c ; STT:  ds = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode
\c ;       in Protected Mode, es should have a selector that
\c ;        references a segment base which matches an 86 Mode segment


\S2{eldputs-puts-ext-next} ELD multi-purpose puts handler: puts_ext_next entrypoint

If a multi-purpose \cw{puts} handler wishes to display
text that differs from what it was passed,
it should call to the \cw{puts_ext_next} handler.
The call may be an \cw{extcall} or \cw{extcallcall}.
The handler must pass an appropriate entrypoint into
the ELD code section in cx.
This is usually the chain entry of the handler,
which is either a jump to a downlink or an extcall (not extcallcall)
to \cw{puts_ext_done}.
(If the chain entry is passed, there is no risk of
re-entering the calling handler.)

The protocol for \cw{puts_ext_next} is as follows:

\c ; INP:  es:dx -> message to display
\c ;       ax = length of message
\c ;       NC
\c ; CHG:  ax, bx, cx, dx
\c ; OUT:  -
\c ; STT:  ds = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode
\c ;       in Protected Mode, es should have a selector that
\c ;        references a segment base which matches an 86 Mode segment
\c ;        (this is true of the debugger stack selector)

Passing a CY to \cw{puts_ext_next} could indicate
to skip the message displayed.
However, if the chain entry passed in cx has a downlink
to another multi-purpose \cw{puts} handler
then the Carry Flag is most likely ignored.

If the entry is a final transfer to \cw{puts_ext_done},
the debugger function \cw{transfer_ext_cx} used to bounce
the control flow back into the ELD code section
will now preserve the Carry Flag.
(A prior bug would force NC in this transfer function
for lDebugX, the _PM=1 build.)

Finally, there is no supported use for passing CY here
as the effect of not displaying a message at all
can be achieved by not calling \cw{puts_ext_next} to begin with.


\S{eldputs-copyoutput} ELD puts copyoutput handler

This handler was added to support the co.eld (Copy Output ELD).
It is called whenever the debugger actually outputs text
to the debugger terminal.
This does not include output written only to the silent buffer
or suppressed in the multi-purpose \cw{puts} handler.
Also not included are paging prompts as they are inserted later,
after the \cw{puts} copyoutput handler has returned.

The handlers for this hook form a chain similar to
the ELD command handler. However, they use the variable
\cw{ext_puts_copyoutput_handler} and the last handler
transfers control to \cw{puts_copyoutput_ext_done}.

\c ; INP:  es:dx -> message to display
\c ;       ax = length of message
\c ;       NC
\c ;       byte [in_getinput] = boolean flag indicating if output
\c ;        is from getinput session, either 0 (false) or 0FFh (true)
\c ; CHG:  bx, cx
\c ; OUT:  NC
\c ;       (could set CY and transfer directly to puts_copyoutput_ext_done
\c ;        in order to suppress output)
\c ; STT:  ds = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode
\c ;       in Protected Mode, es should have a selector that
\c ;        references a segment base which matches an 86 Mode segment

As noted above, a \cw{puts} copyoutput handler can suppress
the output passed to it. However,
this is not recommended and no handler currently does this.


\S{eldputs-getline} ELD puts getline handler

This handler was added to support the co.eld (Copy Output ELD)
and errfix.eld (Error carat display fix ELD).

The co.eld functions 0 and 1
are called after getline has received a complete input line
either from int 21h service 0Ah or from the getinput function.
It is not called if a "file" type input source has yielded a line of input.
This happens to match when the debugger enters a line into its
line editor history, which the debugger does directly after
this handler chain returns.

The four functions 2, 3, 4, 5 are for errfix.eld.
Of these, function 2 is called after getline_eol
if the input line was not displayed and
function 3 is called in the same spot if the input line was displayed.
Function 4 is called by the error handler with an offset
to where the error occurred in line_in.
Function 4 may be chained either as function 4 or as function 5,
where function 5 passes an amount of columns while function 4
passes the offset.

The handlers for this hook form a chain similar to
the ELD command handler. However, they use the variable
\cw{ext_puts_getline_handler} and the last handler
transfers control to \cw{puts_getline_ext_done}.

The following protocol is used for the dispatch types 0 and 1 in bl:

\c ; INP:  byte [line_in + 1] = length of text (excluding CR), 0 to 254
\c ;       es:line_in + 2 -> text received, terminated by a CR
\c ;       bl = dispatch type,
\c ;        = 0 if input is from int 21h service 0Ah
\c ;        = 1 if input is from getinput function
\c ;         (note that output corresponding to this input has already
\c ;         been written to the ELD puts copyoutput handler)
\c ; CHG:  ax, bh, cx, dx, si, di
\c ; OUT:  pass along bl to next handler
\c ; STT:  es = ds = ss
\c ;       UP, EI
\c ;       may be in Protected Mode, Real 86 Mode, or Virtual 86 Mode
\c ;       in Protected Mode, es has a selector (stack selector) that
\c ;        references a segment base which matches an 86 Mode segment

The following protocol is used for the dispatch types 2 and 3 in bl:

\c ; INP:  byte [line_in + 1] = length
\c ;       line_in + 2 -> text
\c ;       word [promptlen] = length of prompt
\c ;       al = first non-whitespace text byte
\c ;       si -> next text
\c ;       bl = 2 or 3 means from getline_eol, any line read
\c ;       bl = 2 if not displayed, = 3 if displayed
\c ; CHG:  ah, bh, cx, dx, di
\c ; STT:  ds = es = ss
\c ;       UP, EI

The following protocol is used for the dispatch types 4 and 5 in bl:

\c ; INP:  bl = 4 means want to get effective carat position,
\c ;        si -> text with error
\c ;       bl = 5 means want to get carat position with
\c ;        si = input value for counter
\c ; OUT:  bl == 4 if to run default handling,
\c ;        si may be modified
\c ;       bl == 5 if to use si as number of spaces to indent,
\c ;        si = value for counter
\c ;       bl must be 4 or 5
\c ; CHG:  ax, bh, cx, dx, di
\c ; STT:  ds = es = ss
\c ;       UP, EI

The following protocol is used for the dispatch types >= 6 in bl,
until further notice:

\c ; INP:  bl >= 6 if unknown dispatch type, should just pass along
\c ; CHG:  fl
\c ; STT:  preliminary assumption:
\c ;        ds = es = ss
\c ;        UP, EI


\S{eldvar} ELD variables

ELD variables allow an ELD to add variables
to the debugger's \cq{isvariable?} function,
which is used in the expression evaluator
as well as in the R variable commands.

A certain number of ELD variables are allocated space
in the list of multi-byte-text \cq{isvariable?} structures.
The build option to add these defaults to
reserving space for 16 ELD variables.

ELD variables can be used for special purpose read-only variables,
as the ELD is called for the "special set up" implementation for the variable.
However, writable variables are possible using this interface
only if they are trivial.

An ELD should use the following to install an ELD variable:

\b Data link \cw{ext_var} points to the 10-byte ELD variable structures

\b Data link \cw{ext_var_amount} specifies how many structures exist

\b Data link \cw{ext_var_format} indicates the format of the structures,
currently only format 1 is defined (this should be checked)

\b Data link \cw{ext_var_size} indicates the \cw{ISVARIABLESTRUC_size}
(this should be checked)

\b Data link \cw{isvariable_morebyte_nameheaders.ext} points to
the 2-byte name headers for each ELD variable

\b Data link \cw{var_ext_setup} (albeit actually pointing at code)
is provided to fill in the ELD variable structure,
specifically the \cw{ivSetup} field
which must point to a near function in the expr.asm code section
(hence an ELD has to use this particular function to branch to the ELD's code)

\b Code link \cw{var_ext_setup_done} which the ELD variable set up code
should branch to using an extcall (\e{not} an extcallcall!) once it is done

The following protocol specifies what the variable set up code is called as:

\c ; INP:  ax = array index (0-based)
\c ;       cx = offset of this handler (ip)
\c ;       dil = default size of variable (1..4)
\c ;       dih = length of variable name
\c ; CHG:  si, ax, dx
\c ; OUT:  NC if valid,
\c ;        bx -> var, di = 0 or di -> mask
\c ;        cl = size of variable (1..4)
\c ;        ch = length of variable name


An ELD variable should be installed by scanning the structures
pointed to by \cw{ext_var} for a structure with the first word
(\cw{ivName}) equal to zero.
If this is found, the ELD variable structure is to be copied
into this slot of the \cw{isvariable?} structure array.
The appropriate slot in the name headers also has to be filled
with the first two text bytes of the variable name.

An ELD variable is uninstalled by clearing the first three words
of the structure (\cw{ivName}, \cw{ivFlags}, and importantly \cw{ivAddress}),
and also clearing the name headers slot to a zero value.


\S{eldneartransfer} ELD near transfer interface

This hook allows to enter an ELD from a near call in the
(first) debugger code section.
The ELD can return to the near caller, too.

The entrypoint is \cw{near_transfer_ext_entry}.
This entrypoint's offset address is available as a data link
in order to allow it to be entered into callback variables.

When this entry is run,
the original value of \cw{cx} is pushed,
then the value of \cw{word [near_transfer_ext_address]}
is loaded to \cw{cx},
and then control is transferred to the ELD
via \cw{transfer_ext_cx}.

Note that there is only one entrypoint and
one variable for this interface.
That means either it can only be used for
one particular callback,
or the called ELD function has to
dispatch based on the near return address on the stack.

The bootloaded directory scanner,
accessed by calling \cw{scan_dir_aux},
provides several offsets in its code as data links
to facilitate such dispatching:

\dt \cw{..@boot_scan_dir_return_fat16_root_entry}

\dd Return when called as a FAT12 or FAT16 root directory entry
is to be scanned,
calling \cw{word [handle_scan_dir_entry]}

\dt \cw{..@boot_scan_dir_return_subdir_or_fat32_entry}

\dd Return when called as a subdirectory or FAT32 root directory entry
is to be scanned,
calling \cw{word [handle_scan_dir_entry]}

\dt \cw{..@boot_scan_dir_return_filenotfound}

\dd Return when called as the directory search has ended
after the scan function returned CY,
calling \cw{word [handle_scan_dir_not_found]}


To return to the near caller,
the ELD function should transfer the control flow
to \cw{near_transfer_ext_return}
with an \cw{extcall}, \e{not} an \cw{extcallcall}.
This handler will pop \cw{cx} four times then return near.


\C{cmdhelp} Command help

\H{cmdhelp-ldebug} lDebug help

\c lDebug (YYYY-MM-DD), debugger.
\c
\c Usage: LDEBUG[.COM] [/C=commands] [[drive:][path]progname.ext [parameters]]
\c
\c /C=commands   semicolon-separated list of commands (quote spaces)
\c /IN           discard command line buffer, do not run config
\c /A=MAX        expand auxiliary buffer to maximum, #24_576 Bytes
\c /A=MIN        restrict auxiliary buffer to minimum, #8_208 Bytes
\c /A=number     set auxiliary buffer size to hex number of bytes
\c /A=#number    set auxiliary buffer size to decimal number of bytes
\c /A            alias for /A=MAX
\c /X=[MAX|MIN|number]   change ELD code buffer size, 0 to #65_520 Bytes
\c /Y=[MAX|MIN|number]   change ELD data buffer size, 0 to #29_504 Bytes
\c /H=[MAX|MIN|number]   change history buffer size, #260 to #65_520 Bytes
\c /B            run a breakpoint within initialisation
\c /P[+|-]       append ext to initial filename and search path
\c /F[+|-]       always treat executable file as a flat binary
\c /E[+|-]       for flat binaries set up Stack Segment != PSP
\c /V[+|-]       enable/disable video screen swapping
\c /2[+|-]       enable/disable use alternate video adapter for output
\c progname.ext  (executable) file to debug or examine
\c parameters    parameters given to program
\c
\c For a list of debugging commands, run LDEBUG and type ? at the prompt.


\H{cmdhelp-instsect} INSTSECT help

\c INSTSECT: Install boot sectors. 2018--2024 by E. C. Masloch
\c
\c Usage of the works is permitted provided that this
\c instrument is retained with the works, so that any entity
\c that uses the works is notified of this instrument.
\c
\c DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
\c
\c Options:
\c
\c a:              load or update boot sectors of specified drive
\c /M=filename     operate on FS image file instead of drive
\c /MN             operate on drive instead of image file (default)
\c /MS=number      set sector size of FS image file (default 512)
\c /MO=number      set offset in image file in bytes (default 0)
\c /MOx=number     set offset (x = S sectors, K 1024, M 1024 * 1024)
\c
\c /Fx=filename    replace Xth name in the boot sector, X = 1 to 4
\c /F=filename     alias to /F1=filename
\c
\c /U KEEP         keep default/current boot unit handling (default)
\c /U AUTO         patch boot loader to use auto boot unit handling
\c /U xx           patch boot loader to use XXh as a fixed unit
\c
\c /P KEEP         keep default/current part info handling (default)
\c /P AUTO         patch boot loader to use auto part info handling
\c /P NONE         patch boot loader to use fixed part info
\c
\c /Q KEEP         keep default/current query geometry handling (default)
\c /Q AUTO         patch boot loader to use auto query geometry handling
\c /Q NONE         patch boot loader to use fixed geometry
\c
\c /L KEEP         keep default/current LBA handling (default)
\c /L AUTO         patch boot loader to use auto LBA handling
\c /L AUTOHDD      patch boot loader to use auto LBA (HDD-only) handling
\c /L NONE         patch boot loader to use only CHS
\c
\c /G KEEP         keep all current geometry (default)
\c /G AUTO         read all auto geometry from DOS
\c /G HEADS=x      set geometry CHS heads (x = KEEP, AUTO, numeric)
\c /G SECTORS=x    set geometry CHS sectors (x = KEEP, AUTO, numeric)
\c /G HIDDEN=x     set geometry hidden (x = KEEP, AUTO, numeric)
\c
\c /SR             do not read boot sector from source file (default)
\c /S=filename     read boot sector loader from source file
\c /S12=filename   as /S=filename but only for FAT12 (also /S16, /S32)
\c /SV             validate boot sector jump and FS ID (default)
\c /SN             do not validate boot sector jump and FS ID
\c /SI             validate FAT32 FSIBOOT compatibility (default)
\c /SJ             do not validate FAT32 FSIBOOT compatiblity
\c /SG=sign        check for FAT32 FSIBOOT exact signature match
\c
\c /BS             write boot sector to drive's boot sector (default)
\c /B=filename     write boot sector to file, not to drive
\c /BN             do not write boot sector
\c /BR             replace boot sector loader with built-in one (default)
\c /BO             keep original boot sector
\c /BC             restore boot sector from backup copy
\c
\c Only applicable for FAT32 with sector size below or equal to 512 bytes:
\c
\c /IS             write FSIBOOT to drive's FSINFO sector (default)
\c /I=filename     write FSIBOOT to file, not to drive
\c /IB             write FSIBOOT to boot sector file (see /B=filename)
\c /IN             do not write FSIBOOT
\c /IR             replace reserved field with built-in FSIBOOT (default)
\c /IO             keep original reserved fields (including FSIBOOT area)
\c /IC             restore FSINFO from backup copy
\c /IZ             zero out reserved fields (including FSIBOOT area)
\c /II             leave invalid FSINFO structure
\c /IV             make valid FSINFO if there is none (default)
\c
\c Only applicable for FAT32:
\c
\c /C              force writing to backup copies
\c /CB             force writing sector to backup copy
\c /CI             force writing info to backup copy
\c /CN             disable writing to backup copies
\c /CNB            disable writing sector to backup copy
\c /CNI            disable writing info to backup copy
\c /CS             only write backup copies if writing sectors (default)
\c /CSB            only write sector to backup copy if writing sector
\c /CSI            only write info to backup copy if writing sector


\C{helptopics} Online help pages

\H{helpmain} ? - Main online help

\c lDebug (YYYY-MM-DD) help screen
\c assemble        A [address]
\c attach process  ATTACH psp
\c set breakpoint  BP index|AT|NEW address
\c                   [[NUMBER=]number] [WHEN=cond] [ID=id]
\c  set ID         BI index|AT address [ID=]id
\c  set condition  BW index|AT address [WHEN=]cond
\c  set offset     BO index|AT address [OFFSET=]number
\c  set number     BN index|AT address|ALL number
\c  clear          BC index|AT address|ALL
\c  disable        BD index|AT address|ALL
\c  enable         BE index|AT address|ALL
\c  toggle         BT index|AT address|ALL
\c  swap           BS index1 index2
\c  list           BL [index|AT address|ALL]
\c compare         C range address
\c dump            D [range]
\c dump bytes      DB [range]
\c dump words      DW [range]
\c dump dwords     DD [range]
\c dump interrupts DI[R][M][L] interrupt [count]
\c dump MCB chain  DM [segment]
\c display strings DZ/D$/D[W]# [address]
\c dump text table DT [T] [number]
\c enter           E [address [list]]
\c run extension   EXT [partition/][extensionfile] [parameters]
\c fill            F range [RANGE range|list]
\c go              G [=address] [breakpts]
\c goto            GOTO :label
\c hex add/sub     H value1 [value2 [...]]
\c base display    H BASE=number [GROUP=number] [WIDTH=number] value
\c input           I[W|D] port
\c if numeric      IF [NOT] (cond) THEN cmd
\c if script file  IF [NOT] EXISTS Y file [:label] THEN cmd
\c load program    L [address]
\c load sectors    L address drive sector count
\c move            M range address
\c 80x86/x87 mode  M [0..6|C|NC|C2|?]
\c set name        N [[drive:][path]progname.ext [parameters]]
\c set command     K [[drive:][path]progname.ext [parameters]]
\c output          O[W|D] port value
\c proceed         P [=address] [count [WHILE cond] [SILENT [count]]]
\c quit            Q
\c quit process    QA
\c quit and break  QB
\c register        R [register [value]]
\c Run R extended  RE
\c RE commands     RE.LIST|APPEND|REPLACE [commands]
\c Run Commandline RC
\c RC commands     RC.LIST|APPEND|REPLACE [commands]
\c toggle 386 regs RX
\c search          S range [REVERSE] [SILENT number] [RANGE range|list]
\c sleep           SLEEP count [SECONDS|TICKS]
\c trace           T [=address] [count [WHILE cond] [SILENT [count]]]
\c trace (exc str) TP [=address] [count [WHILE cond] [SILENT [count]]]
\c trace mode      TM [0|1]
\c enter TSR mode  TSR
\c unassemble      U [range]
\c view screen     V [ON|OFF [KEEP|NOKEEP]]
\c write program   W [address]
\c write sectors   W address drive sector count
\c run script      Y [partition/][scriptfile] [:label]
\c
\c Additional help topics:
\c  Registers      ?R
\c  Flags          ?F
\c  Conditionals   ?C
\c  Expressions    ?E
\c  Variables      ?V
\c  R Extended     ?RE
\c  Run keywords   ?RUN
\c  Options pages  ?OPTIONS
\c  Options        ?O
\c  Boot loading   ?BOOT
\c  lDebug build   ?BUILD
\c  lDebug build   ?B
\c  lDebug sources ?SOURCE
\c  lDebug license ?L


\H{helpr} ?R - Registers

\c Available 16-bit registers:             Available 32-bit registers: (386+)
\c AX      Accumulator                     EAX
\c BX      Base register                   EBX
\c CX      Counter                         ECX
\c DX      Data register                   EDX
\c SP      Stack pointer                   ESP
\c BP      Base pointer                    EBP
\c SI      Source index                    ESI
\c DI      Destination index               EDI
\c DS      Data segment
\c ES      Extra segment
\c SS      Stack segment
\c CS      Code segment
\c FS      Extra segment 2 (386+)
\c GS      Extra segment 3 (386+)
\c IP      Instruction pointer             EIP
\c FL      Flags                           EFL

Enter ?F to display the recognized flags.


\H{helpf} ?F - Flags

Recognized flags:

\c Value   Name                      Set                     Clear
\c 0800  OF  Overflow Flag         OV  Overflow            NV  No overflow
\c 0400  DF  Direction Flag        DN  Down                UP  Up
\c 0200  IF  Interrupt Flag        EI  Enable interrupts   DI  Disable interrupts
\c 0080  SF  Sign Flag             NG  Negative            PL  Plus
\c 0040  ZF  Zero Flag             ZR  Zero                NZ  Not zero
\c 0010  AF  Auxiliary Flag        AC  Auxiliary carry     NA  No auxiliary carry
\c 0004  PF  Parity Flag           PE  Parity even         PO  Parity odd
\c 0001  CF  Carry Flag            CY  Carry               NC  No carry

The short names of the flag states are displayed when dumping registers
and can be entered to modify the symbolic F register with R. The short
names of the flags can be modified by R.


\H{helpc} ?C - Conditionals

In the register dump displayed by the R, T, P and G commands, conditional
jumps are displayed with a notice that shows whether the instruction will
cause a jump depending on its condition and the current register and flag
contents. This notice shows either "jumping" or "not jumping" as appropriate.

The conditional jumps use these conditions: (second column negates)

\c  jo             jno             OF
\c  jc jb jnae     jnc jnb jae     CF
\c  jz je          jnz jne         ZF
\c  jbe jna        jnbe ja         ZF||CF
\c  js             jns             SF
\c  jp jpe         jnp jpo         PF
\c  jl jnge        jnl jge         OF^^SF
\c  jle jng        jnle jg         OF^^SF || ZF
\c  j(e)cxz                        (e)cx==0
\c  loop                           (e)cx!=1
\c  loopz loope                    (e)cx!=1 && ZF
\c  loopnz loopne                  (e)cx!=1 && !ZF

Enter ?F to display a description of the flag names.


\H{helpe} ?E - Expressions

Recognized operators in expressions:

\c |       bitwise OR              ||      boolean OR
\c ^       bitwise XOR             ^^      boolean XOR
\c &       bitwise AND             &&      boolean AND
\c >>      bit-shift right         >       test if above
\c >>>     signed bit-shift right  <       test if below
\c <<      bit-shift left          >=      test if above-or-equal
\c ><      bit-mirror              <=      test if below-or-equal
\c +       addition                ==      test if equal
\c -       subtraction             !=      test if not equal
\c *       multiplication          =>      same as >=
\c /       division                =<      same as <=
\c %       modulo (A-(A/B*B))      <>      same as !=
\c **      power

Implicit operater precedence is handled in the listed order, with increasing
precedence: (Brackets specify explicit precedence of an expression.)

\c  boolean operators OR, XOR, AND (each has a different precedence)
\c  comparison operators
\c  bitwise operators OR, XOR, AND (each has a different precedence)
\c  shift and bit-mirror operators
\c  addition and subtraction operators
\c  multiplication, division and modulo operators
\c  power operator

Recognized unary operators: (modifying the next number)

\c +       positive (does nothing)
\c -       negative
\c ~       bitwise NOT
\c !       boolean NOT
\c ?       absolute value
\c !!      convert to boolean

Note that the power operator does not affect unary operator handling.
For instance, "- 2 ** 2" is parsed as "(-2) ** 2" and evaluates to 4.

Although a negative unary and signed bit-shift right operator are provided
the expression evaluator is intrinsically unsigned. Particularly the division,
multiplication, modulo and all comparison operators operate unsigned. Due to
this, the expression "-1 < 0" evaluates to zero.

Recognized terms in an expression:

\c  32-bit immediates
\c  8-bit registers
\c  16-bit registers including segment registers (except FS, GS)
\c  32-bit compound registers made of two 16-bit registers (eg DXAX)
\c  32-bit registers and FS, GS only if running on a 386+
\c  32-bit variables V00..VFF
\c  32-bit special variables DCO, DCS, DAO, DAS, DIF, DPI, PPI
\c  16-bit special variables DPR, DPP, PSP, PPR
\c   (fuller variable reference in the manual)
\c  byte/word/3byte/dword memory content (eg byte [seg:ofs], where both the
\c   optional segment as well as the offset are expressions too)

The expression evaluator case-insensitively checks for names of variables
and registers as well as size specifiers.

Enter ?R to display the recognized register names.
Enter ?V to display the recognized variables.


\H{helpv} ?V - Variables

Available lDebug variables:

\b V0..VF  User-specified usage

\b DCO     Debugger Common Options

\b DAO     Debugger Assembler/disassembler Options

 The following variables cannot be written:

\b PSP     Debuggee Process

\b PPR     Debuggee's Parent Process

\b PPI     Debuggee's Parent Process Interrupt 22h

\b DIF     Debugger Internal Flags

\b DCS     Debugger Common Startup options

\b DAS     Debugger Assembler/disassembler Startup options

\b DPR     Debugger Process

\b DPP     Debugger's Parent Process (zero in TSR mode)

\b DPI     Debugger's Parent process Interrupt 22h (zero in TSR mode)

Enter ?O to display the options and internal flags.


\H{helpre} ?RE - R Extended

The RUN commands (T, TP, P, G) and the RE command use the RE command
buffer to run commands. Most commands are allowed to be run from the
RE buffer. Disallowed commands include program-loading L, A, E that
switches the line input mode, TSR, Q, Y, RE, and further RUN commands.
When the RE buffer is used as input during T, TP, or P with the
SILENT keyword, commands that use the auxbuff are also disallowed and
will emit an error noting the conflict.

RE.LIST shows the current RE buffer contents in a format usable by
the other RE commands. RE.APPEND appends the following commands to
the buffer, if they fit. RE.REPLACE appends to the start of the
buffer. When specifying commands, an unescaped semicolon is parsed
as a linebreak to break apart individual commands. Backslashes can
be used to escape semicolons and backslashes themselves.

Prefixing a line with an @ (AT sign) causes the command not to be
shown to the standard output of the debugger when run. Otherwise,
the command will be shown with a percent sign % or ~% prompt.

The default RE buffer content is @R. This content is also
detected and handled specifically; if found as the only command
the handler directly calls the register dump implementation
without setting up and tearing down the special execution
environment used to run arbitrary commands from the RE buffer.


\H{helprun} ?RUN - Run keywords

T (trace), TP (trace except proceed past string operations), and P (proceed)
can be followed by a number of repetitions and then the keyword WHILE,
which must be followed by a conditional expression.

The selected run command is repeated as many times as specified by the
number, or until the WHILE condition evaluates no longer to true.

After the number of repetitions or (if present) after the WHILE condition
the keyword SILENT may follow. If that is the case, all register dumps
done during the run are buffered by the debugger and the run remains
silent. After the run, the last dumps are replayed from the buffer
and displayed. At most as many dumps as fit into the buffer are
displayed. (The buffer is currently 8 KiB sized by default, though the
/A switch can be specified to init to grow it up to 24 KiB.)

If a number follows behind the SILENT keyword, only at most that many
dumps are displayed from the buffer. The dumps that are displayed
are always those last written into the buffer, thus last occurred.


\H{helpoptions} ?OPTIONS - Options pages

Enter one of the following commands to get a corresponding help page:

\b ?O1     DCO1 - Options

\b ?O2     DCO2 - More Options

\b ?O3     DCO3 - More Options

\b ?O4     DCO4 - Interrupt Hooking Options

\b ?O6     DCO6 - More Options

\b ?OI     DIF - Internal Flags

\b ?OA     DAO - Assembler/Disassembler Options


\H{helpo} ?O - Options

Available options: (read/write DCO, read DCS)

\b 0001 RX: 32-bit register display

\b 0002 TM: trace into interrupts

\b 0004 allow dumping of CP-dependent characters

\b 0008 always assume InDOS flag non-zero, to debug DOS or TSRs

\b 0010 disallow paged output to StdOut

\b 0020 allow paged output to non-StdOut

\b 0040 display raw hexadecimal content of FPU registers

\b 0100 when prompting during paging, do not use DOS for input

\b 0200 (in 86 Mode) do not execute HLT instruction to idle

\b 0400 do not idle, the keyboard BIOS idles itself

\b 0800 use getinput function for int 21h interactive input

\b 1000 in disp_*_size use SI units (kB = 1000, etc). overrides 2000!

\b 2000 in disp_*_size use JEDEC units (KB = 1024)

\b 4000 enable serial I/O (port 02F8h interrupt 0Bh)

\b 8000 disable serial I/O when breaking after 5 seconds Ctrl pressed

\b 0001_0000 gg: do not skip a breakpoint (bb or gg)

\b 0002_0000 gg: do not auto-repeat

\b 0004_0000 T/TP/P: do not skip a (bb) breakpoint

\b 0008_0000 gg: do not auto-repeat after bb hit

\b 0010_0000 T/TP/P: do not auto-repeat after bb hit

\b 0020_0000 gg: do not auto-repeat after unexpectedinterrupt

\b 0040_0000 T/TP/P: do not auto-repeat after unexpectedinterrupt

\b 0080_0000 S: do not dump data after matches

\b 1000_0000 R: do not repeat disassembly

\b 2000_0000 R: do not show memory reference in disassembly

\b 4000_0000 quiet command line buffer input

\b 8000_0000 quiet command line buffer output


More options: (read/write DCO2, read DCS2)

\b 0001 DB: show header

\b 0002 DB: show trailer

\b 0010 DW: show header

\b 0020 DW: show trailer

\b 0100 DD: show header

\b 0200 DD: show trailer

\b 0800 use getinput function for int 21h interactive input in DPMI

\b 1000 H: stay compatible to MS-DOS Debug

\b 2000 idle and check for Ctrl-C in getc

\b 4000 idle and check for Ctrl-C in getc in DPMI

\b 8000 T/TP/P/G: cancel run after RE command buffer execution

\b 01_0000 N: operate in MS Debug style instead of K command alike

\b 02_0000 N: capitalise command line tail

\b 04_0000 explicit 0-length ranges operate in partial MS Debug style

\b 08_0000 R: 16-bit 80-column register dump in MS Debug style

\b 10_0000 R: do variable prompts in MS Debug style

\b 20_0000 R: do variable prompts with underscore separator

\b 40_0000 display linebreak before R command register dump

\b 8000_0000 do not execute HLT to idle in PM


More options: (read/write DCO3, read DCS3)

\b 0001 T: do not page output

\b 0002 TP: do not page output

\b 0004 P: do not page output

\b 0008 G: do not page output

\b 0100 T/TP/P: modify paging for silent dump

\b 0200 T/TP/P: if 0100 set: turn paging on, else off

\b 01_0000 R: highlight changed digits (needs ANSI for DOS output)

\b 02_0000 R: highlight escape sequences to int 10h, else video attributes

\b 04_0000 R: highlight changed registers (overrides 01_0000)

\b 08_0000 R: include highlighting of EIP

\b 10_0000 set PM ss B bit

\b 20_0000 break on entering Protected Mode

\b 0100_0000 highlight prefix/suffix in getinput if text parts are not visible

\b 0200_0000 do not call int 2F.1680 for idling

\b 0400_0000 delay for a tick before writing breakpoints

\b 0800_0000 do not call other lDebug instance's AMIS services

\b 1000_0000 disable auto-repeat

\b 2000_0000 check int 16h buffer for Control-C if inputting from int 16h

\b 4000_0000 call DOS service 0Bh to check for Control-C

\b 8000_0000 when Q command is used while TSR, leave TF as is


More options: (read/write DCO4, read DCS4)

\b 0002 enable interrupt 2Fh hook while in 86 Mode

\b 0004 enable interrupt 8 hook

\b 0008 enable interrupt 2Dh hook

\b 0010 enable 86 Mode fault interrupt hooks

\b 0001_0000 force serial interrupt unhooking

\b 0002_0000 force interrupt 2Fh unhooking

\b 0004_0000 force interrupt 8 unhooking

\b 0008_0000 force interrupt 2Dh unhooking

\b 0010_0000 force interrupt 0Dh unhooking

\b 0020_0000 force interrupt 0Ch unhooking

\b 0100_0000 force interrupt 0 unhooking

\b 0200_0000 force interrupt 1 unhooking

\b 0400_0000 force interrupt 3 unhooking

\b 0800_0000 force interrupt 6 unhooking

\b 1000_0000 force interrupt 18h unhooking

\b 2000_0000 force interrupt 19h unhooking


More options: (read/write DCO6, read DCS6)

\b 0001 enable video screen swapping

\b 0002 keep video screen when disabling swapping

\b 0010 read key from interrupt 16h when swapping (V command)

\b 0100 enable debug mode (and BU command)

\b 0200 use ROM-BIOS output even when DOS available

\b 0400 load and write .EXE and .COM files like flat .BIN files (/F+)

\b 0800 for loading flat .BIN files set up Stack Segment != PSP (/E+)

\b 1000 enable 40-column friendly mode

\b 2000 in 40-column mode indent odd D lines more

\b 4000 in 40-column mode display dashes at half of D length

\b 01_0000 allow to share serial IRQ handler

\b 0100_0000 use ROM-BIOS I/O even when DOS available (disables script file read)

\b 2000_0000 display flags in style 2 for R command register dump

\b 4000_0000 display flags in style 3 for R command register dump

\b 8000_0000 linebreak before R register dump if not column 0 (int 10h only)


Internal flags: (read DIF)

\b 00_0001 Int25/Int26 packet method available

\b 00_0002 Int21.7305 packet method available

\b 00_0004 VDD registered and usable

\b 00_0008 internal flag for paged output

\b 00_0010 DEBUG's input isn't StdIn

\b 00_0020 DEBUG's input is a file

\b 00_0040 DEBUG's output isn't StdOut

\b 00_0080 DEBUG's output is a file

\b 00_1000 state of debuggee's A20

\b 00_2000 state of debugger's A20 (not implemented: same as previous)

\b 00_4000 debugger booted independent of a DOS

\b 00_8000 CPU is at least a 386 (32-bit CPU)

\b 01_0000 internal flag for tab output processing

\b 02_0000 running inside NTVDM

\b 10_0000 internal flag for paged output

\b 40_0000 in TSR mode (detached debugger process)

\b 0100_0000 running inside dosemu

\b 0400_0000 T/TP/P: while condition specified

\b 0800_0000 TP: P specified (proceed past string ops)

\b 1000_0000 T/TP/P: silent mode (SILENT specified)

\b 2000_0000 T/TP/P: silent mode is active, writing to silent buffer


Available assembler/disassembler options: (read/write DAO, read DAS)

\b 01 Disassembler: lowercase output

\b 02 Disassembler: output blank behind comma

\b 04 Disassembler: output addresses in NASM syntax

\b 08 Disassembler: lowercase referenced memory location segreg

\b 10 Disassembler: always show SHORT keyword

\b 20 Disassembler: always show NEAR keyword

\b 40 Disassembler: always show FAR keyword

\b 80 Disassembler: NEC V20 repeat rules (for segregs)

\b 0100 Disassembler: 40-column friendly mode (only 4 bytes machine code per line)

\b 0200 Disassembler: do not indent disassembly operands

\b 0400 Disassembler: MS Debug style opcode field width

\b 1000 Disassembler: access data in a16 referenced memory operand

\b 2000 Disassembler: access data in a32 referenced memory operand

\b 4000 Disassembler: simulate repeated a16 scas/cmps string operation

\b 8000 Disassembler: simulate repeated a32 scas/cmps string operation

\b 01_0000 Disassembler: hide needed MODRM keywords

\b 02_0000 Disassembler: use LOOP rel, (E)CX rather than LOOPW/LOOPD

\b 04_0000 Disassembler: always display MODRM keyword even if not needed


\H{helpboot} ?BOOT - Boot loading

Boot loading commands:

\b BOOT LIST HDA

\b BOOT DIR [partition] [dirname]

\b BOOT READ|WRITE [partition] segment [[HIDDEN=sector] sector] [count]

\b BOOT QUIT       [exits dosemu or shuts down using APM]

\b BOOT [PROTOCOL=SECTOR] partition

\b BOOT PROTOCOL=proto [opt] [partition] [filename1] [filename2] [cmdline]

\b         the following partitions may be specified:

\lcont{

\b          HDAnum first hard disk, num = partition (1-4 primary, 5+ logical)

\b          HDBnum second hard disk (etc), num = partition

\b          HDA    first hard disk (only valid for READ|WRITE|PROTOCOL=SECTOR)

\b          FDA    first floppy disk

\b          FDB    second floppy disk (etc)

\b          LDP    partition the debugger loaded from

\b          YDP    partition the most recent Y command loaded from

\b          SDP    last used partition (default if no partition specified)

\b         filename2 may be double-slash // for none

\b         cmdline is only valid for lDOS, RxDOS.2, RxDOS.3 protocols

\b         files' directory entries are loaded to 500h and 520h
}

Available protocols: (default filenames, load segment, then entrypoint)

\b  LDOS           LDOS.COM or L[D]DEBUG.COM at 200h, 0:400h

\b  FREEDOS        KERNEL.SYS or METAKERN.SYS at 60h, 0:0

\b  DOSC           IPL.SYS at 2000h, 0:0

\b  EDRDOS         DRBIO.SYS at 70h, 0:0

\b  MSDOS6         IO.SYS + MSDOS.SYS at 70h, 0:0

\b  MSDOS7         IO.SYS at 70h, 0:200h

\b  IBMDOS         IBMBIO.COM + IBMDOS.COM at 70h, 0:0

\b  DRDOS          IBMBIO.COM + IBMDOS.COM at 70h, 0:0

\b  NTLDR          NTLDR at 2000h, 0:0

\b  BOOTMGR        BOOTMGR at 2000h, 0:0

\b  RXDOS.0        RXDOSBIO.SYS + RXDOS.SYS at 70h, 0:0

\b  RXDOS.1        RXBIO.SYS + RXDOS.SYS at 70h, 0:0

\b  RXDOS.2        RXDOS.COM at 70h, 0:400h

\b  RXDOS.3        RXDOS.COM at 200h, 0:400h

\b  CHAIN          BOOTSECT.DOS at 7C0h, -7C0h:7C00h

\b  SECTOR         (default) load partition boot sector or MBR

\b  SECTORALT      as SECTOR, but entry at 07C0h:0

Available options:

\b  MINPARA=num            load at least that many paragraphs

\b  MAXPARA=num            load at most that many paragraphs (0 = as many as fit)

\b  SEGMENT=num            change segment at that the kernel loads

\b  ENTRY=[num:]num        change entrypoint (CS (relative) : IP)

\b  BPB=[num:]num          change BPB load address (segment -1 = auto-BPB)

\b  CHECKOFFSET=num        set address of word to check, must be even

\b  CHECKVALUE=num         set value of word to check (0 = no check)

Boolean options: [opt=bool]

\b  SET_DL_UNIT            set dl to load unit

\b  SET_BL_UNIT            set bl to load unit

\b  SET_SIDI_CLUSTER       set si:di to first cluster

\b  SET_DSSI_DPT           set ds:si to DPT address

\b  PUSH_DPT               push DPT address and DPT entry address

\b  DATASTART_HIDDEN       add hidden sectors to datastart var

\b  SET_AXBX_DATASTART     set ax:bx to datastart var

\b  SET_DSBP_BPB           set ds:bp to BPB address

\b  LBA_SET_TYPE           set LBA partition type in BPB

\b  MESSAGE_TABLE          provide message table pointed to at 1EEh

\b  SET_AXBX_ROOT_HIDDEN   set ax:bx to root start with hidden sectors

\b  NO_BPB                 do not load BPB

\b  SET_DSSI_PARTINFO      load part table to 600h, point ds:si + ds:bp to it

\b  CMDLINE                pass a kernel command line (recent FreeDOS extension)


\H{helpbuild} ?BUILD - lDebug build (only revisions)

\c lDebug (YYYY-MM-DD)
\c Source Control Revision ID: hg xxxxxxxxxxxx (vvvv ancestors)
\c Uses yyyyyyyy: Revision ID hg zzzzzzzzzzzz (www ancestors)
\c [etc]


\H{helpb} ?B - lDebug build (with options)

\c lDebug (YYYY-MM-DD)
\c Source Control Revision ID: hg xxxxxxxxxxxx (vvvv ancestors)
\c Uses yyyyyyyy: Revision ID hg zzzzzzzzzzzz (www ancestors)
\c [etc]
\c
\c DI command
\c DM command
\c D string commands
\c S match dumps line of following data
\c RN command
\c Access SDA current PSP field
\c Load NTVDM VDD for sector access
\c X commands for EMS access
\c RM command and reading MMX registers as variables
\c Expression evaluator
\c  Indirection in expressions
\c Variables with user-defined purpose
\c Debugger option and status variables
\c PSP variables
\c Conditional jump notice in register dump
\c TSR mode (Process detachment)
\c Boot loader
\c Permanent breakpoints
\c Intercepted interrupts: 00, 01, 03, 06, 18, 19
\c Extended built-in help pages


\H{helpx} ?X - EMS commands

\c Expanded memory (EMS) commands:
\c   Allocate      XA count
\c   Deallocate    XD handle
\c   Map memory    XM logical-page physical-page handle
\c   Reallocate    XR handle count
\c   Show status   XS


\H{helpsource} ?SOURCE - lDebug source reference

The original lDebug sources can be obtained from the repo located at
\W{https://hg.pushbx.org/ecm/ldebug}{https://hg.pushbx.org/ecm/ldebug}
(E. C. Masloch's repo)

Releases of lDebug are available via the website at
\W{https://pushbx.org/ecm/web/#projects-ldebug}{https://pushbx.org/ecm/web/#projects-ldebug}

The most recent manual is hosted at
\W{https://pushbx.org/ecm/doc/}{https://pushbx.org/ecm/doc/}
in the
files
\W{https://pushbx.org/ecm/doc/ldebug.htm}{ldebug.htm},
\W{https://pushbx.org/ecm/doc/ldebug.txt}{ldebug.txt}, and
\W{https://pushbx.org/ecm/doc/ldebug.pdf}{ldebug.pdf}


\H{helpl} ?L - lDebug license

lDebug - libre 86-DOS debugger

\b Copyright (C) 1995-2003 Paul Vojta

\b Copyright (C) 2008-2024 E. C. Masloch

Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.

DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.


All contributions by Paul Vojta or E. C. Masloch to the debugger are available
under a choice of three different licenses. These are the Fair License, the
Simplified 2-Clause BSD License, or the MIT License.

This is the license and copyright information that applies to lDebug; but note
that there have been substantial contributions to the code base that are not
copyrighted (public domain).


\C{ldebug-ad} Comparison of lDebug to MS-DOS Debug

This section lists some benefits of lDebug,
as compared to MSDebug.
It originates in
\W{https://pushbx.org/ecm/doc/msdebug.htm#ldebug-ad}{the MSDebug manual}.
MSDebug is based on the Debug of
the 2018 free software release of MS-DOS version 2.

First, there are some differences between MSDebug and
the original MS-DOS Debug which make MSDebug more similar to lDebug:

\b K command to modify only the internal buffers for
the program load filename, the PSP command line tail, and the PSP FCBs

\b Child process allocated using interrupt 21h function 48h
and initialised using function 55h

\b After termination of debuggee a new child process is created

\b Restores interrupt 1 and 3 vectors (similar to lDDebug)

\b BU command like lDDebug's

\b .HEX file read ends on NUL byte (0), EOF byte (1Ah), or End Of File

\b Bugfix: Move command M will correctly move forwards or backwards
based on the linear address,
fixing overlapping moves in which the segments differ
in the opposite way to the linear addresses


Here's the advantages of lDebug as compared to MSDebug:

\b Expression evaluator can be used whereever a number is to be parsed

\b D, U, T, TP, P, G commands can be repeated with autorepeat

\b Permanent breakpoints (B commands)

\b G command can re-use prior breakpoints list with G AGAIN command
(or autorepeat)

\b Several variables beyond the 16-bit registers
to control the debugger or store calculation results

\b Paging to allow reading longer outputs

\b 686 level assembler and disassembler

\b DPMI build lDebugX for debugging DPMI clients,
supporting 32-bit offsets in segments

\b InDOS mode to switch to ROM-BIOS video and keyboard I/O
rather than DOS's standard output and input

\b Line editor and line history
(if not using the DOS line input function)

\b Can be boot loaded for debugging Real/Virtual 86 Mode kernels

\b Can be installed as a device driver in CONFIG.SYS

\b Script for lDebug (SLD) file reading
using the Y command

\b Serial I/O mode

\b Conditional tracing for the T, TP, and P commands
using a condition after a WHILE keyword

\b Buffered tracing for T, TP, and P using a SILENT keyword

\b T defaults to proceeding past software interrupt calls,
can be modified using Trace Mode (TM command)

\b TP command which proceeds past repeated string instructions

\b DM command to list MCBs

\b DI command to dump interrupt handler chains

\b DW and DD commands to dump data in words or dwords

\b 32-bit numeric handling

\b F and S commands can use a memory source instead of
a list, using a RANGE keyword

\b H command can display an expression result in
hexadeximal, decimal, or one arbitrary base of choice

\b I and O commands have IW/OW and ID/OD variants
for word and doubleword port I/O

\b R command can be switched to display 32-bit and 386 registers

\b Machine type can be set to make the assembler and disassembler
display when the machine does not support an instruction

\b QA command can be used to try to terminate an attached process

\b S command can search backwards using the REVERSE keyword

\b Provides a number of online help pages

\b RN command to dump 8087 registers

\b RM command to dump MMX registers,
and variables to read and write them

\b RE command buffer to run commands from T, TP, P, or G dump calls

\b RC command buffer to run commands at startup or group
several commands later on

\b Numeric inputs can be specified with a hash sign \cq{#} modifier
to enter in arbitrary numeric bases

\b Access variables and VALUE IN constructs
to detect memory accesses before they are actually carried out
(requiring to trace instructions)

\b TSR and ATTACH commands to detach from or attach to a process

\b IF command to conditionally run another command

\b Timer and AMIS interrupt hooks (optional)

\b Ability to load Extensions for lDebug (ELDs)


lDebug can be built using the free software Netwide Assembler (NASM),
but as of MSDebug release 2 the same is true of MSDebug.

However, there are some disadvantages to lDebug as well:

\b Memory use and executable size can easily reach
as much as ten times that of MSDebug

\b Less compatibility to original MS-DOS Debug

\b Performance may be worse

\b May require some MS-DOS version 3 or version 5 features


\C{testref} Test Reference

This chapter lists all tests in the test suite.


\H{test-beep} test_beep

Runs the command \cq{... invalid command} and
checks that the returned error carat display contains
a bell codepoint (byte 07h, U+0007).


\H{test-build} test_build

Checks the \cq{?build} and \cq{?version} commands.


\H{test-rh} test_rh

Checks the Register dump History mode.
Includes subtests for many RH commands.
Refer to \k{cmdrh}.


\H{test-dt} test_dt

Checks the DT command text table
and the DT command to dump byte values' corresponding texts.
Refer to \k{cmddt}.


\H{test-rr-status} test_rr_status

Checks that the R command's jumping notices are correct.
Also checks for flag status display,
referenced memory contents display,
and the \cq{[needs 386]} machine requirement display.
Includes subtests for many conditions.
Refer to \k{cmdr}.


\H{test-aa-basic} test_aa_basic

Tests the assembler's output.
Includes many subtests, some of which are expected failures.


\H{test-rr-basic} test_rr_basic

Tests the R command to display and modify variables,
either debugger variables or memory indirect variables.
Includes subtests for a number of different commands.
Some of the tests also use complex expressions
to test the expression evaluator.
Some of the subtests contain no-op commands
(commented out as \cq{; nothing})
that only check an additional result of a prior subtest.


\H{test-misc} test_misc

Miscellaneous subtests:

\b S command tests

\b D command tests, including D TOP, dollar sign addresses,
and pointer type expressions

\b Reading variables using the R command, up to DCO7 and DIF7
(with expected failures for DCO8 and DIF8)

\b Calculations using the H command
and various expression evaluator constructs

\b Reading debugger variables (PSP variables and registers)
using the H command

\b Reading some compound variables using H commands

\b Checking the equality of some compound variables

\b Checking value limits on assigning to AX or an indirect word variable


Further miscellaneous tests include:

\b Autorepeat for T command, without or with blanks

\b Disable autorepeat

\b H command expression evaluation overflow

\b Register change highlighting

\b Line editor history

\b Line editor

\b Sleep command

\b Paging of long command output

\b C command

\b T/TP/P commands

\b F command with overlong pattern

\b F command with a range instead of list pattern

\b S command with range, too long range, too long list


\H{test-timeout} test_timeout

Instructs the debugger to sleep so long
that the test tear down handler will terminate
the debugger process.


\H{test-int2D-unhook} test_int2D_unhook

Installs the debugger's AMIS handler (int 2Dh handler)
then installs a tiny handler on top of it,
testing how attempting to unhook the debugger's handler
works in this case.
The tiny handler
is first of the form \cq{90 EA offset segment 00 00}
(no IISP header detected)
and then of the form \cq{90 EA offset segment "KB"}
(uninstalled iHPFS style IISP header detected).

This test requires running under a DOS.


\H{test-bb-gg} test_bb_gg

Tests permanent (bb) and temporary (gg) breakpoints.


\H{test-bb-fill} test_bb_fill

Tests permanent breakpoint setup, listing,
and overflows of structures.


\H{test-access-var} test_access_var

Checks for access variables working.
Refer to \k{varaccess}.


\H{test-dpmimini} test_dpmimini

Enters Protected Mode using a small DPMI test case.

First, if need be a DPMI host may be run.
Next, the client executable is loaded.
Subsequently the debugging hint in text form
is searched within the loaded program.
It is checked that PM is entered successfully.

\W{https://hg.pushbx.org/ecm/ldebug/rev/b2212e4d65fb}{The fix for a bug in the R command}
is tested next, except under lDDebugX where a failure
would crash the debugger.
The PM interrupts hooked by lDebugX are checked,
except when lDDebugX is used.
Several subtests check PSP variables.

Finally,
the return to 86 Mode via client process termination is checked.

This test requires running under a DOS,
for a DPMI host to be available,
and for an lDebugX build to be used (detected by the "x" in the build name).


\H{test-dpmioffs} test_dpmioffs

This test has a setup similar to test_dpmimini.
Two different breakpoints are detected in the debugging hint texts.
At both of the breakpoints,
several C commands are tested.
One point of the tests is to insure that
32-bit offsets in part of an expression
such as memory indirection or a LINEAR expression
do not set the 32-bit offset status
for the entire expression's caller.

This test requires running under a DOS,
for a DPMI host to be available,
and for an lDebugX build to be used (detected by the "x" in the build name).


\H{test-dpmialoc} test_dpmialoc

This test has a setup similar to test_dpmimini.
It checks that when a permanent breakpoint is set in
a DPMI allocation (beyond 1088 KiB) and then
the debugger is entered in 86 Mode via mode switch
(not by terminating the client)
and then an interrupt instruction is to be disassembled,
the debugger will not have losts its Extra Segment
and the disassembly operand stack special opcode scan
will succeed.

This is based on
\W{https://hg.pushbx.org/ecm/ldebug/rev/e49b20df1831}{a bugfix in the mode switching}
done by the debugger in this circumstance,
\W{https://hg.pushbx.org/ecm/ldebug/rev/abc7c761c83d}{added as a test case}
afterwards, both in 2022 April.

This test requires running under a DOS,
for a DPMI host to be available,
and for an lDebugX build to be used (detected by the "x" in the build name).


\H{test-missing-executable} test_missing_executable

This test tries to load nonexisting executables
specified to the N command followed by an L command.
First a file should not be found and then a path.

This test requires running under a DOS.


\H{test-error-executable} test_error_executable

This test tries to load a corrupt executable
specified to the N command followed by an L command.
The MZ executable header specifies a too large image
for any 86 Mode operating system in this executable.

This test requires running under a DOS.


\H{test-load-boot} test_load_boot

This checks that several BOOT commands work.

An lDOS protocol load is attempted to run without a failure,
and its entrypoint address (200h:400h) is checked.
A check value mismatch is forced.
The RxDOS.3 protocol load is attempted
with the default filename, which should not be found.
A FreeDOS protocol load is attempted to run without a failure,
and its entrypoint address (60h:0) is checked.
A boot directory listing is attempted
and the presence of the debugger executable
and startup script is matched.

The boot sector of the debugger diskette is loaded to segment 1000h
and it is checked that the informational \cq{FAT12} identifier
shows up exactly once in the sector.
The 55h, AAh signature is checked in the sector.
The boot sector is read repeatedly to segment 1020h with
implied start sector and length,
explicit start sector but implied length,
and all explicit parameters.
The sectors are matched with the first read.
Also, it is insured that a sentinel byte after
the 512 Bytes for the subsequent reads does not change.


This test requires running without a DOS.


\H{test-yy} test_yy

Tests Y commands to read Script for lDebug files.

A simple script is tested first.
Then 20 nested scripts are tested,
expecting an error that the nesting is too deep
but still executing all commands
from the opened files in the correct order.
Then 3 nested scripts are tested,
which should not cause an error.

Subsequently, sleeping within nested scripts is tested.
Further, cancelling a running command with Control-C
(codepoint U+0003) is tested, utilising the sleeping scripts.
The first cancellation is done with IOL equal to zero,
to cancel only the sleep command and
none of the Scripts for lDebug. (Refer to \k{variol}.)
The second involves IOL equal to one,
cancelling the sleep command as well as one script level.
The third involves IOL equal to one again
but with two Control-C codes sent from the terminal,
twice cancelling one sleep command and one script level.
The fourth cancellation uses IOL equal to two,
cancelling the sleep and two script levels.

A further SLD tests calling subfunctions
(labels) within the same SLD file.
A final SLD tests visibility of commands
in a Script for lDebug using
the \cq{@} prefix as well as setting YSF flag 4000h
to hide some of the commands.
(Refer to \k{varysf}.)


\H{test-double-ctrlc} test_double_ctrlc

This test sends a double Control-C from the serial terminal
to the debugger.
At this point the debuggee is running in an idle loop
so that the double Control-C can act as a breakpoint.
In order to work, the timer interrupt 8 is hooked
by the debugger.

After the debugger breaks out of the loop,
the code segment is matched against the debuggee code segment.
If it matches and the offset is plausible,
the test is considered finished.
Otherwise,
the debugger attempts to trace-proceed
out of the current interrupt handler
until it has executed an \cw{iret} or \cw{retf imm16} instruction
and checks the segment for the debuggee code segment after.


\H{test-eee-interactive} test_eee_interactive

This tests the interactive enter mode (\k{cmde}).


\H{test-rc} test_rc

This tests the RC (command line) buffer
and execution from it.
First a single R command is written and ran.
Then two more R commands are appended and the RC buffer
is ran again.

Then a small loop is written into the RC buffer
using IF and GOTO commands, as well as labels.
The display of the commands themselves
is disabled by using \cq{@} prefixes.
The correct amount of iterations
as well as hiding of commands is tested.

A longer loop is ran next,
but the loop is placed into the RE buffer instead,
with the RC buffer containing only an \cq{RE} command.
The RCLIMIT variable (\k{varrclimit}) is set so low
that it would abort the loop if the RE buffer commands
were to be counted against it.

A similar construct is used next,
except that the loop is in a Script for lDebug file
and the RC buffer contains a Y command to load this SLD.


\H{test-ext-extlib} test_ext_extlib

Runs the help of the extlib Extension for lDebug.
Both on its own,
with the long descriptions,
and with the wide list of ELDs.
It is checked that at least 40 ELDs are listed.


\H{test-ext-ldmem} test_ext_ldmem

Runs the ldmem Extension for lDebug.
The MEM and ELD keywords are tested
by directly running the ELD.
The ELD noun should display the transient ELD.

Then the ELD is installed residently.
The ELD noun is used first.
It is checked that the resident ELD is displayed.
Next, COMMANDHANDLER, INJECTHANDLER, STACK, and HISTORY
nouns are ran.
Finally the resident ELD is uninstalled.


\H{test-ext-aformat} test_ext_aformat

Installs the aformat Extension for lDebug
then tests it by assembling several instructions.


\H{test-ext-checksum} test_ext_checksum

Installs the checksum Extension for lDebug
and runs it on several data blocks.
The results are checked.


\H{test-ext-list} test_ext_list

Runs the transient list Extension for lDebug.
The first run is with an empty command line tail.
As only the extlib.eld is known to be available
it is specified as the ELD file to list
for the second run.
Contents and format of the output are tested.


\H{test-ext-amitsrs} test_ext_amitsrs

This runs the Extension for lDebug that lists multiplexers
installed according to the Alternate Multiplex Interrupt Specification (AMIS).
To make sure at least one multiplexer is installed,
this test runs \cq{install amis} initially,
which installs the debugger's AMIS handler.

The \cw{amitsrs} command is run as is, and then
with the keywords \cq{int}, \cq{mpx}, and \cq{verbose}.
In the interrupts display it is insured that
at least one multiplexer hooks interrupt 2Dh (necessary)
and interrupt 3 (always true for normal lDebug builds).


\H{test-ext-reclaim} test_ext_reclaim

In this test, a resident ldmem Extension for lDebug is installed.
It is then tested that running the help for
extlib.eld leaves a transient ELD installed.
Finally, the reclaim ELD is used to reclaim this transient ELD.
(Reclamation is built-in to the debugger's ELD loader as well,
however this will not reclaim the last loaded ELD when it
returns control to the debugger.)


\H{test-ext-amount} test_ext_amount

This test installs the amount Extension for lDebug,
which provides the ELDAMOUNT variable.
It is checked that this variable reads as at least 2,
one each for the LINKCALL ELD and the amount ELD.
Then an ldmem.eld is installed and it is checked
that the value in the ELDAMOUNT variable increments.


\H{test-ext-alias} test_ext_alias

Tests the alias Extension for lDebug.
Installs the ELD, then runs a list command,
adds an alias,
lists the alias,
runs the alias,
and deletes the alias again.


\H{test-ext-dosseek} test_ext_dosseek

To test the dosseek Extension for lDebug,
a small stub is assembled first to open a file handle.
The extlib.eld file is opened, as it always exists.
Then the dosseek.eld is used to get the current seek,
set it to 4096, get it again, and then set it to the EOF.
The final seek is checked to match the filesize.
Finally, it is attempted to get the seek for file handle
#19 (valid process handle but closed)
and FFFF (never a valid process handle)
and the error messages are checked.

This test requires running under a DOS.


\H{test-ext-history} test_ext_history

Installs the history Extension for lDebug,
and checks that its show and clear commands work.


\H{test-ext-amismsg} test_ext_amismsg

Installs the debugger's AMIS handler and the amismsg Extension for lDebug.
Several small handlers that pass messages to AMIS function 40h
are assembled.
An overflow is tested to truncate a message that is too long,
along with returning a different status in AL.
AMIS function 41h is tested as well.


\H{test-ext-amiscmd} test_ext_amiscmd

Installs the debugger's AMIS handler and the amiscmd Extension for lDebug.
An rvm command is injected using AMIS function 43h.
Next the same command is injected again
but with all flags in CX set, which should be rejected.
After this, four commands are injected at once.
Then 16 commands are injected at once, padded to the maximum length
with blanks. This should overflow the ELD's buffer.
Finally two differing commands are injected
and it is insured that the order of injection matches the order
of the calls into the ELD.


\H{test-ext-amisoth} test_ext_amisoth

Installs the debugger's AMIS handler and the amisoth Extension for lDebug.
The AMIS function 42h is tested.
The status returned in AL is insured to be FFh.
The segment returned in DX is matched to equal the Debugger PSP.
The ELD link info header (refer to \k{eldlinkinfo})
is tested a little.
The signature is matched as E1D1h,
the use link hash word is matched as 1 or 0,
and the amount of data and code links
are both matched to be at least 64 and at most 256.


\# \H{test-} test_
