Index of Topics
- - A -
- Address information class
ARRAY (value 0x2?)
- B -
- Base Types
Byte Order
- C -
- CHARACTER_BLOCK (value 0x8?)
CODE (value 0x2?)
Core Requests
- D -
- Debugging Information Format
- E -
- ENUMERATED (value 0x5?)
Environment requests
Executable file structures
- F -
- File I/O requests
- G -
- GET_MOVED_SECTION
GET_OVERLAY_STATE
GET_OVL_TBL_ADDR
GET_SECTION_DATA
GET_STATE_SIZE
Global symbols class
- H -
- The Handler Routine
The Hook Routine
- I -
- The Interface Routines
- L -
- Line number information
Line numbers class
Local symbol information
Local symbols class
Location information
- M -
- Master debug header
Module information class
- N -
- NEW_BASE (value 0x3?)
- O -
- Object file structures
Overlay manager interface
Overlay requests
Overlay Table Structure
- P -
- POINTER (value 0x4?)
Pointer Sizes
PROCEDURE (value 0x7?)
- R -
- REQ_ASYNC_ADD_BREAK
REQ_ASYNC_GO
REQ_ASYNC_POLL
REQ_ASYNC_REMOVE_BREAK
REQ_ASYNC_STEP
REQ_ASYNC_STOP
REQ_CAPABILITIES_GET_EXACT_BP
REQ_CAPABILITIES_SET_EXACT_BP
REQ_CHECKSUM_MEM
REQ_CLEAR_BREAK
REQ_CLEAR_WATCH
REQ_CONNECT
REQ_DISCONNECT
REQ_ENV_GET_VAR
REQ_ENV_SET_VAR
REQ_FILE_CLOSE
REQ_FILE_ERASE
REQ_FILE_GET_CONFIG
REQ_FILE_INFO_GET_DATE
REQ_FILE_INFO_SET_DATE
REQ_FILE_OPEN
REQ_FILE_READ
REQ_FILE_RUN_CMD
REQ_FILE_SEEK
REQ_FILE_STRING_TO_FULLPATH
REQ_FILE_WRITE
REQ_FILE_WRITE_CONSOLE
REQ_GET_ERR_TEXT
REQ_GET_LIB_NAME
REQ_GET_MESSAGE_TEXT
REQ_GET_NEXT_ALIAS
REQ_GET_SUPPLEMENTARY_SERVICE
REQ_GET_SYS_CONFIG
REQ_MACHINE_DATA
REQ_MAP_ADDR
REQ_OVL_GET_DATA
REQ_OVL_GET_REMAP_ENTRY
REQ_OVL_READ_STATE
REQ_OVL_STATE_SIZE
REQ_OVL_TRANS_RET_ADDR
REQ_OVL_TRANS_VECT_ADDR
REQ_OVL_WRITE_STATE
REQ_PERFORM_SUPPLEMENTARY_SERVICE
REQ_PROG_GO/REQ_PROG_STEP
REQ_PROG_KILL
REQ_PROG_LOAD
REQ_READ_IO
REQ_READ_MEM
REQ_READ_REGS
REQ_READ_USER_KEYBOARD
REQ_REDIRECT_STDIN/REQ_REDIRECT_STDOUT
REQ_RESUME
REQ_RFX_FINDCLOSE
REQ_RFX_FINDFIRST
REQ_RFX_FINDNEXT
REQ_RFX_GETCWD
REQ_RFX_GETDATETIME
REQ_RFX_GETDRIVE
REQ_RFX_GETFILEATTR
REQ_RFX_GETFREESPACE
REQ_RFX_MKDIR
REQ_RFX_NAMETOCANONICAL
REQ_RFX_RENAME
REQ_RFX_RMDIR
REQ_RFX_SETCWD
REQ_RFX_SETDATETIME
REQ_RFX_SETDRIVE
REQ_RFX_SETFILEATTR
REQ_RUN_THREAD_GET_NAME
REQ_RUN_THREAD_GET_NEXT
REQ_RUN_THREAD_GET_RUNTIME
REQ_RUN_THREAD_INFO
REQ_RUN_THREAD_POLL
REQ_RUN_THREAD_SET
REQ_RUN_THREAD_SIGNAL_STOP
REQ_RUN_THREAD_STOP
REQ_SET_BREAK
REQ_SET_DEBUG_SCREEN
REQ_SET_USER_SCREEN
REQ_SET_WATCH
REQ_SPLIT_CMD
REQ_SUSPEND
REQ_THREAD_FREEZE
REQ_THREAD_GET_EXTRA
REQ_THREAD_GET_NEXT
REQ_THREAD_SET
REQ_THREAD_THAW
REQ_WRITE_IO
REQ_WRITE_MEM
REQ_WRITE_REGS
Request Example
The Request Interface
Request Structure
The Requests
RFX requests
- S -
- Section debug header
Section debug information
Segment address table
SET_OVERLAY_STATE
Some Definitions
Source language table
Special Line Number Table
STRUCTURE (value 0x6?)
SUBRANGE (value 0x3?)
System Dependent Aspects
- T -
- Thread requests
TRANSLATE_RETURN_ADDR
TRANSLATE_VECTOR_ADDR
Trap File Interface
Trap Files Under DOS
Trap Files Under Netware 386 or PenPoint
Trap Files Under OS/2
Trap Files Under QNX
Trap Files Under Windows NT.
Trap Files Under Windows.
TrapFini
TrapInit
TrapRequest
TYPE_NAME (value 0x1?)
Types class
Typing information
- V -
- VARIABLE (value 0x1?)
Version number and source language identification
This document describes the object and executable file structures used by the Open Watcom Debugger to provide symbolic
information about a program. This information is subject to change.
Note that version 4.0 of the Open Watcom debugger supports the DWARF and CodeView symbolic debugging information formats
in addition to the format described in this document. For the purposes of discussion, this format will be known as
the "WATCOM" format. DWARF is now the primary format used by Open Watcom compilers. Support for generating
the WATCOM format will probably remain but is only useful for debugging DOS overlays.
Before reading this document you should understand the Intel 8086 Object Module Format (OMF). This format is
described in the Intel document 8086 Relocatable Object Module Formats and also the October 1985 issue of
PC Tech Journal.
Responsibility for the Intel/Microsoft OMF specification has been taken over by the Tools Interface Standards (TIS)
Committee. The TIS standards (including the OMF spec) may be obtained by phoning the Intel literature center at 1-800-548-4725
and asking for order number 241597.
This document is for the Open Watcom Debugger version 4.0 (or above.)
Object file structures
The compiler is responsible for placing extra information into the object file in order to provide symbolic information
for the Open Watcom Debugger. There are three classes of information, each of which may be present or absent from the
file individually. These classes are line number, type and local symbol information.
For the Open Watcom C compiler, line number information is provided when the "/d1" switch is used and all three
classes are provided when the "/d2" switch is used.
Version number and source language identification
Since there may be different versions of the type and local symbol information, and there may be multiple front-ends a
special OMF COMENT record is placed in the object file. It has the following form:
comment_class = 0xfe
'D'
major_version_number (char)
minor_version_number (char)
source_language (string)
The comment_class of 0xfe indicates a linker directive comment. The character 'D' informs the linker
that this record is providing debugging information. The major_version_number is changed whenever there is
a modification made to the types or local symbol classes that is not upwardly compatible with previous versions. The
minor_version_number increments by one whenever a change is made to those classes that is upwardly compatible with previous
versions. The source_language field is a string which determines what language that the file was compiled
from.
If the debugging comment record is not present, the local and type segments (described later) are not in WATCOM format
and should be omitted from the resulting executable file's debugging information. The current major version is one,
and the current minor version is three.
Line number information is provided by standard Intel OMF LINNUM records. A kludge has been added that allows for
line numbers to refer to more than one source file. See the section on the "Special Line Number Table" in
the executable structures portion of the document for more details.
A type or symbol definition may contain a location field. This field is of variable length and identifies the memory
(or register) location of the symbol in question. A location field may consist of a single entry, or a list of entries.
Each entry describes an operation of a stack machine. The value of the location field is the top entry of the
stack after all the operations have been performed. To tell whether a field is a single entry or a list, the first
byte is examined. If the value of the byte is greater than 0x80, then the field consists of a list of entries, and
the length in bytes of the list is the value of the first byte minus 0x80. If the first byte is less than 0x80, the
byte is the first byte of a single entry field. The top nibble of the first byte in each entry is a general location
class while the low nibble specifies the sub-class.
BP_OFFSET (value 0x1?)
BYTE (value 0x10) offset_byte
WORD (value 0x11) offset_word
DWORD (value 0x12) offset_dword
CONST (value 0x2?)
ADDR286 (value 0x20) memory_location_32_pointer
ADDR386 (value 0x21) memory_location_48_pointer
INT_1 (value 0x22) const_byte
INT_2 (value 0x23) const_word
INT_4 (value 0x24) const_dword
MULTI_REG (value 0x3?)
Low nibble is number of register bytes that follow - 1.
The registers are specified low order register first.
REG (value 0x4?)
Low nibble is low nibble of the appropriate register value.
This may only be used for the first 16 registers.
IND_REG (value 0x5?)
CALLOC_NEAR (value 0x50) register_byte
CALLOC_FAR (value 0x51) register_byte, register_byte
RALLOC_NEAR (value 0x52) register_byte
RALLOC_FAR (value 0x53) register_byte, register_byte
OPERATOR (value 0x6?)
IND_2 (value 0x60)
IND_4 (value 0x61)
IND_ADDR286 (value 0x62)
IND_ADDR386 (value 0x63)
ZEB (value 0x64)
ZEW (value 0x65)
MK_FP (value 0x66)
POP (value 0x67)
XCHG (value 0x68) stack_byte
ADD (value 0x69)
DUP (value 0x6a)
NOP (value 0x6b)
Here is the list of register numbers:
0-AL, 1-AH, 2-BL, 3-BH, 4-CL,
5-CH, 6-DL, 7-DH
8-AX, 9-BX, 10-CX, 11-DX, 12-SI, 13-DI, 14-BP,
15-SP
16-CS, 17-SS, 18-DS, 19-ES
20-ST0, 21-ST1, 22-ST2, 23-ST3, 24-ST4, 25-ST5, 26-ST6, 27-ST7
28-EAX, 29-EBX, 30-ECX, 31-EDX, 32-ESI, 33-EDI, 34-EBP, 35-ESP
36-FS, 37-GS
CONST pushes a single constant value onto the expression stack. INT_1 and INT_2 constant values are sign-extended
to four bytes before being pushed.
The OPERATOR class performs a variety of operations on the expression stack.
- IND_2
- Pick up two bytes at the location specified by the top entry of the stack, sign-extend to four bytes and replace top of stack
with the result.
IND_4
- Replace the top of stack with the contents of the four bytes at the location specified by the top of stack.
IND_ADDR286
- Replace the top of stack with the contents of the four bytes, treated as a far pointer, at the location specified by the top
of stack.
IND_ADDR386
- Replace the top of stack with the contents of the six bytes, treated as a far pointer, at the location specified by the top
of stack.
ZEB
- Zero extend the top of stack from a byte to a dword (clear the high three bytes).
ZEW
- Zero extend the top of stack from a word to a dword.
MK_FP
- Remove the top two entries from the stack, use the top of stack as an offset and the next element as a segment to form a far
pointer and push that back onto the stack.
POP
- Remove the top entry from the stack.
XCHG
- Exchange the top of stack with the entry specified by stack_byte. "XCHG 1" would exchange the top
of stack with the next highest entry.
ADD
- Remove the top two entries from the stack, add them together and push the result.
DUP
- Duplicate the value at the top of the stack.
NOP
- Perform no operation.
REG and MULTI_REG push the 'lvalue' of the register. If they are the only entry then the symbol exists in the specified
register. To access the value of the register, you must indirect it.
BP_OFFSET locations are for variables on the stack. The values given are offsets from the BP register for 286
programs and from the EBP register for 386 programs. A BP_OFFSET could also be expressed with the following series
of operations:
MULTI_REG(1) SS
IND_2
MULTI_REG(1) EBP
IND_4
MK_FP
INT_1 offset_byte
ADD
The IND_REG location type is used for structured return values. The register or register pair is used to point
at the memory location where the structure is returned. CALLOC means that the calling procedure is responsible for
allocating the return area and passing a pointer to it as a parameter in the specified registers. RALLOC means that
the called routine allocated the area and returns a pointer to it in the given registers.
The Open Watcom Debugger typing information is contained in a special segment in the object file. The segment name
is "$$TYPES" and the segment class is "DEBTYP". To allow greater flexibility in demand loading
the typing information and also let it exceed 60K for a single module, each object file may have multiple $$TYPES segments.
Each segment is identified by an entry in the demand link table (described in the executable file structures section).
No individual segment may exceed 60K and no individual type record may be split across a segment boundry. Also,
any type which is described by multiple records (structures, enums, procedures) may not be split across a segment boundry.
Since each segment is loaded as a whole by the debugger when demand loading, increasing the segment size requires larger
amounts of contiguous memory be present in the system. Decreasing the size of the individual segments reduces memory
requirements, but increases debugger lookup time since it has to traverse more internal structures. The current code
generator starts a new type segment when the current one exceeds 16K. The segments are considered to be a stream of
variable length definitions, with each definition being preceded by a length byte. A number of the definitions contain
indices of some form. These indices are standard Intel format, with 0 meaning no index, 1 to 127 is represented in
one byte, 128 to 32767 in high byte/low byte form with the top bit on in the high byte. Definitions are given index
numbers by the order in which they appear in the module, with the first being index one. Character strings representing
names are always placed at the end of a definition so that their length can be calculated by subtracting the name's start
point from the length of the record. They are not preceded by a length byte or followed by a zero byte.
The first byte identifies the kind of the type definition that follows. The top nibble of the byte is used to
indicate the general class of the type definition (there are eight of these). The low order nibble is used to qualify
the general type class and uniquely identify the definition type.
TYPE_NAME (value 0x1?)
This definition is used to give names to types. There are three sub-classes.
SCALAR (value 0x10) scalar_type_byte, name
SCOPE (value 0x11) name
NAME (value 0x12) scope_index, type_index, name
CUE_TABLE (value 0x13) table_offset_dword
EOF (value 0x14)
SCALAR is used to give a name to a basic scalar type. It can also be used to give a type index to a scalar type
without a name by specifying the null name. The scalar_type_byte informs the Open Watcom Debugger what sort
of scalar item is being given a name. It has the following form:
BIT: 7 6 5 4 3 2 1 0
| | | | |
| | | +-----+--- size in bytes - 1
| +---+----------- class (000 - integer)
|
(001 - unsigned)
|
(010 - float)
|
(011 - void (size=0))
|
(100 - complex)
+----------------- unused
To create an unnamed scalar type, for use in other definitions, just use a zero length name.
NOTE: BASIC would have been a better name for this, since complex is not a scalar type, but the name
was chosen before complex support was added.
SCOPE is used to restrict the scope of other type names. A restricted scope type name must be preceded by its
appropriate scope name in order for the Open Watcom Debugger to recognize it as a type name. This is useful for declaring
C structure, union, and enum tag names. You declare SCOPE names of "struct", "union", and "enum"
and then place the appropriate value in the scope_index field of the NAME record when declaring the tag.
NAME gives an arbitrary type a name. The field, scope_index , is either zero, which indicates an unrestricted
type name, or is the type index of a SCOPE definition, which means that the type name must be preceded by the given scope
name in order to be recognized.
The next two records are kludges to allow OMF line numbers to refer to more than one source file. See the section
of on the "Special Line Number Table" in the executable structure for more details.
CUE_TABLE is followed by table_offset_dword which gives the offset in bytes from the begining of the typing
information for a module to the special line number table. If this record is present, it must be in the first $$TYPES
segment for the module and preferably as close to the begining of the segment as possible.
EOF marks the end of the typing information for the module and the begining of the special line number table.
ARRAY (value 0x2?)
This definition is used to define an array type. There are 6 sub-classes.
BYTE_INDEX (value 0x20) high_bound_byte, base_type_index
WORD_INDEX (value 0x21) high_bound_word, base_type_index
LONG_INDEX (value 0x22) high_bound_dword, base_type_index
TYPE_INDEX (value 0x23) index_type_index, base_type_index
DESC_INDEX (value 0x24) scalar_type_byte, scalar_type_byte,
bounds_32_pointer,
base_type_index
DESC_INDEX_386 (value 0x25) scalar_type_byte, scalar_type_byte,
bounds_48_pointer,
base_type_index
BYTE_INDEX, WORD_INDEX, LONG_INDEX are all used to describe a restricted form of array. If one of these forms
is used then the index type is an integer with the low bound of the array being zero and the high bound being whatever is
specified.
The DESC_INDEX form is used when the array bounds are not known at compile time. The bounds_32_pointer
is a far pointer to a structure in memory. The type and size of the first field is given by the first scalar_type_byte
and indicates the lower bound for the index. The second field's type and size is given by the second scalar_type_byte.
This field gives the number of elements in the array.
The DESC_INDEX_386 is the same as DESC_INDEX except that a 48-bit far pointer is used to locate the structure in memory.
SUBRANGE (value 0x3?)
This definition is used to define a subrange type. There are 3 sub-classes.
BYTE_RANGE (value 0x30) lo_bnd_byte, hi_bnd_byte, base_type_index
WORD_RANGE (value 0x31) lo_bnd_word, hi_bnd_word, base_type_index
LONG_RANGE (value 0x32) lo_bnd_dword, hi_bnd_dword, base_type_index
If the base type is unsigned then the low and high bounds should be interpreted as containing unsigned quantities,
otherwise they contain integers. However, the decision to use the byte, word, or long form of the definition is always
made considering the high and low bounds as signed numbers.
POINTER (value 0x4?)
This definition is used to define a pointer type. There are 10 sub-classes.
NEAR (value 0x40) base_type_index
[,base_locator]
FAR (value 0x41)
base_type_index
HUGE (value 0x42) base_type_index
NEAR_DEREF (value 0x43) base_type_index [,base_locator]
FAR_DEREF (value 0x44) base_type_index
HUGE_DEREF (value 0x45) base_type_index
NEAR386 (value 0x46) base_type_index [,base_locator]
FAR386 (value 0x47) base_type_index
NEAR386_DEFREF (value 0x48) base_type_index [,base_locator]
FAR386_DEREF (value 0x49) base_type_index
When a symbol is one of the *_DEREF types, the Open Watcom Debugger will automatically dereference the pointer.
This "hidden" indirection may be used to define reference parameter types, or other indirectly located symbols.
The *_DEREF types have now been superceeded by location expressions. They should no longer be generated.
The NEAR* pointer types all have an optional base_locator field. The debugger can tell if this field is present
by examining the length of the debug type entry at the begining of the record and seeing if there are additional bytes after
the base_type_index field. If there are more bytes, the base_locator is a location expression whose
result is an address, the value of which is the base selector and offset value when indirecting through the pointer (based
pointers). The contents of the based pointer variable are added to result of the location expression to form the true
resulting address after an indirection. The address of the pointer variable being indirected through is pushed on the
stack before the location expression is evaluated (needed for self-based pointers). If the base_locator field
is not present, the debugger will use the default near segment and a zero offset.
ENUMERATED (value 0x5?)
This definition is used to define an enumerated type. There are 4 sub-classes.
LIST (value 0x50) #consts_word, scalar_type_byte
CONST_BYTE (value 0x51) value_byte, name
CONST_WORD (value 0x52) value_word, name
CONST_LONG (value 0x53) value_dword, name
LIST is used to inform the Open Watcom Debugger of the number of constants in the enumerated type and the scalar type
used to store them in memory. It will be followed immediately by all the constant definitions for the enumerated type.
See TYPE_NAME for a description of the scalar_type_byte.
CONST_BYTE, CONST_WORD, and CONST_LONG define the individual constant values for an enumerated type. The type
of the constant is provided by the preceeding LIST definition. The decision to use the byte, word, or long form of
the definition is made always by considering the value as a signed number. The CONST_* definition records are not counted
when determining type index values.
The LIST record and its associated CONST_* records must all be contained in the same $$TYPES segment.
STRUCTURE (value 0x6?)
This definition is used to define a structure type. There are 10 sub-classes.
LIST (value 0x60) #fields_word [,size_dword]
FIELD_BYTE (value 0x61) offset_byte, type_index, name
FIELD_WORD (value 0x62) offset_word, type_index, name
FIELD_LONG (value 0x63) offset_dword, type_index, name
BIT_BYTE (value 0x64) offset_byte, start_bit_byte, bit_size_byte,
type_index, name
BIT_WORD (value 0x65) offset_word, start_bit_byte, bit_size_byte,
type_index, name
BIT_LONG (value 0x66) offset_dword, start_bit_byte, bit_size_byte,
type_index, name
FIELD_CLASS (v 0x67) attrib_byte, field_locator, type_index, name
BIT_CLASS (value 0x68) attrib_byte, field_locator, start_bit_byte,
bit_size_byte, type_index, name
INHERIT_CLASS (v 0x69) adjust_locator, ancestor_type_index
LIST is used to introduce a structure definition. It is followed immediately by all the field definitions that
make up the structure. The optional size_dword gives the size of the structure in bytes. If it is not
present, the debugger calculates the size of the structure based on field offsets and sizes.
FIELD_BYTE, FIELD_WORD, FIELD_LONG, and FIELD_CLASS define a single field entry in a structure defintion.
BIT_BYTE, BIT_WORD, BIT_LONG, and BIT_CLASS define a bit field in a structure. :The FIELD_CLASS and BIT_CLASS
records are used for defining fields in a C++ class. The attrib_byte contain a set of bits describing attributes
of the field:
BIT: 7 6 5 4 3 2 1 0
| | | | | |
| | | | | +--- internal
| | | | +----- public
| | | +------- protected
| | +--------- private
+-----+----------- unused
An internal field is one that is generated for compiler support. It is not normally displayed to the user.
The other bits have their usual C++ meanings.
The field_locator is a location expression describing how to calculate the field address. Before begining
to evaluate the expression, the debugger will implicitly push the base address of the class instance onto the stack.
The following is an example of the location expression used to calculate an ordinary field at offset 10 from the start of
the class:
INT_1 10
ADD
The INHERIT_CLASS record indicates that a particular class should inherit all the fields specified by ancestor_type_index.
This field must point at either a STRUCTURE LIST record or a TYPE NAME that eventually resolves to a STRUCTURE LIST.
The adjust_locator is a location expression that tells the debugger how to adjust the field offset expressions
in the inherited class to their proper values for a class of this instance.
The FIELD_*, BIT_*, and INHERIT_CLASS records are not counted when determining type index values.
A C union, or Pascal variant record is described by having a number of fields all beginning at the same offset.
The Open Watcom Debugger will display the fields in the reverse order that the records define them. This means that
ordinarily, the records should be sorted by descending offsets and bit positions.
The LIST record and it's associated field descriptions must all be contained in the same $$TYPES segment.
PROCEDURE (value 0x7?)
This definition is used to define a procedure type. There are 4 sub-classes.
NEAR (value 0x70) ret_type_index, #parms_byte {,parm_type_index}
FAR (value 0x71) ret_type_index, #parms_byte {,parm_type_index}
NEAR386 (value 0x72) ret_type_index, #parms_byte {,parm_type_index}
FAR386 (value 0x73) ret_type_index, #parms_byte {,parm_type_index}
EXT_PARMS (value 0x74) {,parm_type_index}
The EXT_PARMS sub-class is used when there are too many parameter types to fit into one PROCEDURE record. This
condition can be recognized when the #parms_byte indicates there are more parameter types than fit into the record according
to the length field at the beginning. In this case the remaining parameter types are continued in the record immediately
following, which will always be of type EXT_PARMS. The EXT_PARMS record must be contained in the same $$TYPES segment
as the preceeding procedure record.
CHARACTER_BLOCK (value 0x8?)
Items of type CHARACTER_BLOCK are length delimited strings. There are 4 sub-classes.
CHAR_BYTE (value 0x80) length_byte
CHAR_WORD (value 0x81) length_word
CHAR_LONG (value 0x82) length_dword
CHAR_IND (value 0x83) scalar_type_byte, length_32_pointer
CHAR_IND_386 (value 0x84) scalar_type_byte, length_48_pointer
CHAR_IND_LOC (value 0x85) scalar_type_byte, address_locator
The CHAR_BYTE, CHAR_WORD, and CHAR_LONG forms are used when the length of the character string is known at compile
time. Even though the length given is an unsigned quantity, the decision on which form to use is made by considering
the value to be signed. The CHAR_IND form is used when the length of the string is determined at run time. The
length_32_pointer gives the far address of a location containing the length of the string. The size of this location
is given by the scalar_type_byte. The CHAR_IND_386 form is the same as CHAR_IND except that the location of
the length is given by a 48-bit far pointer. The CHAR_IND_LOC form is the same as CHAR_IND except that the address
of the length is given by a location expression.
The Open Watcom Debugger local symbol information is contained in a special segment in the object file. The segment
name is "$$SYMBOLS" and the segment class is "DEBSYM". The segment is considered to be a stream
of variable length definitions, with each definition being preceded by a length byte. A number of the definitions contain
indices of some form. These indices are standard Intel format, with 0 meaning no index, 1 to 127 is represented in
one byte, 128 to 32767 in high byte/low byte form with the top bit on in the high byte. Character strings representing
names are always placed at the end of a definition so that their length can be calculated by subtracting the name's start
point from the length of the record. They are not preceded by a length byte or followed by a zero byte.
The first byte identifies the kind of the symbol definition that follows. The top nibble of the byte is used
to indicate the general class of the symbol definition. The low order nibble is used to qualify the general definition
class.
Symbol definitions are used to provide the Open Watcom Debugger with the location and scoping of source language local
symbols. There are two general classes of symbol definition, one for variables and one for code.
VARIABLE (value 0x1?)
This definition is used to define the location of a data symbol. There are 4 sub-classes.
MODULE (value 0x10) memory_location_32_pointer, type_index, name
LOCAL (value 0x11) address_locator, type_index, name
MODULE386 (value 0x12) memory_location_48_pointer, type_index, name
MODULE_LOC (value 0x13) address_locator, type_index, name
MODULE defines either an exported, domestic, or imported variable in the module. It is not necessary to generate
symbol information for an imported variable since the Open Watcom Debugger will look for local symbol information in the
module which defines the variable if required.
LOCAL defines a symbol that is local to a code block or procedure. The defining block is the first one previous
to this definition. Local symbols only "exist" for the purpose of the Open Watcom Debugger lookups when the
program is executing in a block which defines the symbol.
CODE (value 0x2?)
This definition is used to define an object in the code. There are 6 sub-classes.
BLOCK (value 0x20) start_offset_word, size_word,
parent_block_offset
NEAR_RTN (value 0x21) <BLOCK>, pro_size_byte, epi_size_byte,
ret_addr_offset_word, type_index,
return_val_loc, #parms_byte
{,parm_location}, name
FAR_RTN (value 0x22) <BLOCK>, pro_size_byte, epi_size_byte,
ret_addr_offset_word, type_index,
return_val_loc, #parms_byte
{,parm_location}, name
BLOCK_386 (value 0x23) start_offset_dword, size_dword,
parent_block_offset
NEAR_RTN_386 (value 0x24) <BLOCK_386>, pro_size_byte, epi_size_byte,
ret_addr_offset_dword, type_index,
return_val_loc, #parms_byte
{,parm_location}, name
FAR_RTN_386 (value 0x25) <BLOCK_386>, pro_size_byte, epi_size_byte,
ret_addr_offset_dword, type_index,
return_val_loc, #parms_byte
{,parm_location}, name
MEMBER_SCOPE (value 0x26) parent_block_offset, class_type_index
[obj_ptr_type_byte, object_loc]
BLOCK is used to indicate a block of code that contains local symbol definitions. The field parent_block_offset
is used to tell the Open Watcom Debugger the next block to search for a symbol definition if it is not found in this block.
The field is set to zero if there is no parent block.
NEAR_RTN and FAR_RTN are used to specify a routine definition. Notice that the first part is identical to a
code block definition. The ret_addr_offset_word is the offset from BP (or EBP) that the return address is
located on the stack. The #parms_byte and parm_location following are only for those parms which
are passed in registers. The remainder of the parms are assumed to be passed on the stack.
The MEMBER_SCOPE record is used for C++ member functions. It introduces a scope where the the debugger looks
up the fields of the class identified by class_type_index as if they were normal symbols. If the obj_ptr_type_byte
and object_loc location expression portions of the record are present, it indicates that the function has a C++
"this" pointer, and all fields of the class structure are accessable. The location expression evaluates to
the address of the object that the member function is manipulating. The obj_ptr_type_byte contains a value
from the low order nibble of a POINTER type record. It indicates the type of `this' pointer the routine is expecting.
I.e.:
- Value
- Definition
0
- 16-bit near pointer
1
- 16-bit far pointer
6
- 32-bit near pointer
7
- 32-bit far pointer
If the portions following the class_type_index are absent from the record, the routine is a static member function
and only has access to static data members.
To use this record, the member function's parent_block_offset is pointed at the MEMBER_SCOPE record, and the
MEMBER_SCOPE's parent_block_offset field is pointed at what the member function would normally be pointing at.
In effect, a new block scope has been introduced.
The *_386 versions of the records are identical to their 286 counterparts excepts that the start_offset ,
size , and ret_addr_offset fields have been widened to 32 bits.
NOTE: There should be a better mapping of parm number to parm location. There is no provision for
Pascal calling conventions (reversed parm order) or other strangeness.
The BLOCK definition contains a start_offset_word (or start_offset_dword in a BLOCK_386).
This is the offset from a given memory location provided by NEW_BASE entries and indicates the address of the start of executable
code for the block.
All the code location definitions are assumed to be sorted in order of increasing end offsets (start offset + size).
This ensures that the first scope that the debugger encounters in a traversal of the symbolic information is the closest
enclosing scope.
NEW_BASE (value 0x3?)
ADD_PREV_SEG (value 0x30) seg_increment_word
SET_BASE (value 0x31) memory_location_32_pointer
SET_BASE386 (value 0x32) memory_location_48_pointer
For ADD_PREV_SEG, the specified amount is added to the segment value of the code start address of the module.
The code start offset is reset to zero. All BLOCK definitions occuring after this item are relative to the new value.
After a SET_BASE or SET_BASE386 all BLOCK definitions are relative to the memory location that is given by the record.
NOTE: Avoid the use of the ADD_PREV_SEG record. Its operation is only valid in real mode.
It is included for backwards compatiblity only.
Executable file structures
The linker is responsible for processing the debugging information contained in the object files and some of its internal
structures and appending them to the executable file.
After linking, the executable file looks like this:
+-----------------------+
|
|
| EXE file
|
|
|
+=======================+
|
|
| Overlays
|
|
|
+=======================+
| Any Other Stuff |
+=======================+<--- start of debugging information
| source language table |
+-----------------------+
| segment address table |
+-----------------------+
|
|<-\
| section debug info | +-- repeated for each overlay &
root
|
|<-/
+-----------------------+
| master debug header |
+=======================+<--- end of file
The section marked as "EXE file" is the normal executable file. All debugging information is appended
to the end of the file, after any overlay sections or other information. The master debug header begins at
a fixed offset from the end of the file, and provides the location of the remainder of the debug information. The
source language table contains the source languages used by the program. The section debug info is repeated
once for the root and each overlay section defined in the executable. It contains all the debugging information for
all object modules defined in the root or a particular overlay section. The section debug info is further
divided into a number of debugging information classes, these will be explained later. All offsets in the debugging
information that refer to other information items are relative to the start of the information, the start of a section of
information, or the start of a class of the information. In other words, the information is not sensitive to its location
in the executable file.
The master debug header allows the Open Watcom Debugger to verify the fact that there is debugging information, to locate
the other sections and to verify that it is capable of handling the version of debugging information. The master header
structure is as follows:
struct master_dbg_header {
unsigned_16 signature;
unsigned_8 exe_major_ver;
unsigned_8 exe_minor_ver;
unsigned_8 obj_major_ver;
unsigned_8 obj_minor_ver;
unsigned_16 lang_size;
unsigned_16 segment_size;
unsigned_32 debug_size;
};
The signature word contains the value 0x8386. This is the first indication to the Open Watcom Debugger
that there is debugging information present. The exe_major_ver field contains the major version number of
the executable file debugging information structures. The major version number will change whenever there is a modification
to these structures that is not upwardly compatible with the previous version. The current major version number is
three. The exe_minor_ver field contains the minor version number of the executable file debugging information
structures. The minor version number increments by one whenever there is a change to the structures which is upwardly
compatible with the previous version. The current minor version number is zero. This means that in order for
the Open Watcom Debugger to process the debugging information the following must be true:
- FILE exe debug info major version == debugger exe debug info major version
- FILE exe debug info minor version <= debugger exe debug info minor version
The obj_major_ver field contains the major version number of the object file debugging information structures
(internal format of the types and local symbol information). The major version number will change whenever there is
a modification to these structures that is not upwardly compatible with the previous version. The current major version
number is one. The obj_minor_ver field contains the minor version number of the object file debugging information
structures. The minor version number increments by one whenever there is a change to the structures which is upwardly
compatible compatible with the previous version. The current minor version number is three. This means that in
order for the debugger to process the debugging information the following must be true:
- FILE obj debug info major version == debugger obj debug info major version
- FILE obj debug info minor version <= debugger obj debug info minor version
These two fields are filled in by the linker by extracting the version information from special debug comment record in
the processed object files. If two object files in the link contain different major version numbers, the linker should
report an error or warning and not process the type or local symbol information for the 'incorrect' file. The minor
version number placed in the master header should be the maximum of all the minor version numbers extracted from the object
files.
The lang_size field contains the size of the source language table at the beginning of the debug information.
The segment_size field informs the debugger of the size, in bytes, of the segment address table. The
field, debug_size , gives the total size of the debugging information, including the size of the master header itself.
This allows the debugger to calculate the start of the debugging information by subtracting the value of the debug_size
field from the location of the end of file. This gives the start of the source language and segment address tables,
whose sizes are known from the master header. Once the location of the first section of debugging information is determined,
it can be processed. Within the section information is a indicator of its total size, which allows the debugger to
find the start of the next section, and process that as well. This continues until all the debug sections have been
processed. the debugger knows there are no more debug sections to process when the indicated start of a section is
the same as the start of the master header.
Source language table
The source language table is merely the collection of unique source languages used in the program. The strings are
extracted from the special debug comment records in the object files and placed in this section one after another with zero
bytes separating them.
Segment address table
The segment address table is an array of all the unique segment numbers used by the executable. Essentially, any
segment value that would appear in the map file will be represented in the table.
Each section debug info contains the following:
+-----------------------+
| section header |
+-----------------------+
| local symbols |
+-----------------------+
| types
|
+-----------------------+
| line numbers |
+-----------------------+
| module info |
+-----------------------+
| global symbols |
+-----------------------+
| address info |
+-----------------------+
The local symbols, types and line numbers classes are demand loaded by the debugger as it requires pieces of the classes
for various modules. The module info, global symbols, and address info classes are permanently loaded by the debugger
at the start of a debugging session. The global symbol, module, and address info classes have no size restriction,
however there is a limit of 65536 modules per section and there are some restrictions on how the address info class may be
laid out. These restrictions are described in the section explaining the address info class.
The section header class allows the debugger to determine the size of the section information and the location of the
permanently loaded classes. The header structure is as follows:
struct section_dbg_header {
unsigned_32 mod_offset;
unsigned_32 gbl_offset;
unsigned_32 addr_offset;
unsigned_32 section_size;
unsigned_16 section_id;
};
The mod_offset , gbl_offset , and addr_offset fields are offsets, from the beginning of
the section debug header to the module info, global symbol, and address info classes of debugging information. The
section_size field is the size of the debugging information for the section, including the section header. The
following conditions must hold true for the debugger to recognize the debugging information as valid:
- mod_offset < gbl_offset
- gbl_offset < addr_offset
- addr_offset < section_size
The section_id field contains the overlay number for this section. This is zero for the root.
Local symbols class
The local symbols segments are processed normally by the linker, except that the data in the segments is placed in this
section, no relocation entries are output for any fixups in the data and fields in the module structure are intialized to
point to the beginning and size of each object file's contribution to the section.
Types class
The type segments are processed normally by the linker, except that the data in the segments is placed in this section,
no relocation entries are output for any fixups in the data and fields in the module structure are intialized to point to
the beginning and size of each object file's contribution to the section.
Line numbers class
The LINNUM records for each object file are collected and placed in this class using an array of arrays. The top
level array is the following structure:
struct line_segment {
unsigned_32 segment;
unsigned_16 num;
line_info line[1];
}
The segment field contains a offset, from the start of the address info class, to an addr_info structure
(see the address info class description). This provides the segment value for the array of line_info's following.
The next field, num , provides the number of line_info's in the array. The line is a variable size
array containing the following structure:
struct line_info {
unsigned_16 line_number;
unsigned_32 code_offset;
};
The line_number contains the source line number whose offset is being defined. If the top bit of the
line number is on, this line number refers to an entry in the special line number table. See the "Special Line
Number Table" section for more details. The code_offset field contains the offset from the begining of
the module for the first instruction associated with the line number. To get the true code address for the instruction
you must add code_offset to the address given by the segment field in the line_segment structure.
All the instructions up to the next element's code_offset , or the end of the object file's code for that segment
if there is no next code_offset are considered to be part of the line_number source line. Within
each line_segment structure the line_info array is assumed to be sorted in order of ascending code_offset.
The module structure for the object file contains fields which indicate the start and size of the line_segment array within
the class.
Each line_segment structure may not exceed 60K, however the total amount of line information for a module may exceed
60K with multiple line_segment structures and multiple entries in the demand link table (described in the module information
section).
To obtain a line number from an address, the debugger performs the following steps
- Given an address, the defining module is found from the address information class. This allows the debugger to find
and load the line number information for that module, if it is not already loaded.
- Walk down the array of line_segment structures until one with the appropriate segment is found.
- Binary search the array of line_info's until the proper one is located.
Special Line Number Table
The OMF line number record does not allow for more than one source file to be referenced in an object file. This
kludge gets around the restriction. If the top bit is on in line_number than that field refers to an entry
in the special line number table. The debugger then searches the typing information for the module for a CUE_TABLE
record. If it finds one, it uses the offset given to find the begining of the table in the typing information.
The table looks like this:
/* cue entry table */
unsigned_16 cue_count
struct {
unsigned_16 cue;
unsigned_16 fno;
unsigned_16 line;
unsigned_16 column;
} cue_entry; /* repeated cue_count times, sorted by the 'cue' field */
/* file name index table */
unsigned_16 file_count
struct {
unsigned_16 index;
} file_name_index_entry; /* repeated file_count times */
/* file name table */
A list of zero terminated source file names
To find the correct cue entry given the value in a line_number , search the cue_entry table for
the cue which satisfies the following:
cue_entry[entry].cue <= (line_number & 0x7fff) < cue_entry[entry+1].cue
Once you have the cue entry, you can extract the true line number by:
line = cue_entry[entry].line + (line_number & 0x7fff)
- cue_entry[entry].cue;
The file name is found by:
fname_index = file_name_index_table[ cue_entry[entry].fno ]
fname = file_name_table[ fname_index ]
The code offset and segment are found in the line_info and line_segment structures as usual.
The module information class is built from the linker's list of object files that it processes to build the executable
file, which are either specified on the linker command line or extracted from libraries. All the modules are implicitly
given an index number by their order in the class. These index numbers start at zero and are used by other classes
to identify individual modules. The module structure contains the following fields:
struct mod_info {
unsigned_16 language;
demand_info locals;
demand_info types;
demand_info lines;
unsigned_8 name[1];
};
The language field contains an offset, from the start of the source language table to the string of the source
language for this module. The name field is a variable length array of characters with the first element of
the array being the length of the name. The remaining characters identify the source file the compiler used to generate
the object file (e.g. "C:\DEV\WV\C\DBGMAIN.C"). The source file name is obtained from the THEADR record
of the object file. the debugger uses the file name part of the file specification as its "module name".
The remaining fields, locals , types , and lines are a structure type which define the location
and size of this module's demand loaded information from those classes. The structure contains these fields:
struct demand_info {
unsigned_32 offset;
unsigned_16 num_entries;
};
The offset field contains the offset from the beginning of the debugging information section to first entry
in the demand link table containing the information for that particular demand load class. The num_entries
field gives the number of contiguous entries in the demand link table that are present for the module's demand load information
of that particular class.
The demand link table consists of an array of unsigned_32 offsets, which are relative from the debugging information
section, to the individual demand info class data blocks. The array is in ascending order of offsets so that the debugger
may calculate the size of a particular demand load data block by subtracting the offset of the next data block from the offset
of the current data block. This implies that there is an extra entry at the end of the table whose offset points to
the end of the final demand load data block so that the debugger always has a 'next' link entry to calculate size of a data
block with. The size of each individual block may not exceed 60K. A picture may be useful here to show how all
the pieces fit together:
module info
class
+--------+
| |
demand link
...
table demand info
| |
+--------+ data block
| |
| | +------+
+--------+ ...
+--->| |
| offset | ---+ | |
| ...
+--------+ | +--------+ |
| |
|#entries| +---->| offset |---+ +------+
+--------+ +--------+
| |
| |
...
...
| |
| |
+--------+ +--------+
demand info
| offset |---+ data block
+--------+ | +------+
| | +--->|
|
...
...
| | |
|
+--------+ +------+
When the debugger wishes to look something up in a demand load class for a module. It uses the offset in the
mod_info structure to locate the array entry in the demand link table which has the offset for the first info data block.
It then loads the first block and searches it for the information. If the information is not present in that
block, it moves to the next entry in the demand link table and repeats the above process. This continues until all
the entries for that particular class of the module (identified by the num_entries field in the mod_info structure)
have been examined, or the information is located.
Global symbols class
All PUBDEF records processed by the linker create entries in this class. The fields in the structure are:
struct gbl_info {
addr48_ptr addr;
unsigned_16 mod_index;
unsigned_8 kind;
unsigned_8 name[1];
};
The addr field contains the location in memory associated with this symbol. The value placed in this
field is the same that the linker places in the map file (i.e. unrelocated, as if the executable loads at location
0:0). The field contains a 48 bit value (32 bit offset followed by a 16 bit segment). The mod_index
field is an index which identifies the module which defines the symbol (i.e. contained the [L]PUBDEF record).
The kind gives rudimentary typing information for the symbol. It consists of the following set of bits:
BIT: 7 6 5 4 3 2 1 0
| | | | |
| | | | +--- STATIC symbol
| | | +----- DATA symbol
| | +------- CODE symbol
+-------+--------- unused
Bit zero is 1 if the global was defined by a LPUBDEF record and 0 if it was defined by a PUBDEF record. LPUBDEF
symbols are generated by the code generator for static symbols, so this allows a debugger to see static symbols even when
no compiler debug switches are being used. Bit one is 1 if the producer of the information is able to determine that
the symbol is a data symbol. Bit two is one if the producer is able to determine that the symbol is a code symbol.
Both bits may be zero if the producer is unable to determine whether the symbol is a code or data item. The final
field, name is a variable length array, with the first character indicating the length of the name, and the remaining
characters being the actual name of the symbol.
The address information class allows the debugger, given a memory address, to determine the module which defines that
memory address. The linker builds this class from the SEGDEF and GRPDEF records in the object files that it processes.
The class consists of an array of structures with the following fields:
struct seg_info {
addr48_ptr addr;
unsigned_16 num;
addr_info sects[1];
};
The addr field identifies the start of a segment in memory. This field contains the unrelocated value
of the segment starting address (i.e. as if the executable had been loaded at 0:0). The the low order 15 bits
of the next field, num tells how many of the sects entries there are in the structure. The top bit
of the field is a one when the segment belongs to "NonSect". "NonSect" is the overlay section which
holds all program data that is not in the root or an overlay section. Typically this consists of DGROUP and FAR_DATA
segments. NonSect always is located at the highest address of all sections. It is preloaded by the overlay manager
and is never moved. If the segment does not belong to NonSect, the top bit of the num field is zero.
The sects field is a variable size array of structures. This addr_info structure contains the following fields:
struct addr_info {
unsigned_32 size;
unsigned_16 mod_index;
};
The mod_index field indicates the module in the module information class which defines this piece of the
segment. The size field identifies how large a piece of the segment specified by the seg_info structure belongs
to the module. The starting address of the segment piece is given by adding all the previous size fields in the
sects array to the original starting address in the seg_info structure.
The size of a seg_info structure may not exceed 60K. If a single physical segment would have more sects
than would fit into this restriction ( num greater than 10238), it should be split into two separate seg_info structures.
To identify the module that defines a location in memory, the debugger does the following:
- Walk down the array of seg_info structures until one is found with the same segment address as the location that is being
identified. If no such seg_info is found, or the starting offset of the segment is greater than the offset of the memory
location, then there is no defining module.
- Walk down the array of addr_info's in the seg_info structure until an entry is found whose starting offset is less than
or equal to the memory location offset and whose ending offset is greater than the memory location offset. If there
is no such entry, there is no defining module.
- Otherwise, the mod_offset field of the addr_info entry is added to the beginning of the module information class,
which gives a pointer to the module structure that defines the memory location.
Trap File Interface
The Open Watcom debugger consists of a number of separate pieces of code. The main executable, WD.EXE (wd on UNIX
systems), provides a debugging `engine' and user interface. When the engine wishes to perform an operation upon the
program being debugged such as reading memory or setting a breakpoint, it creates a request structure and sends it to the
`trap file' (so called because under DOS, it contains the first level trap handlers). The trap file examines the request
structure, performs the indicated action and returns a result structure to the debugger. The debugger and trap files
also use Machine Architecture Description (MAD) files which abstract the CPU architecture. This design has the following
benefits:
- OS debugging interfaces tend to be wildly varying in how they are accessed. By moving all the OS specific interface
code into the trap file and having a defined interface to access it, porting the debugger becomes much easier.
- By abstracting the machine architecture specifics through MAD files, it becomes possible to use one debugger for several
target CPU architectures (such as x86 and Alpha AXP). Unlike most other debuggers, the Open Watcom debugger is not
tied to a single host/target combination and if appropriate trap and MAD files are available, the debugger running on any
host can remotely debug any target.
- The trap file does not have to actually perform the operation. Instead it could send the request out to a remote
server by a communication link such as a serial line or LAN. The remote server can retrieve the request, perform the
operation on the remote machine and send the results back via the link. This enables the debugger to debug applications
in cases where there are memory constraints or other considerations which prevent the debugger proper from running on the
remote system (such as Novell Netware 386).
This document describes the interface initially used by version 4.0 of the WATCOM debugger (shipped with the 10.0 C/C++
and FORTRAN releases). It has been revised to describe changes incorporated in Watcom 11.0 release, as well as subsequent
Open Watcom releases. It is expected to be modified in future releases. Where possible, notification of expected
changes are given in the document, but all aspects are subject to revision.
Some Definitions
Next follow some general trap definitions.
Byte Order
The trap file interface is defined to use little endian byte order. That is, the least significant byte is stored
at the lowest address. Little endian byte order was chosen for compatibility with existing trap files and tools.
Fixed byte order also eases network communication between debuggers and trap files running on machines with different byte
order.
Pointer Sizes
In a 16-bit hosted environment such as DOS, all pointers used by the trap file are "far" 16:16 pointers.
In a 32-bit environment such as Windows NT the pointers are "near" 0:32 pointers.
Base Types
A number of basic types are used in the interface. They are defined as follows:
- Type
- Definition
unsigned_8
- 1 byte unsigned quantity
unsigned_16
- 2 byte unsigned quantity
unsigned_32
- 4 byte unsigned quantity
trap_req
- The first field of every request is of this type. It is a 1 byte field which identifies the request to be performed.
addr48_ptr
- This type encapsulates the concept of a 16:32 pointer. All addresses in the debuggee memory are described with these.
The debugger always acts as if the debuggee were in a 32-bit large model environment since the 32-bit flat model and
all 16-bit memory models are subsets. The structure is defined as follows:
typedef struct {
unsigned_32 offset;
unsigned_16 segment;
} addr48_ptr;
The segment field contains the segment of the address and the offset field stores the offset of
the address.
bytes
- The type bytes is an array of unsigned_8. The length is provided by other means. Typically a field of type bytes
is the last one in a request and the length is calculated from the total length of the request.
string
- The type string is actually an array of characters. The array is terminated by a null ('\0') character. The length
is provided by other means. Typically a field of type string is the last one in a request and the length is calculated
from the total length of the request.
trap_error
- Some trap file requests return debuggee operating system error codes, notably the requests to perform file I/O on the remote
system. These error codes are returned as an unsigned_32. The debugger considers the value zero to indicate no
error.
trap_phandle
- This is an unsigned_32 type which holds process (task) handle. A task handle is used to uniquely identify a debuggee
process.
trap_mhandle
- This is an unsigned_32 type which holds a module handle. Typically the main executable will be one module, and on systems
which support DLLs or shared libraries, each library will be identified by a unique module handle.
The Request Interface
Next follow detailed description of interface elements.
Request Structure
Each request is a composed of two sequences of bytes provided by the debugger called messages. The first set contains
the actual request code and whatever parameters that are required by the request. The second sequence is where the
result of the operation is to be stored by the trap file.
The two sequences need not be contiguous. The sequences are described to the trap file through two arrays of
message entry structures. This allows the debugger to avoid unnecessary packing and unpacking of messages, since
mx_entry can be set to point directly at parameter/result buffers.
Multiple requests are not allowed in a single message. The mx_entry is only used to provide
scatter/gather capabilities for one request at a time.
The message entry structure is as follows (defined in trptypes.h ):
typedef struct {
void
*ptr;
unsigned len;
} mx_entry;
The ptr is pointing to a block of data for that message entry. The len field gives the length
of that block. One array of mx_entry describes the request message. The second array describes the return
message.
It is not legal to split a message into arbitrary pieces with mx_entries. Each request documents where an
mx_entry is allowed to start with a line of dashes.
The Interface Routines
The trap file interface must provide three routines: TrapInit , TrapRequest , and TrapFini.
How the debugger determines the address of these routines after loading a trap file, as well as the calling convention
used, is system dependent and described later. These functions are prototyped in trpimp.h.
TrapInit
This function initializes the environment for proper operation of TrapRequest.
trap_version TRAPENTRY TrapInit(
char *parm,
char *error,
unsigned_8 remote
);
The parm is a string that the user passes to the trap file. Its interpretation is completely up to
the trap file. In the case of the Open Watcom debugger, all the characters following the semicolon in the /TRAP
option are passed as the parm. For example:
wd /trap=nov;testing program
The parm would be "testing". Any error message will be returned in error.
The remote field is a zero if the Open Watcom debugger is loading the trap file and a one if a remote server is
loading it. This function returns a structure trap_version of the following form (defined in trptypes.h
):
typedef struct {
unsigned_8 major;
unsigned_8 minor;
unsigned_8 remote;
} trap_version;
The major field contains the major version number of the trap file while the minor field tells the
minor version number of the trap file. Major is changed whenever there is a modification made to the trap
file that is not upwardly compatable with previous versions. Minor increments by one whenever a change is
made to the trap file that is upwardly compatible with previous versions. The current major verion is 1, the current
minor version is 3. The remote field informs the debugger whether the trap file communicates with a remote
machine.
TrapInit must be called before using TrapRequest to send a request. Failure to do so may result
in unpredictable operation of TrapRequest.
TrapRequest
All requests between the server and the remote trap file are handled by TrapRequest.
unsigned TRAPENTRY TrapRequest(
unsigned num_in_mx,
mx_entry *mx_in,
unsigned num_out_mx,
mx_entry *mx_out
);
The mx_in points to an array of request mx_entry's. The num_in_mx field contains the number
of elements of the array. Similarly, the mx_out will point to an array of return mx_entry's. The number
of elements will be given by the num_out_mx field. The total number of bytes actually filled in to the return
message by the trap file is returned by the function (this may be less than the total number of bytes described by the
mx_out array).
Since every request must start with an trap_req field, the minimum size of a request message is one byte.
Some requests do not require a return message. In this case, the program invoking TrapRequest must pass
zero for num_out_mx and NULL for mx_out.
Request Example
The request REQ_READ_MEM needs the memory address and length of memory to read as input and will return the memory block
in the output message. To read 30 bytes of memory from address 0x0010:0x8000 into a buffer, we can write:
mx_entry in[1];
mx_entry out[1];
unsigned char buffer[30];
struct in_msg_def {
trap_req
req;
addr48_ptr
addr;
unsigned_16 len;
} in_msg = { REQ_READ_MEM, { 0x8000, 0x0010 }, sizeof( buffer ) };
unsigned_16 mem_blk_len;
in[0].ptr = &in_msg;
in[0].len = sizeof( in_msg );
out[0].ptr = &buffer;
out[0].len = sizeof( buffer );
mem_blk_len = TrapRequest( 1, in, 1, out );
if( mem_blk_length != sizeof( buffer ) ) {
printf( "Error in reading memory\n" );
} else {
printf( "OK\n" );
}
The program will print "OK" if it has transferred 30 bytes of data from the debuggee's address space to
the buffer variable. If less than 30 bytes is transfered, an error message is printed out.
TrapFini
The function terminates the link between the debugger and the trap file. It should be called after finishing all
access requests.
void TRAPENTRY TrapFini( void );
After calling TrapFini , it is illegal to call TrapRequest without calling TrapInit again.
The Requests
This section descibes the individual requests, their parameters, and their return values. A line of dashes indicates
where an mx_entry is allowed (but not required) to start. The debugger allows (via REQ_GET_SUPPLEMENTARY_SERVICE/REQ_PERFORM_SUPPLEMENTARY_SERVICE)
optional components to be implemented only on specific systems.
The numeric value of the request which is placed in the req field follows the symbolic name in parentheses.
Core Requests
These requests need to be implemented in all versions of the trap file, although some of them may only be stub implementations
in some environments. Note that structures suitable for individual requests are declared in trpcore.h.
REQ_CONNECT
Request to connect to the remote machine. This must be the first request made.
Request message:
trap_req req
unsigned_8 major; <-+- struct trap_version
unsigned_8 minor; |
unsigned_8 remote; <-+
The req field contains the request. The trap_version structure tells the version of the program
making the request. The major field contains the major version number of the trap file while the minor
field tells the minor version number of the trap file. The major is changed whenever there is a modification
made to the trap file that is not upwardly compatable with previous versions. The minor increments by one
whenever a change is made to the trap file that is upwardly compatable with previous versions. The current major version
is 1, the current minor version is 3. The remote field informs the trap file whether a remote server is between
the Open Watcom debugger and the trap file.
Return message:
unsigned_16 max_msg_size
----------------------------
string err_msg
If error has occurred, the err_msg field will returns the error message string. If there is no error,
error_msg returns a null character and the field max_msg_size will contain the allowed maximum size of a message
in bytes. Any message (typically reading/writing memory or files) which would require more than the maximum number
of bytes to transmit or receive must be broken up into multiple requests. The minimum acceptable value for this field
is 256.
REQ_DISCONNECT
Request to terminate the link between the local and remote machine. After this request, a REQ_CONNECT must be the
next one made.
Request message:
trap_req req
The req field contains the request.
Return message:
NONE
REQ_SUSPEND
Request to suspend the link between the server and the remote trap file. The debugger issues this message just before
it spawns a sub-shell (the "system" command). This allows a remote server to enter a state where it allows
other trap files to connect to it (normally, once a remote server has connected to a trap file, the remote link will fail
any other attempts to connect to it). This allows the user for instance to start up an RFX process and transfer any
missing files to the remote machine before continuing the debugging process.
Request message:
trap_req req
The req field contains the request.
Return message:
NONE
REQ_RESUME
Request to resume the link between the server and the remote trap file. The debugger issues this request when the
spawned sub-shell exits.
Request message:
trap_req req
The req field contains the request.
Return message:
NONE
REQ_GET_SUPPLEMENTARY_SERVICE
Request to obtain a supplementary service id.
Request message:
trap_req req
------------------------
string service_name
The req field contains the request. The service_name field contains a string identifying the
supplementary service. This string is case insensitive.
Return message:
trap_error err;
trap_shandle id;
The err field is non-zero if something went wrong in obtaining or initializing the service. Id is the
identifier for a particular supplementary service. It need not be the same from one invocation of the trap file to
another. If both it and the err field are zero, it means that the service is not available from this trap
file.
NOTE: integrated with the debugger. There would be two components, one to be added to the debugger
and one to be added to the trap file. The two pieces could communicate with each other via the supplementary services
mechanism.
Request to perform a supplementary service.
Request message:
trap_req req
unsigned_32 service_id
------------------------
unspecified
The req field contains the request. The service_id field indicates which service is being
requested. The remainder of the request is specified by the individual supplementary service provider.
Return message:
unspecified
The return message is specified by the individual supplementary service provider.
REQ_GET_SYS_CONFIG
Request to get system information from the remote machine.
Request message:
trap_req req
The req field contains the request.
Return message:
unsigned_8 cpu;
unsigned_8 fpu;
unsigned_8 osmajor;
unsigned_8 osminor;
unsigned_8 os;
unsigned_8 huge_shift;
unsigned_8 arch;
The arch field specifies the architecture in use and determines how the other fields will be interpreted.
Currently the following architectures are used:
DIG_ARCH_X86 - Intel Architecture IA-32 compatible
DIG_ARCH_X64 - Intel Architecture X64 compatible
DIG_ARCH_AXP - Alpha Architecture
DIG_ARCH_PPC - PowerPC Architecture
DIG_ARCH_MIPS - MIPS Architecture
DIG_ARCH_MSJ - Java Virtual Machine (Microsoft)
DIG_ARCH_JVM - Java Virtual Machine (Sun)
The cpu fields returns the type of the remote CPU. The size of that field is unsigned_8. Possible
CPU types for DIG_ARCH_X86 are:
bits 0-3
X86_86 = 0 - 8086
X86_186 = 1 - 80186
X86_286 = 2 - 80286
X86_386 = 3 - 80386
X86_486 = 4 - 80486
X86_586 = 5 - Pentium
X86_686 = 6 - Pentium Pro/II/III
X86_P4 = 15 - Pentium 4
bit 4 - MMX registers
bit 5 - XMM registers
bits 6 - unused
bits 7 - unused
The fpu fields tells the type of FPU. The size of the field is unsigned_8. FPU types for DIG_ARCH_X86
include:
X86_NOFPU = 0 - No FPU
X86_87 = 1 - 8087
X86_287 = 2 - 80287
X86_387 = 3 - 80387
X86_487 = 4 - 486 integrated FPU
X86_587 = 5 - Pentium integrated FPU
X86_687 = 6 - Pentium Pro/II/III integrated FPU
X86_P47 = 15 - Pentium 4 integrated FPU
X86_EMU = 255 - Software emulated FPU
The osmajor and osminor contains the major and minor version number for the operating system of
the remote machine. The type of operating system can be found in os field. The size of this field is
unsigned_8. The OS can be:
DIG_OS_IDUNNO = 0 - Unknown operating system
DIG_OS_DOS = 1 - DOS
DIG_OS_OS2 = 2 - OS/2
DIG_OS_PHAR = 3 - Phar Lap 386 DOS Extender
DIG_OS_ECLIPSE = 4 - Eclipse 386 DOS Extender (obsolete)
DIG_OS_NW386 = 5 - NetWare 386
DIG_OS_QNX = 6 - QNX 4.x
DIG_OS_RATIONAL = 7 - DOS/4G or compatible
DIG_OS_WINDOWS = 8 - Windows 3.x
DIG_OS_PENPOINT = 9 - PenPoint (obsolete)
DIG_OS_NT = 10 - Win32
DIG_OS_AUTOCAD = 11 - ADS/ADI development (obsolete)
DIG_OS_NEUTRINO = 12 - QNX 6.x
DIG_OS_LINUX = 13 - Linux
DIG_OS_FREEBSD = 14 - FreeBSD
DIG_OS_WIN64 = 15 - Windows 64-bit
The huge_shift field is used to determine the shift needed for huge arithmetic in that system. It stores
the number of left shifts required in order to calculate the next segment correctly. It is 12 for real mode programs.
The value in a protect mode environment must be obtained from the OS of the debuggee machine. This field is only
relevant for 16-bit segmented architectures.
REQ_MAP_ADDR
Request to map the input address to the actual address of the remote machine. The addresses in the symbolic information
provided by the linker do not reflect any relocation performed on the executable by the system loader. This request
obtains that relocation information so that the debugger can update its addresses.
Request message:
trap_req req;
addr48_ptr in_addr;
trap_mhandle mod_handle;
The req field contains the request. The in_addr tells the address to map. The mod_handle
field identifies the module which the address is from. The value from this field is obtained by REQ_PROG_LOAD or REQ_GET_LIB_NAME.
There are two magical values for the in_addr.segment field.
MAP_FLAT_CODE_SELECTOR = -1
MAP_FLAT_DATA_SELECTOR = -2
When the in_addr.segment equals one of these values, the debugger does not have a map segment value and is
requesting that the trap file performs the mapping as if the given offset was in the flat address space.
Return message:
addr48_ptr out_addr
addr48_off lo_bound;
addr48_off hi_bound;
The mapped address is returned in out_addr. Note that in addition to the segment portion being modified,
the offset of the portion of the address may be adjusted as well if the loader performs offset relocations (like OS/2 2.x
or Windows NT). The lo_bound and hi_bound fields identify the lowest and highest input offsets for
which this mapping is valid. If the debugger needs to map another address whose input segment value is the same as
a previous request, and the input offset falls within the valid range identified by the return of that previous request,
it can perform the mapping itself and not bother sending the request to the trap file.
REQ_CHECKSUM_MEM
Request to calculate the checksum for a block of memory in the debuggee's address space. This is used by the debugger
to determine if the contents of the memory block have changed since the last time it was read. Since only a four byte
checksum has to be transmitted back, it is more efficient than actually reading the memory again. The debugger does
not care how the checksum is calculated.
Request message:
trap_req req;
addr48_ptr in_addr;
unsigned_16 len;
The req field stores the request. The in_addr contains the starting address and the len
field tells how large the block of memory is.
Return message:
unsigned_32 result
The checksum will be returned in result.
REQ_READ_MEM
Request to read a block of memory.
Request message:
trap_req req;
addr48_ptr mem_addr;
unsigned_16 len;
The mem_addr contains the address of the memory block to read from the remote machine. The length of
the block is determined by len. The memory data will be copied to output message.
Return message:
bytes data
The data field stores the memory block read in. The length of this memory block is given by the return
value from TrapRequest. If error has occurred in reading memory, the length of the data returns will not be equal to
the number of bytes requested.
REQ_WRITE_MEM
Request to write a block of memory.
Request message:
trap_req req
addr48_ptr mem_addr
------------------------
bytes data
The data field stores the memory data to be transferred. The data will be stored in the debuggee's
address space starting at the address in the mem_addr field.
Return message:
unsigned_16 len
The len field tells the length of memory block actually written to the debuggee machine. If error has
occurred in writing the memory, the length returned will not be equal to the number of bytes requested.
REQ_READ_IO
Request to read data from I/O address space of the debuggee.
Request message:
trap_req req
unsigned_32 IO_offset
unsigned_8 len
The IO_offset contains the I/O address of the debuggee machine. The length of the block is determined
by len. It must be 1, 2 or 4 bytes. The data will be copied from IO_offset to the return message.
Return message:
bytes data
The data field stores the memory block read in. The length of this memory block is given by the return
value from TrapRequest. If an error has occurred in reading, the length returned will not be equal to the number of
bytes requested.
REQ_WRITE_IO
Request to write data to the I/O address space of the debuggee.
Request message:
trap_req req
unsigned_32 IO_offset
-------------------------
bytes data
The IO_offset contains the I/O address of the debuggee machine. The data stored in data field
will be copied to IO_offset on the debuggee machine.
Return message:
unsigned_8 len
The len field tells the number of bytes actually written out. If an error has occurred in writing,
the length returned will not be equal to the number of bytes requested.
REQ_PROG_GO/REQ_PROG_STEP
Requests to execute the debuggee. REQ_PROG_GO causes the debuggee to resume execution, while REQ_PROG_STEP requests
only a single machine instruction to be executed before returning. In either case, this request will return when a
breakpoint, watchpoint, machine exception or other significant event has been encountered. While executing, a trap
file is allowed to return spurious COND_WATCH indications. The debugger always checks its own watchpoint table for
changes before reporting to the user. This means that a legal implementation of a trap file (but very inefficient)
can just single step the program and return COND_WATCH for every instruction when there are active watchpoints present.
Request message:
trap_req req
The request is in req field.
Return message:
addr48_ptr stack_pointer
addr48_ptr program_counter
unsigned_16 conditions
The stack_pointer and program_counter fields store the latest values of SS:ESP and CS:EIP (or their
non-x86 equivalents) respectively. The conditions informs the debugger what conditions have changed since
execution began. It contains the following flags:
Bit 0 : COND_CONFIG
- Configurations change
Bit 1 : COND_SECTIONS - Program
overlays change
Bit 2 : COND_LIBRARIES - Libraries
(DLL) change
Bit 3 : COND_ALIASING - Alias
change
Bit 4 : COND_THREAD
- Thread change
Bit 5 : COND_THREAD_EXTRA - Thread extra change
Bit 6 : COND_TRACE
- Trace point occurred
Bit 7 : COND_BREAK
- Break point occurred
Bit 8 : COND_WATCH
- Watch point occurred
Bit 9 : COND_USER
- User interrupt
Bit 10 : COND_TERMINATE - Program terminated
Bit 11 : COND_EXCEPTION - Machine exception
Bit 12 : COND_MESSAGE - Message
to be displayed
Bit 13 : COND_STOP
- Debuggee wants to stop
Bit 14 : COND_RUNNING - Debuggee
is running
Bit 15 : not used
When a bit is off, the debugger avoids having to make additional requests to determine the new state of the debuggee.
If the trap file is not sure that a particular item has changed, or if it is expensive to find out, it should just
turn the bit on.
REQ_PROG_LOAD
Request to load a program.
Request message:
trap_req req
unsigned_8 true_argv
-------------------------
bytes argv
The true_argv field indicates whether the argument consists of a single string, or a true C-style argument
vector. This field is set to be one for a true argument vector and zero otherwise. The argv is a set
of zero-terminated strings, one following each other. The first string gives the name of the program to be loaded.
The remainder of the argv field contains the program's arguments. The arguments can be a single string
or an array of strings.
Return message:
trap_error err
trap_phandle task_id
trap_mhandle mod_handle
unsigned_8 flags
The err field returns the error code while loading the program. The task_id shows the task
(process) ID for the program loaded. The mod_handle is the system module identification for the executable
image. It is used as input to the REQ_MAP_ADDR request. The flags field contains the following information:
Bit 0 : LD_FLAG_IS_BIG
- 32-bit program (obsolete)
Bit 1 : LD_FLAG_IS_PROT
- Protected mode (obsolete)
Bit 2 : LD_FLAG_IS_STARTED - Program
already started
Bit 3 : LD_FLAG_IGNORE_SEGMENTS - Ignore segments (flat)
Bit 4 : LD_FLAG_HAVE_RUNTIME_DLLS - DLL load breaks supported
Bit 5 : LD_FLAG_DISPLAY_DAMAGED - Debugger must repaint screen
Bit 6 : not used
Bit 7 : not used
REQ_PROG_KILL
Request to kill the program.
Request message:
trap_req req
trap_phandle task_id
The req field contains the request. The task_id field (obtained from REQ_PROG_LOAD) identifies
the program to be killed.
Return message:
trap_error err
The err field returns the error code of the OS kill program operation.
REQ_SET_WATCH
Request to set a watchpoint at the address given.
Request message:
trap_req req
addr48_ptr watch_addr
unsigned_8 size
The address of the watchpoint is given by the watch_addr field. The size field gives the number
of bytes to be watched (1, 2, 4 or 8 bytes).
Return message:
trap_error err
unsigned_32 multiplier
The err field returns the error code if the setting failed. If the setting of the watchpoint worked,
the 31 low order bits of multiplier indicate the expected slow down of the program when it's placed into execution.
The top bit of the field is set to one if a debug register is being used for the watchpoint, and zero if the watchpoint
is being done by software.
REQ_CLEAR_WATCH
Request to clear a watchpoint at the address given. The trap file may assume all watch points are cleared at once.
Request message:
trap_req req
addr48_ptr watch_addr
unsigned_8 size
The address of the watch point is given by the watch_addr field. The size field gives the
size of the watch point (1, 2, 4 or 8 bytes).
Return message:
NONE
REQ_SET_BREAK
Request to set a breakpoint at the address given.
Request message:
trap_req req
addr48_ptr break_addr
The address of the break point is given by the break_addr field.
Return message:
unsigned_32 old
The old field returns the original byte(s) at the address break_addr.
REQ_CLEAR_BREAK
Request to clear a breakpoint at the address given. The trap file may assume all breakpoints are cleared at once.
Request message:
trap_req req
addr48_ptr break_addr
unsigned_32 old
The address of the break point is given by the break_addr field. The old field holds the old
instruction returned from the REQ_SET_BREAK request.
Return message:
NONE
REQ_GET_NEXT_ALIAS
Request to get alias information for a segment. In some protect mode environments (typically 32-bit flat) two different
selectors may refer to the same physical memory. Which selectors do this is important to the debugger in certain cases
(so that symbolic information is properly displayed).
Request message:
trap_req req
unsigned_16 seg
The seg field contains the segment. To get the first alias, put zero in this field.
Return message:
unsigned_16 seg
unsigned_16 alias
The seg field contains the next segment where an alias appears. If this field returns zero, it implies
no more aliases can be found. The alias field returns the alias of the input segment. Zero indicates
a previously set alias should be deleted.
REQ_SET_USER_SCREEN
Request to make the debuggee's screen visible.
Request message:
trap_req req
Return message:
NONE
REQ_SET_DEBUG_SCREEN
Request to make the debugger's screen visible.
Request message:
trap_req req
Return message:
NONE
REQ_READ_USER_KEYBOARD
Request to read the remote keyboard input.
Request message:
trap_req req
unsigned_16 wait
The request will be time out if it waits longer than the period specifies in the wait field. The waiting
period is measured in seconds. A value of zero means to wait forever.
Return message:
unsigned_8 key
The key field returns the input character from remote machine.
REQ_GET_LIB_NAME
Request to get the name of a newly loaded library (DLL).
Request message:
trap_req req
trap_mhandle mod_handle
The mod_handle field contains the library handle. It should be zero to get the name of the first DLL
or the value from the mod_handle of a previous request.
Return message:
trap_mhandle mod_handle
---------------------------
string name
The mod_handle field contains the library handle. It contains zero if there are no more DLL names to
be returned. The name of the library will be returned in name field. If the name field is an
empty string (consists just of the '\0' character), then this is a indication that the DLL indicated by the given handle
has been unloaded, and the debugger should remove any symbolic information for the image. It is an error to attempt
to remove a handle that has not been loaded in a previous REQ_GET_LIB_NAME request.
REQ_GET_ERR_TEXT
Request to get the error message text for an error code.
Request message:
trap_req req
trap_error err
The err field contains the error code number of the error text requested.
Return message:
string error_msg
The error message text will be returned in error_msg field.
REQ_GET_MESSAGE_TEXT
Request to retrieve generic message text. After a REQ_PROG_LOAD, REQ_PROG_GO or REQ_PROG_STEP has returned with
COND_MESSAGE or COND_EXCEPTION, the debugger will make this request to obtain the message text. In the case of a COND_EXCEPTION
return text describing the machine exception that caused the return to the debugger. Otherwise return whatever generic
message text that the trap file wants to display to the user.
Request message:
trap_req req
Return message:
unsigned_8 flags
---------------------
string msg
The message text will be returned in the msg field. The flags contains a number of bits which
control the next action of the debugger. They are:
Bit 0 : MSG_NEWLINE
Bit 1 : MSG_MORE
Bit 2 : MSG_WARNING
Bit 3 : MSG_ERROR
Bit 4 : not used
Bit 5 : not used
Bit 6 : not used
Bit 7 : not used
The MSG_NEWLINE bit indicates that the debugger should scroll its display to a new line after displaying the message.
The MSG_MORE bit indicates that there is another line of output to come and the debugger should make another REQ_GET_MESSAGE_TEXT.
MSG_WARNING indicates that the message is a warning level message while MSG_ERROR is an error level message.
If neither of these bits are on, the message is merely informational.
REQ_REDIRECT_STDIN/REQ_REDIRECT_STDOUT
Request to redirect the standard input (REQ_REDIRECT_STDIN) or standard output (REQ_REDIRECT_STDOUT) of the debuggee.
Request message:
trap_req req
------------------------
string name
The file name to be redirected to/from is given by the name field.
Return message:
trap_error err
When an error has occurred, the err field contains an error code indicating the type of error that has been
detected.
REQ_SPLIT_CMD
Request to split the command line into the command name and parameters.
Request message:
trap_req req
------------------------
string cmd
The cmd field contains the command. Command can be a single command line or an array of command strings.
Return message:
unsigned_16 cmd_end
unsigned_16 parm_start
The cmd_end field tells the position in command line where the command name ends. The parm_start
field stores the position where the program arguments begin.
REQ_READ_REGS
Request to read CPU register contents. The data returned depends on the target architecture and is defined by the
MAD file.
Request message:
trap_req req
Return message:
unspecified
The return message content is specific to the MAD in use and will contain a mad_registers union (defined
in madtypes.h ).
REQ_WRITE_REGS
Request to write CPU register contents. The data is target architecture specific.
Request message:
trap_req req
-------------------
unspecified
The message content is specific to the MAD in use and will contain a mad_registers union.
Return message:
NONE
REQ_MACHINE_DATA
Request to retrieve machine specific data.
Request message:
trap_req req;
unsigned_8 info_type;
addr48_ptr addr;
-----------------------------
unspecified
The info_type field specifies what kind of information should be returned and addr determines the
address for which the information is requested. The remainder of the message is MAD specific.
Return message:
addr48_off cache_start;
addr48_off cache_end;
-----------------------------
unspecified
The return message content is specific to the MAD in use.
File I/O requests
This section describes requests that deal with file input/output on the target (debuggee) machine. These requests
are actually performed by the core request REQ_PERFORM_SUPPLEMENTARY_SERVICE and appropriate service ID. The following
descriptions do not show that "prefix" to the request messages.
The service name to be used in the REQ_GET_SUPPLEMENTARY_SERVICE is "Files".
The file requests use a new basic type in addition to the ones already described:
- Type
- Definition
trap_fhandle
- This is an unsigned_64 which holds a debuggee file handle.
REQ_FILE_GET_CONFIG
Request to retreive characteristics of the remote file system.
Request message:
trap_req req
Return message:
char ext_separator;
char path_separator[3];
char newline[2];
The ext_separator contains the separator for file name extensions. The possible path separators can
be found in array path_separator. The first one is the "preferred" path separator for that operating
system. This is the path separator that the debugger will use if it needs to construct a file name for the remote system.
The new line control characters are stored in array newline. If the operating system uses only a single
character for newline, put a zero in the second element.
REQ_FILE_OPEN
Request to create/open a file.
Request message:
trap_req req
unsigned_8 mode
------------------------
string name
The name of the file to be opened is given by name. The mode field stores the access mode
of the file. The following bits are defined:
Bit 0 : DIG_OPEN_READ
Bit 1 : DIG_OPEN_WRITE
Bit 2 : DIG_OPEN_CREATE
Bit 3 : DIG_OPEN_TRUNC
Bit 4 : DIG_OPEN_APPEND
Bit 5 : reserved
Bit 6 : reserved
Bit 7 : reserved
For read/write mode, turn both DIG_OPEN_READ and DIG_OPEN_WRITE bits on. The DIG_OPEN_TRUNC
bit should only be used together with DIG_OPEN_CREATE and indicates that the created file needs executable permission
(if relevant on the target platform).
Return message:
trap_error err
trap_fhandle handle
If successful, the handle returns a handle for the file. When an error has occurred, the err
field contains a value indicating the type of error that has been detected.
REQ_FILE_SEEK
Request to seek to a particular file position.
Request message:
trap_req req
trap_fhandle handle
unsigned_8 mode
unsigned_32 pos
The handle of the file is given by the handle field. The mode field stores the seek mode.
There are three seek modes:
DIG_SEEK_ORG = 0 - Relative to the start of file
DIG_SEEK_CUR = 1 - Relative to the current file position
DIG_SEEK_END = 2 - Rrelative to the end of file
The position to seek to is in the pos field.
Return message:
trap_error err
unsigned_32 pos
If an error has occurred, the err field contains a value indicating the type of error that has been detected.
The pos field returns the current position of the file.
REQ_FILE_READ
Request to read a block of data from a file.
Request message:
trap_req req
trap_fhandle handle
unsigned_16 len
The handle of the file is given by the handle field. The len field stores the number of bytes
to be transmitted.
Return message:
trap_error err
--------------------------
bytes
data
If successful, the data returns the block of data. The length of returned data is given by the return
value of TrapRequest minus 4 (to account for the size of err ). The length will normally be equal to the
len field. If the end of file is encountered before the read completes, the return value will be less than the
number of bytes requested. When an error has occurred, the err field contains a value indicating the type
of error that has been detected.
REQ_FILE_WRITE
Request to write a block of data to a file.
Request message:
trap_req req
trap_fhandle handle
------------------------
bytes data
The handle of the file is given by the handle field. The data is given in data field.
Return message:
trap_error err
unsigned_16 len
If there is no error, len will equal to that in the data_len field. When an error has occurred,
the err field contains a value indicating the type of error that has been detected.
REQ_FILE_WRITE_CONSOLE
Request to write a block of data to the debuggee's screen.
Request message:
trap_req req
------------------------
bytes data
The data is given in data field.
Return message:
trap_error err
unsigned_16 len
If there is no error, len will equal to the data_len field. When an error has occurred, the
err field contains a value indicating the type of error that has been detected.
REQ_FILE_CLOSE
Request to close a file.
Request message:
trap_req req
trap_fhandle handle
The handle of the file is given by the handle field.
Return message:
trap_error err
When an error has occurred, the err field contains a value indicating the type of error that has been detected.
REQ_FILE_ERASE
Request to erase a file.
Request message:
trap_req req
-------------------------
string file_name
The file_name field contains the file name to be deleted.
Return message:
trap_error err
If error has occurred when erasing the file, the err field will return the error code number.
REQ_FILE_STRING_TO_FULLPATH
Request to convert a file name to its full path name.
Request message:
trap_req req
unsigned_8 file_type
-------------------------
string file_name
The file_type field indicates the type of the input file. File types can be:
DIG_FILETYPE_EXE = 0
DIG_FILETYPE_DBG = 1
DIG_FILETYPE_PRS = 2
DIG_FILETYPE_HLP = 3
This is so the trap file can search different paths for the different types of files. For example, under QNX,
the PATH environment variable is searched for the DIG_FILETYPE_EXE type, and the WD_PATH environment variable is searched
for the others. The file_name field contains the file name to be converted.
Return message:
trap_error err
--------------------------
string path_name
If no error occurs the err field returns a zero and the full path name will be stored in the path_name
field. When an error has occurred, the err field contains an error code indicating the type of error that
has been detected.
REQ_FILE_RUN_CMD
Request to run a command on the target (debuggee's) system.
Request message:
trap_req req
unsigned_16 chk_size
------------------------
string cmd
The chk_size field gives the check size in kilobytes. This field is only useful in the DOS implementation.
It contains the value of the /CHECKSIZE debugger command line option and represents the amount of memory the user wishes
to have free for the spawned sub-shell. The cmd field stores the command to be executed.
Return message:
trap_error err
If error has occurred when executing the command, the err field will return the error code number.
Overlay requests
This section describes requests that deal with overlays (supported only under 16-bit DOS). These requests are actually
performed by the core request REQ_PERFORM_SUPPLEMENTARY_SERVICE and appropriate service ID. The following descriptions
do not show that "prefix" to the request messages.
The service name to be used in the REQ_GET_SUPPLEMENTARY_SERVICE is "Overlays".
The overlay requests use a new basic type in addition to the ones already described:
- Type
- Definition
addr32_ptr
- This type encapsulates the concept of a 16:16 pointer into the debuggee's address space. Since overlays are only useful
for 16-bit environments, using the addr48_ptr type would be inefficient. The structure is defined as follows:
typedef struct {
unsigned_16 offset;
unsigned_16 segment;
} addr32_ptr;
The segment field contains the segment of the address and the offset field stores the offset of
the address.
ovl_address
- This type contains the overlay address and the number of entries down in the overlay stack. The structure is defined
as follows:
typedef struct {
addr32_ptr mach;
unsigned_16 sect_id;
} ovl_address;
The mach field is the machine address. The sect_id field stores the address section number.
REQ_OVL_STATE_SIZE
Request to return the size of the overlay state information in bytes of the task program. This request maps onto
the overlay manager's GET_STATE_SIZE request. See the Overlay Manager Interface document for more information on the
contents of the return message.
Request message:
trap_req req
The req field contains the request.
Return message:
unsigned_16 size
The size field returns the size in bytes. A value of zero indicates no overlays are present in the
debuggee and none of the other requests dealing with overlays will ever be called.
REQ_OVL_GET_DATA
Request to get the address and size of an overlay section. This request maps onto the overlay manager's GET_SECTION_DATA
request. See the Overlay Manager Interface document for more information on the contents of the return message.
Request message:
trap_req req
unsigned_16 sect_id
The sect_id field indicates the overlay section the information is being requested of.
Return message:
unsigned_16 segment
unsigned_32 size
The segment field contains the segment value where the overlay section is loaded (or would be loaded if it
was brought into memory). The size field gives the size, in bytes, of the overlay section. If there
is no section for the given id, the segment field will be zero.
REQ_OVL_READ_STATE
Request to read the overlay table state. This request maps onto the overlay manager's GET_OVERLAY_STATE request.
See the Overlay Manager Interface document for more information on the contents of the return message. The size
of the returned data is provided by the REQ_OVL_STATE_SIZE trap file request.
Request message:
trap_req req
Return message:
bytes data
The data field contains the overlay state information requested.
REQ_OVL_WRITE_STATE
Request to write the overlay table state. This request maps onto the overlay manager's SET_OVERLAY_STATE request.
See the Overlay Manager Interface document for more information on the contents of the return message.
Request message:
trap_req req
--------------------
bytes data
The data field contains the overlay state information to be restored.
Return message:
NONE
REQ_OVL_TRANS_VECT_ADDR
Request to check if the input overlay address is actually an overlay vector. This request maps onto the overlay
manager's TRANSLATE_VECTOR_ADDR request. See the Overlay Manager Interface document for more information on the contents
of the messages.
Request message:
trap_req req
ovl_address ovl_addr
The mach field is the machine address. The sect_id field stores the number of entries down
in the overlay stack.
Return message:
ovl_address ovl_addr
The translated address will be returned in the ovl_addr field. If the address is not an overlay vector,
then the input address will be returned and the sect_id field will be zero.
REQ_OVL_TRANS_RET_ADDR
Request to check if the address is the overlay manager parallel return code. This request maps onto the overlay
manager's TRANSLATE_RETURN_ADDR request. See the Overlay Manager Interface document for more information on the contents
of the messages.
Request message:
trap_req req
ovl_address ovl_addr
Return message:
ovl_address ovl_addr
The translated address will be returned in the ovl_addr field. If the address is not an parallel return
code, then the input address will be returned and the sect_id field in the structure ovl_addr will be zero.
REQ_OVL_GET_REMAP_ENTRY
Request to check if the overlay address needs to be remapped. This request maps onto the overlay manager's GET_MOVED_SECTION
request. See the Overlay Manager Interface document for more information on the contents of the messages.
Request message:
trap_req req
ovl_address ovl_addr
The ovl_addr field contains the overlay address.
Return message:
unsigned_8 remapped
ovl_address ovl_addr
If the address gets remapped the remapped field will return one. The remapped address will be returned
in the ovl_addr field. The input address will be unchanged if the address has not been remapped.
Thread requests
This section descibes requests that deal with threads. These requests are actually performed by the core request
REQ_PERFORM_SUPPLEMENTARY_SERVICE and appropriate service ID. The following descriptions do not show that "prefix"
to the request messages.
The service name to be used in the REQ_GET_SUPPLEMENTARY_SERVICE is "Threads".
The thread requests use a new basic type in addition to the ones already described:
- Type
- Definition
trap_thandle
- This is an unsigned_32 type which holds a thread handle.
REQ_THREAD_GET_NEXT
Request to get next thread.
Request message:
trap_req req
trap_thandle thread
The thread contains the either a zero to get information on the first thread, or the value of the thread
field in the return message of a previous request.
Return message:
trap_thandle thread
unsigned_8 state
The thread field returns the thread ID. There are no more threads in the list, it will contain zero.
The state field can have two values:
THREAD_THAWED = 0
THREAD_FROZEN = 1
REQ_THREAD_SET
Request to set a given thread ID to be the current thread.
Request message:
trap_req req
trap_thandle thread
The thread contains the thread number to set. If it's zero, do not attempt to set the thread, just
return the current thread ID.
Return message:
trap_error error
trap_thandle old_thread
The old_thread field returns the previous thread ID. If the set fails, the err field will
be non-zero.
REQ_THREAD_FREEZE
Request to freeze a thread so that it will not be run next time when executing the task program.
Request message:
trap_req req
trap_thandle thread
The thread contains the thread number to freeze.
Return message:
trap_error err
If the thread cannot be frozen, the err field returns non-zero value.
REQ_THREAD_THAW
Request to allow a thread to run next time when executing the program.
Request message:
trap_req req
trap_thandle thread
The thread contains the thread number to thaw.
Return message:
trap_error err
If the thread cannot be thawed, the err field returns non zero value.
Request to get extra information about a thread. This is arbitrary textual data which the debugger merely displays
in its thread window. The trap file can place any information in the return message which it feels would be useful
for the user to know.
Request message:
trap_req req
unsigned_32 thread
The thread field contains the thread ID. A zero value means to get the title string for the thread
extra information. This is displayed at the top of the thread window.
Return message:
string extra
The extra information of the thread will be returned in extra field.
RFX requests
This section deals with requests that are only used by the RFX (Remote File Xfer) program. These requests are actually
performed by the core request REQ_PERFORM_SUPPLEMENTARY_SERVICE and appropriate service ID. The following descriptions
do not show that "prefix" to the request messages.
The service name to be used in the REQ_GET_SUPPLEMENTARY_SERVICE is "Rfx".
REQ_RFX_RENAME
Request to rename a file on the debuggee's system.
Request message:
trap_req req
-------------------------
string from_name
-------------------------
string to_name
The file whose name is indicated by the field from_name will be renamed to the name given by the field
to_name.
Return message:
trap_error err
If error has occurred, the err field will return the error code number.
REQ_RFX_MKDIR
Request to create a directory on the target (debuggee) system.
Request message:
trap_req req
------------------------
string dir_name
The dir_name field contains the name of the directory to be created.
Return message:
trap_error err
If error has occurred when creating the directory, the err field will return the error code number.
REQ_RFX_RMDIR
Request to remove a directory on the target system.
Request message:
trap_req req
------------------------
string dir_name
The dir_name field contains the name of the directory to be removed.
Return message:
trap_error err
If error has occurred, the err field will return the error code number.
REQ_RFX_SETDRIVE
Request to set the current drive on the target system.
Request message:
trap_req req
unsigned_8 drive
The drive field contains the drive number to be set on the target system (0=A,1=B,...).
Return message:
trap_error err
If error has occurred, the err field will return the error code number.
REQ_RFX_GETDRIVE
Request to get the current drive on the target system.
Request message:
trap_req req
The req field contains the request.
Return message:
unsigned_8 drive
The drive field returns the current drive number on the target system (0=A,1=B,...).
REQ_RFX_SETCWD
Request to set a directory on the target system.
Request message:
trap_req req
------------------------
string dir_name
The dir_name field contains the name of the directory to be set.
Return message:
trap_error err
If error has occurred, the err field will return the error code number.
REQ_RFX_GETCWD
Request to get the current directory name on the target system.
Request message:
trap_req req
unsigned_8 drive
The drive field contains the target drive number (0=current drive,1=A,2=B,...).
Return message:
trap_error err
--------------------------
string dir_name
The dir_name field contains the name of the directory to be set. If error has occurred, the err
field will return the error code number.
REQ_RFX_SETDATETIME
Request to set a file's date and time information on the target system.
Request message:
trap_req req
trap_fhandle handle
time_t time
The handle contains the file handle. The time field follows the UNIX time format. The
time represents the time since January 1, 1970 (UTC).
Return message:
NONE
REQ_RFX_GETDATETIME
Request to get the date and time information for a file on the target system.
Request message:
trap_req req
trap_fhandle handle
The handle contains the file handle.
Return message:
time_t time
The time field follows the UNIX time format. The time represents the time since January 1,
1970 (UTC).
REQ_RFX_GETFREESPACE
Request to get the amount of free space left on the drive.
Request message:
trap_req req
unsigned_8 drive
The drive field contains the target drive number (0=current drive,1=A,2=B,...).
Return message:
unsigned_32 size
The size field returns the number of bytes left on the drive.
REQ_RFX_SETFILEATTR
Request to set the file attribute of a file.
Request message:
trap_req req
unsigned_32 attribute
-------------------------
string name
The name field contains the name whose attributes are to be set. The attribute field contains
the new attributes of the file.
Return message:
trap_error err
If error has occurred, the err field will return the error code number.
REQ_RFX_GETFILEATTR
Request to get the file attribute of a file.
Request message:
trap_req req
--------------------
string name
The name field contains the name to be checked.
Return message:
unsigned_32 attribute
The attribute field returns the attribute of the file.
REQ_RFX_NAMETOCANONICAL
Request to convert a file name to its canonical form.
Request message:
trap_req req
-------------------------
string file_name
The file_name field contains the file name to be converted.
Return message:
trap_error err
--------------------------
string path_name
If there is no error, the err field returns a zero and the full path name will be stored in the path_name
field. When an error has occurred, the err field contains an error code indicating the type of error that
has been detected.
REQ_RFX_FINDFIRST
Request to find the first file in a directory.
Request message:
trap_req req
unsigned_8 attrib
----------------------
string name
The name field contains the name of the directory and the attrib field contains the attribute of
the files to list in the directory.
Return message:
trap_error err
-----------------------
rfx_find info
If found, the err field will be zero. The location and information of about the first file will be
in the structure info. Definition of the structure rfx_find is as follows:
typedef struct rfx_find {
unsigned_8
reserved[21];
unsigned_8
attr;
unsigned_16 time;
unsigned_16 date;
unsigned_32 size;
unsigned_8
name[260];
} rfx_find;
REQ_RFX_FINDNEXT
Request to find the next file in the directory. This request should be used only after REQ_RFX_FINDFIRST.
Request message:
trap_req req
--------------------
rfx_find info
The req field contains the request. The info field contains the rfx_find structure returned
from the previous REQ_FIND_NEXT or REQ_FIND_FIRST.
Return message:
trap_error err
-----------------------
rfx_find info
The info field is the same as in REQ_FIND_FIRST.
REQ_RFX_FINDCLOSE
Request to end the directory search operation.
Request message:
trap_req req
The req field contains the request.
Return message:
trap_error err
If successful, the err field will be zero, otherwise the system error code will be returned.
Environment requests
This section describes requests that deal with Environment on the target (debuggee) machine. These requests are
actually performed by the core request REQ_PERFORM_SUPPLEMENTARY_SERVICE and appropriate service ID. The following
descriptions do not show that "prefix" to the request messages.
The service name to be used in the REQ_GET_SUPPLEMENTARY_SERVICE is "Environment".
REQ_ENV_GET_VAR
Request to retreive Environment variable from the remote system.
Request message:
trap_req req
------------------------
string name
Return message:
trap_error err
string value;
The value contains the value for name Environment variable from the remote system.
REQ_ENV_SET_VAR
Request to set Environment variable on the remote system.
Request message:
trap_req req
------------------------
string name
string value;
Return message:
trap_error err
The value contains the new value for Environment variable name on the remote system.
File Info requests
REQ_FILE_INFO_GET_DATE
Request message:
trap_req req
Return message:
trap_error err
REQ_FILE_INFO_SET_DATE
Request message:
trap_req req
Return message:
trap_error err
Asynchronous Debugging requests
REQ_ASYNC_GO
Request message:
trap_req req
Return message:
trap_error err
REQ_ASYNC_STEP
Request message:
trap_req req
Return message:
trap_error err
REQ_ASYNC_POLL
Request message:
trap_req req
Return message:
trap_error err
REQ_ASYNC_STOP
Request message:
trap_req req
Return message:
trap_error err
REQ_ASYNC_ADD_BREAK
Request message:
trap_req req
Return message:
trap_error err
REQ_ASYNC_REMOVE_BREAK
Request message:
trap_req req
Return message:
trap_error err
Non-blocking Thread requests
REQ_RUN_THREAD_INFO
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_GET_NEXT
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_GET_RUNTIME
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_POLL
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_SET
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_GET_NAME
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_STOP
Request message:
trap_req req
Return message:
trap_error err
REQ_RUN_THREAD_SIGNAL_STOP
Request message:
trap_req req
Return message:
trap_error err
Capabilities requests
REQ_CAPABILITIES_GET_EXACT_BP
Request to get information if exact breakpoints are supported on the remote system.
Request message:
trap_req req
Return message:
trap_error err
unsigned_8 status
The status contains true if exact breakpoints are supported on the remote system otherwise status
contains false.
REQ_CAPABILITIES_SET_EXACT_BP
Request to set if exact breakpoints are active on the remote system.
Request message:
trap_req req
unsigned_8 status
Return message:
trap_error err
unsigned_8 status
The input status contains if exact breakpoints are required to be active on the remote system.
The output status contains status if exact breakpoints are currently active on the remote system.
System Dependent Aspects
Every environment has a different method of loading the code for the trap file and locating the TrapInit, TrapRequest,
and TrapFini routines. This section descibes how the Open Watcom debugger performs these operations for the various
systems.
Trap Files Under DOS
A trap file is an "EXE" format file with the extension ".TRP". The debugger searches the directories
specified by the PATH environment variable. Once found, it is loaded into memory and has the normal EXE style relocations
applied to the image. Then the lowest address in the load image (NOTE: not the starting address from EXE header
information) is examined for the following structure:
typedef struct {
unsigned_16 signature; /* == 0xDEAF */
unsigned_16 init_off;
unsigned_16 acc_off;
unsigned_16 fini_off;
} trap_header;
If the first 2 bytes contain the value 0xDEAF, the file is considered to be a valid trap file and the init_off
, acc_off , and fini_off fields are used to obtain the offsets of the TrapInit, TrapRequest, and TrapFini
routines repectively.
The starting address field of the EXE header should be set to point at some code which prints out a message about
not being able to be run from the command line and then terminates.
Trap Files Under OS/2
A trap file is a normal OS/2 DLL. The system automatically searches the directories specified by the LIBPATH command
in the CONFIG.SYS file. Once loaded, the Open Watcom debugger uses export ordinal 1 from the DLL for TrapInit, export
ordinal 2 for TrapFini and export ordinal 3 for TrapRequest. Some example code follows:
rc = DosLoadModule( NULL, 0, trap_file_name, &dll_module );
if( rc != 0 ) {
return( "unable to load trap file" );
}
if( DosGetProcAddr( dll_module, "#1", &TrapInit ) != 0
|| DosGetProcAddr( dll_module, "#2", &TrapFini ) != 0
|| DosGetProcAddr( dll_module, "#3", &TrapRequest ) != 0 ) {
return( "incorrect version of trap file" );
}
Trap Files Under Windows.
A trap file is a normal Windows DLL. The system automatically searches the directories specified by the PATH environment
variable. Once loaded, the Open Watcom debugger uses export ordinal 2 from the DLL for TrapInit, export ordinal 3 for
TrapFini and export ordinal 4 for TrapRequest. Some example code follows:
dll = LoadLibrary( trap_file_name );
if( dll < 32 ) {
return( "unable to load trap file" );
}
TrapInit = (LPVOID) GetProcAddress( dll, (LPSTR)2 );
TrapFini = (LPVOID) GetProcAddress( dll, (LPSTR)3 );
TrapRequest = (LPVOID) GetProcAddress( dll, (LPSTR)4 );
if( TrapInit == NULL || TrapFini == NULL || TrapRequest == NULL ) {
return( "incorrect version of trap file" );
}
Trap Files Under Windows NT.
A trap file is a normal Windows NT DLL. The system automatically searches the directories specified by the PATH
environment variable. Once loaded, the Open Watcom debugger uses export ordinal 1 from the DLL for TrapInit, export
ordinal 2 for TrapFini and export ordinal 3 for TrapRequest. Some example code follows:
dll = LoadLibrary( trap_file_name );
if( dll < 32 ) {
return( "unable to load trap file" );
}
TrapInit = (LPVOID) GetProcAddress( dll, (LPSTR)1 );
TrapFini = (LPVOID) GetProcAddress( dll, (LPSTR)2 );
TrapRequest = (LPVOID) GetProcAddress( dll, (LPSTR)3 );
if( TrapInit == NULL || TrapFini == NULL || TrapRequest == NULL ) {
return( "incorrect version of trap file" );
}
Trap Files Under QNX
A trap file is a QNX load module format file with the extension ".trp" and whose file permissions are not marked
as executable. The debugger searches the directories specified by the WD_PATH environment variable and then the "/usr/watcom/wd"
directory. Once found, it is loaded into memory and has the normal loader relocations applied to the image. Then
the lowest address in the load image (NOTE: not the starting address from load module header information) is examined
for the following structure:
typedef struct {
unsigned_16 signature; /* == 0xDEAF */
unsigned_16 init_off;
unsigned_16 acc_off;
unsigned_16 fini_off;
} trap_header;
If the first 2 bytes contain the value 0xDEAF, the file is considered to be a valid trap file and the init_off
, acc_off , and fini_off fields are used to obtain the offsets of the TrapInit, TrapRequest, and TrapFini
routines repectively.
The starting address field of the load image header should be set to point at some code which prints out a message
about not being able to be run from the command line and then terminates.
Trap Files Under Netware 386 or PenPoint
The trap file routines are linked directly into the remote server code and TrapInit, TrapRequest, TrapFini are directly
called.
Overlay manager interface
For Open Watcom Debugger to be able to debug overlays, it must be able to make requests of the overlay manager for certain
operations. The overlay manager must also be able to inform Open Watcom Debugger when a new overlay section is loaded.
When Open Watcom Debugger loads a DOS program, it looks at the initial CS:IP value for the following structure:
struct ovl_header {
unsigned_8 short_jmp_opcode;
/* == 0xeb */
signed_8 short_jmp_displacment;
unsigned_16 signature;
/* == 0x2112 */
void (far *hook)();
unsigned_16 handler_offset;
};
Open Watcom Debugger checks to make sure that the first instruction is a short jump (opcode 0xeb) and that the word
following that instruction contains the value 0x2112. If this occurs, Open Watcom Debugger assumes that it is debugging
an overlaid application.
Open Watcom Debugger then fills in the hook field with the far address of a routine that is invoked with
a far call whenever a change in the overlay state occurs. The initial CS value and the contents of the handler_offset
field gives the far address of the overlay manager routine responsible for handling debugger requests.
The Hook Routine
After the routine addresses have been exchanged, Open Watcom Debugger starts the program executing, to allow the overlay
manager to initialize. After the manager has finished its initialization, it performs a far call to the debugger hook
routine, with the return address on the stack being the "real" starting address of the program being debugged.
All register contents (including flags) should be preserved by the hook routine.
After initialization, the debugger hook routine is invoked with a far call every time a new overlay section is loaded
into memory. In this case the AX register contains the section number that was just loaded. The DL register contains
a zero or non-zero value if the overlay load was caused by a call or return, respectively. The CX:BX registers form
a far pointer to the last byte of the call instruction that caused the overlay load, in the case of a overlay load being
caused by a return instruction (DL is non-zero) the far pointer is to the last byte of the call instruction that the return
is returning from.
NOTE: may be loaded by the overlay manager before the hook routine is called. The current overlay
manager also loads all of the ancestors of a section (See the WLINK documentation in the Users' Guide for a description of
what an ancestor is). To find out what sections are really in memory the debugger should invoke the handler routine
with a GET_OVERLAY_STATE request.
The Handler Routine
The handler routine is responsible for processing requests from the debugger pertaining to overlays. It is invoked
by the debugger by performing a far call with a request number in the AX register. The AX register is used to return
the result or return status of the request. The CX and BX registers are used for some requests to pass a far pointer
to memory.
There are two structures that the handler routines deals with. The first is called an overlay state. An
overlay state consists of a block of memory containing all the information necessary for the overlay manager to restore the
overlays to their current condition at some later point in time. The first portion of this block is a bit vector, with
each bit representing an overlay section. If the bit is a one, then the overlay section is currently in memory.
If the bit is a zero then the overlay section is not in memory. To convert from a section number to a bit position
use the following formulas:
byte_offset = (section_number - 1) / 8;
bit_number = (section_number - 1) % 8;
Following the bit vector is information that the manager uses to restore the overlay stack.
The second structure used is an overlay address. This consists of a far pointer followed by a 16-bit section
number.
The following requests are recognized by the debug handler routine.
GET_STATE_SIZE
Inputs:
Outputs:
AX = request number (0) AX = size of overlay
state
This request returns the number of bytes required for an overlay state.
GET_OVERLAY_STATE
Inputs:
Outputs:
AX = request number (1) AX = 1
CX:BX = far pointer to memory
to store overlay state
This request copies the overlay state into the memory pointed at by the CX:BX registers. A one is always returned
in AX.
SET_OVERLAY_STATE
Inputs:
Outputs:
AX = request number (2) AX = 1
CX:BX = far pointer to memory
to load overlay state
This request takes a previously obtained overlay state and causes the overlay manager to return itself to that overlay
configuration. A one is always returned in AX. The overlay manager will not explicitly unload a section that
is not in memory according to the given overlay state, so a GET_OVERLAY_STATE request following a SET_OVERLAY_STATE may not
return the same bit vector portion. This request may also be used by the debugger to explicitly load a section, so
the assembly code may be examined, perhaps. To do this, zero out a block of memory the size of an overlay state, and
then turn on the appropriate section number in the bit vector, then make a SET_OVERLAY_STATE request. Remember that
not only that section will be loaded, but all of its ancestor sections as well.
TRANSLATE_VECTOR_ADDR
Inputs:
Outputs:
AX = request number (3) AX = 1 if addr was
translated,
CX:BX = far pointer to
0 otherwise
overlay address
This request checks to see if the far pointer portion of the overlay address pointed at by CX:BX is actually an overlay
vector. If the address is a vector then the vector address is replaced by the true address of the routine that the
vector is for, and the section number portion is filled in with the section number the of routine. A one is returned
in AX in this case. If the address is not an overlay vector, then the overlay address is untouched and an zero is returned
in AX.
TRANSLATE_RETURN_ADDR
Inputs:
Outputs:
AX = request number (4) AX = 1 if addr was
translated,
CX:BX = far pointer to
0 otherwise
overlay address
In order to handle parallel overlay calls, the overlay manager replaces the true return address on the stack with
that of some special code (the parallel return code). It then takes the original return address and section number
an places them on the overlay stack. When a routine returns to the overlay manager, it pops the top entry of the overlay
stack, makes sure that the original overlay section is loaded, and returns to the original return address.
This function performs much the same function as TRANSLATE_VECTOR_ADDR, except that rather than checking for a vector
address, it checks to see if the address is that of the overlay manager parallel return code. If it is then the section
number in the overlay address is used as the number of entries down in the overlay stack that the real return address and
section number is to be found (zero is the top entry of the overlay stack). The true return address and section number
then replaces the contents of the overlay address and a one is returned in AX. If the address is not the parallel return
code, then the overlay address is left untouched and a zero is returned in AX.
GET_OVL_TBL_ADDR
Inputs:
Outputs:
AX = request number (5) AX = 0
CX:BX = far pointer to variable
of type far pointer to
be filled in with
overlay table address
This request fills in the far pointer pointed at by CX:BX with the address of the overlay table so that a profiler
can find out where sections are located in the executable, or overlay files. The sampler program, when it detects that
it is sampling a overlaid application, can perform this function and write the result into the sample file. Since the
overlay table is always in the root, the profiler can then find the overlay table and from that, find the other sections.
It should be noted that the format of the overlay table may change, so this call should be avoided if at all possible.
GET_MOVED_SECTION
Inputs:
Outputs:
AX = request number (6) AX = 1 if the section
exists
CX:BX = far pointer to
0 otherwise
overlay address
With the dynamic overlay manager, sections may be loaded, or moved, to positions other than where the linker originally
placed them. The debugger must be informed of the new positions so that it can update the locations of its symbolic
information. The GET_MOVED_SECTION request is responsible for informing the debugger what sections have moved and their
new locations. The debugger will call this request after the hook routine has been called, or the debugger has invoked
the SET_OVERLAY_STATE request. The request returns the first section whose id larger than the section number that is
in the overlay address being passed in. The overlay manager will fill in the overlay address with the section number
that has moved and its new segment address. The offset portion of the overlay address is unused. The request
will return a one in AX. If there are no sections numbers larger than the one being passed in that have moved, a zero
is returned.
Here is some example debugger code:
void CheckMovedSections()
{
overlay_address addr;
addr.sect_id = 0;
while( OvlHandler( GET_MOVED_SECTION, &addr ) ) {
HandleMovedSection( addr.sect_id, addr.segment
);
}
}
GET_SECTION_DATA
Inputs:
Outputs:
AX = request number (7) AX = 1 if the section
exists
CX:BX = far pointer to
0 otherwise
overlay address
This request returns information on the current location of a section while it is in memory (or where it would be
if it was loaded). The section number portion of the overlay address is filled in with the section id that information
is being requested about before the request is made. The overlay manager returns zero in AX if the section does not
exist. Otherwise it returns one and fills in the overlay address with the location that the section is in memory, or
where it would currently go if it was loaded at that time. It also fills in the section number portion of the address
with the size of the section in paragraphs.
Overlay Table Structure
The pointer returned by the GET_OVL_TBL_ADDR request has the following format:
typedef struct ovl_table {
unsigned_8 major;
unsigned_8 minor;
void
far *start;
unsigned_16 delta;
unsigned_16 ovl_size;
ovltab_entry entries[ 1 ];
} ovl_table;
The fields major and minor field contain version numbers for the overlay table structure.
If an upwardly compatible change in the structures is made, the minor number will be incremented. If a non-upwardly
compatible change to the structures is made, the major field will be incremented. The current major version is 3, the
current minor version is 0. The start field contains a 32-bit far pointer to the "actual" starting
address of the program. The overlay manager jumps to this address after it has finished initializing (If a debugger/sampler
is present then the overlay manager calls into the hook routine with this address on the return stack). The delta
field contains the value to be added to each of the segment relocations when a section is loaded into memory (it contains
the segment value for the first segment in the program). The ovl_size field contains the size of the overlay
area. This is only used in the dynamic overlay manager. The final field, entries , is a variable sized
array containing one entry for each overlay section in the program (e.g. the tenth element in the array describes overlay
section 10). Each entry has the following form:
typedef struct ovltab_entry {
unsigned_16 flags_anc;
unsigned_16 relocs;
unsigned_16 start_para;
unsigned_16 code_handle;
unsigned_16 num_paras;
unsigned_16 fname;
unsigned_32 disk_addr;
} ovltab_entry;
The top bit of the flag_anc field contains an indicator, while the program is running, of whether the overlay
section is in memory (value one) or must be loaded from disk (value zero). The next highest bit is filled in by the
linker and informs the overlay manager that the section must be loaded during the overlay manager initialization. The
remaining bits contain the overlay number for the ancestor of this section (zero if there is none). The relocs
field say how many segment relocation items there are for this section, while the start_para field gives the location
in memory (relative to the start of the program) that the section should be placed when loaded. The num_paras
field contains the size of the section in paragraphs, and the code_handle field is used for various purposes inside
the dynamic overlay loader. The fname field has the offset of the address of a zero terminated string for
the name of the file containing the overlay section data and relocations (The segment value is the same as the overlay table).
If the top bit of the offset is on, then the file is the original EXE file rather than a separate overlay file, and
the overlay manager should use the program file name obtained from DOS (if the version is 3.0. or greater). The
disk_addr field gives the starting offset the overlay data in the overlay file. The segment relocation items immediately
follow the data.
The end of the entries array is indicated when an element's flags_anc field contains the value 0xffff.
The remaining fields in that element contain garbage values.