Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ cdb(1) — HP-UX 5.20

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

cc(1)

echo(1)

fc(1)

pc(1)

ld(1)

more(1)

creat(2)

exec(2)

fork(2)

open(2)

setjmp(3C)

printf(3S)

system(3S)

a.out(4)

adb(1)

ptrace(2)

core(4)

CDB(1)  —  HP-UX

Series 200, 300, 500 Only

NAME

cdb, fdb, pdb − C, FORTRAN, Pascal symbolic debugger

SYNOPSIS

cdb [−d dir] [−r file] [−p file] [−S num] [objectfile [corefile]]

fdb [ cdb options ]

pdb [ cdb options ]

TABLE OF CONTENTS

 DESCRIPTION
CONVENTIONS
Notational Conventions
Variable Name Conventions
Expression Conventions
Procedure Call Conventions
COMMANDS
File Viewing Commands
Display Formats
Data Viewing Commands
Stack Viewing Commands
Job Control Commands
Breakpoint Commands
Assertion Control Commands
Signal Control Commands
Record and Playback Commands
Miscellaneous Commands
HARDWARE DEPENDENCIES
FILES
SEE ALSO
DIAGNOSTICS
WARNINGS
BUGS

DESCRIPTION

Cdb, fdb, and pdb are alternate names for a source level debugger for C, HP FORTRAN, and HP Pascal programs.  It provides a controlled environment for their execution. 

Objectfile is an executable program file having one or more of its component modules compiled with the −g option.  The main procedure (main program) must have been compiled with −g.  The support module /usr/lib/end.o must be included as the last object file in the list of those linked, except for libraries included with the −l option to ld(1). (done automatically with -g option to cc(1), fc(1), and pc(1)). The default for objectfile is a.out. 

Corefile is a core image from a failed execution of objectfile.  The default corefile is core. 

The options are:

−d dir names an alternate directory where source files are located.  (The current directory is searched last.) 

−r file names a record file which is invoked immediately (for overwrite, not for append).  Used with Record and Playback Commands. 

−p file names a playback file which is invoked immediately.  Used with Record and Playback Commands. 

−S num sets the size of the string cache to num bytes (default is 1024).  The string cache holds data read from objectfile. 

Only one objectfile and one corefile are allowed per debugging session.  The program (objectfile) is not invoked as a child process until an appropriate Job Control Command command is given.  The same program can be restarted many times (as different child processes) during a single debugging session. 

CONVENTIONS

The debugger remembers the current file, current procedure, current line, and current data location.  They are a function of what you have been viewing (not necessarily executing) most recently.  Many commands use these current locations as defaults, and many commands set them as a side effect.  It is important to keep this in mind when deciding what a command does in any particular situation. 

For example, if you stop in procedure "abc", then view procedure "def", then ask for the value of local variable "xyz", the debugger assumes that the variable belongs to procedure "def". 

Notational Conventions

Most commands are of the form "[modifier] command-letter [options]". Numeric modifiers before and after commands can be any numeric expression. They need not be just simple numbers. A blank is required before any numeric option.  Multiple commands on one line must be separated by ";". 

These are common modifiers and other special notations:

(A | B | C) Any one of A or B or C is required. 

[A | B | C] Any one of A or B or C is optional. 

file A file name. 

proc A procedure (or function, or subroutine) name. 

var A variable name. 

number A specific, constant number (e.g. "9", not "4+5").  Floating point (real) numbers may be used any place a constant is allowed. 

expr Any expression, but with limitations stated below. 

depth A stack depth, as printed by the "t" command.  The top procedure is at a depth of zero.  A negative depth acts like a depth of zero.  Stack depth usually means "exactly at the specified depth", not "the first instance at or above the specified depth". 

format A style for printing data.  Used with Data Viewing Commands. 

commands A series of debugger commands, separated by ";", entered on the command line or saved with a breakpoint or assertion.  Semicolons are ignored (as commands) so they can be freely used as command separators.  Commands may be grouped with "{}" for the "a", "b", "if", and "!" commands.  In all other cases commands inside "{}" are ignored. 

Variable Name Conventions

Variables are referenced exactly as they are named in your source file(s).  Case sensitivity is controlled by the "Z" command.  Be careful with one letter variable names, since they can be confused with commands.  If an expression begins with a variable that might be mistaken for a command, just enclose the expression in "()" (e.g. "(k)"), or eliminate any white space between the variable and the first operator (use "k= 9" instead of "k = 9"). 

If you are interested in the value of some variable var, there are a number of ways of getting it, depending on where and what it is:

var Search the stack for the most recent instance of the current procedure.  If found, see if var is a parameter or local variable of that procedure.  If not, search for a global variable named either var or _var, in that order. 

proc.var Search the stack for the most recent instance of proc.  If found, see if it has a parameter or local variable named var, as before. 

proc.depth.var Use the instance of proc that is at depth depth (exactly), instead of the most recent instance.  This is very useful for debugging recursive procedures where there are multiple instances on the stack. 

:var Search for a global (not local) variable named either var or _var, in that order. 

. Dot is shorthand for the last thing you viewed.  It has the same size it did when you last viewed it.  For example, if you look at a long as a char, then "." is considered to be one byte long.  This is useful for treating things in unconventional ways, like changing the second highest byte of a long without changing the rest of the long.  Dot may be treated like any other variable. 

NOTE:  "." is the name of this magic location.  If you use it, it is dereferenced like any other name.  If you want the address of something that is, say, 30 bytes farther on in memory, do not say ".+30".  That would take the contents of dot and add 30 to it.  Instead, say "&.+30", which adds 30 to the address of dot. 

Special variables are names for things that are not normally directly accessible.  Special variables include:

$var The debugger has room in its own address space for a number of user-created special variables.  There are 26 of them by default (this number is adjustable using the −s invocation option).  They are all of type long, and do not take on the type of any expression they are assigned.  Names are defined when they are first seen.  For example, saying "$xyz = 3∗4" creates special symbol "$xyz", and assigns to it the value 12.  Special variables may be used just like any other variables. 

$pc, $fp, $sp, $r0, etc. 
These are the names of the program counter, the frame pointer, the stack pointer, the registers, etc. To find out which names are available on your system, use the "l r" (list registers) command.  All registers act as type integer. 

$result
This is used to reference the return value from the last command-line procedure call. Where possible, it takes on the type of the procedure. $short and $long are available as alternate ways of looking at $result. 

$signal
This lets you see and modify the current child process signal number.

$lang
This lets you see and modify the current language (0 for C, 1 for FORTRAN, or 2 for Pascal). 

$line This lets you see and modify the current source line number, which is also settable with a number of different commands. 

$malloc
This lets you see the current amount of memory (bytes) allocated at run-time for use by the debugger itself.

$cBad
This lets you see and modify the number of machine instructions the debugger will step while in a non-debuggable procedure before setting an up-level breakpoint and free-running to it. Setting it to a small value can improve debugger performance, at the risk of taking off free-running after missing the up-level break for some reason.

$pagelines
This lets you set the number of lines per "page" of debugger output. The prompt "Hit RETURN for more..." occurs between pages.  Values of zero or less turn off paging.

To see all the special variables, including the predefined ones, use the "l s" (list specials) command. 

You can also look up code addresses with

proc#line

which searches for the given procedure name and line number (which must be an executable line within proc) and uses the code address of that line. Just referring to a procedure proc by name uses the code address of the entry point to that procedure. 

Expression Conventions

Every expression has a value, even simple assignment statements, as in C.  "Naked" expression values (those which aren’t command modifiers) are always printed unless the next token is ";" (command separator) or "}" (command block terminator).  Thus breakpoint and assertion commands are normally silent.  To force an expression result to be printed, follow the expression with "/n" (print in normal format). 

Integer constants may begin with "0" for octal or "0x" or "0X" for hexadecimal (the forms are equivalent).  They are int (which may be the same as long) if they fit in two bytes, long otherwise.  If followed immediately by "l" or "L", they are forced to be of type long (this is useful on systems where int is two bytes). 

Floating point constants must be of the form digits.digits[e|E|d|D[+|-]digits], for example, "1.0", "3.14e8", or "26.62D-31". One or more leading digits is required to avoid confusion with "." (dot). A decimal point and one or more following digits is required to avoid confusion for some command formats. If the exponent doesn’t exactly fit the pattern shown, it is not taken as part of the number, but as separate token(s). The "d" and "D" exponent forms are allowed for compatibility with FORTRAN.  However, all floating point constants are taken as doubles, regardless. 

Character constants must be entered in ” and are treated as integers.  String constants must be entered in "" and are treated like "char *" (i.e. pointer to char).  Character and string constants may contain the standard backslashed escapes understood by the C compiler and the echo(1) command, including "\b", "\f", "\n", "\r", "\t", "\\", "\′", and "\nnn". However, "\<newline>" is not supported, neither in quotes nor at the end of a command line. 

Expressions are composed of any combination of variables, constants, and C operators.  If the debugger is invoked as cdb, the C operator "sizeof" is also available.  If the debugger is invoked as fdb, FORTRAN operators are also available and FORTRAN meanings take precedence where there is a conflict.  The same is true for Pascal if the debugger is invoked as pdb. 

If there is no active child process and no corefile, you can only evaluate expressions containing constants. 

Expressions approximately follow the C rules of promotion, e.g. char, short, and int become long, and float becomes double.  If either operand is a double, floating math is used.  If either operand is unsigned, unsigned math is used.  Otherwise, normal (integer) math is used.  Results are then cast to proper destination types for assignments. 

If a floating point number is used with an operator that doesn’t normally permit it, the number is cast to long and used that way.  For example, the C binary operator "~" (bit invert) applied to the constant "3.14159" is the same as "~3". 

Note that "=" means "assign" except for Pascal; use "==" or ".EQ." for FORTRAN.  In Pascal, "=" is a comparison operator; use ":=" for assignments.  For example, if you invoke the debugger as cdb, then set "$lang = 2" (Pascal), you must say "$lang := 0" to return to C. 

Use "//" for division, instead of "/", to distinguish from display formatting (see Data Viewing Commands). 

The special unary operator "$in" (not to be confused with debugger local variables) evaluates to 1 (true) if the operand is an address inside a debuggable procedure and $pc (the current child process program location) is also in that procedure, else it is 0 (false).  For example, "$in main" is true if the child process is stopped in main(). 

If the first expression on a line begins with "+" or "−", use "()" around it to distinguish from the "+" and "−" commands (see Data Viewing Commands).  Parentheses may also be needed to distinguish an expression from a command it modifies. 

You can attempt to dereference any constant, variable, or expression result using the C "∗" operator.  If the address is invalid, an error is given. 

Whenever an array variable is referenced without giving all its subscripts, the result is the address of the lowest element referenced.  For example, consider an array declared as "x[5][6][7]" in C, "x(5,6,7)" in FORTRAN, or "x[1..5,2..6,3..7]" in Pascal.  Referencing it simply as "x" is the same as just "x" in C, the address of "x(1,1,1)" in FORTRAN, or the address of "x[1,2,3]" in Pascal.  Referencing it as "x[4]" is the same as "& (x[4][0][0])" in C, the address of "x(1,1,4)" in FORTRAN, or the address of "x[4,2,3]" in Pascal. 

If a not-fully-qualified array reference appears on the left side of an assignment, the value of the right-hand expression is stored into the element at the address specified. 

Array indices are not checked against declared bounds. 

String constants are stored in a magic buffer in the file /usr/lib/end.o, which you link with your program.  The debugger starts storing strings at the beginning of this buffer, and moves along as more assignments are made.  If the debugger reaches the end of the buffer, it goes back and reuses it from the beginning.  In general this doesn’t cause any problems.  However, if you use very long strings, or if you assign a string constant to a global pointer, problems could arise.  To fix them, you can edit and compile a personal copy of /usr/lib/end.c to increase the size of the buffer.  (Some systems don’t support this; see the Hardware Dependencies section below.) 

Procedure Call Conventions

Procedures may be invoked from the command line, even within expressions.  For example:

xyz = $abc ∗ (3 + def (ghi − 1, jkl, "Hi Mom"))

calls procedure "def" when its value is needed in the expression. 

Any breakpoints encountered during command line procedure invocation are handled as usual.  However, the debugger has only one active command line at a time.  If it stops in a called procedure for any reason, the remainder (if any) of the old command line is tossed, with notice given. 

If you attempt to call a procedure when there is no active child process, one is started for you as if you gave a single-step command first.  Unfortunately, this means that the data in corefile (if any) may disappear or be reinitialized. 

If you send signal SIGINT (e.g., hit the BREAK key) while in a called procedure, the debugger aborts the procedure call and returns to the previous stopping point (the start of the main program for a new process). 

You can call any procedure that is in your objectfile, even if it is not debuggable (was not compiled with debug on).  For example, assume that you reference "printf()" in your program, so the code for it is in your objectfile.  Then you can enter on the command line:

printf ("This works! %d %c\n", 9, ′?′);

If you wonder what procedures are available, do a list labels command ("l l").  If you want to have some library routines available for debugging, but they aren’t referenced anywhere in your code (so they aren’t linked), you can modify a personal copy of /usr/lib/end.c to reference them.  (Some systems don’t support this; see the Hardware Dependencies section below.)  It is not necessary to have correct calls.  For example, just "printf()" works fine, since you never execute the statements in end.c. 

Note that procedure name "_end_" is declared in end.c. 

COMMANDS

The debugger has various commands for viewing and manipulating the program being debugged. 

File Viewing Commands

These commands may change the current viewing position, but they do not affect the next statement to be executed in the child process, if any. 

dir "directory"
Add directory to the list of alternate source directories.  Same as using -d invocation option.  Main procedure file must reside in the current directory or be specified with the -d option. 

e Show the current file, procedure, line number, and source line. 

e (file | proc)
Enter (view) file or proc and print its first executable line.  File can be any file, but must not be object code. 

[depth] E
Like "e", but sets viewing location to the current location in proc on the stack at depth depth (not necessarily the first executable line in the procedure).  Default Depth is zero (where program is currently stopped). 

L This is a synonym for 0E. 

line Print source line number line in the current file. 

[line] p [count]
Print one (or count) lines starting at current line (or line number line). If multiple lines are printed, current line is marked with "=" in leftmost column.

+[lines]
Move to lines (default one) lines after current line. 

−[lines]
Move to lines (default one) lines before current line. 

[line] w [size]
Print window of text containing size (default 11) lines centered around current line (or line). Target line is marked with "=" in leftmost column if multiple lines printed.

[line] W [size]
Same as "w", but size defaults to 21 lines. 

+w [size]

+W [size]
Print window of text of given or default size, beginning at end of previous window if the previous command was a window command; otherwise at current line. 

−w [size]

−W [size]
Print window of text of given or default size, ending at beginning of previous window if previous command was a window command; otherwise at current line. 

/[string]
Search forward through the current file for string, starting at the line after the current line. 

?[string]
Search backward for string, starting with the line before the current line. 

Searches wrap around the end or beginning of the file, respectively.  If string is not specified, the previous one is used.  Wild cards and regular expressions are not supported; string must be literal. 

n Repeat previous "/" or "?" command using same string as before. 

N The same as "n", but search goes in opposite direction from that specified by previous "/" or "?" command. 

Display Formats

A format is of the form "[∗][count]formchar[size]".  Display formats apply only to Data Viewing Commands, described in the next sub−section.

"∗" means "use alternate address map" (if maps are supported). 

Count is the number of times to apply the format style formchar (must be a number). 

Size is the number of bytes to be formatted for each count (overrides the default size for the format style); must be positive decimal number (except short hand notations).  Size is disallowed with formchars where it makes no sense.

For example, "abc/4x2" prints, starting at the location of "abc", four two-byte numbers in hexadecimal. 

The formats which print numbers allow an upper-case character to be used instead, for the same results as appending "l" (see below).  For example, "O" prints in long octal.  These formats, which are useful on systems where integer is shorter than long, are noted below.  The following formats are available:

n Print in the "normal" format, based on the type.  Arrays of char and pointers to char are interpreted as strings, and structures are fully dumped. 

(d | D) Print in decimal (as integer or long). 

(u | U) Print in unsigned decimal (as integer or long). 

(o | O) Print in octal (as integer or long). 

(x | X) Print in hexadecimal (as integer or long). 

(b | B) Print a byte in decimal (either way). 

(c | C) Print a character (either way). 

(e | E) Print in "e" floating point notation (as float or double) (see printf(3S)). Remember that floating point constants are always doubles!

(f | F) Print in "f" floating point notation (as float or double). 

(g | G) Print in "g" floating point notation (as float or double). 

a Print a string using expr as the address of the first byte. 

s Print a string using expr as the address of a pointer to the first byte (same as "∗expr/a", except for arrays). 

t Show the type of expr (usually a variable or procedure name).  For true procedure types you must actually call the procedure, e.g. "def(arg)/t". 

p Print the name of the procedure containing address expr. 

S Do a formatted dump of a structure.  expr must be the address of a structure, not the address of a pointer to a structure. 

There are some short hand notations for size:

b 1 byte (char). 

s 2 bytes (short). 

l 4 bytes (long). 

These can be appended to formchar instead of a numeric size.  For example, "abc/xb" prints one byte in hexadecimal. 

If you view an object with a size (explicitly or implicitly) less than or equal to the size of a long, the debugger changes the basetype to something appropriate for that size.  This is so "." (dot) works correctly for assignments. For example, "abc/c2" sets the type of "." to short.  One side effect is that if you look at a double using a float format, dot loses accuracy or has the wrong value. 

Data Viewing Commands

expr If expr does not resemble anything else (such as a command), it is handled as "expr/n" (print expression in normal format), unless followed by ";" or "}", in which case nothing is printed. 

expr/format
Print the contents (value) of expr using format. 

expr?format
Print the address of expr using format. 

^[[/]format]
Back up to the preceding memory location (based on the size of the last thing displayed). Use format if supplied, or the previous format if not.  No "/" is needed after the "^".  To reverse direction again (e.g. start going forward), enter "." (dot) (always an alias for the current location) followed by carriage return.

l [proc[.depth]]
List all parameters and local variables for current procedure (or proc, if given, at the specified depth, if any).  Data display uses "/n" format, except arrays and pointers are shown as addresses; only the first word of a structure is shown. 

l (a | b | d | z)
List all assertions, breakpoints, directories (where to search for files), or zignals (signal actions). 

l (f | g | l | p | r | s) [string]
List all files (source files which built objectfile), global variables, labels (program entry points known to the linker), procedure names, registers, or special variables (except registers).  If string is present, only those things with the same initial characters are listed. 

Stack Viewing Commands

[depth] t Trace the stack for the first depth (default 20) levels. 

[depth] T The same as "t", but local variables are also displayed using "/n" format (except that arrays and pointers are shown as addresses; structures show first word only). 

Job Control Commands

The parent (debugger) and child (objectfile) processes take turns running. The debugger is only active while the child process is stopped due to a signal (includes hitting a breakpoint) or terminated for whatever reason.

r [arguments]
Run a new child process with given argument list, if any (an existing child process is terminated first). If no arguments are given, those used with the last "r" command are used again (none if "R" was used last). 

Arguments may contain "<" and ">" for redirecting standard input and standard output.  ("<" does an open(2) of file descriptor 0 for read-only; ">" does a creat(2) of file descriptor 1 with mode 0666; ">>" is not supported.)  Arguments may contain shell variables, quote marks, or other special syntax (expanded by Bourne shell).  "{}" are shell metacharacters, so "r" cannot be safely saved in a breakpoint or assertion command list. 

R Run a new child process with no argument list. 

k Terminate (kill) the current child process, if any. 

[count] c [line]
Continue after a breakpoint or a signal, ignoring the signal, if any. If count is given, the current breakpoint, if any, has its count set to that value.  If line is given, a temporary breakpoint is set at that line number, with a count of −1 (see Breakpoint Commands). 

[count] C [line]
Continue like "c", but allow the signal (if any) to be received. 

[count] s
Single step 1 (or count) statements (successive carriage-returns repeat with a count of 1).  If count is less than one, the child process is not stepped.  The child process continues with the current signal, if any (set "$signal = 0" to prevent). 

[count] S
Single step like "s", but treat procedure calls as single statements (don’t follow them down).  If a breakpoint is hit in such a procedure, or in one that it calls, its commands are executed.  (This is usually all right unless there is a "c" command in that breakpoint’s command list.) 

The debugger has no knowledge about or control over child processes forked in turn by the process being debugged.  Programs being debugged should not execute a different program via exec(2).

Child process output may be buffered, so it may not appear immediately after you step through an output statement such as printf(3S). It may not appear at all if you kill the process.

Breakpoint Commands

A breakpoint has three attributes associated with it:

address All the commands which set a breakpoint are simply alternate ways to specify the breakpoint address.  The breakpoint is encountered whenever address is about to be executed, regardless of the path taken to get there.  Only one breakpoint at a time (of any type or count) may be set at a given address.  Setting a new breakpoint at address replaces the old one, if any. 

count The number of times the breakpoint is encountered prior to recognition.  If count is positive, the breakpoint is "permanent", and count decrements with each encounter.  Each time count goes to zero, the breakpoint is recognized and count is reset to one (so it stays there until explicitly set to a different value by "c" or "C"). 

If count is negative, the breakpoint is "temporary", and count increments with each encounter.  Once count goes to zero, the breakpoint is recognized, then deleted. 

commands Actions to be taken upon recognition of a breakpoint before waiting for command input.  These are separated by ";" and may be enclosed in "{}" to delimit the list saved with the breakpoint from other commands on the same line. 

Results of expressions followed by ";" or "}" are not printed unless you specify a print format. 

Saved commands are not parsed until the breakpoint is recognized.  If there are no commands, the debugger will wait for command input when the breakpoint is recognized.  For immediate continuation, finish the command list with "c". 

Breakpoint commands:

l b

B Both forms list all breakpoints in the format:

num: count: nnn  proc: ln: contents
{commands}

The leftmost number num is an index number for use with the "d" (delete) command. 

[line] b [commands]
Set a permanent breakpoint at the current line (or at line in the current procedure). 

[expr] d
Delete breakpoint number expr.  If expr is absent, delete the breakpoint at the current line, if any.  If there is none, the debugger executes a "B" command instead. 

bp [commands]
Set permanent breakpoints at the beginning (first executable line) of every debuggable procedure. When any procedure breakpoint is hit, commands are executed. 

D [b] Delete all breakpoints (including "procedure" breakpoints).  The "b" is optional. 

D p Delete all "procedure" breakpoints.  All breakpoints set by commands other than "bp" remain set. 

For the following commands, if the second character is upper case, for example, "bU" instead of "bu", the breakpoint is temporary (count is −1), not permanent (count is 1). 

[depth] bb [commands]

[depth] bB [commands]
Set a breakpoint at the beginning (first executable line) of the procedure at the specified stack depth.  If depth is not specified, use the current procedure (may not be the same as the one at depth zero). 

[depth] bx [commands]

[depth] bX [commands]
Set a breakpoint at the exit (last executable line) of the procedure at the given stack depth.  If depth is not specified, use the current procedure (may not be the same as the one at depth zero).  The breakpoint is set such that all returns of any kind go through it. 

[depth] bu [commands]

[depth] bU [commands]
Set an up-level breakpoint. The breakpoint is set immediately after the return to the procedure at the specified stack depth (default one, not zero).  Zero depth means "current location". 

[depth] bt [proc] [commands]

[depth] bT [proc] [commands]
Trace current procedure (or procedure at depth, or proc). Set breakpoints at entrance and exit of a procedure. Default entry breakpoint commands are "Q;2t;c" (show top two procedures on stack and continue).  The exit breakpoint always executes "Q;L;c" (print current location and continue). 

If depth is given, proc must be absent or it is taken as part of commands.  If depth is missing but proc is specified, the named procedure is traced.  If both depth and proc are omitted, the current procedure is traced, which might not be the same as the one at depth zero. 

If commands are present, they are used for the entrance breakpoint, instead of the default shown above. 

address ba [commands]

address bA [commands]
Set a breakpoint at the given code address. address can be the name of a procedure or an expression containing such a name.  If the child process is stopped in a non-debuggable procedure, or in prologue code (before the first executable line of a procedure), results may seem a little strange. 

The next few commands are not strictly part of the breakpoint group, but are used almost exclusively as arguments to breakpoints (or assertions). 

if [expr] {commands}[{commands}]
If expr evaluates to a non-zero value, the first group of commands (the first "{}" block) is executed, otherwise it (and the following "{", if any) is skipped.  All other "{}" blocks are always ignored (skipped), except when given as an argument to an "a", "b", or "!" command.  The "if" command is nestable, and can be abbreviated to "i". 

Q If the "quiet" command appears as the first command in a breakpoint’s command list, the normal announcement of "proc: line: text" is not made.  This allows quiet checks of variables, etc. to be made without cluttering up the screen with unwanted output.  The "Q" command is ignored if it appears anywhere else. 

"any string you like"
Print the given string.  String may contain standard backslashed character escapes, including "\n" for newline.  Useful for labelling output from breakpoint commands. 

Assertion Control Commands

Assertions are command lists that are executed before every statement.  Thus, if there is even one active assertion, the program is single stepped at the machine instruction level (runs very slowly).  They are primarily used for tracking down nasty bugs (such as the corruption of a global variable). 

Assertions can be activated or suspended individually, plus there is an overall mode. 

a commands
Create new assertion with given command list. List is not parsed until execution time. Command list can be enclosed in "{}" to delimit it from other commands on the same line.  The "l a" command lists all current assertions and the overall mode. 

expr a (a | d | s)
Modify the assertion numbered expr:  activate it, delete it, or suspend it.  Suspended assertions continue to exist, but do nothing until reactivated. 

A Toggle the overall state of the assertions mechanism between active and suspended. 

D a Delete all assertions. 

[flag] x
Force exit from assertions mode. If flag is absent or evaluates to zero, exit immediately.  Otherwise, finish executing the current assertion first.  If an assertion executes an "x" command, the child process stops and the assertion doing the "x" is identified. 

The debugger has only one active command line at a time.  The current command line is discarded when assertion execution begins. 

Commands "r", "R", "c", "C", "s", "S", and "k" are not allowed while assertions are running.  They must appear after the "x", if at all. 

Signal Control Commands

The debugger catches all signals bound for a child process before the child process sees them (a function of the ptrace(2) mechanism).

[signal] z [i][r][s][Q]
Maintains the "zignal" (signal) handling table. Signal is a valid signal number (default is the current signal).  The options (which must be all one word) toggle the state of the appropriate flag:  ignore, report, or stop.  If "Q" is present, the new signal state is not printed. 

"l z" lists the current handling of all signals.  "z" (with no options) shows the state of the current or selected signal. 

For example, assuming a start up state of (don’t ignore, don’t report, don’t stop), the command "14z sr" sets the alarm clock signal to stop (but still don’t ignore) and report that it occurred.  Doing "14z sr" again toggles the flags back to the original state. 

When the child process stops or terminates on a signal it is always reported, except for the breakpoint signal when the breakpoint commands start with "Q". 

When the debugger ignores a signal, the "c" command does not know about it.  A signal is never ignored when the child process terminates, only when it stops. 

Record and Playback Commands

The debugger supports a record/playback feature to help recreate program states and to record all debugger output. 

Commands are:

>file Set or change recordfile to file and turn recording on.  This rewrites file from the start.  Only commands are recorded to this file. 

>>file
Same as >>file but appends to file instead of overwriting. 

>@file

>>@file
Set or change record-all file to file, for overwriting or appending.  The record-all file can be opened or closed independent of the recordfile.  All debugger standard output is copied to the record-all file, including prompts, commands entered, and command output (does not capture child process output). 

>(t | f | c)
Turn recording on ("t") or off ("f"), or close the recording file ("c").  When recording is resumed, new commands are appended to previous file contents.  In this context, ">>" is equivalent to ">". 

>@(t | f | c)
Turn record-all on, off, or close the record-all file. In this context, ">>@" is equivalent to ">@". 

> Tell the current recording status (same as ">>"). 

>@ Tell the current record-all status (same as ">>@"). 

<file Start playback from file. 

<<file
Start playback from file, using the single-step feature of playback. 

Only command lines read from the keyboard or a playback file are recorded in the recordfile. 

Command lines beginning with ">", "<", or "!" are not copied to the current recordfile (they are copied to the record-all file).  To override this, begin such lines with blanks. 

NOTE:  The debugger can be invoked with standard input, standard output, and/or standard error redirected, independent of record and playback.  If the debugger encounters an end-of-file while standard input is redirected from anything other than a terminal, it prints a message to standard output and exits, returning zero. 

Miscellaneous Commands

<carriage-return>

~ An empty line or a "~" command causes the debugger to repeat the last command, if possible, with an appropriate increment, if any.  Repeatable commands are those which print a line, print a window of lines, print a data value, single step, and single step over procedures.  <carriage-return> is saved in a record file as a "~" command, to distinguish from ^D. 

^D Control-D is like <carriage-return>, but repeats the previous command ten times.  This command is saved in a record file as an empty line. 

! [command-line]
This shell escape invokes a shell program. If command-line is present, it is executed via system(3S). Otherwise, the environment variable SHELL gives the name of the shell program to invoke with a −i option, also using system(3S). If SHELL is not found, the debugger executes "/bin/sh −i".  In any case, the debugger then waits for the shell or command-line to complete. 

As with breakpoints, command-line may be enclosed in "{}" to delimit it from other (debugger) commands on the same line.  For example,

14b {!{date};c}; t; l a

sets a breakpoint at line 14 that calls date(1), then continues; then (after setting the breakpoint), the debugger does a stack trace, then lists assertions.

f ["printf-style-format"]
Set address printing format, using printf(3S) format specifications (not debugger format styles).  Only the first 19 characters are used.  If there is no argument, the format is set to a system-dependent default.  All addresses are assumed to be of type long, so you should handle all four bytes to get something meaningful. 

F Find and fix bug (a useless but humorous command). 

g line Go to an address in the procedure on the stack at depth zero (not necessarily the current procedure).  Changes the program counter so line is the next line to be executed. 

h

help Print the debugger help file (command summary) using more(1).

I Print information (inquire) about the state of the debugger. 

M Print the current text (objectfile) and core (corefile) address maps.

M (t | c) [expr; [expr;...]]
Set the text (objectfile) or core (corefile) address map. The first zero to six map values are set to the exprs given.

q Quit the debugger.  Requests confirmation. 

Z Toggle case sensitivity in searches.  This affects everything:  File names, procedure names, variables, and string searches!  The debugger starts out as not case sensitive. 

HARDWARE DEPENDENCIES

The "bx" (break on exit) command requires that compilers support it by funneling all exits through one point.  The breakpoint is always set at the last line of the procedure, which should be, but may not be, the sole exit point. 

Series 300, 500

When a C parameter is declared as an array of anything, the highest type qualifier (array) shows up as a pointer instead.  For example, "int x[]" looks like "int *x", and "char (*x)[]" looks like "char **x", but "char *x[]" is treated correctly as "pointer to array of char". 

There is limited support for command-line calls of functions which return structures.  The debugger interprets the start of heap as a structure of the return type.  However, a call such as "abc()/t" displays the return type correctly. 

$short and $long are available in addition to $result.  If command-line procedure call returns a double, $result is set to the value cast to long. 

The source file end.c is not supported, so you can’t customize /usr/lib/end.o.  The buffer size is fixed at 200 bytes.  To force linking of library routines not otherwise referenced, use the −u option to ld(1).

Procedures in FORTRAN and Pascal may have alias names in addition to normal names.  Aliases are shown by the "l p" (list procedures) command.  They can be used in place of the normal name, as desired. 

The procedure name "_MAIN_" is used as the alias name for the main program (main procedure) in all supported languages.  Do not use it for any debuggable procedures. 

FORTRAN ENTRY points are flagged "ENTRY" by the "l p" command. 

When a compiler does not know array dimensions, such as for some C and FORTRAN array parameters, it uses 0:MAXINT or 1:MAXINT, as appropriate.  The "/t" format shows such cases with "[]" (no bounds specified), and subscripts from 0 (or 1) to MAXINT are allowed in expressions. 

There is no support for:  C structure, union, and enumeration tags, C typedefs, and Pascal types. 

Some variables are indirect, so a child process must exist in order for the debugger to know their addresses.  When there is no child process, the address of any such variable is shown as 0xfffffffe. 

The optional pattern given with the "l g" (list globals) command must be an exact match, not just a leading pattern. 

Symbol names in the Value Table are never preceded by underscores, so the debugger never bothers to search for names of that form.  The only time a prefixed underscore is expected is when searching the Linker Symbol Table for names of non-debuggable procedures. 

Series 300
Series 300 supports two types of string formats in addition to null-terminated C strings. FORTRAN character variables consist of a string of bytes (no null terminator).  Pascal string variables consist of a length byte, followed by the string characters.  The "\s" and "\a" formats will display these types correctly, only if the current language is FORTRAN or Pascal. 

Series 500
"bx" works, except for FORTRAN multiple returns.  The compilers emit a special source line symbol for this exit point, after the last "visible" source line. 

Series 500 supports two types of string formats in addition to null-terminated C strings.  FORTRAN character variables consist of four-word (16-byte) string markers, where the second word plus the third word plus three is the byte address of the string itself, and the fourth word is the length of the string.  Pascal string variables consist of a four-byte, word-aligned length word followed by the string characters. 

If the current language is FORTRAN, or if you use "/s" format with fdb or pdb, the debugger interprets the variable (or expression) as a string marker (or address thereof), which is a null pointer if the second word of the marker is zero.  Multiple-count formats show a series of fixed-length strings, beginning with the first one pointed to by the marker.  Using "<cr>" or "^" to go forward or backward in memory uses the four words after or before the current string marker as the new marker. 

If the current language is Pascal, or if you use "/a" format with fdb or pdb, the debugger interprets the variable (or expression) as a Pascal string (or address thereof).  Multiple-count formats show a series of random-length strings, using successive length words, skipping any wasted bytes in the last word of the previous string.  Likewise, using "<cr>" or "^" to go through memory skips the total bytes consumed in the last display. 

There is no easy way to assign into a FORTRAN or Pascal string (nor, for that matter, into a Pascal packed array of char, which looks like a simple array).  Only one word is copied into the first word of the string marker or into the length word, regardless of the type of the expression result. 

There are no address maps in the usual sense, so the "M" command is not supported. 

If a child process receives a signal and you then step with the "s" command (or run with assertions active), the process free-runs through the signal handler procedure (if any) before pausing (or doing assertions). 

Code and data pointers in objectfile both contain segment numbers.  At exec(2) time, all such pointers are mapped from ld(1) pseudo-values to real values based on actual segment numbers allocated. The debugger operates in "pseudo-address-space", so you won’t notice anything unusual most of the time. All addresses look the same each time you invoke a new child process. For example, the heap always begins at "broken" address zero (0).

WARNING:  The debugger’s interaction with a child process is somewhat complicated, due to the "fixing" of pointer values written to the child and the "breaking" of pointers read from the child.  If you tell the debugger to treat a pointer as a non-pointer, it may get confused, with unpredictable results.  In particular, if you set a debugger special variable equal to a pointer value, then attempt to dereference that special variable, you will either get garbage or cause an access error. 

In the rare case where maxheap is set very large (greater than ~70Mb) and your program uses shared EMS segments (from memallc(2)), the debugger may confuse pointers into the EMS segments with large addresses in the heap.

Addresses of unknown (non-debuggable) procedures are shown as call-type pointers, not data pointers.  They can be distinguished because the high bit is set (e.g., the decimal value looks negative).  Pointers of this form are not usable for anything; you can’t dereference them nor set breakpoints based on them. 

FILES

a.out Default objectfile to debug.
core Default corefile to debug.
/usr/lib/cdb.help Text file listed by the "help" command.
/usr/lib/cdb.error Text file which explains debugger
error and warning messages.
/usr/lib/end.o Object file to link with all debuggable
programs.

AUTHOR

Cdb was developed by Third Eye Software. 

SEE ALSO

cc(1), echo(1), fc(1), pc(1), ld(1), more(1), creat(2), exec(2), fork(2), open(2), setjmp(3C), printf(3S), system(3S), a.out(4), and the cdb Debugger tutorial in HP-UX Concepts and Tutorials. 

On some systems any of the following may exist:  adb(1), ptrace(2), core(4). 

DIAGNOSTICS

Most errors cause a reasonably accurate message to be given.  Normal debugger exits return zero and error exits return one.  All debugger output goes to standard output except error messages given just before non-zero exits, which go to standard error. 

Debugger errors are preceded by "panic: ", while user errors are not.  If any error occurs during initialization, the debugger then prints "cannot continue" and quits.  If any error happens after initialization, the debugger attempts to reset itself to an idle state, waiting for command input.  If any error occurs while executing a procedure call from the command line, the context is reset to that of the normal program. 

Child process (program) errors result in signals which are communicated to the debugger via the ptrace(2) mechanism. If a program error occurs while executing a procedure call from the command line, it is handled like any other error (i.e. you can investigate the called procedure). To recover from this, or to abort a procedure call from the command line, type DEL, BREAK, ^C, or whatever your interrupt character is. 

For more information, see the text file /usr/lib/cdb.errors. 

WARNINGS

Code that is not debuggable or does not have a corresponding source file is dealt with in a half-hearted manner.  The debugger shows "unknown" for unknown file and procedure names, cannot show code locations or interpret parameter lists, etc.  However, the linker symbol table provides procedure names for most procedures, even if not debuggable.  The main procedure (main program) must be debuggable and have a corresponding source file. 

If the address given to a "ba" command is a not a code address in the child process, strange results or errors may ensue. 

If you set the address printing format to something printf(3S) doesn’t like, you may get an error (usually memory fault) each time you try to print an address, until you fix the format with another "f" command. 

Do not use the "z" command to manipulate the SIGTRAP signal.  If you change its state you had better know what you are doing or be a very good sport! 

If you single step or run with assertions through a call to longjmp(3C), the child process will probably take off free-running as the debugger sets but never hits an up-level breakpoint.

Do not modify any file while the debugger has it open.  If you do, the debugger gets confused and may display garbage. 

Although the debugger tries to do things reasonably, it is possible to confuse the recording mechanism.  Be careful about trying to playback from a file currently open for recording, or vice versa; strange things can happen. 

Many compilers only issue source line symbols at the end of each logical statement or physical line, whichever is greater.  This means that, if you are in the habit of saying "a = 0; b = 1;" on one line, there is no way to put a breakpoint after the assignment to "a" but before the assignment to "b". 

Some statements do not emit code where you would expect it.  For example, assume:

99:for (i = 0; i < 9; i++) {
100:xyz (i);
101:}

A breakpoint placed on line 99 will be hit only once in some cases.  The code for incrementing is placed at line 101.  Each compiler is a little different; you must get used to what your particular compiler does.  A good way of finding out is to use single stepping to see in what order the source lines are executed. 

The output of some program generators, such as yacc(1), have compiler line number directives in them that can confuse the debugger. It expects source line entries in the symbol table to appear in sorted order. Removal of line directives fixes the problem, but makes it more difficult to find error locations in the original source file. The following script, run after yacc(1) and before cc(1), comments out line number changes in C programs:

sed "/# ∗line/s/^.∗$/\/∗&∗\//" y.tab.c >temp.c

yacc(1) will leave out line directives if invoked with the −l option.  In general, line number directives (or compiler options) are only safe so long as they never set the number backwards. 

BUGS

The C operators "++", "−−", and "?:" are not available.  The debugger always understands all the other C operators, except "sizeof", if the default language is FORTRAN or Pascal. 

For FORTRAN, only the additional operators ".NE.", ".EQ.", ".LT.", ".LE.", ".GT.", and ".GE." are supported. 

For Pascal, only the operators ":=", "<>", "^", "^." (as in "x^.y"), "and", "or", "not", "div", "mod", "addr", and "sizeof" are added. 

There is no support for FORTRAN complex variables, except as a series of two separate floats or doubles. 

The debugger doesn’t understand C type casts. 

The C operators "&&" and "||" aren’t short circuit evaluated as in the compiler.  All parts of expressions involving them are evaluated, with any side-effects, even if it’s not necessary. 

The debugger doesn’t understand C pointer arithmetic.  "∗(a+n)" is not the same as "a[n]" unless "a" has an element size of 1. 

There is no support for C local variables declared in nested blocks, nor for any local overriding a parameter with the same name.  When looking up a local by name, parameters come first, then locals in the order of the "}"s of the blocks in which they are declared.  When listing all locals, they are shown in the same order.  When there is a name overlap, the address or data shown is that of the first variable with that name. 

CDB does not support identically-named procedures (legal in Pascal if the procedures are in different scopes).  CDB will always use the first procedure with the given name. 

There is no support for Pascal packed arrays where the element size is not a whole number of bytes.  Any reference into such an array may produce garbage or a bad access. 

Pascal WITH statements are not understood.  To access any variable you must specify the complete "path" to it. 

The debugger supports call-by-reference only for known parameters of known (debuggable) procedures.  If the object to pass lives in the child process, you can fake such a call by passing "& object", i.e. the address of the object. 

Array parameters are always passed to command-line procedure calls by address.  This is correct except for Pascal call-by-value parameters.  Structure parameters are passed by address or value, as appropriate, but only a maximum of eight bytes is passed, which can totally confuse the called procedure.  Series 500 FORTRAN string markers are never passed correctly.  Only the first number of a complex pair is passed as a parameter.  Functions which return complex numbers are are not called correctly; insufficient stack space is allocated for the return area, which can lead to overwriting the parameter values. 

Assignments into objects greater than four bytes in size, from debugger special variables, result in errors or invalid results. 

Command lines longer than 1024 bytes are broken into pieces of that size.  This may be relevant if you run the debugger with playback or with input redirected from a file. 

INTERNATIONAL SUPPORT

cdb: 8-bit filenames, messages. 

Hewlett-Packard Company  —  Version B.1,  May 11, 2021

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026