Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ ups(1) — 386BSD 1.0

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

cc(1)

f77(1)

ld(1)

dbx(1)

UPS(1)

NAME

ups − X11 and SunView based source level C debugger

SYNOPSIS

ups target [corefile|pid] [[:]srcdir[:srcdir]] [-a target-args]

DESCRIPTION

Ups is a graphical source level debugger for the C programming language running under the X11 and SunView window systems.  It supports both run time debugging with breakpoints and post-mortem debugging from a core file.  On Suns you can attach ups to a running process.  Ups runs in its own window, thus not interfering with the target program’s I/O.  The ups window has two major areas − one showing a structured document representing the target state, the other showing the source that is being executed.  Ups makes heavy use of direct manipulation and feedback.  When you add a breakpoint it is shown as a pseudo C statement (#stop) in the source display.  The current point of execution is highlighted in the source display and you can watch it move as you step through loops and function calls.  You can edit in fragments of interpreted C code (including assignments to variables and calls to target functions).  There are powerful facilities for exploring linked data structures − you can recursively expand and collapse structures to follow links. 

GETTING STARTED

This section gives step by step instructions on how to use ups on a small example C program.  The idea is to get a feel for how to use ups without getting bogged down in details.  After following the instructions here you should be able to explore a little on your own and then be ready to have a look at the reference material that follows.  Here is the sample source code:

struct argst { char ∗a_name; struct argst ∗a_next; };
struct argst ∗listhead = 0;
 void stash(name)
char ∗name;
{
struct argst ∗a;
char ∗malloc();
 a = (struct argst ∗)malloc(sizeof(struct argst));
a->a_name = name;
a->a_next = listhead;
listhead = a;
}

int main()
{
stash("foo");
stash("bar");
}

We skip error checking code here in the interests of brevity. Put a copy of the code above into a .c file (e.g. sample.c) by cut-and-paste or by snarfing the lines from the file that contains this manual page. If you have the source directory of ups around you will find this code below there in the file ups/doc/sample.c.  Assuming you have a copy of the above code in a file and you are sitting at a workstation or X terminal and have an X or Sunview session running, here is what you do: • Compile and link the code with the -g flag to cc(1) or gcc(1).

The -g flag directs the compilers to include extra symbol table information in the object file that is needed by debuggers.  • Give the command ‘ups a.out’ (or whatever you called the object file).  After a short pause a window will be created; the details obviously depend on your window manager. 

This is the simplest way of invoking ups. For a complete description of the command line flags and arguments see UPS COMMAND LINE ARGUMENTS. 

In the window you should see a display divided into various rectangular boxes and menus, with two large regions in the upper and lower halves of the window.  The top region is the display area − it contains captions looking roughly like:

Target a.out
a.out
Signals
Environment
Untyped variables
Source files
Functions
Breakpoints

In the lower region you should see the start of main() displayed.  Note: the layout of the window is explained in detail in a later section.  • Move the mouse cursor over the Breakpoints caption in the upper region, and press and release the left mouse button. 

You should see two things happen: the caption is inverted to show that it is selected, and a menu appears near the top of the window with the captions Add new breakpoint and Remove all breakpoints. 

All the objects in the display area (except Functions) can be selected like this and have their own menus.  Selecting an object (or many objects) and clicking on one of the commands in its associated menu is the primary way of issuing commands to ups. • Click (press and release) the left mouse button over the Add new breakpoint menu caption. 

You should see a line below the Breakpoints caption looking like:

Function:|line:0

The vertical line is a marker bar − it indicates where characters will appear when you type.  • Type ‘main’

You can use the delete key as you would expect to fix typos.  There are various other useful control characters − see the EDITABLE FIELDS section for details.  • Press ESC (the escape key). 

This confirms the edit.  You should see the text

#stop;

appear at the start of main in the source region.

Ups represents breakpoints as this fragment of pseudo C.  You can edit breakpoints to do things other than just stop (e.g. call a target function or only stop if a certain condition is true).  This is covered later in this section, and described fully in the section ADDING INTERPRETED CODE. 

You can also add breakpoints by pointing at the appropriate line in the source region − this is described later in this section.  • Click the left button over the caption Start at the left hand side of the menu just below the display area. 

This menu is the target control menu.  Here is a brief description of what the other commands in this menu do (these are explained in more detail in the CONTROLLING TARGET EXECUTIION section).  As you have just seen Start starts the target running.  Step and Next step execution over single lines of code (Step steps into function calls, Next doesn’t).  Cont makes the target process run until it hits a breakpoint or exits.  Stop stops a running target process, and Exit kills off the target process, ready for another run using Start. 

You should see the first line of code in main highlighted.  This means that execution has stopped just before this line.  If you look at the display area you will also see that a new line has appeared under the Functions object.  This should look like:

mainsample.c:18

This shows that you are stopped at line 18 of sample.c in function main. 

At this point you are in the usual state for ups: you have the target stopped, with the line that is about to be executed highlighted in the source window and your current position in the source file shown under the Functions object in the display area.  • Click on Step in the target control menu. 

The source display switches to function stash, which you have just stepped into.  You will also see an extra line under Functions − the display should look like:

mainsample.c:18
stashsample.c:10

As you can see this is a stack trace, showing you which function called which starting from main and working inwards towards the function you are currently stopped in.  • In the source region move the mouse over the ‘a’ at the start of the highlighted line and click the left mouse button. 

You should see a line added to the stack trace, making it look like:

mainsample.c:18
stashsample.c:10
  struct argst ∗<a>0x4

This is one of the main strengths of ups: to see the type and value of any variable that is visible in the source window you simply click on its name.

This is showing that a is a variable of type struct argst ∗ with the value 4. Ignore the angle brackets round the ‘a’ for now − they will be explained later.  This is an uninitialised variable, so the value you see will probably be different from this. 

You will also notice that the menu near the top of the display area has changed.  Every object in the display area has an associated menu, which is displayed when that object is selected.  Ignore the menu for now.  • Click on Step in the target control menu. 

The value displayed for the variable a changes to whatever is returned by malloc.  This shows another key feature of ups − displayed variables remain in the display area as you step through the program code so you can watch the values change.  • Now click the left mouse button over the displayed line for the variable a. 

The line will be inverted to show that it is selected and a menu will appear as before near the top of the display area.  • Click on Expand in the menu that was produced by the last step. 

You will see an entry added for each member of the structure, giving a display under the Functions object that looks something like:

mainsample.c:18
stashsample.c:11
  struct argst <a{0}>      0x60c8
    char <a_name{0}>         ∗NULL
    struct argst ∗<a_next>   0x0

The member types and values are shown in the same way as the structure pointer ‘a’ itself.  As before the values are uninitialised, so the values you see will depend on the exact behaviour of your malloc implementation.  • Click on next in the target menu. 

The highlighting in the source window will move on to the next line, and the value displayed for the a_name field will change. 

This sort of interaction is typical use of ups − you expand structures to see members of interest, and then step through the source code watching how they change.  • Move the mouse over the highlighted source line, press and hold down the right hand mouse button then release it. 

When you pressed the mouse button you will have seen a popup menu with the captions Add breakpoint and Execute to here.  You will also have seen an arrow to the left of the menu pointing at the source line you pressed the mouse over. 

When you release the mouse button a breakpoint is added just before the source line.  You will see the text #stop; appear. 

This is the simplest and most common way of adding breakpoints in ups. The normal sequence of actions is:

•Type the name of the function you are interested in (or enough of it to uniquely identify it) and hit ESC (the escape key).  The source of the function is displayed in the source window. 

•Scroll the source to make visible the line where you want to add a breakpoint. 

•Add a breakpoint by clicking the right mouse button over the source line. 

• Click on Cont in the target control menu. 

The target continues until it hits a breakpoint.  In this case the target stops in the second call of stash from main.  You will notice that in the display area the displayed value of a_name has changed.  • Click on Cont again. 

The target continues to completion and exits.  The stack trace and variables disappear from the display area, and all the target control menu captions except Start are greyed out to indicate that they are unavailable while the target is stopped.  We are almost at the end of this example.  These last steps are to show how you can add printf calls (in fact any interpreted C).  The actions we are about to cover are:

•Editing some interpreted C into a breakpoint. 

•Scrolling the source window to show the other breakpoint and removing it. 

•Re-running the target to see the effect of the interpreted code.  • Move the mouse over the ‘#stop;’ text that indicates the breakpoint in the stash function and click the middle mouse button. 

You should see a marker bar (a thick vertical bar) appear.  If it is not at the end of the ‘#stop;’ text then click the middle mouse button further to the right.  • Use the delete key to delete the ‘#stop;’ text.  • Type the following text: $printf("Setting a->a_name to %s\n", a->a_name);

$printf is a built in ups function with an interface almost identical to printf except that it sends output to an region in the ups display.  • Hit ESC (the escape key)

If you haven’t made any errors ups will silently accept the line and the marker bar will disappear. 

If you have made a syntax error ups will beep, give you an error message and put the marker bar at the point of the error.  You can then correct the error.  • Press and hold down the left mouse button in the scroll bar to the left of the source window, and with the mouse button pressed move the mouse button a few pixels towards the top of the window. 

You should see the source text scrolling slowly upwards.  The more you move the mouse from the place you first pressed it, the faster the source scrolls.  • When you see the source of main appear in the source window release the mouse button. 

The scrolling will stop.  • Click the left mouse button on the #stop at the start of main. 

You will see the breakpoint entry in the display is highlighted, as well as a menu with the captions Remove and Source near the top of the window.  • Click on Remove in the menu

You will see the breakpoint entry in the display area disappear, along with the #stop; line in the source window.  • Click on Start in the target control menu. 

You should see a third subregion appear in the display.  This looks similar to the source window, with a controlling menu above it and a scroll bar on the left hand side. 

This is the output region. It is where output from the built in function $printf appears.  This region appears the first time $printf is called by interpreted code. 

You will see that the text

Setting a->a_name to foo
Setting a->a_name to bar

has appeared.  This was produced by the interpreted code that you added. 

Note that the target ran to completion without stopping.  A breakpoint only stops the target if the pseudo C statement #stop is executed.  This lets you add conditional breakpoints simply by putting an if statement around them. 

One final point: you can call target functions (like stash in this example) from interpreted breakpoint code.  This is often used to call printf in cases where you do want the debugging output interspersed with the target program’s output.  Here endeth the example.  It certainly hasn’t covered all of the features of ups, but hopefully it has given you a feel for the way it works. Some basic points:

•The two important areas in the display are the display area (top) and the source region (bottom). 

•The display area contains captions representing objects of different types. 

•You can select an object by clicking on it with the left mouse button. 

•Each different object type has an associated menu which appears near the top of the ups window when the object is selected. 

•Commands selected from these menus act on the currently selected objects. 

•The source region displays the currently executing source code, with the line that is about to be executed highlighted. 

•You can add any variable to the display area by clicking on an instance of it in the source window with the left mouse button. 

•You can add breakpoints by pointing at lines of source. 

•You can edit breakpoints to add printf statements and conditional breakpoints. 

•You can expand and collapse structures to explore data structures. 

•Variables remain in the display area as you step through the code so you can watch the values change.  The rest of this manual page gives a complete description of ups .  You should probably skim through it at first reading before playing with ups on some of your own code for a while.  When you are more familiar with ups reread these sections in more detail. 

UPS COMMAND LINE ARGUMENTS

This section gives a complete description of the command line arguments accepted by ups.  The command line syntax is:

ups target [corefile|pid] [[:]srcdir[:srcdir]] [-a target-args] The only mandatory argument is the name of the executable file containing the program to be debugged (the target).  If a corefile argument is given it is taken to be the name of a core image dumped from target.  If no corefile argument is given and there is a core image file called ‘core’ in the directory of the target then that is taken as the core file.  Old core files, and core files which weren’t dumped from the target, are silently ignored unless you give the name of the core file explicitly (in which case ups will use it, but give a warning message).  If the corefile argument consists solely of digits, it is taken to be the process id of the target.  This allows you to attach ups to an already running process on machines with the necessary support (currently only Suns).  If you subsequently quit ups while still attached in this way, it detaches from the target, allowing the target to continue.  By default ups looks for source files in the directory of the target.  You can specify alternative source directories by giving a list of directories separated by ‘:’ characters.  An empty initial path (i.e. a leading ‘:’) means the directory of the target.  On Suns running SunOS 4, the C compiler includes directory paths for source files, so ups will normally find source files in other directories even without the source path argument.  You can specify the arguments that the target should be invoked with by giving the -a option, followed by a single argument.  You can give multiple arguments for the target by enclosing the list of arguments in single or double quotes.  Ups will itself interpret metacharacters like ‘∗’ and ‘>’ − see TARGET COMMAND LINE ARGUMENTS. 

LAYOUT OF THE UPS WINDOW

The ups window is divided into a number of rectangular regions.  This section gives a brief description of each region.  It won’t make much sense unless you are also looking at an ups window. 

•At the top of the window on the left is the typing line.  On startup a vertical bar known as a marker bar is shown.  Typed characters appear in this region, and some ups commands use the text in this window as an argument (e.g., the command to search for a regular expression in a source file). 

•Below the typing line is the dynamic menu area.  On startup this area is greyed out.  See THE DISPLAY AREA below for a description of the dynamic menu. 

•Below the dynamic menu area is a region where messages from ups appear (usually with a beep). 

•To the right of the above three regions is a mousehole.  This has a representation of the three mouse buttons, and captions for each button saying what that button will do.  The captions change as you move from region to region, reflecting the fact that the mouse buttons have different functions in different regions. 

•Below the preceding four regions is the display area − a large region used to display and investigate the current state of the target.  There is a scroll bar to the left of the display area.  See THE DISPLAY AREA. 

•Below the display area is the target menu.  This has a set of commands for controlling target execution.  See CONTROLLING TARGET EXECUTION below. 

•Below the target menu is the source menu, with a set of commands for managing the source region, which is below this menu.  There is a scroll bar to the left of the source region.  See THE SOURCE REGION below. 

THE DISPLAY AREA

The display area is the large region in the upper half of the ups window.  Its main use is to show the state of the program when it stopped, though it is also used for other control functions.  There are a number of captions in the display area, like Signals, Breakpoints etc.  These are known as objects.  To select an object, press and release the left mouse button over it.  Any objects that were previously selected are deselected, the object is inverted to show that it is selected, and a menu of commands applicable to that object appears in the second of the three slots at the top of the window.  At any time this region of the display either contains a menu corresponding to a selected object, or is empty (painted a uniform grey) if there are no objects selected.  A command selected from the menu (by pressing and releasing the left mouse button over the caption) is applied to the currently selected objects.  It is possible to apply a command to a group of objects.  To do this, select a group of objects by pressing the left mouse button over the first object and then dragging the mouse over the other objects you wish to select before releasing the button.  You cannot select objects of different types simultaneously as each different type of object has its own menu.  Once the first object has been selected, only objects of the same type will be selected (and highlighted) as the cursor passes over them.  The right hand mouse button is used to toggle whether an object is selected − clicking it over a selected object deselects that object, and clicking over an object that isn’t selected adds that object to the selection.  As with the left mouse button, you can drag the mouse with the right button down to toggle a group of objects.  Several of the menu commands add new objects to the display.  For example, when you expand an entry in the stack trace all the local variables for the function it represents are added to the display (see EXAMINING VARIABLE VALUES below).  These new objects can be selected in the same way as the existing ones, and have an associated menu of commands.  Once a few objects have been added to the display area, there is usually not enough room to display all of them at once.  There is a scroll bar to the left of the display area which lets you scroll the display area up and down.  To scroll, press and hold down the left mouse button whilst within the scroll bar, and move the mouse in the direction you wish the display to move.  The further you move the mouse, the faster the scrolling.  The black blob in the scroll bar represents the proportion of the entire display that is currently visible, and the position of this visible part within the whole display.  For example, if the black blob is one third the height of the scroll bar, and in the middle, it means that the total height of the objects is about three times the height of the display area, and the middle third is currently being displayed.  You can also use the scroll bar to go directly to a given point in the display.  Press and release the middle mouse button at a point in the scroll bar.  The black blob is moved so that it centres around the point, and the display is moved correspondingly. 

THE SOURCE REGION

The source region is used to display the source line that the target is currently stopped at, or more precisely the line that is about to be executed.  Like the display area, the source region has a scroll bar to the left of it, which behaves in the same way as the display area scroll bar.  Above and to the left of the source region is a box where the name of the current source file and the current line number is displayed.  To the right of this is the source region menu with commands back, search, up and down.  The up and down commands scroll the source region up and down half a page respectively − they are an alternative to the scroll bar for paging through a source file.  The search command is used to search for regular expressions (using the same syntax as grep(1) patterns) in the currently displayed source file.  First type in the pattern to be searched for (typed characters appear in the typing line at the top of the window on the left) then press and hold down the left mouse button over the search caption.  A popup menu appears with the options backwards and forwards.  Move the mouse over the one you want and release the button.  If the pattern is found, the matching text is made visible in the source region and highlighted.  You can click the left mouse button on any function name in the source window to display the source for that function (this is similar to the tags facility in vi(1)).  Ups maintains a stack of where you’ve been.  After you have clicked on a function name you can use the back command in the source menu to return to where you were.  You can also get a function displayed by typing the name into the typing line at the top of the ups window.  You do not need to type the whole name − just enough characters to uniquely identify the function.  If a function appears by the same name in more than one source file, you can use the syntax ‘filename:funcname’ to specify which function you want.  Ups will also understand shell-style globbing (e.g.  ‘∗foo_func∗’) for function and global variable names, with the restriction that the pattern must match only a single name.  Whenever the source region switches to a new source file, ups checks the last modified time of the source file against the last modified time of the target object file.  If the source file is newer than the target you get a warning message and the source code is displayed with foreground and background colours reversed as a reminder that this source code might not correspond the object file you are debugging. 

EDITABLE FIELDS

All editable fields in ups work in the same way.  To start editing you click the middle mouse button over the editible text.  A vertical marker bar appears − characters that you type appear to to the left of the marker bar.  You can reposition the marker bar by clicking in the new position with the middle mouse button.  Clicking the left or right button confirms the edit.  Clicking the middle mouse button outside the editable text area also confirms the edit.  In both cases the mouse click is then interpreted as normal − this means that to confirm an edit you can simply move on to another activity.  The final way to confirm an edit is to type ESC (the escape key).  To paste the current window system cut buffer, click on the middle mouse button with the shift key down.  When you try to confirm an edit ups checks that the new field value is reasonable.  If not you get an error message and you are left in the edit.  An immediate second attempt to quit abandons the edit and restores the original field value.  The following special characters are recognised while editing text:

^C (control-C)
Cancel the edit and restore the original text.

DEL (the delete key)
Delete the character just before the marker bar.

^U Delete the text from the start of the line to the marker bar. 

ESC (the escape key)
Confirm the edit.

^H (backspace)
Move the marker bar back one character.

^L Move the marker bar forward one character.  Note: Don’t resize the ups window in the middle of an edit as this cancels the edit.  This misfeature will be fixed in a future release. 

EXAMINING THE TARGET’S STATE

When the target is stopped at a breakpoint or when ups has been started with a core file, the target’s state is show in the form of a stack trace in the display area.  This consists of a line for each active function giving the name of the function, the source line number of the line that was being executed, and the name of the source file containing the function.  The stack trace appears under the Functions object in the display area.  As an example, consider the following stack trace:

Functions
  mainmain.c:42
  docmdcommands.c:84
  getlineio.c:21

In this example, execution in function main reached line 42, at which point main called docmd.  In turn, docmd at line 84 called getline.  Getline is stopped at line 21 (which is yet to be executed).  When the target stops, the source of the innermost function is displayed, with the line that is just about to be executed highlighted (displayed in reverse video).  To look at the source of other functions in the stack trace:

•Click the left mouse button over a line in the stack trace.  The line is highlighted, and a menu appears near the top of the window with the captions Expand, Collapse, Add expr and Source. 

•Click on Source in the menu.  The source corresponding to the selected line in the stack trace is shown, with the line that is currently executing highlighted.  In this way you can see exactly where the target is stopped at any level in the stack. 

EXAMINING VARIABLE VALUES

There are several ways to find the values of variables.  The simplest and most often used is simply to click with the left mouse button on the name of a variable in the source region.  A line is added to the display area which looks something like:

int <varname>73

In this example, an integer variable called varname with a current value of 73 is shown.  The meaning of the angle brackets around the name is explained later − ignore them for now.  If the variable is local to a function, it is added just below the line in the stack trace for that function.  If the variable is global, an entry for the source file of the variable is added below the Source files object in the display area and the variable is displayed below that.  In rare cases ups does not know the type of the variable, in which case it is assumed to be an integer and displayed under the Untyped variables object.  Once the variable is added to the display, it remains there until its function returns (for a local variable) or you explicitly delete it (see later for how to do this).  This means that you can watch the value change as you control the execution of the target.  As well as selecting individual variables to be shown, you can add all the local variables of a function in the stack trace to the display.  Select the function in the stack trace whose variables you wish to see, and select Expand from the menu produced.  To remove all the variables select Collapse.  When you use Expand to add all the local variables of a function, you may see some lines like this:

    lines 84..93

These lines are added for variables declared within inner blocks of a function. In this example, there is an inner block starting at line 84 and ending at line 93 which contains local variable declarations (the line numbers are sometimes inaccurate because of bad information supplied by some compilers). If you click the left mouse button over one of these entries, a menu with the options Expand, Collapse, Add expr and Source is produced.  Selecting Expand adds to the display all variables declared in the block.  Collapse removes them again, and Source makes the first line of the block visible in the source region.  See the later section CONTROLLING THE DISPLAY OF VARIABLES for information on (among other things) how to change the format of a displayed variable, indirect through pointers, expand structures and unions and step through the elements of an array. 

CONTROLLING TARGET EXECUTION

Once you have the target stopped at a breakpoint there are several ways of controlling its execution.  Most of these are invoked from the target menu − the permanent menu just below the display area.  The usual way of debugging is to set a breakpoint in the function which you think is misbehaving and then step through its code one line at a time.  The GETTING STARTED section above explains how to set breakpoints and start the target running.  To step over a line of source, select Step from the target menu.  The code on the highlighted line is executed, and the highlighting moves on to the next line to be executed.  The values of variables in the display area are updated every time the target stops, so you can watch values change as you step through the code.  On colour displays variables are shown in a different colour if their values have changed since the last time the target stopped.  If the line to be executed calls a function, Step takes you to the first line of the called function, and stepping continues in the function.  If you don’t want to step through the code of called functions in this way, use the Next command.  This behaves like Step, except that it never steps into called functions.  Both Next and Step work with respect to the currently displayed source.  If you click on a function in the stack trace and select Source to display its source, a subsequent Next or Step moves to the next line of the displayed source.  This makes it easy to get out of a function that you have stepped into by accident and don’t wish to step all the way through.  Use the Source command to display the source of the calling function, then use Next or Step.  The Cont command in the target menu offers a third way to control the target − this command runs the target until it hits another breakpoint, gets a signal, or exits.  Finally, you can ‘drag’ execution in the target to a line in the source file.  Move the mouse cursor over the line you wish to get to, and press and hold down the right mouse button.  A popup menu appears, with the captions Add breakpoint and Execute to here.  Drag the mouse down so that the Execute to here caption is highlighted, and release the button.  The effect of this is to set a temporary breakpoint at the line, temporarily disable all other breakpoints, and then continue the target.  You can use this command to move past uninteresting bits of code without having to set up and remove breakpoints.  The other command on the popup menu, Add breakpoint, adds a breakpoint at the line of source you pointed at.  Unfortunately, to set a breakpoint at (or execute to) a single statement that extends over several text lines, you must point at the last text line.  This is due to limitations in the symbol table information put out by the compilers.  You can stop the target running at any time by clicking on Stop in the target control menu.  The target will then stop wherever it is currently executing as if it had hit a breakpoint.  The Exit command kills off the current instance target process.  You can then use Start or Execute to here to start the target again.  Quitting ups also kills the target process (unless you attached ups to a running process, in which case ups detaches from the process and leaves it to continue unmolested). 

TARGET COMMAND LINE ARGUMENTS

The second line of the display area shows the command line arguments that will be given to the target when it is next started.  The arguments shown include the zero’th argument which is initially set to the name of the target.  You can specify an initial set of arguments for the target with the -a option when you start ups.  If you don’t give the -a option and you are debugging from a core file, ups attempts to extract the command line arguments from the core file.  Otherwise the command line contains no arguments other than the name of the target.  Ups parses the command line in a similar way to the shell.  It supports Bourne shell type redirection (>, >>, <, >&dig, etc.) as well as the csh forms >& and >>&.  Ups also understands most csh metacharacters − globbing with ‘∗’, ‘?’ and ‘[xyz]’, the ‘~’, ‘~user’ and ‘{a,b,c}’ shorthands, and quoting with single or double quotes and backslash.  The current version of ups does not support $var type shell variable substitution.  You can edit the command line at any time to change the command line arguments (although the changes will only take effect when you next start the target).  The command name shown is just the zero’th argument and can be edited just like the other arguments.  This is useful with programs which use the zero’th argument as a sort of hidden flag.  Changing the command name only affects the arguments given to the target − it does not change which program is being debugged. 

CONTROLLING THE DISPLAY OF VARIABLES

When you add a variable to the display (see EXAMINING VARIABLE VALUES above) it is displayed in a default format.  If you click the left button over the line for the variable, a menu appears in the top part of the window.  You can use this menu to set the display format for the variable (Format), to change the level of indirection for pointers (∗ and &), to show all the members of structures and unions (Expand and Collapse), to choose the format variables are displayed in Format, to duplicate or delete entries for variables (dup and del) and to control whether typedefs are used in displayed variables (Decl)..  Pointers The default for a pointer variable is simply to show the pointer value in hex.  To take a common example, if you add a variable of type pointer to pointer to char called argv to the display, you will get a line like:

char ∗∗<argv>0x7fffe184

The angle brackets separate the type from the value. In this example, what is shown is the value of argv, which is of type char ∗∗.  If you now click with the left mouse button on this line, and select ‘∗’ (the leftmost caption) in the variables menu, the format of the line changes to something like:

char ∗<argv{0}>0x7fffe1d0

This says that what is shown is the value of argv[0], which is of type char ∗.  The braces (‘{’ and ‘}’) are used to distinguish a dereferenced pointer from a true array.  A second click on the ‘∗’ menu option changes the line to:

char <argv{0}{0}>"foo"

This is a special case in ups − variables of type char are displayed as strings if they are indirected pointers or members of arrays.  The ‘&’ menu option is the opposite of ‘∗’ − it drops one level of indirection.  You can only use this on indirected pointers.  Use an expression if you want to see the address of a variable (see EXPRESSIONS IN THE DISPLAY AREA below).  Arrays Arrays are initially displayed with all subscripts zero.  You can edit the subscript to another value by clicking on it with the middle mouse button.  A marker bar appears, and you can use the delete key to delete the old subscript and type a new one.  When you hit ESC, the value of the new array element is shown.  Often you wish to quickly scan through all the elements of an array.  You can do this using the ‘>’ and ’<’ keys.  When editing an array subscript, the ’>’ key adds one to the subscript value and displays the new element.  Similarly, the ’<’ key subtracts one from the subscript value.  Using these keys you can rapidly scan up or down an array.  Vi users can use ’j’ and ’k’ instead of ’>’ and ’<’.  Structures Note: in this section ‘structures’ also include unions: they are simply treated as structures with all members having an offset of zero.  Variables that are structures or pointers to structures are initially displayed with just the address in hex.  You can use the Expand command in the variables menu to add all the members of a structure to the display.  The structure members are indented to make it clear which structure they belong to.  If a structure element is itself a structure or a pointer to a structure, it can be expanded in turn to show all its members.  In this way linked data structures can be explored.  For a more selective way of exploring a linked data structure, see the EXPLORING LINKED DATA STRUCTURES section below.  To remove all the members of a structure from the display, use the Collapse command in the variables menu.  This has a submenu with the options First level and Completely.  The first of these removes all members except expanded ones; the second recursively collapses all expanded structures below the selected one.  Changing formats By default integer variables are displayed in decimal and pointer values are shown in hex.  You can change the format with the Format command in the variables menu.  The possible formats are signed or unsigned decimal, hex, octal and binary, as well as ‘ascii’ and ‘string’.  The ‘ascii’ format displays integers in C character notation (e.g.  the value 65 is displayed as ‘a’).  The ‘string’ format is applicable to variables of type char that are indirected pointers or arrays − it treats the address as the first character of a NUL terminated string.  Floating point values are shown in the conventional notation (using the printf %g format).  You can use the Format command to display a hex representation of the value (it makes no difference whether you select signed or unsigned hex from the menu).  This shows in hex the bit pattern used to represent the floating point value.  Duplicating and deleting entries The Delete command in the variables menu deletes all selected variables from the display area.  This is useful for tidying up the display by removing variables that are no longer of interest.  Sometimes it is useful to have a variable displayed more than once.  One common case is where you want to see several elements of an array simultaneously.  The Dup command in the variables menu duplicates the entries for all selected variables.  So to see multiple elements of an array, use dup to add an entry for each element you wish to see, then edit the subscripts separately for each entry.  Use of typedefs If a structure, union or enum has a typedef name then ups will use it in the display area.  Thus if you have the following in a function:

typedef struct foo_s {
int x;
int y;
} foo_t;
 foo_t ∗f;

then clicking on variable f will add a line like:

foo_t ∗<f>0x40ec

to the display area. Typedefs are not used if they hide a level of indirection or an array, or if the typedefed type is not a struct, union or enum. If you want to see the non-typedef type for a variable in the display area, select the variable and press and hold down the left mouse button over the Decl command in the variables menu.  This produces a popup menu with the captions Use typedefs and Ignore typedefs.  Release the mouse over Ignore typedefs and you will be shown the non-typedefed type for all the selected variables. 

CHANGING VARIABLE VALUES

You can change the value of a displayed variable simply by editing the displayed value (i.e. by clicking on it with the middle mouse button and editing in the new value).  This works for C pointers and integral types (including enums), floating point values and strings.  You can use any of the integer display formats for the new value (decimal, hex, octal, binary or ASCII character).  You can use enum constant names for new enum values, and function names for function pointers.  When editing strings or characters you can use the standard C notation for special characters (‘\n’, ‘\b’, ‘\007’ etc).  Normally ups will not let you edit extra characters into a string as this would overwrite whatever was stored in memory just after the string.  If space is known to exist (for example if the string is stored in an array of known size and there are unused bytes) then you can add as many characters as will fit.  If you know you want to overwrite memory beyond the end of the string you can force ups to accept a long value by putting ‘>>’ before the leading quote character of the string.  Normally a trailing NUL (’\0’) is added to the edited string in the normal C way.  If you delete the trailing quote character then this is omitted. 

EXPRESSIONS IN THE DISPLAY AREA

You can add C expressions as well as variables to the display area.  This is useful if you wish to see what an expression in the source code evaluates to.  It also allows you to use casts when you know better than the source code what the type of a given variable is.  To add an expression, select a function in the stack trace and click on Add expr in the function menu.  A marker bar appears, ready for you to enter an expression.  When you have finished type ESC, and if the expression is legal the value will be displayed.  If there is an error in the expression you will get an error message and the marker bar will be repositioned at the point of the error.  In an expression you can use any variable name, structure tag or typedef name that is in scope in the function.  If you want to add expressions using a variable in an inner block, you will have to add the expression to the appropriate inner block.  The easiest way to get the inner block object displayed is to click on a variable in the inner block in the source region.  Once it is displayed select the block header and click on Add expr in its menu.  You can ‘bump’ numbers in expressions in a similar way to array subscripts.  Hitting ^J (control-J) over a number while editing an expression increases the digit to the right of the marker bar and displays the new value of the expression.  Similarly ^K (control-K) decreases the digit to the right of the marker bar an redisplays the expression value.  Expressions are reevaluated like variable values every time the target stops.  They also disappear like variables when the target exits or the function they are attached to returns.  In a future release of ups expressions in the display area will be made less ephemeral.  Expressions have the same menu associated with them as variables, and you can have both expressions and variables in the same selection.  The ‘∗’ and ‘&’ menu commands don’t work on expressions, but all the others work as they do on variables.  This means in particular that if you add an expression whose type is ‘pointer to struct’ (or union) you can use Expand to show the structure elements.  You can also use Format to change the format used to display the expression value.  You can’t call target functions or modify target data in a display area expression (thus operators like ‘++’ are illegal). 

ADDING INTERPRETED CODE

The ups display area gives a good picture of that state of a program at any one time.  Often though, you want a record of what happened over a series of calls of a function.  This is one of the reasons why people still tend to put print statements in code despite the availability of debuggers and the inconvenience of recompiling the code.  To make it easier to add diagnostic output statements, ups allows you to insert fragments of C code at any breakpoint.  The default breakpoint action − stopping the target − is represented as a fragment of pseudo C code.  This is the

#stop;

line that appears in the source region when you add a breakpoint. You can change this to a fragment of C code, editing the text in the usual way by clicking the middle mouse button to position a marker bar. You can use the RETURN key to enter multi-line code fragments. As with other editable fields, you end the edit with ESC. If there is an error in the code, an error message is given and the marker is positioned at the point of the error. For example, you could change the breakpoint action to:

printf("Entered function foo with x = %d\n", x);

From now on, whenever the target reaches this point in the program, it will call printf rather than stopping.  Note that a breakpoint will not stop the target unless the special keyword #stop is executed.  You can use this to set conditional breakpoints, like:

if (i == 72)
#stop;

or, to use a more sophisticated example:

if (strcmp(p->p_name, "foo") == 0)
#stop;

In the above examples, the function calls (printf and strcmp) are implemented as calls to functions in the target.  You can call any target function from a breakpoint, but in the current version of ups all functions are assumed to return int.  You can often get around this by casting the return value to the correct type.  One problem with calling functions like printf to do diagnostic output is that the output is mixed up with the normal output of the target program.  If you want the output kept separate, use the built in ups function $printf.  This function creates a new region in the ups window the first time it is called, and sends output to that region.  The menu at the top of the region allows you to search for regular expressions in the output, as well as page through it and clear all output.  The $printf function takes the same format string as printf, with one addition.  The ‘%v’ format string can be used with any variable type, and means print in the default ups format for the type.  The ‘%v’ format character will print symbolic names for enum values and function pointers (i.e. you will get output like RED and close_callback rather than 23 and 0x5e748.  In addition ‘%v’ applied to a struct or union pointer will print the names and values of all the fields of the pointed-to struct or union.  You can declare your own variables in breakpoint code.  This is useful when you want only want to stop at a breakpoint after it has been hit a given number of times.  A code fragment to do this would look something like:

{
static int count = 0;
 if (++count == 74)
#stop;
}

This would stop the target the 74th time the breakpoint was encountered. Static variables are reinitialised every time the target is started. Automatic variables are uninitialised and do not preserve their values between separate executions of breakpoint code. You can mix C interpreter variables with real target variables in expressions in breakpoint code, with some restrictions. You can assign to target variables, but making a target pointer point at an interpreter variable will not work, as interpreter variables do not exist in the target’s address space. On the other hand, the interpreter knows about the target address space, so you can point interpreter variables at target variables. Note that you can only add interpreted code − you can’t directly affect the flow of control of the compiled code.  For example adding a return statement will not cause the compiled function to return to the caller.  It is sometimes possible to indirectly affect the flow of control by judicious changes to variable values.  You cannot add C interpreter variables to the display; clicking the left mouse button anywhere over breakpoint code just selects the corresponding breakpoint object in the display area.  This may change in future releases of ups.  [ You probably want to skip this paragraph. ] For people who want to live at the ragged edge, the C interpreter uses copy-in copy-out semantics when passing interpreter addresses to the target.  If you pass an argument of type pointer to T to a compiled target function then the interpreter copies sizeof(T) bytes to the target address space and passes a pointer to that copy.  When the target function returns the same number of bytes are copied back from the target into the interpreter address space.  Similarly when you pass an array, the contents of the array are copied in and out.  Note that this mechanism does not work in general − it only copes with passing an array or a pointer to a single object.  The main motivation for this feature was to make string literals (e.g. "hello") work as expected when passed to target functions like strcmp. 

EXAMINING LINKED DATA STRUCTURES

Ups has several facilities that are useful for examining linked data structures.  Firstly, you can expand structures or structure pointers.  By repeatedly expanding structures you can follow down a linked list or tree.  Often this adds too much information to the display, as you are probably not interested in all the structure elements.  There is a more selective method of expanding lists and trees which lets you easily see just the elements you want.  Suppose you have a structure declaration like this:

struct linkst {
struct linkst ∗li_prev, ∗li_next;
int li_key;
};

Suppose also that you have a variable linkptr displayed which is a pointer to this structure.  If you type in a ‘.’ followed by the name of element, such as li_prev, that element of any selected structures or structure pointers will be added to the display and selected when you hit ESC.  Assume linkptr in the example above is displayed and selected.  Typing .li_next followed by ESC will add the li_next field of linkptr to the display and select it, and deselect linkptr.  Typing ESC again will add the next element of the list.  Thus by repeatedly typing ESC you can easily walk down a linked list.  You can give many structure elements separated by spaces.  Thus the line

.li_key .li_next

would add both fields to the display. In this way you can walk down a linked list with members of interest displayed as well as the links. One problem with this way of looking at lists is that the indentation of structure elements tends to make the list wander off the right hand side of the display area. To avoid this you can say ‘@member’ rather than ‘.member’. The ‘@’ character means do not indent − this is the only difference between it and ‘.’. Thus to get a nicely laid out list in the example above you could enter the line:

.li_key @li_next

and keep typing ESC to walk down the list. One last wrinkle: if you add ‘#nnn’ to the end of the typing line, where ‘nnn’ is a decimal number, the effect is as if you had pressed ESC that number of times. This is handy if you want to see all of a 500 element linked list without having to type ESC 500 times. In C interpreter code (described in the previous section) you can scan through a linked list as if it were an array using the (non-standard) ‘->[count]’ operator.  This is a shorthand for applying the ‘->’ operator count times.  You can use ^J and ^K as described in the previous section to bump the count parameter up or down and step through a linked list one element at a time.  Thus in the example above, adding the following expression to the display area:

linkptr->[0]li_next

would just show the value of linkptr (the -> operator is being applied zero times).  You can expand the structure and add and delete elements to get the display set up as you like.  Then you can edit the ‘0’ to ‘1’ to see the next element of the list, and so on. 

ENVIRONMENT VARIABLES

By default the target inherits the same set of environment variables as ups .  You can change this using the Environment object in the display area.  Any changes to the target environment take effect the next time the target is started.  Selecting the Environment object produces a menu with the commands Expand, Collapse, Add entry and Reset env.  The Expand command adds an entry to the display area for each environment variable.  You edit an environment variable name or value by clicking on it in the normal way with the middle mouse button.  Collapse removes all the entries from the display area.  To add a new entry select Add entry from the environment menu and type in the ‘name=value’ string.  Ups will accept any string as an entry, but gives a warning for odd-looking entries.  If you wish to abandon any changes you have made to the environment select Reset env.  This resets to the environment to the state it was in when ups was started.  If you select an individual environment entry you get a menu with the options Hide, Delete and Append entry.  The Hide command removes the entry from the display but not from the environment.  This is useful for clearing the display of uninteresting entries.  By contrast the Delete command removes the entry from the environment.  The Append entry command allows you to add a new environment variable just after the one selected; this is useful if you need the environment set in a particular order. 

SIGNALS

When the target gets a signal control returns to ups.  Depending on the signal and the way you have specified it should be handled, the target is either stopped or restarted (possibly with a display refresh), and the signal can either be passed on to the target or ignored.  Near the top of the main display area is a Signals object.  Selecting this produces a menu with Expand and Collapse as options.  Expanding the signals object produces a list of all signals, with the current way the signal is handled displayed for each signal.  Selecting a signal produces a menu which lets you change the way it is handled.  You can control whether a given signal causes ups to stop the target, refresh the display and continue the target or just continue the target without refreshing the display.  You can also control whether the signal should be passed on to the target.  You can trim the signals display by selecting the ones you aren’t interested in and clicking on Hide in the signals menu.  This will remove those signals from the display area.  The ‘Next’ and ‘Step’ commands both step over functions called as a result of a signal.  Breakpoints in signal handling functions work normally. 

X AND SUNVIEW COMMAND LINE FLAGS

Under SunView ups recognises the standard SunView tool flags.  These can occur anywhere on the command line.  Under X ups recognises most common X11 command line arguments.  The currently recognised flags are:

−iconic
Start up as an icon rather than as a window.

−display displayname
Create a window on the named display rather than using the value of the DISPLAY environment variable. 

−geometry geometry
Use the specified X geometry for the window.

−name name
Use name rather than the default ups as the window and icon name.  This name is also used when fetching X defaults. 

−fn fontname
Use X font fontname rather than the default. 

−fg colorspec
Use colorspec (which should be a standard X11 color specification) as the color of the foreground pixel. 

−bg colorspec
Use colorspec as the color of the background pixel. 

−rv Reverse the foreground and background pixel colors.  These options are available under X and SunView:

−mono
Force monochrome mode even if when using a color display. Use this flag to stop ups interfering with the colormap on pseudocolor displays (e.g. when you are debugging a program with a colormap related problem).  The flag is also useful on some Sun displays under SunView where using monochrome significantly increases the display speed. 

−wn_record filename
Record mouse and keyboard events in file filename.

−wn_replay filename
Read mouse and keyboard input from file filename rather than the mouse and keyboard.  The file filename must have been created with the −wn_record flag in a previous session. 

−wn_replay_warp
When replaying events with −wn_replay, warp the mouse in the ups window to reflect the recorded mouse movement events. 

X RESOURCES

Ups recognises a number of X defaults.  By default it uses the last pathname component of the name you run it with as the application name when looking up resources (i.e. if you run it as ‘/usr/bin/ups’ it will use ‘ups’).  You change the name with the −name flag described above.  If it fails to find a resource with the application name, ups does a lookup using ‘Ups’ (note the initial upper case letter).  A resource specified as ‘Ups.xxx’ will thus always be noticed.  Finally ups looks in the resource file /usr/lib/X11/app-defaults/Ups if a resource is not found anywhere else.  The current list of recognised resources is:

Font The name of the normal font.  The default is ‘fixed’. 

MenuFont
The font used for menu captions. The default is to use the normal font.

SrcFont
The font used for text in the source window. The default is to use the normal font.

EditFont
The font used for editable text in the source window. The default under X11 is ‘-∗-fixed-bold-r-normal--15-140-∗-∗-∗-∗-∗-∗’. Under SunView the default is ‘screen.b.14’.

Foreground
The color of the foreground pixel. The default is whatever the BlackPixel macro returns for the display. 

Background
The color of the background pixel. The default is whatever the WhitePixel macro returns for the display. 

ReverseVideo
If this is set (to anything) it has the same effect as the -rv flag. 

Geometry
The size and (optionally) position of the ups window.  The default is to suggest to the window manager a window 650 pixels wide by 550 pixels deep at a user-specified position.  Most window managers will of course let you sweep out a window of the size you require. 

EditlinesColor
The color used for editable text in the source window. The default is yellow.

HighlightColor
The color used to highlight variables in the display area whose values have changed since the last time the target stopped. The default is yellow.

MouseholeWidth
The width of the mousehole in pixels.

PermanentMenuWidth
The width of the ‘Quit’ menu in pixels.

ScrollbarWidth
The width of all the scroll bars in pixels.

SrcwinNameWidth
The width in pixels of the box above the source window containing the current source file name and line number.

SrcwinPercent
The percentage of the window height used for the source window (after space used by the fixed size regions is subtracted). The default is 50 (i.e. half).

DisplayAreaPercent
The percentage of the window height used for the display area (after space used by the fixed size regions is subtracted). The default is 50 (i.e. half). If DisplayAreaPercent and SrcwinPercent are both set they need not add up to 100 − the values actually specify a proportion of the total.  Thus setting both to 20 (or any pair of identical values) results in a 50-50 split. 

OutwinPercent
The percentage of the window height used for the output window if and when it is added. The default is 50 (which actually means a third of the total − see the note about SrcwinPercent above. 

WantTypedefs
If this is set to ‘no’, then ups will not attempt to use typedefs in display area variable declarations.  See Use of typedefs in the CONTROLLING THE DISPLAY OF VARIABLES section. 

TabWidth
The width in characters of a tab character (for use in the source window). The default is eight.

UseMono
If this is set to ‘yes’ then ups will always use mono even on colour displays.  This resource has exactly the same effect as the −mono flag (see above). 

SEE ALSO

cc(1), f77(1), ld(1), dbx(1)

BUGS

On the SPARC you can’t step or next through the return statement of a function returning a struct or union (functions returning pointers to structs or unions work fine).  This is due to the peculiar and undocumented protocol that the SPARC uses for returning structs and unions by value.  On the SPARC you get surpising behaviour if you use in interpreted code a struct or union that is a formal parameter.  Your interpreted code must be written as if the variable is a pointer to a struct rather than a struct.  This is again due to the SPARC structure passing protocol.  The SPARC C compiler emits an inline loop to implement structure assignmemt for large structs.  Because of the way next and step are implemented in ups you have to hit Next or Step several times to step over a line containing such a struct assignment.  Workaround: use Execute to here to get to the next line.  If you change a binary while you are debugging it ups will get very upset (read: will probably core dump with a fatal error message).  This is unsatisfactory and will be fixed in a future release.  The Step command does not step into routines from SunOS shared libraries - it steps over them as if Next had been selected.  Breakpoints in shared library routines do work, however.  Core files dumped from dynamic executables are incomplete which means that you can only examine the non shared parts of the binary.  The Stop button in the target menu doesn’t work if you are hitting lots of fragments of interpreted code that don’t stop the target.  If you resize the ups window while you are in the middle of an edit, the edit is cancelled.  There should be a way to remember breakpoint code and other configuration information between sessions.  This will be added in a future major release.  Expressions and variables in the display area should be less ephemeral. 

ACKNOWLEDGEMENTS

The regular expression matching algorithm was written by Ozan S. Yigit of the Department of Computer Science, York University. 

AUTHORS

Mark Russell, University of Kent.  Original version for the ICL Perq and many of the important ideas by John Bovey, University of Kent. 

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