SIX12 User's Manual Version 8 BLISS-36 Compatible Version TOPS10/TOPS20 Compatible Version NOTE This version of SIX12 has removed much of the prior support for code produced by BLISS-10, in favor of improvements to the Bliss-36 support and simplicity of the implementation of SIX12 functionality. - 1 - SIX12 User's Manual Page ii CHAPTER 1 INTRODUCTION 1.1 ACKNOWLEDGEMENTS . . . . . . . . . . . . . . . . . . 1 1.2 SIX12 OVERVIEW . . . . . . . . . . . . . . . . . . . 1 1.3 ADVANTAGES OF SIX12 OVER DDT . . . . . . . . . . . . 3 1.4 DISADVANTAGES OF SIX12 . . . . . . . . . . . . . . . 3 1.5 CAVEATS FOR BLISS-36 USERS . . . . . . . . . . . . . 4 CHAPTER 2 BASIC SIX12 CHAPTER 3 SIX12 EXPRESSIONS CHAPTER 4 BASIC BLISS OPERATORS 4.1 ASSIGNMENT IN SIX12 . . . . . . . . . . . . . . . 13 4.2 STRUCTURE ACCESSES . . . . . . . . . . . . . . . . 14 4.3 NUMBERS, NAMES AND STRINGS . . . . . . . . . . . . 14 CHAPTER 5 PEEKING AND POKING CHAPTER 6 BREAKPOINTING, TRACING CHAPTER 7 GETTING IN AND OUT OF SIX12 7.1 GETTING IN . . . . . . . . . . . . . . . . . . . . 24 7.2 GETTING OUT . . . . . . . . . . . . . . . . . . . 25 7.3 KNOWING WHERE YOU ARE . . . . . . . . . . . . . . 26 CHAPTER 8 CONCERNING DDT 8.1 CONTROL TRANSFERS BETWEEN SIX12 AND DDT . . . . . 28 8.2 CAUTIONS WITH DDT BREAKPOINTS . . . . . . . . . . 29 8.3 MODIFYING ACS FROM DDT . . . . . . . . . . . . . . 29 CHAPTER 9 CONSOLE INPUT MONITORING CHAPTER 10 MONITORING VARIABLES CHAPTER 11 MACROS AND SYMBOL DEFINITION CHAPTER 12 LINE PRINTER AND DISK I/O - 2 - SIX12 User's Manual Page iii CHAPTER 13 DISPLAY 13.1 DISPLAYING ROUTINE-CALL STACK . . . . . . . . . . 39 13.2 SYMBOL-TABLE SEARCHING . . . . . . . . . . . . . . 40 13.3 EXAMINING THE STATE OF SIX12 . . . . . . . . . . . 41 13.4 WRITING YOUR OWN PARAMETER DISPLAY . . . . . . . . 43 CHAPTER 14 CONDITION HANDLING CHAPTER 15 APR ERROR RECOVERY CHAPTER 16 MISCELLANEOUS OPERATORS CHAPTER 17 USING SIX12 17.1 GENERAL USAGE . . . . . . . . . . . . . . . . . . 51 17.2 LINK-TIME OPTIONS . . . . . . . . . . . . . . . . 52 17.3 TOPS-10 USAGE . . . . . . . . . . . . . . . . . . 52 17.4 SIX12 AND OVERLAYS . . . . . . . . . . . . . . . . 53 17.5 SIX12 AND USER UUO HANDLERS . . . . . . . . . . . 54 CHAPTER 18 DEFINING YOUR OWN OPERATORS 18.1 WHAT DEFINES AN OPERATOR . . . . . . . . . . . . . 56 18.1.1 Important Restriction . . . . . . . . . . . . . 58 18.2 DEFINING OPERATORS FROM SIX12 . . . . . . . . . . 58 18.3 DEFINING OPERATORS FROM A USER PROGRAM . . . . . . 59 APPENDIX A GLOBAL ENTRY POINTS, VALUES AND DATA AREAS APPENDIX B BUILDING A SIX12 B.1 UNUSUAL REGISTER ALLOCATIONS . . . . . . . . . . . 64 APPENDIX C ERROR MESSAGES Index - 3 - CHAPTER 1 INTRODUCTION This document is intended as a from-scratch introduction to SIX12, an extensive debugging aid for Bliss programs on the DEC-System 10/20. It applies to the version of November, 1981. 1.1 ACKNOWLEDGEMENTS A great deal of credit for the development of SIX12 goes to R. K. Johnsson, C. B. Weinstock, W. A. Wulf, T. Lane and J. M. Newcomer, all from Carnegie-Mellon University (CMU). SIX12 began as a symbolic debugger for Bliss-10, which was also developed by CMU. Many of the changes are the work of Ron Brender of Digital Equipment Corporation. These include the changes for Bliss-36 support and TOPS-20 I/O, the multiple configurations which produce the several versions of SIX12 for the cross-product of Bliss-10 and Bliss-36 support for TOPS-10 and TOPS-20 operating systems, cleaned up display formatting, enhanced displays of status, and the ability to access actual parameters and local variables. Joe Newcomer (CMU) added the single-step support, polling override, module qualification, online help, STORE/RECALL facility, WATCH command, and condition handling facilities. This version was re-written in Bliss-36 by Digital. It is supplied with the BLISS V3 release as a favor to the user-community, and it is not a supported part of the BLISS product. Most of the Bliss-10 specific support has been removed and a considerable amount of internal documentation and clean-up has been done. 1.2 SIX12 OVERVIEW SIX12 is a specialized debugger adapted to the Bliss environment. It is not intended as a substitute for DDT; the user is expected to link both with his program and use whichever is more convenient to the need of the moment. Under this assumption there has been no attempt to duplicate functions already well-performed by DDT, namely - 1 - INTRODUCTION Page 1-2 o breakpointing and tracing at the instruction level. o symbolic typeout and typein in any mode required (at last count DDT could display or accept values in over a dozen different modes). SIX12 is oriented to the Bliss programming environment in two ways: o It conforms to Bliss philosophy and notation. A debugging command is syntactically an expression, which is read in, evaluated, and the value (if any) printed. However, much modification has been made to the Bliss syntax in the interests of flexibility. In particular, an expression is not required always to yield a fullword value. It may yield no value, or a vector value of several words. Also the syntax accepted for operators has been expanded to include nullary operators, which have no operands, and postfix operators which follow their operand. For example, A AND 7 uses the infix operator "*AND*" . uses the prefix operator "*." GO uses the nullary operator "*GO*" 137/ uses the postfix operator "*/" BREAK R1,ERROR,PRINT uses the prefix operator "*BREAK*", which accepts a vector operand. A higher-priority infix operator "*," is used to form the vector from elementary operands. (As demonstrated in the last example, with this syntax we can get by without any keyword forms (for declarations etc.) at all. To SIX12 everything is an operator or operand. The user will find it more convenient, of course, to visualize commands formatted in this way as keyword followed by a list of arguments.) o SIX12 is routine-oriented. By this we mean that breakpointing, tracing, and similar functions dealing with flow-of-control all occur at the abstract routine level, rather than at the individual machine instruction level (as in DDT). In still another way: the smallest unit of code that SIX12 can see is a Routine. Breakpoints must always be set at either the entry or exit of a routine, and tracing of execution is always in terms of routine calls and returns. DDT is used when code must be dealt with below the routine level. - 2 - INTRODUCTION Page 1-3 1.3 ADVANTAGES OF SIX12 OVER DDT SIX12 has the following advantages compared to DDT: 1. Source language debugging. SIX12 accepts Bliss-like notation, and does tracing and breaking in a form easily relatable to the original source program. 2. Facilities that DDT does not provide, for instance - the ability to monitor data (not instruction) locations and report when they are modified, - the ability to interrupt the program on console input. If any line-break character (e.g., escape, linefeed, etc.) is typed while the program is executing (i.e., when not in TTY input wait), SIX12 will be entered and will prompt for debugging commands. 3. Extendability. SIX12 permits easy definition of new operators; in addition simple macros can be defined and used in expressions. 4. SIX12 can be used to debug in shared high-segments. The SIX12 linkage has been designed so that two or more people can be debugging the same or different routines, and still others running without using the debugger, all in the same high-segment without interference. DDT breakpoints cannot be used in shared code. 1.4 DISADVANTAGES OF SIX12 SIX12 has the following disadvantages compared to DDT: 1. No access to program at machine code level. 2. Limited variety of modes for symbolic typeout or typein of values. 3. Speed, or rather lack of it. SIX12 requires some computation at every routine call or return, while DDT requires time only at breakpoints (and less time at that). 4. Space required. SIX12 uses about 18P (9K) in the high segment and 7P (3.5K) in the low segment, besides the 2K low-segment space for DDT, and the program-dependent low-seg space for the symbol table (which, however, is required even for DDT). - 3 - INTRODUCTION Page 1-4 NOTE The first two of these are alleviated by the ease with which one can pass from SIX12 to DDT and back. Thus the full facilities of DDT are still available to the SIX12 user. 1.5 CAVEATS FOR BLISS-36 USERS Although SIX12 has been enhanced for use with Bliss-36, for example, by extending the syntax of identifiers, the addition of Block and Blockvector types of access, and condition handling, Bliss-36 users may be confused by some of the syntactic features of SIX12 which are based on its original design for use with the Bliss-10 language. Some equivalents are given in the table below. There are currently no plans to modify SIX12 to eliminate these inconsistencies. Bliss-10 Bliss-36 SIX12 -------- -------- ----- "X" %C'X' "X" 'abcde' %ascii 'abcde' 'abcde' @ . . #773 %O'773' 773 (base 8) #773 (base 10) 978 978 #978 (base 8) 978 (base 10) ?.JBREL %name('.JBREL') ?.JBREL &JBREL ?%CNVR _CNVR _CNVR %name('%CNVR') ?%CNVR ?$GTMEM $GTMEM $GTMEM A = 5 A = 5 A = 5 A _ 5 - 4 - CHAPTER 2 BASIC SIX12 This chapter is a first-time introduction to SIX12, and for details of the commands you should consult the referenced sections. You must first compile your main module with SIX12 linkages (the DEBUG switch declaration in the module head). Failure to do this is the most common beginner's error, and results in the runtime message: ?Halt at user PC On TOPS-10 or ?Illegal instruction 37000,, at On TOPS-20 ?Undefined operation code If you look at the address given, you will find a DEBUG. instruction, opcode 037 octal. Recompile your main module with the /DEBUG qualifier and relink your system. There are many versions of SIX12 which can be linked into your program. These are selected by such options as TOPS-10 or TOPS-20 support, BLISS36C or BLISS10 linkages, etc. The complete set of options are described in Appendix C. Any time you are in SIX12, as indicated by the & prompt, and want to resume execution of your program, type *GO*. Control returns to your program where it left off. There are several common ways of entering SIX12: 1. When your program starts to run, it enters SIX12 before calling your main routine. 2. If at any time you type a line-terminating character to TOPS-10 or any character to TOPS-20, SIX12 will take control at the next routine entry or exit (this can be disabled). 3. A routine entry or exit occurs at which a breakpoint is set. - 5 - BASIC SIX12 Page 2-2 The complete list of SIX12 entry and resumption techniques is given in chapter 7. The most common operations are examining and modifying locations. The "*/" operator[1], "*!" operator, and "*." operator all allow you to examine locations: &foo/ foo/ 1234 == baz+23 &.foo 1234 == baz+23 & This shows examining the location whose name is foo. The value is printed out both in the prevailing radix (normally octal) and in symbolic form. To examine multiple locations, use the *!* operator (chapter 5) which takes the number of locations to examine: &foo!3 foo/ 1234 == baz+23 foo+1/ 0 == 0 foo+2/ 1235 == baz+24 & To modify a location, use the assignment operator *=* (chapter 5). Remember Bliss is an expression language, so use parentheses to force proper evaluation: &foo = .foo + 5 1241 == baz+30 &(foo+1) = 1 1 == 1 & Another very common operation is to set breakpoints or trace routines. To do this, use the *BREAK* or *TRACE* commands; these take the names of routines to break at or trace: &break foobar,thud &trace gorp & You can also set a breakpoint or tracepoint after a routine by using the *ABREAK* or *ATRACE* commands and remove breakpoints or trace requests by using the *DTRACE*, *DBREAK*, *DATRACE* or *DABREAK* commands. You can single-step your program by using the command; ------------------------------ [1] chosen for similarity to DDT - 6 - BASIC SIX12 Page 2-3 execution progresses routine-by-routine for each given. If you get to some routine entry and know that nothing interesting is going to happen (say, an output routine), use the *OK* command to execute that routine and all the ones it calls without single-stepping thru them. You will get control at the next breakpoint or at the end of the routine you give the *OK* to, whichever comes first. The complete list of breakpointing and tracing options is given in chapter 6. When you are at a breakpoint, the *CALLS* operator will print the entire call stack; or use *CALL* to print out the most recent calls on the stack. Complete details of displaying information are given in chapter 13. The *MONITOR* command lets you "continuously" check several locations to see if they change (the check actually occurs at every routine entry and exit). See chapter 10. The *WHERE* command lets you find out the module and location of some octal value (such as is printed out when an illegal memory reference is taken). You now have enough information to start successfully using SIX12. - 7 - CHAPTER 3 SIX12 EXPRESSIONS At the lexical level, SIX12 treats lower case and upper case identically, so commands may be typed in either case or a mixture of both. In addition, SIX12 will recognize any unique abbreviation (two characters minimum) for any of its alphabetic operators. Thus, all of the lines below say the same thing: IF |.A LSS .B| BREAK FOO,BAZ if |.a lss .b| break foo,baz if |.a ls .b| BREAK foo,baz if |.a ls .b| br foo,baz SIX12 contains a fairly intelligent syntax analyzer/evaluator which can evaluate quite complex expressions. For instance, all of the following are legal Bliss expressions; they are also legal in SIX12 and would produce the same result. .ALPHA SUM = .SUM + 3 NOT .FLAGS<1,1> MYROUTINE (7, .B, XYZ()) SUM = 0; COUNT = .COUNT + 1 The syntax analyzer recognizes two classes of objects: operators and operands. The meaning of operators is not built into the analyzer, but is defined by a table of routines which are to be called to evaluate them. This makes it simple to add new operators or redefine old ones; this can even be done at runtime if the necessary routines are compiled and linked separately with SIX12. (The methods for defining your own operators are discussed later; we assume everywhere in this document that you have not tampered with any standard operators.) The meaning of operands, however, is built into the analyzer. The possible types of operand are - 8 - SIX12 EXPRESSIONS Page 3-2 A is a sequence of digits, possibly preceded by a number sign *#. Its value is the equivalent signed, two's complement binary integer. The number is assumed to be written in the default radix or base, which can be set or examined by the standard operator *BASE*. The escape character *# is provided to ease the use of two radices: a number preceded by *#* is taken to be written in octal radix regardless of the default radix, unless the default radix is octal, in which case the number is taken as decimal. For example, Default Radix Input Value ------------- ----- ----- 10 (decimal) 34 000042 octal 10 #34 000034 octal 2 (binary) 10110 000026 octal 2 #34 000034 octal 8 ( octal) 34 000034 octal 8 #34 000042 octal Thus when the default base is decimal, this is the same as the Bliss-10 source convention. When SIX12 is initialized, the default base is octal (as with DDT). Strings are entered as 'string' or "string" corresponding to left- and right-adjusted ASCII strings respectively. In either type of string the other string delimiter can appear freely, and double occurrences of the string delimiting character are used to denote it once. This is precisely the same as the Bliss-10 convention. However, note the following differences: o ? is not implemented as an escape character (not relevant for Bliss-36 users). o Carriage return cannot appear in a string; it terminates the string just as if the matching delimiter had been encountered (CR or LF always terminate debug input expressions). o %RADIX50_10, %ASCIZ and %SIXBIT stringtype converters have not been implemented. (They could be easily included by defining appropriate operators). Examples: 'HI!' "Q" 'a CR or LF terminates me anyway A long-string, as in the last example, generates a vector value which may be larger than a bliss-value. This is most useful in conjunction with user-defined operators. (See chapter 18) - 9 - SIX12 EXPRESSIONS Page 3-3 Symbols are the most complex type of operand. A symbol is looked up in the Linker-generated symbol table, and its value is the value entered for it in the table. Thus a name is an address, as in Bliss. DDT has a complex search convention to deal with the problem of multiply defined symbols (which exists because the table only contains six characters of a name, and/or because the same local name can be defined in many modules). SIX12 uses this much simpler rule: identical symbols are implicitly numbered in the order in which they are linked. If there exists more than one symbol with the same name, the name must be "qualified", either suffixed by *%*n, where n is the ordinal you want, or prefixed with a module name if the name is unique within that module. This is discussed in detail in section 4.3 Examples: HELPME Value of the symbol 'HELPME' LOTSOFME%5 Value of fifth symbol 'LOTSOF' FOO\LOTSOF Value of 'LOTSOF' in module 'FOO' LOTSOFME Error - ambiguous There are symbol table searchers included in the standard set of operators to help you decide which ordinal you want, or remember what name you need in the first place. See chapter 13. Since names (letter-digit strings) can also refer to operators (e.g., *AND* *OR*) the *%*-convention is also used to distinguish symbols from operators. An unadorned name is first searched for in the macro table, then in the table of operators, and finally in the symbol table, taking the first match in the process. However, *%* (for greater than 0) is only searched for in the symbol table. Thus "*OR%1*" always gets you the symbol "*OR*" but "*OR*" is taken for the operator *OR*. Since Bliss-36 maps underscore ("_") into percent ("%") and period (".") into dollar-sign ("$"), SIX12 also performs this conversion. Thus, if you declare OWN meta_1 ; DDT will display this as "META%1", while SIX12 will know this symbol as "META_1". The SIX12 symbol "META%1" refers to a different symbol, namely the first occurance of "META" in the DDT symbol table. Further note The only source of program symbols that SIX12 has is the Linker symbol table (also used by DDT). Therefore, locals, formals, structures, and so on are unknown to SIX12. Only GLOBAL, OWN, link-time constant BIND, ROUTINE and MODULE names will be present in the table. - 10 - SIX12 EXPRESSIONS Page 3-4 We have now fully discussed operands, and turn to the operators which work upon them. Operators are denoted either by names (e.g., *GEQ*, *BREAK*) or by special characters (e.g., *% + *). In the latter category, *' " # %* may not name operators. The syntax analyzer distinguishes four syntactic types of operators, namely Nullary, having no operands: Prefix, preceding its operand: Postfix, following its operand: Infix, having both operands: The same symbol may represent more than one operator in different parses. For example + E E + F show "*+*" in prefix and infix parses; these two instances will actually result in the invocation of two different routines to evaluate "*+*". In theory the same symbol could be given all four parses, invoking one to four different routines; in practice this is a poor idea. An operator with more than one parse can introduce ambiguity: the classic case is with "*/*", which in the standard definition has postfix ("*A/*" prints contents of A, as DDT would) and infix ("*A/B*" does division) parses. Now, does A/-N invoke postfix "*/*" followed by infix *"*-*"*, or prefix *"*-*"* followed by infix "*/*"? With the definitions given above the second is clearly the correct choice, but the analyzer can hardly be expected to know that. In point of fact this will be evaluated in the first way, due solely to an arbitrary design decision. The moral of this story is that the analyzer cannot be expected to always do the right thing. It works fine for pure Bliss expressions; a key thing is to be wary of using expressions which yield a null value (as *x/* does) in larger expressions. The analyzer assumes that operators will yield a value, and gets confused when they don't (since its assumptions about the parsing of subsequent operators must be junked). If an expression with side-effects blows up, always check to see how much of it had already been evaluated. Two good rules to keep out of trouble are 1) parentheses can fix lots of things, and 2) avoid semicolons - you can afford to do it on two lines. With these words of warning we pass to a description of the standard set of operators. This is the meat of what you can do with SIX12. - 11 - CHAPTER 4 BASIC BLISS OPERATORS We do not pretend to have implemented a Bliss interpreter. However, a fair subset of the simple expressions (*not* control expressions) is available, and more could be implemented if you need it. The following operators are defined exactly as in Bliss: + - for example -E1 E2+E3 * / as A*B (beware of E/, which is not an error) ^ as in A^B (shift) [1] ( ) as in Bliss: AND NOT OR logical operators GEQ thru LSS relational operators () Grouping indicator or as routine callers () Routine call For instance 5*(.ALPHA-1) MYROUTN(41, .PARM) (.RTNVEC[.I])(.parm1+5,22) The value of the second expression is the value returned by calling ------------------------------ [1] In Bliss-36, *^* is a logical shift left and an arithmetic shift right. SIX12 does the appropriate shift. - 12 - BASIC BLISS OPERATORS Page 4-2 the routine *MYROUT* with two actuals. The value of the last expression is the value returned by calling the routine named in the i+[th] position of RTNVEC with the parameters indicated. *< >* have the same meaning, of creating a byte pointer. However, sign-extension is not accepted; there must be exactly two values within the brackets, i.e. [addr]<[position],[size]> is the only allowable syntax for them. . performs the same function, 'contents', as in Bliss. = performs the same function, 'store', as in Bliss. For instance .A1 .FLAG<17,1> SE = .SE * 200 FOO = .A1 + 23 You should be aware, however, of a difference, discussed below in section 4.1 [ ] Perform structure access for simple structures. 4.1 ASSIGNMENT IN SIX12 SIX12 evaluates names as addresses, just like Bliss-36. Because of its Bliss-10 origins, if the left half of a pointer word is zero, it is treated as a fullword pointer in dot or assignment contexts, but words with nonzero left halves are taken as true byte pointers. Extended Addressing Limitation Thus, SIX12 is guaranteed to break in __________ the presence of extended addressing. (The same applies to the *MONITOR*/*WATCH* operation, which may be given either word addresses or byte pointers). The only way this will be noticeable to the user is that sometimes *dot* will act like a CH$RCHAR, and = will act like a CH$WCHAR. In Bliss-10, *.41* will yield zero every time (being equivalent to *.41<0,0>*) but in Bliss-36 or SIX12 it will yield the contents of word *41* (corresponding to *@41* in Bliss-10). Similarly for *41 = E*. Also, to get Bliss-10 semantics for *A = B*, it must be written *A = B<0,36>*. - 13 - BASIC BLISS OPERATORS Page 4-3 If an attempt is made to fetch from or store into an address not in the user's address space, SIX12 will detect this and report the illegal address. TOPS-20 Difference Because of the way TOPS-20 deals with "create on reference" pages, SIX12 may report an illegal address if you attempt to access static storage (using SIX12's fetch or store operators) before your program has "referenced" the memory involved. SIX12 detects illegal addresses by asking the monitor if the pages are "readable" using the RPACS JSYS. If the page has not been referenced yet, RPACS will return "doesn't exist". 4.2 STRUCTURE ACCESSES Brackets *[ ]* with a single parameter do a structure access according to the standard VECTOR structure. Hence *E1[E2]* is equivalent to *(E1+E2)<0,36>*. Brackets with three parameters do a structure access according to the standard Bliss-36 BLOCK structure, and those with four parameters do a structure access according to the Bliss-36 BLOCKVECTOR structure. In addition, if the user sets the contents of *SIXREF* to a true value, the access will be done as a REF-structure rather than a structure access. Perhaps someday we will get structure information from the compiler... 4.3 NUMBERS, NAMES AND STRINGS A number is a sequence of digits interpreted in the current radix (initially base 8). See chapter 16. # A number preceded by a *#* changes to the "other" radix, i.e., if in base 8, the number is interpreted in base 10; if in base 10, it is interpreted in base 8. If the default base is neither decimal nor octal, the # indicates octal radix. See chapter 16. %A Refers to the address of the n'th actual parameter of - 14 - BASIC BLISS OPERATORS Page 4-4 the current routine (when stopped at routine entry or exit). In the example below, the break at routine "TestZero" will occur only if the first actual parameter is zero. &if |.1%A eql 0| BREAK TestZero %L Refers to the n'th local word of the stack frame of the current routine. Local words include any saved register values, stack management control words, etc. that may be allocated after the frame pointer. Consequently, a machine code listing might be required to determine the actual correct offset for a local variable. In particular, Bliss-36 may allocate local variables to the registers. A name is 1 to 6 characters from the set "*A" - "*Z", "*a" - "*z", "*0" - "*9", "$", "&", "*_". The first character must not be a digit. Characters after the first six are not used for name resolution. Lower case letters are converted to uppercase, "&" is converted to "." and "_" is converted to "%". This conversion is used in the Bliss-36 compiler to translate "_" into a character acceptable in RADIX50. Names are looked up in one of three symbol tables in this order: 1. The SIX12 macro table 2. the SIX12 operator/command table 3. the DDT symbol table In the case of multiple DDT symbol tables, where one is in the TOPS-10 high segment and another is in the TOPS-10 low segment, there are more complex rules for symbol resolution in the DDT symbol table. See section 17.4. The value of a name is the address or offset obtained from the DDT symbol table. (Module names, which also occur in the DDT symbol table, are ignored during name lookup). ? ? allows the name which follows to include the characters "." and "%", so the transliteration of "$" is converted to "." and "_" is converted to "%" . Names are typed out using "." and "_". Names are looked up in one of three symbol tables in this order: - 15 - BASIC BLISS OPERATORS Page 4-5 1. The SIX12 macro table 2. the SIX12 operator/command table 3. the DDT symbol table In the case of multiple DDT symbol tables, where one is in the TOPS-10 high segment and another is in the TOPS-10 low segment, there are more complex rules for symbol resolution in the DDT symbol table. See section 17.4. The value of a name is the address or offset obtained from the DDT symbol table. (Module names, which also occur in the DDT symbol table, are ignored during name lookup). ("&" and "_") need not be used. If %n is used after such a name to disambiguate it, a space must separate the %n from the name. The name may also begin with a digit, e.g. "?01$A" is recognized as an identifier. &?.JBSYM 116 == 116 &.?.JBSYM -447765030 == 777330,,PAT..+100 name %n Refers to the n'th entry in the DDT symbol table for the name (for "n" greater than zero). (Module names are ignored and not counted). If a name is unique within a module, it may be qualified with the "\" qualifier (see below). A name which is qualified with "\" may not be further qualified with "%". name %0 Refers to the SIX12 command or operator with the given name. This is required when a macro definition conflicts with a SIX12 operator name, and the operator name is required. module\name Qualifies a name to lie within a module. Thus, if the name is unique in the module, qualification with "%" (see above) is not required. The rules for simple names (e.g., the use of "?" to enable the use of special characters in the name) apply to both the module name and the symbol name. If a QUALIFY command (see chapter 16) is given, the module name (but not the \) may be omitted. &C .^ Multiple entries in DDT symbol table for C &PRS C C%1 400360 Own SIG Routine C%2 5645 Own FOO.. 0 &SIG\C 400360 == C - 16 - BASIC BLISS OPERATORS Page 4-6 Using default qualification to search the SIG module's DDT symbol-table would be done with &QUALIFY SIG &\C 400360 == C &?FOO..\C 5645 == C - 17 - CHAPTER 5 PEEKING AND POKING One basic requirement on a debugger is the ability to examine and modify program locations. The only standard operator for changing memory locations is assignment (=), which should need no explanation. We should point out, however, that SIX12 never associates from right to left. Therefore, A = B = C = 0 will not work in SIX12. In order to discourage accidental use of this construct, the assignment operator is defined to have no value. In the example above, the address of B would be stored into A, then a syntax error would occur since the second = would have no left operand. One Bliss-compatible method for examination of program locations is provided by the dot *. operator. As we mentioned in passing previously, SIX12 prints out the result of every evaluated expression. Thus one need only type .ALPHA to see the contents of ALPHA; for example, a terminal interaction could look like this: &.FLAGS,.PNTR 677 == 677 5737 == FFAREA+5 (Note: & is SIX12's prompt character). A DDT-like notation has also been implemented. The operator "/", used in a postfix fashion, prints out the contents of the fullword whose address is its argument: &STACKCNT/ STACKC/ 566005322 == 566,,SPACE+203 The infix operator "*!" does the same thing for a consecutive set of words; A*!n prints n words beginning at A. For example: - 18 - PEEKING AND POKING Page 5-2 &BUFF!3 BUFF/ 57 == 57 BUFF+1/ 122 == 122 BUFF+2/ 0 == 0 In addition, unless the user has explicitly disabled console polling (see chapter 9), typing any line termination character (TOPS-10) or any character (TOPS-20) will terminate long typeouts. In all cases, values or contents are first printed numerically (in the default radix), then in symbolic halfword format (like DDT $R $H; offsets are in the default radix). Whenever the left half looks like an "interesting" byte pointer[1], the byte pointer values are printed out in decimal following the symbolic name. If the default BASE of 8 is used, a # will precede the values of the position or size designators if they are greater than 7. &IBUFPTR/ IBUFPT/ 4400017360 == IDTREE+316,,BUF+4<0,#36> When an address is given which is outside the user's address space, a ? is printed as a value; for multiword displays, the displaying ceases. &?.JBREL/ .JBREL/ 34177 == 34177 &35000/ 35000/ ? &34176!200 34176/ 0 34177/ 0 35000/ ? & ------------------------------ [1] The definition of "interesting" is subject to change, but presently includes such things as , , , <0,18>, <18,18> and <0,36>. - 19 - CHAPTER 6 BREAKPOINTING, TRACING The other basic requirement for a debugger is the ability to trace execution of a program and stop it ('break') where necessary. As we said earlier, SIX12 does this on a routine level. The operators are given in terms of setting (and later clearing) actions on routines. Any of these actions may be set conditionally. Conditions are fully general because they are given as SIX12 expressions. When required, the text given is evaluated; it must yield 1 in the low-order bit of its value for the action to be taken. (If the expression yields a vector value, only the first word is considered; a test which yields a null value always fails.) For instance, simple conditions might be .FLAGS<17,1> or .CCOUNT GTR 0 Note: it should be apparent that setting a conditional action on a frequently- called routine can cause substantial overhead and significantly degrade execution speed. For simple conditions such as the examples, a conditional breakpoint for which the condition is satisfied executes about 8500 instructions between the breakpoint instruction and requesting input from the user; a conditional breakpoint for which the condition is not satisfied executes about 2500 instructions. The standard syntax for setting unconditional actions is action-name listofroutines e.g., BREAK R2,PRINT,ERR3 The syntax for setting conditional actions is IF |text of condition test| action-name listofroutines e.g., IF |.VALUE<10,1>| TRACE TESTIT where "|" delimits the text which is saved for evaluation. (The $ character could also be used, but you can't backspace over it). Two notes: IF is a noise word and can be dropped. Commas in a list of routines can be replaced by spaces. Never drop commas surrounding - 20 - BREAKPOINTING, TRACING Page 6-2 anything but a simple operand (number,symbol). Thus, in TRACE T34, .PNTR, EXIT the commas are necessary, but they aren't for TRACE T34 EXIT METOO The same applies to commas anywhere else in SIX12 (e.g., routine calls). The syntax for clearing actions is Daction-name listofroutines i.e. same mnemonic with D prefixed, as DBREAK ZURICH This clears either conditional or unconditional action. The actions and conditions for them may be examined with the PRINT ACTION command. Conditional and unconditional actions do not coexist. There cannot be both conditional and unconditional instances of a given action on a given routine, nor can there be more than one condition governing a given action on a given routine. Thus, if a conditional or unconditional break is set on a routine, any previously set break of any type on the same routine is cleared, but other actions, say trace, on that routine are unaffected. For actions which take place after a routine has executed, the value of the routine may be tested. Normally this is in the VREG, but from SIX12 it must be accessed as the variable SIXVREG, e.g., &if |.sixvreg eql 0| abreak getpointer The possible actions are: BREAK list Stop execution at routine entry, with the message <=> At: routine from call-loc Actuals: values ABREAK list Stop execution at routine exit, with the message <=> After: routine Value: value == symbolic DABREAK list Remove ABREAKs from the routines listed. DBREAK list Remove BREAKs from the routines listed. TRACE list Prints a message when routine is entered or left - 21 - BREAKPOINTING, TRACING Page 6-3 without breaking. The messages look like this: --> routine from call-loc Actuals: values <-- routine Value: value == symbolic TRACE AFTER list Initiates trace mode when the routine is entered, so that all routine calls and returns are traced until the routine is exited. The original routine call and return are not traced. (No, Virginia, it won't screw up if the routine is recursive!) TRACE FROM list Equivalent to TRACE plus TRACE AFTER; thus the routine and its subroutines are traced. DTRACE list Remove TRACEs from the routines listed. DTRACE FROM list Remove TRACE FROMs from the routines listed. DTRACE AFTER list Remove TRACE AFTERs from the routines listed. OPAQUE list Tracing and single-stepping are turned off when an OPAQUE routine is entered, and remain off until the matching exit. This lends a degree of abstraction to tracing and single-stepping. OPAQUE 'outranks' TRACE; thus, even if routines with TRACEs set on them are called within the scope of an OPAQUE, they are not traced. OPAQUE AFTER list This does OPAQUE except that the routine itself is traced. Since we know that no trace printout will be required between entry and exit, paper is conserved by not printing a separate tracing notice for exit: --> routine from call-loc Actuals: values Value: value == symbolic (assuming of course that tracing was on when the routine was entered). DOPAQUE list Remove OPAQUEs from the routines listed. DOPAQUE AFTER list Remove OPAQUE AFTERs from the routines listed. COPAQUE This command sets an internal switch so that calls made on user routines from SIX12 will not be traced even if SETTRACE is in effect. This is useful when the user has debug-printout routines which are called - 22 - BREAKPOINTING, TRACING Page 6-4 from SIX12, or has user-defined operator routines which are called from SIX12. If SETTRACE is in effect, it is turned off for the duration of the call. By default, the COPAQUE switch is normally turned off, and must be set by the user. NOCOPAQUE This command resets the internal switch to its default value set at initialization, so that calls on routines made from SIX12 will be traced if a SETTRACE is in effect. TRACE, TRACE AFTER, TRACE FROM, OPAQUE and OPAQUE AFTER control the trace facility during program execution. The user may turn tracing on or off by means of the SETTRACE, CLRTRACE, GOTRACE, and GOCLR operators, overriding OPAQUEs or TRACEs. (see Getting In and Out of SIX12, chapter 7). (The TRACE and OPAQUE operators merely set or reset a switch controlling the printing of trace output. The user can set or clear this switch before resuming program execution.) NOTE Conditional actions set on routine exits may need to test the value which the routine is returning. This value is available as the contents of the global SIXVREG. In general, the user should never attempt to access any registers directly in SIX12 expressions. However, SIXVREG can be treated the same as the VREG (e.g., it can be modified, and the new value will be in the VREG when program execution resumes). Conditionals may also be used to modify the execution of a program in certain restricted ways. For example, consider a routine MOVEIT which is given a pointer to a value, but is expecting a value (as, for example, might be caused by calling it passing the name of a variable instead of its contents). This situation may be rectified as follows: &if |(1%A = ..1%A; 0)| break moveit The compound expression assigns to the first parameter the contents of the word pointed to by the first parameter, and then returns a false value, so the break does not actually take effect. It is not possible, however, to conditionally take actions, for example, to assign the value 10 to a variable if its value is greater than 62. Nonetheless, this technique with conditionals sometimes saves a lengthy recompilation to fix a simple error. - 23 - CHAPTER 7 GETTING IN AND OUT OF SIX12 By getting into SIX12 we mean stopping execution of the user program and causing SIX12 to begin reading and executing user commands. Getting out is the reverse process of resuming user execution. 7.1 GETTING IN - One method of entering SIX12 during execution is through a (previously set) breakpoint; see chapter 6. - Another is through a break caused by terminal input monitoring, or the MONITOR (of data locations) operation. See chapter 9 and chapter 10. - You can enter SIX12 before program execution begins (but after stack initialization) by entering DDT and setting SIXSTA (STARTFLG in module SIX12) to 1. Normally SIXSTA (STARTFLG) is set to a true value, so SIX12 will normally be entered when execution commences. However, if it has been set to a false value (see section 17.2), it may be set true again by the following: .get program .ddt sixsta! 1 $G SIX12 V8-4 (TOPS-10 I/O) for Bliss-36 & Here $ = , and & is SIX12's prompt for an input. Of course, you could also force an exit after making the patch and save the core image. - You can get into SIX12 from DDT by SIXDDT$G. See Concerning DDT, chapter 8. - 24 - GETTING IN AND OUT OF SIX12 Page 7-2 - You can explicitly call SIX12 from your program. Call the external name "SIX12" with one parameter, e.g., external routine SIX12; SIX12( 123 ); ! Fall into Debugger at command-level. SIX12 prints the parameter value and stop location: PAUSE 123 AT & 7.2 GETTING OUT Getting out of SIX12 is accomplished by executing one of 3 operators: GO resumes user program without any special action. GOTRACE turns on tracing before starting. This cancels the effect of any active OPAQUE. Equivalent to typing a SETTRACE and a GO. GOCLR turns off tracing before starting; equivalent to giving CLRTRACE and a GO. RETURN expression The action of this depends on how you got into SIX12. - If you entered by setting SIXSTA (STARTFLAG) and having SIX12 recognize this at program entry, then the expression becomes the value of the CCL flag. - If you entered by an explicit call on SIX12, the expression is the value of the SIX12(x) expression. - If you are at a routine exit, by either setting an ABREAK (including implicit ABREAKs set by STEP and OK), or by MONITOR detecting a change in a variable or by console polling, then the expression becomes the value returned by the routine. - If you are at a routine entry, either by a BREAK (including implicit BREAKs set by STEP) or by MONITOR detecting a change of a value or by console polling, then the execution of the routine is suppressed. Control returns to its caller with the value of the expression. Thus RETURN is useful for hand- simulating unwritten or malfunctioning code. - 25 - GETTING IN AND OUT OF SIX12 Page 7-3 STEP This effectively sets an ABREAK at the current routine, and a BREAK at every routine which may be called from the current routine, then allows execution to proceed much as GO does. This command allows you to single-step through the program. Typing will have the same effect. If single-step execution reaches a routine which is OPAQUE, the single-step breakpoints are suppressed until control returns from that routine. This is extremely convenient for the same reasons OPAQUE is useful for tracing. OK This effectively sets an ABREAK at the current routine, and then allows execution to proceed much as GO does. This command, particularly in conjunction with STEP, allows you to avoid single-stepping through a routine you know already works. 7.3 KNOWING WHERE YOU ARE SIX12 prompts with an ampersand character, &. In addition, assorted status may appear with the prompt: - On nested SIX12 calls, the depth of nesting in SIX12 is printed, 4:& which indicates that this is the fourth recursive call of SIX12. The first level of call would be shown as "1:" except this is so common that the number is suppressed. - If output is going to the line printer (see section 12) and not to the terminal, a "-" is printed to the left of the "&" 2:-& This is so you don't wonder why SIX12 has suddenly stopped printing. If LPTDUP is set, so that output goes to both the terminal and the line printer, then the "-" is not printed. - If NODEBUG mode is set (chapter 16), an N will print to the left, indicating you are in NODEBUG mode. In addition, certain commands will issue a warning message when they are executed. - 26 - GETTING IN AND OUT OF SIX12 Page 7-4 4:-N&break foo Warning: You are in NODEBUG mode 4:-N&ok Operation makes no sense in NODEBUG mode 4:-N&debug 4:-& - 27 - CHAPTER 8 CONCERNING DDT 8.1 CONTROL TRANSFERS BETWEEN SIX12 AND DDT We have not tried to duplicate the many useful facilities already available in DDT. Instead, we have implemented easy transfers between SIX12 and DDT. You can get into DDT[1] from SIX12 by issuing the command DDT To return to SIX12, type SIXRET$X to DDT. If you are in DDT but you didn't get there from SIX12, you can enter SIX12 by typing SIXDDT$G Subsequently issuing GO to SIX12 returns you to DDT. (Clearly, you must not do this if the stack has been destroyed.) A valid stack must be available before calling SIXDDT. If necessary, this can be set using the global symbol SIXSP. SIXSP/ 0 -200,,STACK will set up a stack of 200 (octal) words at location STACK. Once a stack has been set up, SIX12 may be called. If SIX12 has not been initialized, you must initialize it by calling one of the routines SIX10, SIX36C or SIX36, depending upon the version of SIX12 in use. If you enter SIX12 by letting SIXSTA (STARTFLG) have a "true" value, then SIX12 is automatically initialized for you. (It may be necessary to set up a stack even if SIX12 has been initialized, for ------------------------------ [1] In TOPS-10, you must have linked DDT into your program with the /DEBUG linker switch. On TOPS-20, if nothing is mapped at 770000 (octal), SYS:UDDT.EXE is dynamically merged into your address space. - 28 - CONCERNING DDT Page 8-2 example, if the stack pointer register has been inadvertently destroyed). 8.2 CAUTIONS WITH DDT BREAKPOINTS The SIX12 linkage in Bliss-36 produces the following instructions at the head of each routine DEBUG. routine CAI n ; n instructions for routine setup If you set a DDT breakpoint at any of the n instructions following the CAI instruction, it will not be seen. [2] Therefore, to set a breakpoint early in the routine, you must set it somewhere after the n instructions following the CAI. 8.3 MODIFYING ACS FROM DDT If you enter DDT via SIX12's DDT command, the user program ACs are not available. Instead, the ACs contain information peculiar to SIX12. These ACs may be arbitrarily destroyed while inside SIX12, as SIX12 preserves them before it transfers control into DDT and restores them when you return via the SIXRET$X DDT command. To modify the user program ACs, it is necessary to set a DDT breakpoint and modify the ACs at that point. ------------------------------ [2] This is done by black magic; what appears to happen is that DDT will not take a breakpoint instruction which is executed because it is the target of an XCT instruction, and SIX12 uses an XCT instruction to execute the first n instructions of the routine setup. Other explanations may apply. This explanation is not warranted against defects. - 29 - CHAPTER 9 CONSOLE INPUT MONITORING If a line termination character is typed when the program is not in a TTY input wait, SIX12 will shortly fake a breakpoint at some routine entry or exit, and process the line as command input. Unlike earlier versions of SIX12, TOPS-10 does this on a line, rather than character, basis. TOPS-20 does it on a character basis. In addition, long typeouts from some operators, such as !, will be terminated by typing a line termination (TOPS-10) or any (TOPS-20) character. This monitoring is the normal state for SIX12. It can be disabled, permitting type-ahead, by the *DISABLE* operator but will be automatically re-enabled whenever a break occurs (for some other reason, of course). If you issue DISABLE and subsequently regret it (e.g., get caught in an endless loop), you can re-enable monitoring by entering DDT and setting SIXENB (ENABFLG in module SIX12) to 1; the normal procedure is ^C ^C ^T .DDT SIXENB! 1 $G & Here $ = ; & is SIX12's prompt for an input. To permanently disable polling, the *POLLOFF* command can be issued.This permanent disabling can be reset by issuing the *POLLON* command.Usually, the purpose of this is so a system can be released to users with SIX12 still present (very useful for experimental systems). The SIXNPL (NOPOLLFLG) flag controlled by POLLON and POLLOFF can also be set with DDT, so the typical way of setting a file up for users is .get MYPROG .DDT SIXNPL/ 0 1 - 30 - CONSOLE INPUT MONITORING Page 9-2 SIXSTA/ -1 0 calli 12$X EXIT .SAV (or SSAV, or NSAV or NSSAVE) MYPROG saved . The primary distinction between DISABLE and POLLOFF is that DISABLE disables console polling only until the next SIX12 event which calls the SIX12 command interpreter, at which point polling is re-enabled, while POLLOFF absolutely positively disables console polling until SIXNPL is reset either with DDT or the POLLON command. - 31 - CHAPTER 10 MONITORING VARIABLES SIX12 can keep track of the contents of specified program locations, and report when they change. The contents of each location being monitored are compared against its last reported contents at every routine call and return. When any changes are found, SIX12 reports them and, if requested, stops program execution (the same as a breakpoint). The monitoring message is one of *** Before routine-name from caller at an entry *** During routine-name at an exit followed by a list of changes found, in the format M- location Old: oldvalue New: newvalue W- location Old: oldvalue New: newvalue where "M-" indicates the variable was detected by a MONITOR command, and "W-" indicates the variable was detected by a WATCH command. If any MONITOR variable changed, SIX12 stops and enters command mode; if all the variables were selected by WATCH, SIX12 continues executing. The syntax for requesting monitoring is MONITOR listoflocations WATCH listoflocations where each location may be a word address or a byte pointer, as in MONITOR ACCUM, BUFHDR<0,#18>, FLAGS<#30,1>, 41 The syntax for stopping monitoring is DMONITOR listoflocations DWATCH listoflocations For example, the request shown could lead to a message as follows: *** During GETCHR M- ACCUM Old: 122 New: 56 M- FLAGS<#30,1> Old: 1 New: 0 & - 32 - MONITORING VARIABLES Page 10-2 where & indicates that SIX12 is waiting for a command. When the user issues GO, execution will proceed from the exit of GETCHR. NOTE Values are always printed in the default radix. When a monitoring request is not for a fullword, the position and size fields are printed in decimal. The variables being monitored and their current "old values" can be examined using the PRINT MONITOR command; see chapter 13. The DMONITOR and DWATCH commands are identical, and can be used interchangeably; DWATCH was added for symmetry and completeness. It is not necessary to DMONITOR a location in order to WATCH it, or DWATCH it in order to MONITOR it. The MONITOR and WATCH commands, if the location is already defined in the table, will change the flag indicating whether it is a monitored or watched location. - 33 - CHAPTER 11 MACROS AND SYMBOL DEFINITION As a more or less free spin-off from conditional actions, we have implemented simple text substitution macros (no arguments at present). The format for defining a macro is MACRO name=|macro text| where "|" delimits the macro text on both sides (the character could also be used, but you can't backspace over it). The macro is invoked merely by writing its name, as in &MACRO CALLR=|R4P(.A, #37)| &RESULT = CALLR &CALLR 5004 == BUFFER+345 Macros can be deleted by the operator FORGET listofnames e.g., &FORGET CALLR Space for the text is not reclaimed. See Disk I/O, chapter 12, for a recovery method if you run out of text space. The PRINT MACRO operation can be used to examine the text of a macro; see chapter 13. Macro names always have precedence over both operators and symbols; but a name followed by %n is never taken to be a macro. New entries can be made in the DDT symbol table; these names will also be available to DDT. The format is BIND name = expression The name is defined as a global (in module PAT..) with value that of the result of evaluating the expression. For example, &BIND POINT= .PNTR &POINT - 34 - MACROS AND SYMBOL DEFINITION Page 11-2 1234567 == 1,,234567 &DDT POINT=1,,234567 $P & The BIND operation should be used rather than MACRO to define a name with a constant value, as table lookup is much faster than macro substitution. BIND is a good way to create debugging temporaries with user-specified names. For example, &BIND MYTEMP = .?.JBFF<0,#18>; ?.JBFF = .?.JBFF + 1 or &BIND DBGCHR= SIXPAT[2] (SIXPAT[2] names the third of a set of temporary locations set aside in SIX12 for debugging use. See Appendix A). The values of all of the BIND declarations may be seen by using the PRM operator (chapter 13) to print out the module PAT... &PRM ?PAT.. PAT.. 6214 Module 4 symbols POINT 234567 Global PAT.. MYTEMP 34144 Global PAT.. 0 DBGCHR 17622 Global PAT.. 176 - 35 - CHAPTER 12 LINE PRINTER AND DISK I/O Normally, all output from SIX12 is directed to the user's terminal. Under certain circumstances (such as when tracing, or dumping a large area of memory), it may be preferable to save the output on disk, or send it to the line printer. SIX12 contains a facility for doing this, which is controlled by the following operators: LPTOPEN Opens a file named SIX12.LPT on logical device SIX12: if it exists, or if it does not, on logical device LPT:. It does not initiate output to the file. (Normally, by assigning the logical name LPT: to some other device in advance, the user can cause the output to go anywhere. However, this is frequently inconvenient, since all output destined for the LPT: will go to that device. Forgetting to deassign the logical device produces unexpected results from other programs. Therefore, logical device SIX12: is used if it is assigned, since it is very unlikely such a device name will conflict with any other program.) LPTON Sets the output switch for output to the file. All subsequent printout from SIX12 (except error messages) will be directed to the file, not printed on the terminal. This will be indicated by a "-" which prints to the left of the prompt character. &lptopen &foo 34412 == foo &lpton -&foo -&lptoff & LPTOFF Resets the output switch for output to the terminal. It does not close the file, so that more file output may be done later in the same file. LPTDUP Sets the output switch for output to both terminal and file simultaneously. This allows the user to obtain a - 36 - LINE PRINTER AND DISK I/O Page 12-2 transcript of the terminal session, particularly useful when long debug printouts are made. However, this applies only to output generated by SIX12. Output generated by a routine called from SIX12 will go wherever that routine puts it. Since output is coming to the terminal, the "-" printed with the prompt in LPTON mode is not printed. LPTCLOSE Closes the file opened by LPTOPEN. All file output between one pair of LPTOPEN and LPTCLOSE forms a single file, no matter how many LPTONs and LPTOFFs have intervened. An automatic LPTOFF is executed at every break. Thus output will normally go to the terminal during user interaction. LPT I/O on TOPS-10 uses logical channel 17 (octal). Do not use LPT I/O when your program is using channel 17 (octal). An option is provided for saving the state of SIX12 on a disk file, and restoring it at a later debugging session without having to do considerable type-in, or save the whole core image. SAVE 'filespec' saves all presently defined macros, requests for monitoring, and routine actions (including conditions) in a disk file specified by filespec, which is input as a string and must be enclosed by single quotes. The default extension is ".612". LOAD 'filespec' deletes any existing macros, monitoring requests, or routine actions, then loads the information in the SAVE-written file named by filespec. The default extension is ".612". A null extension may be obtained by specifying only the "." in the filespec. - SAVE and LOAD on TOPS-10 use logical channel 16 (octal). You can use them in a program using that channel just as long as you do not issue them when your program has something open on 16 (octal). - The monitor and routine-actions tables contain absolute memory addresses. Thus SAVE/LOAD should not be used to preserve monitors or routine actions across a program relink. Use STORE/RECALL for this. - Since all previously existing macros are deleted by LOAD, text space is compacted. The correct way to recover from a 'No space for macro text' error is to delete any unneeded macros, then &SAVE 'TEMP' &LOAD 'TEMP' - 37 - LINE PRINTER AND DISK I/O Page 12-3 - The device specified (default "DSK:") must be capable of supporting 36-bit binary I/O. In order to save the state across a link, or to have a file of "stored commands" available, the commands STORE and RECALL are available. They are exactly like SAVE and LOAD, except the file is an ASCII text file and thus may be edited or altered by the user. RECALL does not clear the SIX12 state before it is executed, so a user may RECALL several sets of commands in sequence. The default extension, as in SAVE/LOAD, is ".612". Likewise, the I/O on TOPS-10 is done using channel 16 (octal). The output device must support ASCII data mode. Thus, it is possible to see all of the SIX12 state in a single command, by typing: &STO 'TTY:' The file may contain line numbers, and if it does they will be stripped off. If an error occurs, the offending input line will be printed, the error message will be issued, and input will terminate. - 38 - CHAPTER 13 DISPLAY SIX12 has facilities for printing some information in a more meaningful format than could be obtained from dot or slash. In particular, special operators are available for displaying the run-time stack, the symbol table, and SIX12's internal tables. 13.1 DISPLAYING ROUTINE-CALL STACK These operators display the run-time stack in terms of routine calls. CALLS displays the complete stack of routine calls. Each call is displayed in the format routine from calling-loc Actuals: values The first line (i.e., the current routine) is prefixed with "B:" (for Before) if execution is stopped at the routine's entry, or "A:" (for After), if at its exit, as in A:IMHERE from CALLER+17 Actuals: 1: 5 2: 0 CALLER from MAIN.F+12 Actuals: 1: 45 which indicates that we are at the exit of 'IMHERE'. This display also prints out what handlers are enabled for each routine, and whether or not a signal is being processed. The condition handling features are described in chapter 14. LCALLS displays the call stack plus the locals area for each routine (including saved registers)-- this may not be very useful to a user not familiar with the Bliss runtime environment. Locals are displayed after the call to the routine which owns them. In particular, Bliss-36 "local" declarations do not necessarily - 39 - DISPLAY Page 13-2 allocate the variable onto the stack. CALL n displays the most-recent calls on the stack. If n is omitted (i.e., CALL is used as a nullary operator), only the last call (to the present routine) is printed. LCALL n works like CALL but also displays locals. 13.2 SYMBOL-TABLE SEARCHING These operators are included for searching the symbol table. PRS symbollist For each symbol given, PRS prints every entry in the symbol table, in the format name%ordinal value type module contents For instance, &PRS CTYPE,CX CTYPE%1 400360 Own MAIN.. Routine CTYPE%2_* 5601 Own INPU.. 0 CX%1 500040 Global DECL.. Routine w/debug & &PRS MAIN.. MAIN.. 400010 \Module 211 symbols A * next to a name (following the ordinal) means that that entry will not be used for typeout by SIX12 or DDT (i.e., $K has been performed on it by DDT). A "\" next to the word "Module" indicates this module is the default module selected by the QUALIFY command. A "^" to the left of the name indicates the name appears in the high segment symbol table (if there are two symbol tables; see section 17.4). If the value is a valid memory location, and contains what looks like a DEBUG. UUO or the first instruction of a routine entry sequence, then the phrase "Routine w/debug" or "routine" will be printed out. Otherwise, the octal contents of the location will be printed. PRM module-list This operator takes either no operands or a vector of module names. The null operand case will cause the names of all the modules to be listed, along with the location where each is loaded and the number of symbols in each module. If a list of module names is given, it will list each module and the symbols within it. A "^" to the left of the name indicates the name - 40 - DISPLAY Page 13-3 was found in the high segment symbol table (see section 17.4). &prm SIX12 400123 Module 653 symbols USERA 500666 Module 111 symbols ... &prm xback XBACK 454115 Module 4 symbols P.AAA 454115 Own XBACK 251653325130 P.AAB 454117 Own XBACK 251653325130 XPO$BA 454121 Global XBACK Routine SEARCH 'partially-specified-symbol' This allows searches using the "wild-card" convention that question-mark means any character, as in &SEARCH 'P?C?' PICK 500050 Own TABL.. Routine PACE 3001 Global INPU.. 17,,INPU.O+27 &SEARCH '??????' (prints every entry in symbol table) The partially-specified symbol (only one per search) must be entered in single quotes. SEARCH does not print ordinals (the %-qualification). A "^" to the left of the name indicates the symbol was found in the high segment symbol table. WHERE expression Takes an expression or vector of expressions and prints out the module and symbol which are closest to the expression values. &WHERE 410317,.foo 410317: Module thud, XYZ+117 410113: Module AB.., C+2 & HELP Prints out a list of all the operators. PRINT OPER can be used to make inquiries about specific operators. 13.3 EXAMINING THE STATE OF SIX12 The PRINT operation displays the state of SIX12. PRINT OPER name PRINT OPER "char" - 41 - DISPLAY Page 13-4 displays the definition (priority and routine name for each defined parse) of the specified operator, as in PRINT OPER AND PRINT OPER "_^" Note: Priorities are displayed in decimal. If SIX12 has suppressed its internal symbols (see SIXLSF in section 17.2), the routine name printed for default operators will be incorrect. PRINT MACRO name prints the text of the macro named 'name'. For instance, PRINT MACRO CALLR If the macro name is omitted, all macro names and text are displayed. PRINT ACTION actionname routine prints the status of the specified action on the specified routine. The action must be given as one of BREAK ABREAK OPAQ OPAQAFT TRACE TRACEAFT OK ALL (remember that TRACE FROM = TRACE + TRACE AFTER). The "OK" action will indicate the (always unconditional) temporary breakpoint set on a routine from which an OK has been done. If the routine name is omitted, the actions for all routines are printed. The possible responses are 1. Action not set 2. Unconditional 3. the text of the condition test For example, &PRINT BREAK OPAQ XYZ Action not set &PRINT ACTION ABREAK PPP .X LSS 3 PRINT WATCH PRINT MONITOR Prints the locations being monitored and the current recorded "old value" stored in each. &PRINT MONITOR - 42 - DISPLAY Page 13-5 M- FOO = 4407 == TEST.O+23 W- BAZ<18,18> = -773465 == 777777,,4313 & NOTE The byte pointer position and size values are printed in decimal. The initial flag, "M-" or "W-", indicates whether or not the location is being monitored by a MONITOR or WATCH command. PRINT MONITOR and PRINT WATCH are identical commands. In addition, the STORE operator can be used to print the entire set of conditionals, breakpoints, monitors, etc. on the user's terminal by doing &STO 'tty:' 13.4 WRITING YOUR OWN PARAMETER DISPLAY The default SIX12 parameter display is very simple, and not entirely satisfactory for all applications. It is possible to write your own parameter display routine and value display routine by setting the symbol SIXHDR to contain the name of some user-defined routine. This routine is called with the following parameters: (address, name, parmptr, nparms, kind) where the parameters are defined as: address The address of the routine just called or returned from. name The name of the routine just called or returned from, in SIXBIT. parmptr At a routine entry (see kind, below), the address of the first actual parameter to the routine; the second actual is at this address +1, etc. At a routine exit, this is the pointer to the value returned, and the number of parameters is given as 1. nparms The number of actual parameters to the routine. kind A value of 1 if this is a routine entry, a value of 0 if this is a routine exit. Other values, such as for displays of locals, may eventually be supplied, so a simple true/false test should not be used to - 43 - DISPLAY Page 13-6 distinguish the two cases. The user must return a value to indicate if the user has handled the printing of the parameter list, or if SIX12 should. A true value returned by the user handler indicates that the user has actually processed the routines; a false value indicates that the default SIX12 display should be used. The user can use the output routine SIXOCH, which takes a parameter of the single character to be written, and outputs it to the desired devices; thus, if LPTON or LPTDUP modes are set, output will be diverted to or copied to the transaction file. The user may also call the routine SIXDPY, which takes a single parameter, which is an address to be printed symbolically.This is printed (via SIXOCH) on the output device(s). This routine may be called whenever the user wishes the default SIX12 display for some parameter. The user may use the entry point SIXXEQ to execute any SIX12 command, but in particular may pass in the string representing a routine name (as a qualified name with a module name, or with a %-suffix). The value of SIXXEQ is the value of the expression passed in, so in particular the address of the routine will be returned. This may be used for comparison with the address passed to the user routine specified in SIXHDR. The intent of this is to allow the user to read in a text file of routine names and printout requests and be able to relate the external string name to the internal address when SIXHDR is called. Important Note The string passed to SIXXEQ must be terminated with a delete- code, 177 (octal)!!! - 44 - CHAPTER 14 CONDITION HANDLING There are several aspects of condition handling brought about by SIX12. - The user should be able to invoke any of the functionality of the condition handler mechanism from within SIX12. - The condition handler should not interfere with the user's interaction with SIX12. - SIX12 should be able to monitor what the condition handler is doing. The user may wish to invoke the condition handler functions in a variety of ways for a variety of reasons. Typical scenarios might be: - The user, at a breakpoint or other point at which SIX12 has control, wishes to raise a signal, most likely with the intent of terminating the current execution path. - The user has set a breakpoint at a condition handler routine and wishes to take an action different than what the routine would do, e.g., to resignal when the routine would resume, unwind when the routine would resignal, etc. - The user wishes to return to a previous level of SIX12 in order to resume debugging in that context. These are all supported in the current implementation of condition handling in SIX12. The condition handling mechanism may be invoked from SIX12 by the following commands: SIGNAL expression This operator takes a single value, the value to be signalled, and raises that signal. The value returned is the value returned in the mechanism vector by the conditional handler which was invoked. No additional - 45 - CONDITION HANDLING Page 14-2 parameters may be passed to the handler. If an Unwind operation is performed, control returns to the handler for the Unwind, and will not return to SIX12. UNWIND This operation is valid only if SIX12 is in control while a signal is being handled. It invokes the SETUNWIND() operation. When control leaves SIX12, the Unwind will begin (i.e., via GO, RETURN, etc.). RESIGNAL expression This operator is valid only if SIX12 has control at a condition handler routine, e.g., by a BREAK, ABREAK, or single-step operation which puts SIX12 in control at the handler routine. If no operand is given, the current signal is resignalled; thus, it is simply the equivalent of the SIX12 command RETURN 0. If an operand is given, this operand becomes the new signal value in the signal vector. RESUME expression This operator is valid only if SIX12 has control at the condition handler routine (see RESIGNAL, above). If no operand is given, this is simply the equivalent of the SIX12 command RETURN 1. If an operand is given, this operand becomes the value returned to the SIGNAL call. BACKTO expression This operator is valid whenever a recursive call on SIX12 has been made. It invokes a special signal, SIXUNW, which tells SIX12 to unwind back to a previous level, given as the only operand. 5:&backto 2 2:& If the user program is set up to call SIX12 on an error, this provides a way of returning to the previous incarnation of SIX12. An attempt to go back to a non-existent level is an error; an attempt to go back to the current level is a null operation. POP expression This is the same function as BACKTO, except the operand is the number of levels to return, rather than the index of the level to return to. If no operand is given, "1" is assumed. At level 5, the following two commands will both return to level 2: 5:&BACKTO 2 2:& .... 5:&POP 3 2:& - 46 - CONDITION HANDLING Page 14-3 Whenever SIX12 is entered, it establishes a condition handler to trap all signals which may be raised by calls which may be made to the user program. The action of this handler is to print out the message that the signal has been intercepted, then call SIX12 recursively to allow the user to examine the state. When a RETURN or GO is issued, this handler resignals. A SIGNAL issued from SIX12 is also first intercepted by this handler. Conspicuous by its absence is SIGNAL_STOP; this is because resumption of a SIX12 signal would only return to SIX12, which is harmless, whereas a resumption of a SIGNAL_STOP is probably an error, but the user almost certainly does not want to exit to the monitor, but to return to SIX12! In addition, SIX12 establishes a default condition handler in SIX12 initialization, so that any signal not caught anywhere else, or resignalled indefinitely, is ultimately caught by this outermost handler. It issues a message indicating that the outermost SIX12 handler has been called, and then enters SIX12 command mode. An attempt to RESIGNAL out of this handler will give control to the default Bliss-36 condition handler, which issues an error message and exits to the monitor. An attempt to set UNWIND and resume execution will terminate the program, since this handler is established before calling the main routine of the user program. What the user should do here is to print the call stack, discover which, if any, handlers are invoked, and set breakpoints where appropriate. A GO to this outermost handler indicates a resumption is desired. If the signal was raised by a SIGNAL_STOP, then the normal Bliss-36 SIGNAL_STOP mechanism will terminate the program upon exit from SIX12. Special checks are made in the various routines which print out the call stack, e.g., the CALL, CALLS, LCALL, and LCALLS commands, as well as printout at breakpoints. These checks will print out the handlers which are established for routines, indicate when a SIGNAL is being handled or an unwind is in progress, and print out the parameters to the handler routines in a more useful format than the normal parameter printout. In the example below, the routine BH is an active handler routine for some outer routine. <=>At BH from FOO+26 Signalv at 4416 =[1]: 22 Mechanismv at 4424 =[1]: 4407 Enablev at 4430 =[3] 3347 XYZ+22 FOO &CALLS B: BH from FOO+26 Signalv at 4416 =[1]: 22 Mechanismv at 4424 =[1]: 4407 Enablev at 4430 =[3] 3347 XYZ+22 FOO *** SIGNAL(22) *** FOO from BAZ+7 Actuals: 1: .STACK+214,,GORP<0,#36> ... - 47 - CHAPTER 15 APR ERROR RECOVERY It is frequently the case that users write debugging aid routines which they can call from SIX12. Sometimes these are invoked by extended SIX12 operators, which can be defined as in chapter 18, and sometimes they are done as routine calls to be made from SIX12 command level. In any case, when debugging it is particularly annoying to call one of these routines, and for one of several reasons take an APR trap (such as an illegal memory reference trap). Getting back to the level of SIX12 from which the call was made is extremely difficult, and typically is not worth the effort. The reasons such a call might fail are 1. The routine which has been called does not work. 2. The routine works, but the data passed is incorrect and the routine is not robust enough to cope with this. 3. The routine works, but an incorrect value or address has been passed because the user mis-typed it. Recovery from this state is possible by using the BACKTO or POP commands described in chapter 14. Consider the following example: &foo/ 34567 &PrintIt(345667) ? ?Ill mem ref at user pc 405162 . In this example, the user (or perhaps, the user's keyboard) typed an extra 6 in the address. To recover, and return to SIX12, proceed as follows: .DDT SIXDDT$G 2:&pop & - 48 - CHAPTER 16 MISCELLANEOUS OPERATORS QUALIFY name Sets the default module name for symbols which are qualified with the null module name (see section 4.3). A symbol is qualified with a null module name when only the "\" character appears, with no module name before it. BASE n Sets the default base to be n, and prints the new base in decimal. Subsequent input numbers are assumed to be in this base, and output will appear in this base (except for items specified to appear in the alternate base, either decimal or octal by means of the # operator). If n is omitted BASE prints the current base. The initial default BASE is 8 (for octal). The special case of BASE 0 resets the base to the initial base (octal), no matter what it was set to. WBASE n Sets the maximum displacement to be allowed when printing symbolic addresses in the form 'symbol+offset'. If "n" is omitted, WBASE prints the current offset value using the current default base. base. The WBASE is initialized to 1000 (octal). SETTRACE Turns on the trace flag. When execution resumes tracing will begin immediately. This cancels the effects of any active OPAQUE. The GOTRACE operator described earlier is equivalent to SETTRACE ; GO CLRTRACE Turns off the trace flag. This cancels the effects of an active TRACE AFTER or a previous SETTRACE. The GOCLR operator described earlier is equivalent to CLRTRACE; GO - 49 - MISCELLANEOUS OPERATORS Page 16-2 NODEBUG This performs &.JB41 = #255000000000 &GO Note:#255000000000 (octal) is a JFCL 0,0 Thus, the DEBUG. UUO is rendered a no-op. This can be used to improve execution time if you are only running a program without intending to debug it. In addition, should you reenter SIX12 after this, the prompt will include a notation that you are in NODEBUG mode. DEBUG This undoes the modification of the UUO intercept location by establishing the linkage instruction to SIX12. Unlike the NODEBUG operator, this does not do a GO. This is useful if you have at some point done a NODEBUG and now have entered SIX12 (either through DDT or an error call) and wish to turn debugging back on. RESET Performs a RESET (UUO or JSYS). All currently opened files are closed, and various appropriate resetting of the job state is done by the monitor. Note that neither SIX12 nor the program are reset or restarted by this command. IDENT Prints out the version of SIX12, the runtime environment it expects (TOPS-10 or TOPS-20), and the linkage conventions in effect. For example: &IDENT SIX36 V8-6 (TOPS-20 I/O) for Bliss-36 Using default linkage with registers (decimal) Stack pointer: 15 Frame pointer: 13 Value register: 1 Preserved registers: 14,12,11,10,9,8,7,6,0 Non-preserved registers: 5,4,3,2 ! An exclamation point at the start of a line indicates a comment and the remainder of the line is ignored. - 50 - CHAPTER 17 USING SIX12 17.1 GENERAL USAGE The modules to be debugged must be compiled as follows: - Each module to be debugged must be compiled with the DEBUG switch set. This can be accomplished by including DEBUG in the module head, or by specifying "/DEBUG" in the compiler command string. It is not necessary that all modules in a program be compiled with DEBUG. However, if the main module is not compiled with the DEBUG switch, SIX12 will not be properly initialized, and there is the possibility of getting the message: ?Halt at user pc n where the instruction at user pc n is a DEBUG. UUO. If this is the case, call one of the initialization routines SIX10, SIX36C or SIX36 as described in Appendix A. - Should you come up in "old SIX12", (typically V6.24), it is likely that your MAIN module was compiled with an old version of Bliss-36. If so, it contains a .REQUEST of SIX12.REL. The new SIX12 is included in the BLISS OTS library. You can force loading of the new SIX12 by explicitly loading the module SIX36 from the appropriate OTS file. Once you have compiled all your files, link them with the appropriate version of SIX12 and DDT; be sure that local symbols are loaded for your program files. There are several version of SIX12, depending on the version of Bliss being used, the linkage conventions, and the underlying operating system. The Bliss-36 compiler will include a .REQUEST linker directive to obtain the appropriate version. ------------------------------ [1] On TOPS-20, DDT can be implicitly merged at execution time. See Chapter 8, Concerning DDT. - 51 - USING SIX12 Page 17-2 17.2 LINK-TIME OPTIONS Using either the TOPS-10 or TOPS-20 linker, options may be selected at link time for SIX12 switches SIXSTA (STARTFLG), SIXENB (ENABFLG) and SIXNPL (NOPOLLFLG). The LINK switch /DEFINE: can be used to define initial values for these switches: Location LINK name Default value Complement -------- --------- ------------- ---------- SIXSTA SIXSTF -1 /DEFINE:SIXSTF:0 SIXENB SIXENF -1 /DEFINE:SIXENF:0 SIXNPL SIXPOL 0 /DEFINE:SIXPOL:-1 SIXLSF -1 /DEFINE:SIXLSF:0 The values which have runtime locations assigned may also be set at execution time using DDT or SIX12 itself; for example, SIXSTA (STARTFLG) may be defined false (/DEFINE:SIXSTF:0) but set true before execution begins by using DDT. Such redefinition will cause the linker to issue a "multiply defined symbol" warning when the definition in the SIX12 module is encountered, but this message should be ignored. The symbol SIXLSF determines if SIX12 will delete its local symbols at startup. Ordinarily, SIX12 deletes all of its local symbols except STARTFLG (SIXSTA), ENABFLG (SIXENB) and NOPOLLFLG (SIXNPL). Setting SIXLSF to 0 at link time will suppress this automatic deletion, and is normally only done when a SIX12 maintainer is working on SIX12. If the SIX12 local symbols are left in, they frequently cause "Ambiguous symbol" errors because they conflict with user-defined symbols. When the symbols are deleted, the SIX12 symbol table is compacted. Although this saves no space (the space saved is not reclaimed or reused in any way), it saves time because symbol table search is linear, and SIX12 defines nearly 600 deletable symbols. 17.3 TOPS-10 USAGE The easy way to load SIX12 is with the monitor DEBUG command: .DEBUG your program files,REL:SIXB12 If you prefer to use LINK directly, you can issue .R LINK */DEBUG your program files,REL:SIXB12 */GO If space is at a premium, you can save about 1200 words by loading SIX12 without its local symbols, as in .DEBUG your program files,REL:SIXB12%"NOLOCALS" (All global symbols in SIX12 begin with the letters S I X.) SIX12 - 52 - USING SIX12 Page 17-3 normally purges all of the SIX12 local symbols from the symbol table (except for STARTFLG, ENABFLG and NOPOLLFLG). This saves time and prevents "Ambiguous symbol" error messages. 17.4 SIX12 AND OVERLAYS SIX12 does not work particularly well with overlay systems based on the overlay handler supported by LINK. However, there are some modifications which have been made to allow those programs which have user-built overlay systems using either the GETSEG UUO on TOPS-10 or the GET JSYS on TOPS-20 to interact more gracefully with SIX12. The /SEGMENT switch to the Linker can be used to force the code into the correct segment. In order to simplify some of the discussion below, the term "low segment" when applied to TOPS-20 will refer to the resident pages, and "high segment" to the set of pages which are swapped in for each overlay. If the addresses of the overlay segments are not greater than the addresses of the resident segment, SIX12 will probably not work correctly. In order to work at all with an overlay system, SIX12 must be loaded in the low segment so that it is always at the same address. Each overlaid high segment must have its own symbol table, and they all must overlay with the same offset (e.g., if one segment is loaded at location 600000 , all the segments must be loaded at 600000 ). The symbol table for the common code must be in the low segment (this symbol table can contain symbols for one of the overlaid high segments as well); the symbol tables for each of the overlaid high segments must be in the respective high segments (except for one which is typically the first segment used, which may be shared with the symbol table for the resident segment). The Linker /SYMSEG switch can be used to force the symbol table into the correct segment. The high segment symbol table is found (typically) by looking at the location .JBHSM relative to the high segment offset .JBHGH. However, in TOPS-20 systems, if the high segment is relocated with the /SET switch the value of .JBHGH is not changed (this happens correctly in TOPS-10 systems), and the value .HIGH. must be used. Consequently, there is a complex rule for searching symbol tables. - If the symbol .HIGH. is defined, and is different from .JBHGH, it is used as the start of the high segment; otherwise .JBHGH is used. - If the value stored in .JBHSM from the start of the high segment is the same as the value stored in .JBSYM, there is only one symbol table and it is searched. - If the value stored in .JBHSM from the start of the high segment is different from the value stored in .JBSYM, there are two symbol tables. In this case: - 53 - USING SIX12 Page 17-4 * The high segment symbol table is searched first. * If the symbol is not found in the high segment table, the low segment symbol table is searched. Note that this may occasionally produce strange results if the low segment table contains symbols from the initial segment. * Ambiguous symbols whose ambiguity arises because they are defined uniquely in the high segment symbol table but have a duplicate (and different) definition in the low segment table will not be treated as ambiguous; the high segment definition is considered the correct one. If the ambiguity arises exclusively in the high segment symbol table, the symbols are treated as ambiguous. The address of the high segment symbol table is recomputed after each entry into SIX12 and after each call to a user routine or invocation of a user-defined operator, since any of these conditions could change the high segment symbol table. If the high segment disappears, SIX12 will continue to work correctly providing the common symbol table defined in .JBSYM is in the low segment. These rules appear complex, but seem to provide reasonable behavior when overlay systems are used. The correct rules may actually be more complex. 17.5 SIX12 AND USER UUO HANDLERS The debugging linkages generated by the DEBUG switch use the 037 (octal) user UUO. If your program does not use user UUOs (opcodes 001 (octal)-037 (octal)), you can skip the following. If you do use UUOs, you must - Not use opcode 037 (octal), - Arrange for your UUO handler to link to SIX12 properly. This is merely a matter of getting the proper jump address for SIX12's UUO entry point. This is available as the global symbol SIXUUO.You may also retrieve the jump address from location .JB41 before loading it with a branch to your own handler. (SIX12 loads .JB41 with a PUSHJ to itself immediately after stack initialization.) Your UUO initialization code would look something like: Global UUOROUTS : VECTOR[ %O'40' ]; External Routine UUOSwitch External %Name('.JB41'); . - 54 - USING SIX12 Page 17-5 . UUOROUTS[%O'037'] = .%Name(.JB41)<0,18>; ! Put PUSHJ SREG,UUOSWITCH into loc. 41 ! %Name('.JB41') = %O'260'^27 or 15<0,0>^23 or UUOSwitch<0,0>; where the routine UUOSwitch Machop JRST = %O'254'; Global Routine UUOswitch = JRST(0,UUOROUTS[ %Name('.JB41') ],0,1); must be in a module which is compiled without DEBUG switches. - 55 - CHAPTER 18 DEFINING YOUR OWN OPERATORS CAVEAT Programmer This code was not thoroughly tested, after it was converted to Bliss-36. As previously advertised, SIX12 is capable of easy extension. The method for this is normally to define new operators or revise standard ones to suit your needs. (Please review what we said about operators under 'SIX12 expressions', if it is not fresh in your mind.) 18.1 WHAT DEFINES AN OPERATOR The syntax (print name, priority, possible parses) of an operator is defined by an entry in a syntax analyzer table. Its semantics are defined by a routine which the table entry points to. To evaluate the operator, the analyzer calls this routine using a standard linkage convention. The content of this section is a description of 1) the linkage convention and 2) the proper method for making entries in the syntax table. Linkage: Since operands and values can be vectors, it is not possible to transfer them by standard Bliss linkage. Instead, variables are set to point to an operand and give its length. The variables are: SIXLP Contains a pointer to the first word of the left operand. (Undefined if no left operand.) SIXLC Contains the number of words in the left operand. (Zero if no left operand.) SIXRP Like SIXLP, except points to corresponding values for the right operand. SIXRC Contains the number of words in the right operand. - 56 - DEFINING YOUR OWN OPERATORS Page 18-2 (Zero if no right operand). These variables are set at the routine call; the routine may destroy them if it wishes. (The contents of the operands may also be destroyed.) To return a value, the routine should set these two variables before returning: SIXVP Must contain the address of the first word of the value. (The left half of SIXVP is ignored.) SIXVC Must contain the number of words in the value. If no value is to be returned these can be left unmodified. (The criterion for finding a value is that SIXVC be positive; it is set to zero before calling the routine.) Note that operands and values are always vectors of fullwords. An evaluating routine may need to determine what parse it has been called under. The parse in use can always be determined by examining SIXLC and SIXRC, but a more convenient way is provided. Evaluating routines are called with a single parameter (standard Bliss linkage), which has the value 0 for null parse (no operands) 1 for prefix parse (a right operand only) 2 for postfix parse (a left operand only) 3 for infix parse (both operands); thus bit 0 denotes the presence of a right operand and bit 1 that of a left operand. We suggest examining the source of SIX12 to see the best ways to code operators. The macro Apply and the routines XBASE and LPAREN are particularly good objects of study. For each operator symbol, the table of operators contains the symbol itself (print name), and information on each of the four possible parses for the symbol. This information consists of the priority of operation and the address of the evaluating routine for that parse. (If both are zero, the parse does not apply.) Priorities are in increasing sequence, that is an operator of priority 15 is evaluated before one of priority 14. If the user is making a permanent modification to SIX12, he should modify the table in the source program; this is explained by notes in the source. Otherwise, in order to avoid recompiling SIX12, the user can create his new routines separately, compile them, link them together with SIX12 and the program to be debugged, and modify the operator table at run-time. To facilitate this approach, the linkage variables explained above are all global names, and both an operator and a global routine are provided for modifying the table at run-time. - 57 - DEFINING YOUR OWN OPERATORS Page 18-3 18.1.1 Important Restriction The routine which is called to execute the operator, and any routines it calls to do its work, must not have debug linkages!!! This is very important! If any routine is called during the processing of a SIX12 operator which itself contains debug linkages, the contents of locations SIXLP, SIXLC, SIXRP and SIXRC will be destroyed. In cases where it is not possible to call service routines which have not been compiled with debug linkages, or the possibility of debug linkages is suspected, then the parameters must be copied to local storage and never again referred to via the locations in SIX12. The routine actually called to execute the operator must never be compiled with debug linkages, since the debug call will destroy SIXLP, SIXLC, SIXRP and SIXRC before the operator routine even gets to see them! 18.2 DEFINING OPERATORS FROM SIX12 The DEFINE command allows you to add new operators at SIX12 command-prompt level. These definitions would typically be kept as commands in an ascii file and incorporated using a RECALL command. DEFINE name,parse = priority,routine DEFINE "char",parse = priority,routine sets the parse information as requested. "Parse" can be one of keywords NULL PREFIX POSTFIX INFIX or a literal in the range 0..3. Note that only the specified parse is affected; the others remain set as before. (If a new operator symbol is being defined, the other 3 are initialized to zero, i.e. "parse not applicable".) For example, DEFINE SIXBIT,PREFIX = 100,CONVRT where CONVRT names a routine to translate ASCII inputs to SIXBIT outputs, could be used to implement the SIXBIT stringtype. Once this has been entered, the user could issue & FILNAM = SIXBIT 'ABCDEF' Again, DEFINE "?",0 = 10,DISPLAY would make it possible to call the routine DISPLAY by typing a question mark. (If no value were required from "?" and DISPLAY expected no arguments, this could be done even if DISPLAY had not been written explicitly as a SIX12 operator...) Thus - 58 - DEFINING YOUR OWN OPERATORS Page 18-4 & ? (output from DISPLAY) & The PRINT OPER operation can be used to verify the effects of DEFINE. Remember that priorities are printed in decimal by PRINT OPER. Certain characters are illegal as single-character user-defined operators; see page 9. 18.3 DEFINING OPERATORS FROM A USER PROGRAM Many applications programs would like to have SIX12 operators defined, but do not wish to require users to always define them at the SIX12 command level (even using the RECALL command). Therefore, the global entry point is available to user programs. The user program may call SIXOP during initialization to enter new operators in the table. The general form of the SIXOP call is: SIXOP(name,parse,priority,routine) where name is either a SIXBIT name for the operator, left justified in a word, or a single ASCII 7-bit character in the left halfword. (e.g., (%C'~'^18) in Bliss-36, to define the operator ~). parse is 0, 1, 2 or 3 for null, prefix, postfix or infix parse, as described in section 18. priority is the priority of the operator; see the SIX12 source for determining the exact priority (however, most prefix commands like BREAK have priority 20 and most nullary commands have priority 50). routine is the address of a routine to call for the operator. An example is to define a command BP which prints its arguments out as byte pointers: SIXOP(%sixbit 'BP',1,50,outbp); - 59 - DEFINING YOUR OWN OPERATORS Page 18-5 where routine "outbp" is defined as Global Routine OutBP(ptype):NoValue= begin ! Implements the BP n,n,n,... command ! The parse type code (ptype) is ignored, ! since only prefix parse is recognized ! this routine will fail if "outoct" or "write" contain debug ! linkages or call any routines with debug linkages external SIXRP: ref vector; external SIXRC; incr i from 0 to .SIXRC-1 do begin outoct(.SIXRP[.i]<0,18>); write("<"); outdec(.SIXRP[.i]<30,6>); write(","); outdec(.SIXRP[.i]<24,6>); write(">"); end; end; An example of a routine which returns a value is given below. It is important to note that the user is responsible for finding space to store the result pointed to by SIXVP. There are many ways of doing this, but the simplest is to allocate an own variable and put its address into SIXVP. The extent of the variable must be greater than that of the routine stack frame so a local variable will not work. For simple values, a single word can be allocated; for vector values, a multiple word value must be allocated. The Bliss-36 routine below allocates a 20-word vector, and assumes that no call will pass in more characters than will fit; if necessary, a bounds check could be put in, but that would unnecessarily complicate this example. In any case, SIX12 will copy the result out before it calls any other routine. Thus the variable is both serially reusable and "re-entrant". This routine implements the SIXBIT operator described above. The "cvsix" call converts a single character from ASCII to SIXBIT. - 60 - DEFINING YOUR OWN OPERATORS Page 18-6 global routine CONVRT:NoValue= begin ! converts ASCII value to SIXBIT ! SIXRC is the count of the number of words in the ASCII string ! SIXRP points to the words ! SIXVC will contain the number of words of SIXBIT ! SIXVP will contain the addresses of each of the words ! ! we cannot convert a SIXBIT operand longer than 20 ! words (100 characters) own SIXBITVALUE: Vector[20]; local OutPtr, InPtr, InCnt; external SIXRC; external SIXRP: ref VECTOR; InCnt = .SIXRC * 5; ! 5 chars/word OutPtr = ch$ptr(SIXBITVALUE); InPtr = ch$ptr(SIXRP[0]); decr i from .InCnt to 0 do ch$wchar_a(cvsix(ch$rchar_a(InPtr)),OutPtr); SIXVC = ch$allocation(ch$diff(OutPtr,ch$ptr(SIXBITVALUE))); SIXVP = SIXBITVALUE end; - 61 - APPENDIX A GLOBAL ENTRY POINTS, VALUES AND DATA AREAS Symbol Description SIX10 Initialization entry used for Bliss-10. SIX12 User callable entry point to explicitly invoke SIX12; called with one parameter. SIX36C Initialization entry used for Bliss-36. SIX36 Initialization entry used for Bliss-36 with extended addressing PDP-10s; currently unused. SIXDDT Jump address to start SIX12 from DDT using SIXDDT$G. A valid stack pointer (register SIXSP) must be set up first, if necessary. If SIX12 has not been initialized, then use PUSHJ SIXSP,SIXxxx$X instead, where SIXxxx is SIX10, SIX36 or SIX36C. GO from SIX12 will return to DDT. SIXDPY A routine of one parameter; when called, it prints out the name+offset of the address passed as the parameter. This is useful when the user wishes to write other routines (such as APR trap routines) which would like to be able to print out a symbolic address. SIXENB Global symbol for ENABFLG, which controls console polling. SIXENF Initial value of SIXENB (ENABFLG). May be redefined using LINK. SIXHDR Normally 0, can be set to the address of a user routine which is a handler for printing out the parameters to a routine. Thus, non-standard linkages or formatted printout can be done. SIXNPL Global name of NOPOLLFLG, which permanently disables console polling. SIXOCH Routine entry point to print a single character on the selected output devices (e.g., LPT when LPTON mode is selected, LPT and TTY when LPTDUP mode is selected). Takes a single parameter, the character to be printed. SIXOSA Routine entry point to print an ASCIZ string on the terminal using the SIX12 internal routine for this purpose. Called with one parameter, the address of the beginning of the string. If the address is not - 62 - GLOBAL ENTRY POINTS, VALUES AND DATA AREAS Page A-2 valid, nothing is printed and the value of this routine is 0; if the address is valid, the value is 1. SIXOP User-callable entry point for defining new SIX12 operators. SIXPAT Twenty word patch area. BIND may be used to establish symbolic names for variables the user sets in this area, e.g. &BIND CHECKIT = SIXPAT[4] &if |.CHECKIT| BREAK someroutine &CHECKIT = 1 SIXPOL Initial value of SIXNPL (NOPOLLFLG). May be redefined using LINK. SIXRET Instruction to return to SIX12 using SIXRET$X. This is equivalent to JRST @.JBOPC$X or $P. SIXSP Stack register name (suppressed for typeout). SIXSTA Global name for STARTFLG. Controls automatic entry to SIX12 at startup. SIXSTF Initial value of SIXSTA(STARTFLG). May be redefined using LINK. SIXSTK Contains the value of the stack pointer register when SIX12 is initialized. SIXUNW The low-order 18 bits are used as the value of the unwind signal for the BACKTO command.The user must write code so that only the low-order 18 bits are examined when comparing this value. The user must never do a SETUNWIND() call and then resignal this signal, or SIX12 will become terriblly confused. This value is currently 7170 (octal). It is recognized that this could conflict with some signal value established by the user. Thus, the Linker can be used as described in section 17.2 to change the value of this signal: /DEFINE:SIXUNW:12345 would change the value to 12345. Of course, this will cause a multiply-defined-symbol warning from the linker. SIXUUO Address of SIX12 handler for DEBUG. UUO. SIXXEQ A routine of one parameter, a pointer to a string terminated with a DEL code (177 (octal)). The string is evaluated as a SIX12 command, and the value returned, if any, becomes the value of SIXXEQ. If there is any error, if the string pointer is not a valid address, or if the string pointer is 0, the