Symbol Table Format for Sdb
A symbolic debugger, sdb,
has been implemented for the UNIX/32V operating system.
This document describes modifications made to
the C compiler to generate additional
information about the compiled program and to the
assembler and loader to process the information.
It also describes information recognized by the assembler, the loader
and sdb which are intended for use by compilers for other languages
The C compiler was modified to generate additional symbol table
information describing a compiled program.
Two new types of symbol table entries are made.
One describes the variables, giving
their class (local, register, parameter, global, etc.),
their declared type in the program
and their address or offset.
An additional entry is made for structures giving their size.
The other type of entry provides a mapping between the source program
There is an entry for each source line, procedure and source file
giving their addresses in the object file.
All line numbers are relative to the beginning of
All entries are generated with the new assembler pseudo-operation
It always takes 12 arguments of which the first eight usually
represent the name of the symbol as declared in the C program.
prepended to the name as in some other symbol table entries.
\&.stab 'e,'r,'r,'f,'l,'g,0,0,046,0,05,_errflg
For expository convenience,
names in .stab entries will be listed as one word instead of
eight separate characters.
External symbols defined with .comm
The following entry is made for each external symbol which is
defined with a .comm pseudo-op.
\&.stab name,040,0,type,0
The type is a 16-bit value describing the variable's declared type.
This field is described in section 2.13.
The debugger determines the variable's address
from the entry made with the .comm.
It assumes that the name for this entry is _name.
Symbols defined within .data areas
The following entry is made for each symbol which is defined
as a label in a data area.
\&.stab name,046,0,type,address
The type is the variable's declared type.
The address is given symbolically as the label.
Symbols defined with .lcomm
The following entry is made for each symbol which is defined with
\&.stab name,048,0,type,address
The type is the variable's declared type.
The address is given symbolically as the label.
The specification of an octal constant with an 8 occurs for historical
The following entry is made for each variable whose value
\&.stab name,0100,0,type,register
The type is the variable's declared type.
The register is the register number assigned to the variable.
Local non-register symbols
The following entry is made for each local, non-register variable.
\&.stab name,0200,0,type,offset
The type is the variable's declared type.
The offset is a positive number indicating its offset in bytes for the
The following entry is made for each procedure parameter.
\&.stab name,0240,0,type,offset
The type is the variable's declared type.
The offset is a positive number indicating its offset in bytes from
The following entry is made for each structure element.
\&.stab name,0140,0,type,offset
The type is the element's declared type.
The offset is its offset within the structure in bytes.
An additional entry is made for structures giving their size in bytes.
It immediately follows their defining .stab entry.
\&.stab name,0376,0,0,length
The following sequence of entries is used to describe elements of
Fortran equivalence and common blocks.
The entries for each element of the block should then appear
as if they were structure elements.
Finally, one of the following
two entries is used depending on the type of common
If the block is defined as a .globl symbol, use the entry
where name is the name of the block defined in the .globl statement.
It the block is defined in some other way, use
\&.stab 0,0348,0,0,address
Since C is a block-structured language,
it is necessary to know the extent of each block containing symbol definitions.
An entry is made for each right and left bracket which encloses
a block with definitions.
The following entries are for left and right brackets respectively.
\&.stab 0,0300,0,nesting level,address
\&.stab 0,0340,0,nesting level,address
The nesting level is the static nesting level of the block.
It is currently ignored by the debugger.
The address is the address of the first byte of code for the block
for the left brackets and the first byte following the block
The following entry is made for each procedure.
\&.stab name,044,0,linenumber,address
The linenumber is the number of the first line of the procedure in the
The address is the address of the first byte of the procedure.
The following entry is made for each line in the source program.
\&.stab 0,0104,0,linenumber,address
The linenumber is its number.
The address is the address of the first byte of code for the line.
For each block of the program,
the linenumber entries for that block should follow the entries
for the variables of that block.
The following entries are made for each source file.
\&.stab name1,0144,0,0,address
\&.stab name2,0144,0,0,address
\&.stab namen,0144,0,0,address
Each entry contains 8 successive bytes of the name of the source file.
The name is terminated by a null byte.
All bytes following this one should also be null.
The address is the address of the first byte of code for the first
The following entry is made for each included source file which
\&.stab name1,0204,0,0,address
\&.stab name2,0204,0,0,address
\&.stab namen,0204,0,0,address
This entry should appear each time the file is included.
A similar entry giving the name of the original file should be
made at the end of the include.
The format of the name is identical to that for files.
This feature is heavily used by programs generated by yacc and lex.
This 16 bit quantity type describes the declared type of a variable.
We use the same scheme as in S.C. Johnson's Portable C Compiler
The type is divided into the following fields:
There are four derived types:
They are indicated in the two bit fields d1, d2, d3, d4, d5 and d6.
The four bit field basic indicates the basic type as follows:
11 member of enumerated type
Each .stab pseudo-operation generates one entry in the symbol table.
The entry is of the form:
The loader uses the four least significant bits of the type field
to determine how to relocate the .stab entry.
The following are currently used.
It is necessary for the assembler and loader to preserve the order
of symbol table entries produced by .stab pseudo-ops.
Johnson, S.C., "A Portable Compiler: Theory and Practice",
Proc. 5th ACM Symp. on Principles of Programming Languages,
The following definitions are extracted from the file /usr/include/a.out.h.
struct nlist { /* symbol table entry */
char n_name[8]; /* symbol name */
char n_type; /* type flag */
unsigned n_value; /* value */
/* values for type flag */
#define N_UNDF 0 /* undefined */
#define N_ABS 02 /* absolute */
#define N_TEXT 04 /* text */
#define N_DATA 06 /* data */
#define N_FN 037 /* file name symbol */
#define N_GSYM 0040 /* global sym: name,,type,0 */
#define N_FUN 0044 /* function: name,,linenumber,address */
#define N_STSYM 0046 /* static symbol: name,,type,address */
#define N_LCSYM 0048 /* .lcomm symbol: name,,type,address */
#define N_RSYM 0100 /* register sym: name,,register,offset */
#define N_SLINE 0104 /* src line: ,,linenumber,address */
#define N_SSYM 0140 /* structure elt: name,,type,struct_offset */
#define N_SO 0144 /* source file name: name,,,address */
#define N_LSYM 0200 /* local sym: name,,type,offset */
#define N_SOL 0204 /* #line source filename: name,,,address */
#define N_PSYM 0240 /* parameter: name,,type,offset */
#define N_LBRAC 0300 /* left bracket: ,,nesting level,address */
#define N_RBRAC 0340 /* right bracket: ,,nesting level,address */
#define N_BCOMM 0342 /* begin common: name,,, */
#define N_ECOMM 0344 /* end common: name,,, */
#define N_ECOML 0348 /* end common (local name): ,,,address */
#define N_LENG 0376 /* second stab entry with length information */
#define N_EXT 01 /* external bit, or'ed in */