Symbols and Source-level Debugging

NoICE allows the definition and use of symbols during debugging. Symbols may be defined via manual command, or automatically through the use of the symbol processing utilities.

In most cases, symbolic information will bebe loaded from Elf/Dwarf files, IEEE-695 format files, and from other types of loadable files.

Symbols may be defined and used by the operator to specify commonly used addresses or values, and are displayed by the disassembler when an address, jump destination, or instruction argument has a value exactly equal to the value of the symbol.

NoICE symbol names may contain letters, digits, and the special characters underbar (_), period (.), dollar sign ($), or question mark (?). The first character of a name cannot be a digit. Names cannot contain period (.) if CASE has been set to 2, or "C-style", because period is used in C to denote structure and union members.

NoICE defines three types of symbols: global, base, and scoped. These may be defined by the DEFINE, DEFBASE, and DEFSCOPED commands, respectively.

Scoped symbols differ from global and base symbols in that they are active only within a certain program scope, such as within a function or a source file. For example, variables declared within a C function are considered to have "function scope". Variables declared as "static" within a C file, but not within a function; are considered to have "file scope". When debugging assembly programs, one might define all non-global symbols as "file scope" symbols.

When a symbol name is specified, NoICE will search for the symbol using C scoping rules: if the symbol is defined in the current function scope, then that value will be used. If the symbol is not defined in the current function scope, then the current file scope is searched. If the symbol is not defined in the current file scope, then the global scope is searched. Thus, the same symbol name may be defined with the same or a different value in more than one function, or in more than one file. Only one global definition of a symbol name is allowed.

The scope to be used when evaluating a symbol may be specified in one of the following ways

Under the control of a check box, the symbol list box may show all symbols, or only those which are valid in the current scope.

The value of a symbol may be defined by any expression. Of particular interest are register-relative expressions ("SP+nnn"), which are useful for declaring symbols for stack or frame based variables.


DEFINE symbol

    DEFINE name {value} {%type}

Defines a symbol called "name" with value "value", and data type "type".

"Value" is an expression, which may contain a page number, if supported by the target processor.

"Type" is the name of a data type. It specifies the data type to be used when the symbol is specified by a WATCH or EDIT command. Either a pre-defined or a user-defined type may be specified. See DEFTYPE and subsequent commands for more information about data types.

Either "value" or "type", or both, must be specified. If no type is specified during an initial definition, a default of X08 (hex byte) is used. If no value is specified during an initial definition, a default of zero is used.

A symbol may be given a new value or data type by a subsequent DEFINE command. The ability to omit either the type or value parameter allows simpler generation of symbols by source file processors: the symbol name and type may be derived from one file (for example, a C source file), while the value may be derived from a different file (for example, an assembly list or map file).

Examples:

Define "loopy" at address 1000. The default data type (hex byte) is assumed.

    DEF loopy 1000

Define "i" as a signed 16 bit integer at address 123.

    DEF i 123 %S16

Define "buff" as an array of 128 ASCII characters at address 100.

    DEF buff 100 %ASCII[128]

Define "pI" as a pointer at address 180 to an unsigned 32 bit integer.

    DEF pI 180 %*U32

Define the data type of symbol "loopy" to be IEEE floating point.

    DEF main %float

The symbol "name" may be deleted by entering

    DEFINE -name

"DEF" is an abbreviation of "DEFINE".

The command alias "SET" is provided for the convenience of users of certain Motorola/Freescale freeware assemblers, which can output symbols to a file in the form "SET name hex_value". The symbols in such a file can be defined by "executing" the file using the command

    PLAY file.ext

Utilities are provided for automated symbol definition using other assemblers.


DEFBASE: Define base symbol

    DEFBASE name {value} {%type}

Defines a symbol called "name" with value "value", and data type "type".

Base symbols differ from standard symbols in that they are used by the disassembler to show addresses in the form

    BASE+1234

where "BASE" denotes the name of the nearest base symbol whose value is less than or equal to the address in question, and "1234" is a non-negative hex integer which denotes the offset from the value of BASE.

A common usage of base symbols is to define one for each module of a program being debugged. The value of each base symbol is set equal to the address of the first byte of the code segment in the associated module. Thus, the disassembly listing will show offsets which match the offsets in the assembly listing file for the module.

A base symbol may be given a new value or data type by a subsequent DEFBASE command.

The symbol "name" may be deleted by entering

    DEFBASE -name

"DEFB" is an abbreviation of "DEFBASE".

Utilities are provided for automated symbol definition with various assemblers and compilers.


DEFSCOPED: Define scoped symbol

    DEFSCOPE name {value} {%type}

Defines a scoped symbol called "name" with value "value", and data type "type".

The value of a scoped symbol in a high-level language will often be a register-relative expression ("SP+nnnn"), if the symbol describes a stack or frame based variable. Each time such a symbol is evaluated, the current value of the register will be used.

To define a symbol for a register variable (its value is in the register, not its address), place "&" before the register name. For example, to define "foo" as a 16-bit unsigned integer in register 5 (as on an MSP430)

    DEFSCOPE foo &R5 %U16

A scoped symbol may be given a new value or data type by a subsequent DEFSCOPED command.

"DEFS" is an abbreviation of "DEFSCOPED".

Utilities are provided for automated symbol definition with various assemblers and compilers.


SCOPE: Set symbol scope

    SCOPE {name}

Sets the current scope to "name". "Name" may be the name of a file, the name of a function defined in the current file scope, the name of a global function, or a file name and a function name separated by #. If "name" is omitted, a dialog box is displayed which shows the current function and file scope, and which allows the scope to be changed.


FILE: Declare source file

    FILE filename {base}

Declares "filename" to be the current file for line number definitions using the LINE command, and for the declaration of scoped symbols.

"Base" is an optional address expression. If "base" is specified, subsequent LINE commands will add the base value to the offset contained in the LINE command. It is also considered to be the lowest code address in the file when determining symbol scope from a program address.

Multiple FILE commands may be issued for the same file. Typically, such commands will contain different base values.

If no parameters are specified, a dialog box is displayed which shows the current function and file scope, and which allows the scope to be changed.

In most cases, FILE commands will not be issued manually, but will be included within command files. Utilities are provided for automated file and line number definition with various assemblers and compilers.


ENDFILE: Declare end of a source file

    ENDFILE {endaddress}

Declares the end of the current file for the declaration of scoped symbols.

"Endaddress" is an optional address expression. If "endaddress" is specified, it is considered to be the highest code address in the file when determining symbol scope from a program address.

Multiple ENDFILE commands may be issued for the same file.

In most cases, ENDFILE commands will not be issued manually, but will be included within command files. Utilities are provided for automated file and line number definition with various assemblers and compilers.


FUNCTION: Declare a function

    FUNCTION funcname {address}

Declares "funcname" to be the current function for the declaration of scoped symbols. Functions declared with the FUNCTION command have global scope.

"Address" is an optional address expression. If "address" is specified, it is considered to be the lowest code address in the function when determining symbol scope from a program address.

If no parameters are specified, a dialog box is displayed which shows the current function and file scope, and which allows the scope to be changed.

In most cases, FUNCTION commands will not be issued manually, but will be included within command files. Utilities are provided for automated symbol definition with various assemblers and compilers.


STATICFUNCTION: Declare a function with file scope

    STATICFUNCTION funcname {address}

Declares "funcname" to be the current function for the declaration of scoped symbols. Functions declared with the STATICFUNCTION command have file scope in the current file, as if they had been declared using the C keyword "static".

"Address" is an optional address expression. If "address" is specified, it is considered to be the lowest code address in the function when determining symbol scope from a program address.

The STATICFUNCTION command with no parameters will list the currently defined functions.

In most cases, STATICFUNCTION commands will not be issued manually, but will be included within command files. Utilities are provided for automated symbol definition with various assemblers and compilers.

"SFUNC" is an abbreviation of "STATICFUNCTION".


ENDFUNCTION: Declare end of a function

    ENDFUNCTION {endaddress}

Declares the end of the current global or scoped function for the declaration of scoped symbols.

"Endaddress" is an optional address expression. If "endaddress" is specified, it is considered to be the highest code address in the function when determining symbol scope from a program address.

In most cases, ENDFUNCTION commands will not be issued manually, but will be included within command files. Utilities are provided for automated symbol definition with various assemblers and compilers.

"ENDF" is an abbreviation of "ENDFUNCTION".


LINE: Define line number

    LINE linenumber offset

Associates the specified line of the current source file (as specified by the most recent FILE command) with the specified address offset. If the most recent FILE command specified a base, then the line number is associated with the sum of the base address plus the offset given in the LINE command.

In most cases, LINE commands will not be issued manually, but will be included within command files. Utilities are provided for automated file and line number definition with various assemblers and compilers.

    LINE linenumber

If the viewer is open and the LINE command is issued with a line number but no address, the viewer will display a page beginning with the specified line of the current view file.

The LINE command with no parameters will show the number of source lines currently defined, along with the amount of line storage space available.


CLEARLINEINFO: Delete all source line information

    CLEARLINEINFO

Deletes all source line, function and file information, as well as any symbols with function or file scope. Once source line information has been defined, typically by PLAYing a command file, the information should be deleted before the command file is PLAYed again. The latest versions of most NoICE symbol file utilities insert a CLEARLINEINFO command automatically.

A confirmation dialog is shown. This can be avoided by specifying "Y" on the command line:

    CLEARLINEINFO Y
NOFILES is an alias for CLEARLINEINFO.

CLEARSYMBOLS: Delete all symbols

    CLEARSYMBOLS

Deletes all symbols currently defined.

Individual symbols may be deleted by name by using the DEFINE, DEFBASE, and DEFSCOPED commands.

A confirmation dialog is shown. This can be avoided by specifying "Y" on the command line:

    CLEARSYMBOLS Y

AUTOGENERATE: Automatically generate symbols

This command controls the automatic generation of symbols during disassembly. The command
    AUTOGENERATE  1

will enable automatic symbol generation. The command

    AUTOGENERATE  0

will disable automatic symbol generation.

When AUTOGENERATE is enabled, the disassembler will examine the destination addresses of branch, jump, and call instructions. If no symbol exists whose value is equal to the destination address, such a symbol is defined. The symbol is given a name constructed of an "L" followed by the four character hex value of the destination address. If the destination address is in a paged region, the symbol name will begin with "Pxx", where "xx" denotes the memory page of the address. Only explicit destination addresses are examined: destination addresses specified by indirect or register addressing are not processed.

To use AUTOGENERATE to assist in disassembling code, disassemble the code region once to generate the symbols, then again to view the result including all symbols. To save the disassembled output for later rework into source code, use the CAPTURE command.

The AUTOGENERATE command may be found on the SYMBOL menu.


SYMBOL: Show symbol with value "expr"

    SYMBOL expr

This command displays the symbol whose value represents the expression. If the value exactly matches a symbol, the name of the symbol will be shown. If there is no exact match, but a base symbol whose value is lower than the expression exists, the name of the base symbol and the offset from it to the value of the expression will be shown. If no appropriate symbol or base symbol is found, the message "no symbol found" will be shown.

If no expression is specified, the names and values of all defined symbols and base symbols will be shown in a dialog box.

"SYM" is an abbreviation of "SYMBOL".


CASE: Control Symbol Case Sensitivity

Symbols in NoICE are case sensitive by default. The command

    CASE 0

will disable case sensitivity. The command

    CASE 1

will enable case sensitivity. Symbols defined while case sensitivity is turned off will be stored in all upper case. The command

    CASE 2

will enable "C-style" symbols. Such symbols are case sensitive. Furthermore, the "." character is not allowed as part of such a symbol, because this character is used for structure dereferencing.


RADIX: Set numeric radix for formatted output

    RADIX {base}

WATCH and EDIT of integer data may be displayed and entered in either hexadecimal or decimal as specified by this command. "base" must be either 10 or 16, and is always entered in decimal. The selected radix preference is saved when you exit NoICE.


LEADINGDIGIT

This command determines the format for the entry of hexadecimal numbers. This feature is usually controlled via the Leading Digit Required item on the Options Menu. The command

    LEADINGDIGIT 1

will require that the first digit of any hexadecimal value be a digit in the range 0 through 9. This is useful to prevent ambiguity between values such as "ABH", which could be interpreted either as a hex value or as a symbol name.

    LEADINGDIGIT 0

will allow numbers beginning with "A" through "F" to be entered without a leading digit. Entry of hexadecimal numbers in this fashion is convenient, but may cause ambiguity with respect to symbol and register names.

The preference is saved when NoICE exits.


MODE: Set source mode

This command controls the format of the source window.

    MODE 0

sets the mode to "disassembly". The display will show disassembled processor instructions.

    MODE 1

sets the mode to "mixed source and disassembly". The display will show source file lines which produce code, interleaved with the disassembled processor instructions which correspond to the source lines.

    MODE 2

sets the mode to "source". The display will show source code, if it is available. Otherwise, disassembled processor instructions will be shown.

When NoICE starts, the mode is set to zero. When a LINE command is executed, the mode is set to two.


SOURCE: Display source at address

This command allows the user to display a program in target memory as source code, as disassembled processor instructions, or as a mixture of the two. The format of the display is determined by the MODE command and by the availability of source code and line number information.

To begin display at "addr" (where "addr" is an address expression), enter

    SOURCE addr

To continue display at the instruction after the last one shown in the source window, enter

    SOURCE

Note that if the display mode is 1 or 2, then the cursor keys may also be used to move around in the current source file.

"S" is an abbreviation of "SOURCE".


DEFTYPE: Define data type

This command is used to define an alias for an existing data type (corresponding to a C typedef), or to declare a member of a structure or union.

    DEFTYPE offset name %type

Defines a data type or structure member called "name", at "offset" bytes from the base address, and of data type "type".

"Offset" will be zero if the DEFTYPE is being used for a typedef or a union. If the DEFTYPE is defining a member of a structure, then "offset" defines the offset of the member from the beginning of the structure.

"Type" is the name of an existing data type. It specifies the underlying data type of the newly named type. The underlying type may be

To define the standard C data type "int" as a 16 bit integer, use the command

    DEFTYPE 0 int %S16

(This definition is not built in, since "int" may be 8 or 32 bits on some processors.)

A bit field may be defined, specifying both the width in bits and the position of the least significant bit.

    DEFTYPE 6 i %S16:3@2

defines a bitfield "i" as an integer, 3 bits wide, with its least significant bit in bit2 of the 16 bit word stored at offset 6. (Note that if the processor stores word data most significant byte first, the bitfield will actually be in the byte at offset 7.)

Refer to subsequent sections for examples of the use of DEFTYPE in structures and unions. Utilities are provided for automated symbol and type definition with various assemblers and compilers.

Data Type Specifiers

The built-in data types are:

%X08 unsigned hex byte or bytes (default if omitted, unless "addr" has a data type)
%X16 unsigned hex word (16 bits) or words
%X24 unsigned hex "semi-long" (24 bits) or words
%X32 unsigned hex long word (32 bits) or words
%X64 unsigned hex long-long word (64 bits) or words
%B08 binary byte or bytes
%S08 signed byte or bytes in current radix
%S16 signed word (16 bits) or words in current radix
%S24 signed "semi-long" word (24 bits) or words in current radix
%S32 signed long word (32 bits) or words in current radix
%S64 signed long-long word (64 bits) or words in current radix
%U08 unsigned byte or bytes in current radix
%U16 unsigned word (16 bits) or words in current radix
%U24 unsigned "semi-long" word (24 bits) or words in current radix
%U32 unsigned long word (32 bits) or words in current radix
%U64 unsigned long-long word (64 bits) or words in current radix
%ASCII ASCII (actually ISO-8859-1) character or characters
%float IEEE-754 floating point number (32 bits)
%double IEEE-754 double-precision floating point number (64 bits)

In addition to the built-in types and types defined with DEFTYPE, STRUCT, and ENUM, you may apply modifiers to types. For example:

%S16[128] an array of 128 16-bit integers
%Foobars[10][5] a two-dimensional array of a user STRUCT called "Foobar"
%*X32 a pointer to a 32-bit integer, shown in hex
%<*U16 a short pointer to an unsigned 16-bit integer
%*U08[10] an array of 10 pointers to unsigned bytes

ENUM: Define enumerated data type

    ENUM offset {name} {%type}

Begins definition of an enumeration, optionally called "name", stored as underlying data type "type". If "type" is not specified, the enumeration will be stored as a 16 bit signed integer (S16).

"Offset" will be zero if the ENUM is being defined standalone. If the ENUM is defining a member of a structure, then "offset" defines the offset of the member from the beginning of the structure.

Refer to ENDENUM for examples of the use of ENUM. Utilities are provided for automated symbol and type definition with various assemblers and compilers.


ENUMVAL: Define value of enumerated data type

    ENUMVAL value name

Defines a numeric "value" of the last opened enumeration, and associates the string "name" with the value.

Refer to ENDENUMfor examples of the use of ENUM. Utilities are provided for automated symbol and type definition with various assemblers and compilers.


ENDENUM: End definition of enumerated data type

    ENDENUM {name}

Completes the definition of the last opened enumeration, and optionally calls it "name".

A name for the enumeration should be defined by either the ENUM command, the ENDENUM, command or by both.

Example: the C enumeration defined by

    enum color { blue, red, green=6 };
    enum color q;

may be defined in NoICE by the commands:

    ENUM 0 color %U08
    ENUMVAL 0 blue
    ENUMVAL 1 red
    ENUMVAL 6 green
    ENDENUM

    DEFINE q 1000 %color

Here we have defined an enumerated color set stored as an unsigned byte, and defined a variable of the enumerated type. If the memory byte at location 1000 contains the value 1, then WATCH q or EDIT q will show the value as "red". If the command was EDIT, then a new value may be entered as a string such as "green".

If the value of an enumerated variable does not have a defined string, then the numeric value will be displayed instead. If the string entered for an enumerated value does not match any defined value string, then the string will be interpreted as a numeric expression.

Utilities are provided for automated symbol and type definition with various assemblers and compilers.


STRUCT: Define structure or union data type

This command is used to define a structure or union.

    STRUCT offset {name}

Begins definition of a structure, optionally called "name", at "offset" bytes from the base location.

"Offset" will be zero if the STRUCT is being used to define a stand-alone structure or union. If the STRUCT is defining a structure or union which is defined inline as a member of another structure or union, then "offset" defines the offset of the member from the beginning of the outer structure.

Refer to ENDSTRUCT for examples of the use of STRUCT. Utilities are provided for automated symbol and type definition with various assemblers and compilers.


ENDSTRUCT: End definition of structure or union data type

    ENDSTRUCT size {name}

Completes the definition of the last opened structure or union, specifies its size in bytes, and optionally calls it "name".

A name for the structure or union should be defined by either the STRUCT command, the ENDSTRUCT, command or by both.

Example: the C statements

    typedef struct Bag {
       int a;
       char b[4]
       struct {
          uint b;
          uint c;
       } inner;
       long int *d;
       int bi:3;
       int bj:4;
    } Bag2;

    struct Bag q;
    Bag2 q2;

may be defined in NoICE by the commands:

    STRUCT 0. Bag
    DEFTYPE 0. a %int
    DEFTYPE 2. b %char[4]
    STRUCT 6.
    DEFTYPE 0. b %uint
    DEFTYPE 2. c %uint
    ENDSTRUCT 4. inner
    DEFTYPE 10. d %*long
    DEFTYPE 12. bi %int:3@0
    DEFTYPE 12. bj %int:4@3
    ENDSTRUCT 13. Bag2

    DEFINE q 1000 %Bag
    DEFINE q2 1010 %Bag2

Here we have defined a structure called "Bag" which contains the definition of another structure called "inner". We define "Bag2" as an alias for Bag, the result of the typdef in the C code. We define a variable of type Bag, and one of type Bag2. We have assumed that appropriate DEFTYPE definitions for "int", "char", "uint", and "long" have already been made.

Utilities are provided for automated symbol and type definition with various assemblers and compilers.

"ENDS" is an abbreviation of "ENDSTRUCT".


INTSIZE, SHORTSIZE, LONGSIZE: Set sizes of integers

These commands are intended primarily to control the interpretation of IEEE-695 files. However, the values set by these commands will also affect any use of the data types %int, %short, or %long.

    INTSIZE n

Sets the size of the C data type "int" to "n" bytes, where "n" may be 1, 2, or 4. The default value is two bytes.

    SHORTSIZE n

Sets the size of the C data type "short" to "n" bytes, where "n" may be 1, 2, or 4. The default value is two bytes.

    LONGSIZE n

Sets the size of the C data type "long" to "n" bytes, where "n" may be 1, 2, or 4. The default value is four bytes.


POINTERSIZE, SMALLPOINTERSIZE, LARGEPOINTERSIZE: Set sizes of pointers

These commands are intended primarily to control the interpretation of IEEE-695 files. However, the values set by these commands will also affect any pointer defined using size overrides. Size overrides may be generated by utilities such as OMF51NOI and 2500NOI, or by manual command.

    SMALLPOINTERSIZE n

Sets the size of a "small pointer" to "n" bytes, where "n" may be 1, 2, 3, or 4. The default value is one byte for the 8051 and 6502, whose architecture make one-byte pointers meaningful, and two bytes for the other processors. In addition to IEEE-695 small pointers, this definition will be used for a pointer defined with a "small" size override (<). For example,

    DEF pInt 0 %<*S16

defines the variable "pInt" at location zero to be a small pointer to S16.

    LARGEPOINTERSIZE n

Sets the size of a "large pointer" to "n" bytes, where "n" may be 1, 2, 3, or 4. The default value is two bytes. In addition to IEEE-695 large pointers, this definition will be used for a pointer defined with a "large" size override (>). For example,

    DEF pInt 0 %>*S16

defines the variable "pInt" at location zero to be a large pointer to S16.

Many 8051 compilers allow you to define 3-byte "generic pointers" that can point to any address space. Usually, the third byte indicates the address space. NoICE's 8051-specific symbol-processing utilitiesuse the above syntax for generic pointers.

    POINTERSIZE n

Sets the size of a default pointer to "n" bytes, where "n" may be 1, 2, 3, or 4. The default value is two bytes. This should seldom, if ever, need to be changed. This command is provided to deal with special needs of compilers for the 8051 and similar processors with multiple memory models.

Up to ten levels of pointer indirection may be defined, and size overrides may be used at any level. For example,

 DEF pppMess 0 %<**>*S16

defines the variable "pppMess" at location zero to be a small pointer to a default (address sized) pointer to a large pointer to S16.


FRAMEPOINTER: Define frame pointer register

This command is intended primarily to control the interpretation of IEEE-695 files. It defines the processor register to be used as the base register for automatic variables allocated on the stack.

    FRAMEPOINTER X

sets the frame pointer to register "X". The default value is "SP" for most processors. The framepointer must be set to match your compiler before an IEEE-695 file is loaded. The most common place to do this is in NOICE.NOI.

Before loading an Introl IEEE-695 file for the 68HC11, you must set

    FRAMEPOINTER SP+1

because Introl generates offsets relative to the value in X after a TSX instruction, which increments the SP value.

Before loading an IAR IEEE-695 file for the Z80, you must set

    FRAMEPOINTER IX

For other processors or compilers, consult your compiler documentation, or examine the generated code to see which register is being used as a frame pointer. (Compilers for processors like the 8051 typically do not use a framepointer. For these compilers, you may ignore this command.)


LASTFILELOADED {filename}

When a program is changed and rebuilt, code and data addresses often move so that breakpoints, watches, etc. are no longer valid.

The LASTFILELOADED command works with the Debug Context, to preserve breakpoints and watchpoints where possible, but to avoid retaining them if code has changed.

LASTFILELOADED is usually specified as the first command within a .NOI file. In this case, the filename may be omitted and the name and modification time of the .NOI file are used.


NoICE (tm) Debugger, Copyright © 2019 by John Hartman

Using NoICE - Contact us - NoICE Home