From:	ADVAX::"mcnc!CUNYVM.CUNY.EDU!JOE%FHCRCVAX.BITNET" "Joe Meadows"  4-DEC-1990 00:12:18.87
To:	ARISIA::EVERHART
CC:	
Subj:	Re: sstrace

Received: by ADVAX.DECnet (utk-mail11 v1.5) ; Tue, 4 Dec 90 00:02:57 EST
Received:  from mcnc by ge-dab.GE.COM (5.61/GE-DAB 1.15) with UUCP
	id AA08398 for everhart; Tue, 4 Dec 90 00:01:31 -0500
Received: from CUNYVM.CUNY.EDU by mcnc.mcnc.org (5.59/MCNC/6-11-90)
	id AA02421; Mon, 3 Dec 90 23:02:38 -0500
	for ARISIA.dnet.ge.com!EVERHART
Received: from FHCRCVAX.BITNET by CUNYVM.CUNY.EDU (IBM VM SMTP R1.2.2MX) with BSMTP id 4660; Mon, 03 Dec 90 23:01:16 EST
Date: Mon, 3 Dec 90 19:39 PST
From: Joe Meadows <mcnc!CUNYVM.CUNY.EDU!JOE%FHCRCVAX.BITNET>
Subject: Re: sstrace
To: ARISIA::EVERHART
Message-Id: <F5A0F3F1E0FFE00EC0@FHCRCVAX.BITNET>
X-Envelope-To: EVERHART@ARISIA.dnet.ge.com
X-Vms-To: IN%"EVERHART@ARISIA.dnet.ge.com"
 
>I seem to have missed the sstrace program; do you have a copy you can
>email to me perhaps?
 
    Sure enough. Note that this is obviously still very much in it's infancy.
There have been a few related posts, but the following two messages pretty
much cover the current state of affairs. I can't wait till it gets ironed
out a bit further. I should send the author a note encouraging his work.
 
    By the way, I'm not going to be able to make it to Las Vegas :-(
 
    Cheers,
    Joe
 
By the way, there was a response (from Jamie Hanrahan) to the second message
included (basically just pointing out that the guys assumptions as to his
problems were correct).
 
 
From:   IN%"mcsun!cernvax!chx400!cgch!fizciba-geigy.ch!bnebga@uunet.uu.net" 20-N
OV
   -1990 16:44:24.70
To:     info-vax@kl.sri.com
Subj:   Tracing system service calls & problem with DECdecision
Date: 19 Nov 90 13:23:09 GMT
From: mcsun!cernvax!chx400!cgch!fizciba-geigy.ch!bnebga@uunet.uu.net
Subject: Tracing system service calls & problem with DECdecision
Organization: Ciba-Geigy AG, Basel, Switzerland
 
Since VMS V5.4 was installed on our cluster there has been a problem with the
"Edit Macro" facility of DECdecision 1.1. When someone tries to edit a macro a
pop-up message box appears containing the text:
 
    An error has occurred while image activating TPU - SYS$SHARE:TPUSHR. Please
    try again. If this continues to fail, check to see if the image exists.
 
The image certainly exists and other TPU based applications work without
problem (including edit/tpu).
 
I had developed a program to trace system service calls (appended to this
message) and tried to apply it to this problem. It suggests that the actual
problem is in mapping the indirect message section TPUMSG.
 
The reported problem is SECTBLFUL, but the system parameters which seem
relevant to this message so to be in good order. The ouput of
"install list/glo/sum" and a few sysgen values are show below.
 
        Summary of Local Memory Global Sections
 
    273 Global Sections Used,  23982/6018 Global Pages Used/Unused
 
Parameter Name            Current    Default     Min.     Max.     Unit
--------------            -------    -------    -------  -------   ----
GBLSECTIONS                   400        250        60      4095 Sections
GBLPAGFIL                    6024       1024       128        -1 Pages
PROCSECTCNT                    64         32         5      1024 Sections
CHANNELCNT                    127        127        31      2047 Channels
 
I have checked the use of these resources by DECdecision with the SDA commands
"show proc /pst", "show proc /chan" and "show proc /image" and everything seems
to be in good order.
 
The following is an extract from the system service trace at the time of the
failure. The letter before the $ denotes the access mode from which the service
was invoked, the values in () are the parameters with which the service was
invoked and the strings in <> are the text pointed to be one of the arguments.
Return status values are printed in decimal for kernel and executive
invocations and as text for supervisor and user mode invocations. Lines
starting with ***** are my annotations.
 
 
U$IMGACT(7FF231AC,7FF23190,002D8A90,00000030,7FF23188,7FF23188,00000000,
00000000)<TPUSHR>
E$ENQW(0000001F,00000003,7FFE4B62,00000010,80004E98,00040001,00000000,
00000000,00000000,00000001,00000000)=1
E$OPEN(7FFE4800)<TPUSHR>
E$TRNLNM(80422E2B,7FFE9058,7FFB3AD0,7FFB3A9D,7FFB3A5C)<TPUSHR>=444
E$TRNLNM(80422E2B,7FFE9058,7FFB3AD0,7FFB3A9D,7FFB3A5C)<SYS$SHARE>=1
E$TRNLNM(80422E2B,7FFE9058,7FFB3AD0,7FFB3A9D,7FFB3A5C)<SYS$SYSROOT>=1
E$ASSIGN(7FFB3AE0,7FFB1258,00000083,00000000)<ZEUS15$DKA0>=1
E$GETDVIW(0000001F,00000330,00000000,7FFE8FE0,7FFE8FD8,00000000,00000000,
00000000)=1
E$DASSGN(00000330)=1
E$TRNLNM(80422E2B,7FFE903C,7FFB3AD0,7FFB3A9D,7FFB3A5C)<TPUSHR>=444
E$TRNLNM(80422E2B,7FFE903C,7FFB3AD0,7FFB3A9D,7FFB3A5C)<SYS$SHARE>=1
E$TRNLNM(80422E2B,7FFE903C,7FFB3AD0,7FFB3A9D,7FFB3A5C)<SYS$SYSROOT>=1
E$TRNLNM(80422E2B,7FFE903C,7FFB3AD0,7FFB3A9D,7FFB3A5C)<SYS$COMMON>=1
E$ASSIGN(7FFB3AE0,7FFB1258,00000083,00000000)<ZEUS15$DKA0>=1
E$GETDVIW(0000001F,00000330,00000000,7FFE8FC4,7FFE8FBC,00000000,00000000,
00000000)=1
E$CMKRNL(8040E6ED,00000000)=1
=98353   ***** return from $OPEN %RMS-S-KFF, known file found
E$MGBLSC(7FFE9678,7FFE9670,00000003,00608001,7FFE9680,7FFD0BA0,00000000)
<TPUSHR_001>=1
E$CRMPSC(7FFE9678,7FFE9670,00000003,0040000A,00000000,00000000,00000000,
00000330,00000003,000001E9,00000000,00000000)=1561
***** return code is %S-CREATED, file/section did not exist - was created
E$CMKRNL(80002CA0,7FFE9658)=1
E$CRMPSC(7FFE9678,7FFE9670,00000003,0044004A,00000000,00000000,00000000,
00000330,00000001,000001EC,00000000,00000000)=540
                  ^^^^^^^^  ***** VBN of TPUMSG indirect message section
***** return code is %F-SECTBLFUL, section table (process/global) is full
E$DASSGN(00000330)
K$QIOW(0000001E,00000330,00000034,00000000,00000000,00000000,00000000,
00000000,00000000,00000000,00000000,00000000)=620=620
***** DASSGN & QIO return status are both:
***** %F-IVCHNLSEC, invalid channel for create and map section
E$DEQ(00FC0306,00000000,00000000,00000000)=1
=[%F-SECTBLFUL] ***** return from $IMGACT
U$SETAST(00000001)=1
U$UNWIND(00000000,00000000)=1
 
 
Any suggestions as to what to try next would be appreciated - I guess one
possibility would be to just reinstall DECdecision and see whether the problem
just magically disappears.
 
Regards
Gary Nebbett    (/pn=gary.nebbett/ou=chcgbs30/@ciba-geigy.ch)
 
----------------------------ssreadme.txt--------------------------------
---------
sstrace is a program which is intended to trace the system service calls made
by the current process. It has two components:
 
1) sstrace.exe which is used to load and unload the tracing module
 
2) ssload.exe which remains in memory and traces the system calls
 
I recommend creating a DCL symbol along the following lines:
 
$ sstrace :== $exe$files:sstrace exe$files:ssload.exe
 
 
sstrace stores some state information in a block of P1 memory, and it stores a
pointer to this memory in CTL$GL_SITESPEC - the per-process site-specific
longword. If when sstrace is invoked this longword is not zero, sstrace assumes
that you want to terminate the current tracing session, otherwise it loads the
file referenced by its first argument. Thus the command sstrace toggles between
tracing and non-tracing modes.
 
As stated above, the code loaded into memory can also be unloaded - if all goes
well the free memory reported by "show process /memory" should be more or less
the same after ssload is unloaded as it was before it was first loaded.
 
All output produced by sstrace is sent to TT: - i.e. the terminal; if you want
a permanent log of the output you should first perform a "set host /log" before
invoking sstrace.
 
I CURRENTLY KNOW OF THREE IMPORTANT THINGS THAT YOU SHOULD BE WARNED ABOUT WITH
REGARD TO SSTRACE:
 
1) Do not attempt to invoke the debugger whilst tracing system calls - debug
   manipulates the system service vector table in a similar fashion to sstrace.
   You will probably get a Reserved Operand exception in kernel mode which will
   crash the system.
 
2) Do not kill the process whilst sstrace is active. If the process is killed
   it is likely that a "WSLXVANMAT, Working set list entry does not match VA"
   bugcheck will occur which will crash the system.
 
3) Do not pause the output produced by sstrace with XOFF (or any other way come
   to that) - it appears that some of the lock requests made by the XQP are
   also traced. If the process is blocked awaiting output whilst holding a
   critical XQP lock (which it will not be able to relinquish until previous
   output has completed) the entire file-system might stall.
 
 
Further work
------------
 
Currently sstrace produces a voluminous amount of information; some run-time
filtering might be useful.
 
Up to twelve arguments to the system service call are displayed - when an
argument is a pointer to something it is normally more useful to display the
"something". I have done this for one or two "pointer to character string"
arguments.
 
The ability to trace a named process (i.e. not necessarily the current process)
might be useful. I have not yet decided whether sstrace is just a toy or
performs a sufficiently useful purpose to make the effort of this development
worthwhile.
 
Example output
--------------
 
This is one of the simplest examples I could generate:
 
$ =1sho tim
=65537
S$ASCTIM(00000000,7FFECA4C,00000000,00000000)
S$NUMTIM(7FFEC9C8,00000000)=1
S$FAO(7FFEC9C0,7FFEC9D8,7FFEC9DC,000C0013,80475488,000B07C6)=1
S$FAO(7FFEC9B8,7FFEC9DA,7FFEC9DC,0007000C,000A0007,003D000A,7FFE003D)=1=1
S$PUT(7FFE329E)
E$QIO(0000001D,000000B0,00000030,7FFB271C,804125D0,7FFB2710,7FFECA54,000
000016,000
00000,8D010000,00000000,00000000)
=119-NOV-1990 12:07:10
E$SETAST(00000000)=9
E$DCLAST(804125D0,7FFB2710,00000000)=1
E$SETAST(00000001)=1=65537
S$GET(7FFE31D2)
E$QIO(0000001D,000000A0,00008031,7FFB391C,804125D0,7FFB3910,7FFB1000,000
000100,000
00002,00000000,7FFE3306,00000018)
$ =1
 
Upon return from a system call the return status is printed so the trace starts
with the completion status (=1) of the QIO which does the DCL read with prompt
and the completion status of the DCL RMS GET with prompt (=65537). The letter
in front of the $ denotes the mode from which the system service was invoked.
 
Next $ASCTIM is invoked from supervisor mode which in turn invokes $NUMTIM (we
can tell this because no return status from $ASCTIM is printed before $NUMTIM
is invoked). Following the $NUMTIM call are two calls to $FAO; at last we see
the return status from $ASCTIM.
 
Next the program $PUTs the ouput to sys$output, which actually results in an
executive mode $QIO.
 
The $SETAST and $DCLAST calls may be related to I/O completion notification.
 
Finally DCL does a read with prompt which results in the $GET and $QIO.
----------------------------ssbuild.com---------------------------------
---------
$! The component source files sstrace.c, sstracem.mar, ssload.c, ssloadg.mar
$! are compiled or assembled in the normal fashion - no special qualifiers
$! are needed. The link commands are given below. sstrace just requires
$! linking against sys.stb to resolve references to things like
$! CTL$GL_SITESPEC, and is also linked with the S0 system service vector
$! module extracted from starlet.olb (module sys$vector) to prevent problems
$! on return from the $cmkrnl service which installs the new table.
$!
$! ssload is also linked against sys.stb and the S0 vectors for similar
$! reasons. Furthermore ssload is linked /system=0 so that it can be
$! simply read into memory and relocated.
$!
$! ssvector is generated thus:
$!      $ lib sys$share:starlet.olb /extr=sys$vector /out=ssvector
$!
$! ssload.c #includes ssfab.h - ssfab.h is just sys$share:fab.h with the
$! "globalref struct FAB cc$rms_fab" line deleted to save on data space.
$!
$!
$ link sstrace,sstracem,ssvector,sys$system:sys.stb/sel
$ link ssload,ssloadg,ssvector,sys$system:sys.stb/sel/map=ssload/full/system=0
----------------------------ssload.c------------------------------------
---------
/*
 * AUTHOR:       Gary Nebbett, CREATION DATE: 13th November, 1990
 */
 
/*
 * The name X has been used for those cells that are either
 * currently spare or contain code other than a system service
 * entry point (perhaps implementing the waiting form of a system
 * service). If we ever see such a name being printed we should
 * probably give each such cell a distintive name so that we
 * can track it down. We keep the names short to save space.
 *
 * I know that we count the length of the same strings many times;
 * it would be more efficient to build descriptors at compile time
 * for those fixed strings which need them and to explicitly store
 * the length of other fixed length strings. However, if this
 * program is being used performance is probably not a major issue.
 */
 
 
globaldef {"$$$DATA"} const char *ss_names[] = {
    "QIOW",
    "X",
    "X",
    "CLI",
    "ADJSTK",
    "ADJWSL",
    "ALCDNP",
    "ALLOC",
    "ASCEFC",
    "ASCTIM",
    "ASSIGN",
    "BINTIM",
    "CANCEL",
    "CANTIM",
    "CANWAK",
    "CRMPSC",
    "CLRPAR",
    "CMEXEC",
    "CMKRNL",
    "CLREF",
    "CNTREG",
    "GETPTI",
    "CRELOG",
    "CREMBX",
    "CREPRC",
    "CRETVA",
    "DACEFC",
    "DALLOC",
    "DASSGN",
    "DCLAST",
    "DCLEXH",
    "DELLOG",
    "DELMBX",
    "DELPRC",
    "DELTVA",
    "DGBLSC",
    "DLCDNP",
    "DLCEFC",
    "UPDSEC",
    "SNDERR",
    "EXIT",
    "EXPREG",
    "FAO",
    "FAOL",
    "FORCEX",
    "IMGSTA",
    "SNDJBC",
    "GETTIM",
    "UPDSECW",
    "HIBER",
    "IMGACT",
    "LCKPAG",
    "LKWSET",
    "MGBLSC",
    "PURGWS",
    "NUMTIM",
    "SNDOPR",
    "QIO",
    "READEF",
    "RESUME",
    "RUNDWN",
    "SNDSMB",
    "SCHDWK",
    "SETAST",
    "SETEF",
    "SETEXV",
    "SETPRN",
    "SETPRA",
    "SETIMR",
    "SETPRI",
    "SETPRT",
    "SETRWM",
    "SETSFM",
    "SETSWM",
    "SUSPND",
    "TRNLOG",
    "ULKPAG",
    "ULWSET",
    "UNWIND",
    "WAITFR",
    "WAKE",
    "WFLAND",
    "WFLOR",
    "BRDCST",
    "DCLCMH",
    "SETPFM",
    "GETMSG",
    "DERLMB",
    "CANEXH",
    "GETCHN",
    "GETDEV",
    "GETJPI",
    "PUTMSG",
    "EXCMSG",
    "SNDACC",
    "SETIME",
    "SETPRV",
    "CLRAST",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "DELETE",
    "FIND",
    "FREE",
    "GET",
    "PUT",
    "READ",
    "RELEASE",
    "UPDATE",
    "WAIT",
    "WRITE",
    "CLOSE",
    "CONNECT",
    "CREATE",
    "DISCONNECT",
    "DISPLAY",
    "ERASE",
    "EXTEND",
    "FLUSH",
    "MODIFY",
    "NXTVOL",
    "OPEN",
    "REWIND",
    "SPACE",
    "TRUNCATE",
    "ENTER",
    "PARSE",
    "REMOVE",
    "RENAME",
    "SEARCH",
    "SETDDIR",
    "SETDFPROT",
    "SSVEXC",
    "RMSRUNDWN",
    "X",
    "FILESCAN",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "DCLEVT",
    "SETEVTAST",
    "SETEVTASTW",
    "X",
    "X",
    "CANEVTAST",
    "GETEVI",
    "ENQ",
    "DEQ",
    "ENQW",
    "X",
    "X",
    "SETSSF",
    "SETSTK",
    "GETSYI",
    "IMGFIX",
    "X",
    "GETDVI",
    "GETDVIW",
    "GETJPIW",
    "X",
    "GETSYIW",
    "SNDJBCW",
    "SYNCH",
    "X",
    "X",
    "X",
    "X",
    "X",
    "ERAPAT",
    "CRELNT",
    "CRELNM",
    "DELLNM",
    "TRNLNM",
    "GETLKI",
    "GETLKIW",
    "X",
    "ASCTOID",
    "FINISH_RDB",
    "IDTOASC",
    "BRKTHRU",
    "GRANTID",
    "REVOKID",
    "CHKPRO",
    "BRKTHRUW",
    "X",
    "GETQUI",
    "GETQUIW",
    "X",
    "PROCESS_SCAN",
    "DEVICE_SCAN",
    "DCLRNH",
    "CANRNH",
    "EXTRNH",
    "HASH_PASSWORD",
    "MAKE_REF",
    "REMOVE_REF",
    "CREATE_BUFOBJ",
    "DELETE_BUFOBJ",
    "DIAGNOSE",
    "CALL_HANDL_JACKET",
    "TIMCON",
    "GETUTC",
    "NUMUTC",
    "BINUTC",
    "ASCUTC",
    "SUBSYSTEM",
    "DNS",
    "DNSW",
    "READY_TO_COMMIT",
    "READY_TO_COMMITW",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "X",
    "START_RU",
    "PREPARE_RU",
    "COMMIT_RU",
    "ABORT_RU",
    "DCLRUH",
    "CANRUH",
    "JOIN_RU",
    "UNJOIN_RU",
    "RUNDOWN_RU",
    "GET_RUID",
    "END_RU",
    "X",
    "MTACCESS",
    "GETLUI",
    "GRANT_LICENSE",
    "RELEASE_LICENSE",
    "SIGPRC",
    "RESCHED",
    "GETSECI",
    "LOOKUP_LICENSE",
    "IPC",
    "START_TRANS",
    "END_TRANS",
    "ABORT_TRANS",
    "DECLARE_RM",
    "FORGET_RM",
    "JOIN_RM",
    "FINISH_RMOP",
    "ADD_BRANCH",
    "START_BRANCH",
    "START_TRANSW",
    "X",
    "X",
    "END_TRANSW",
    "ABORT_TRANSW",
    "DECLARE_RMW",
    "FORGET_RMW",
    "JOIN_RMW",
    "FINISH_RMOPW",
    "ADD_BRANCHW",
    "START_BRANCHW",
    "IPCW",
    "X",
    "X",
    "CREATE_UID",
    "EMAA",
    "EVDPOSTEVENT",
    "ENABLE_VP_USE",
    "ENABLE_VP_USE_INT",
    "DISABLE_VP_USE",
    "DISABLE_VP_USE_INT",
    "RELEASE_VP",
    "RELEASE_VP_INT",
    "RESTORE_VP_EXCEPTION",
    "RESTORE_VP_EXC_INT",
    "SAVE_VP_EXCEPTION",
    "SAVE_VP_EXC_INT",
    "RESTORE_VP_STATE",
    "X",
    "X",
    "REPORT_EVENT",
    "X",
    "X"
};
 
 
#include <descrip.h>
#include <ssdef.h>
#include <iodef.h>
#include <psldef.h>
#include "ssfab.h"
#include "ssinfo.h"
 
#pragma builtins
 
#define strlenk(str) (65535 - _LOCC(0, 65535, (str)))
 
globalref void * P1SYSVECTORS[];
globalref struct ssinfo * CTL$GL_SITESPEC;
 
 
/*
 * Here we use the saved PC value to calculate an index into the system service
 * vector table. We have to be careful because the PC has been advanced into
 * the next vector cell because the JSB instruction fills the actual cell.
 *
 * Because of the way we are relocated in memory there is a slight problem
 * with the table of system service names - it contains absolute pointers
 * to the strings. To actually reference a string we add the address at which
 * we were loaded to the address of the string stored in the table (this
 * relies on the /system=0 qualifier to the linker).
 *
 * We include in the name an indication of the mode from which the service
 * was invoked.
 *
 * The possibility to print selected information about the current system
 * service parameters exists - it will take a long time to flesh out this
 * section.
 *
 * Finally we return a suitable CALL address back to the assembly language
 * code which invoked use - this is used to invoke the genuine system service.
 */
 
unsigned long enter(unsigned long *args, unsigned long addr)
{
    int ss_num, n, psl, mode;
    char buf[160], *ss;
    struct dsc$descriptor *dsc;
    struct FAB *fab;
 
    ss_num = ((addr - (unsigned long)P1SYSVECTORS - 1) / CELLSIZE);
 
    _MOVPSL(&psl);
    mode = ((psl & PSL$M_CURMOD) >> 24);
 
    ss = ss_names[ss_num] + CTL$GL_SITESPEC->ss_base;
    n = fao(buf, sizeof(buf), "!/ $!AD", strlenk(ss), ss);
 
    switch (mode) {
        case PSL$C_KERNEL   : buf[2] = 'K'; break;
        case PSL$C_EXEC     : buf[2] = 'E'; break;
        case PSL$C_SUPER    : buf[2] = 'S'; break;
        case PSL$C_USER     : buf[2] = 'U'; break;
    }
 
    n += hexargs(&buf[n], sizeof(buf) - n, args);
 
    switch (ss_num) {
        case 10  : /* $ASSIGN */
        case 50  : /* $IMGACT */
                    if ((dsc = args[1]) == 0) break;
                    n += fao(&buf[n], sizeof(buf) - n, "<!AF>",
dsc->dsc$w_length, dsc->dsc$a_pointer);
                    break;
        case 15  : /* $CRMPSC */
        case 53  : /* $MGBLSC */
        case 184 : /* $ENQ */
                    if ((dsc = args[5]) == 0) break;
                    n += fao(&buf[n], sizeof(buf) - n, "<!AF>",
dsc->dsc$w_length, dsc->dsc$a_pointer);
                    break;
        case 210 : /* $TRNLNM */
                    if ((dsc = args[3]) == 0) break;
                    n += fao(&buf[n], sizeof(buf) - n, "<!AF>",
dsc->dsc$w_length, dsc->dsc$a_pointer);
                    break;
        case 121 : /* $CREATE */
        case 129 : /* $OPEN */
                    if ((fab = args[1]) == 0) break;
                    if (!fab->fab$l_fna || !fab->fab$b_fns) break;
                    n += fao(&buf[n], sizeof(buf) - n, "<!AF>", fab->fab$b_fns &
0xffL, fab->fab$l_fna);
                    break;
    }
 
    print(buf, n);
 
    return(0x80000000 + (ss_num * CELLSIZE));
}
 
/*
 * We peak at the return value saved on the stack and if it is not a
 * success value we report the error.
 *
 * The VAX/VMS Internals and Data Structures book says that sys$getmsg
 * is not callable from kernel mode - this is certainly true but I also have
 * problems with executive mode. So if the current mode is supervisor or less
 * privileged we report the sys$getmsg text otherwise we just report the hex
 * value.
 *
 * Note that because of nested system service calls, the error message is not
 * necessarily printed immediately after the name of the failing system
 * service.
 */
 
void leave(unsigned long status)
{
    int psl, mode;
    unsigned short len;
    char buf[32], fbuf[64];
    struct dsc$descriptor buffer;
 
    _MOVPSL(&psl);
    mode = ((psl & PSL$M_CURMOD) >> 24);
 
    if ((mode >= PSL$C_SUPER) && !(status & 1)) {
        buffer.dsc$b_class = buffer.dsc$b_dtype = 0;
        buffer.dsc$w_length = sizeof(buf);
        buffer.dsc$a_pointer = buf;
        sys$getmsg(status, &len, &buffer, 6, 0);
        len = fao(fbuf, sizeof(fbuf), "=[!AF]", len, buf);
    }
    else
        len = fao(fbuf, sizeof(fbuf), "=!UL", status);
 
    print(fbuf, len);
}
 
/*
 * Display up to twelve arguments in hexadecimal.
 */
 
hexargs(char *buf, int n, unsigned long *args)
{
    unsigned short len;
 
    switch (*args) {
        case 0 : return(0);
        case 1 : return(faol(buf, n, "(!XL)", &args[1]));
        case 2 : return(faol(buf, n, "(!XL,!XL)", &args[1]));
        case 3 : return(faol(buf, n, "(!XL,!XL,!XL)", &args[1]));
        case 4 : return(faol(buf, n, "(!XL,!XL,!XL,!XL)", &args[1]));
        case 5 : return(faol(buf, n, "(!XL,!XL,!XL,!XL,!XL)", &args[1]));
        case 6 : return(faol(buf, n, "(!XL,!XL,!XL,!XL,!XL,!XL)", &args[1]));
        case 7 : return(faol(buf, n, "(!XL,!XL,!XL,!XL,!XL,!XL,!XL)",
&args[1]));
        case 8 : return(faol(buf, n, "(!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL)",
&args[1]));
        case 9 : return(faol(buf, n, "(!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL)",
&args[1]));
        case 10 : return(faol(buf, n,
"(!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL)", &args[1]));
        case 11 : return(faol(buf, n,
"(!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL)", &args[1]));
        default : return(faol(buf, n,
"(!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL,!XL)", &args[1]));
    }
}
 
/*
 * Repackage the sys$faol system service. Basically just build
 * the descriptors needed by sys$faol. The argument list parameter
 * of sys$faol is just a pointer to the arguments that we were invoked
 * with.
 *
 * We could invoke faol, but we may as well save on the call overhead
 * and repeat the code here.
 */
 
fao(char *buf, int buflen, char *ctr, unsigned long args, ...)
{
    struct dsc$descriptor outbuf, ctrstr;
    unsigned short len;
 
    outbuf.dsc$w_length = buflen;
    outbuf.dsc$b_dtype = outbuf.dsc$b_class = 0;
    outbuf.dsc$a_pointer = buf;
 
    ctrstr.dsc$w_length = strlenk(ctr);
    ctrstr.dsc$b_dtype = ctrstr.dsc$b_class = 0;
    ctrstr.dsc$a_pointer = ctr;
 
    return(sys$faol(&ctrstr, &len, &outbuf, &args) == SS$_NORMAL ? len : 0);
}
 
/*
 * Repackage the sys$faol system service. Basically just build
 * the descriptors needed by sys$faol.
 */
 
faol(char *buf, int buflen, char *ctr, unsigned long *args)
{
    struct dsc$descriptor outbuf, ctrstr;
    unsigned short len;
 
    outbuf.dsc$w_length = buflen;
    outbuf.dsc$b_dtype = outbuf.dsc$b_class = 0;
    outbuf.dsc$a_pointer = buf;
 
    ctrstr.dsc$w_length = strlenk(ctr);
    ctrstr.dsc$b_dtype = ctrstr.dsc$b_class = 0;
    ctrstr.dsc$a_pointer = ctr;
 
    return(sys$faol(&ctrstr, &len, &outbuf, args) == SS$_NORMAL ? len : 0);
}
 
/*
 * A supervisor mode channel to a terminal device was opened for use by the
 * program which loaded us into memory. The channel number is stored in the
 * information block pointed to by CTL$GL_SITESPEC.
 *
 * The channel is assigned in supervisor mode so that it is not deleted at
 * image rundown. However this prevents user mode code from using the channel;
 * so the user mode calls must first assign a user mode channel, then perform
 * the I/O and finally deassign the channel.
 *
 * You might think that it would be better to open a user mode channel if
 * necessary and just reuse it until it is closed at image run-down, but we
 * have no suitable place to remember the channel number - the information
 * block is not writeable from user mode and we have no other suitable storage.
 * [We could consider changing the protection on the information block
 * page(s)].
 *
 * Note that writing to a file is difficult - we cannot call RMS routines
 * from kernel mode and the QIO interface to the file system is not friendly
 * (and would require some saving of state variables across multiple
 * invocations because we must write full blocks to disk).
 */
 
print(char *str, int n)
{
    unsigned long status, iosb[2];
    struct dsc$descriptor file;
    unsigned short chan;
 
    status = sys$qiow(0, CTL$GL_SITESPEC->ss_file, IO$_WRITEVBLK, iosb, 0, 0,
                      str, n, 0, 0, 0, 0);
 
    if (status == SS$_NOPRIV) {
        file.dsc$b_class = file.dsc$b_dtype = 0;
        file.dsc$w_length = strlenk(CTL$GL_SITESPEC->ss_filename);
        file.dsc$a_pointer = CTL$GL_SITESPEC->ss_filename;
 
        sys$assign(&file, &chan, PSL$C_USER, 0);
        sys$qiow(0, chan, IO$_WRITEVBLK, iosb, 0, 0,
                 str, n, 0, 0, 0, 0);
        sys$dassgn(chan);
    }
}
----------------------------ssloadg.mar---------------------------------
---------
        .TITLE  System Service Trace support routines
        .IDENT  /V01-000/
 
;++
; FACILITY:     System Service Tracing
;
; ABSTRACT:
;
;
; ENVIRONMENT:  VMS V5.4
;
; AUTHOR:       Gary Nebbett, CREATION DATE: 13th November, 1990
;
; MODIFIED BY:
;
;--
 
        .SUBTITLE DECLARATIONS
;
; INCLUDE FILES:
;
 
;
; MACROS:
;
 
;
; EQUATED SYMBOLS:
;
 
;
; OWN STORAGE:
;
        .PSECT  $$$CODE       RD,NOWRT,PIC,SHR,BYTE,EXE
 
        .SUBTITLE INTERCEPT - intercept system calls
;++
; FUNCTIONAL DESCRIPTION:
;
;       This routine is invoked by every system service call: it first calls a
;       routine to record the entry into the system service, then calls the
;       system service and finally calls a routine to record the return from
;       the system service.
;
;       Because some stacks (at least the kernel stack) have an upper bound
;       on their size and cannot always be extended, some checks for the
;       existence of free space are made. Because of the implicit minimisation
;       of privilege level performed by the PROBEx instruction, we only probe
;       when both the current and previous mode is kernel (a PROBEx performed
;       by a kernel mode system service invoked from user mode would always
;       fail because the kernel stack is not readable from user mode).
;       If we are on the kernel stack and the previous mode was not kernel
;       then it is likely that the kernel stack was empty before the current
;       invocation so we need not worry about stack space under these
conditions.
;
;
; CALLING SEQUENCE:
;
;       JSB
;
; INPUT PARAMETERS:
;
;       NONE
;
; IMPLICIT INPUTS:
;
;       Return address on top of stack created by JSB instruction
;
; OUTPUT PARAMETERS:
;
;       NONE
;
; IMPLICIT OUTPUTS:
;
;       NONE
;
; COMPLETION CODES:
;
;       NONE
;
; SIDE EFFECTS:
;
;       NONE - hopefully
;
;--
 
 
INTERCEPT::
        MOVPSL  R1                      ; move PSL into R1
        EXTZV   #22, #4, R1, R1         ; extract the current and previous
access modes
        BNEQ    STACKOK                 ; only check for stack space if current
and previous mode = K
        PROBEW  #0, #512, -516(SP)      ; probe next 512 bytes of stack for
write access
        BNEQ    STACKOK                 ; if stack space is scarce do not invoke
trace function
        POPL    R0                      ; get saved return address - will be in
range of P1 vector table
        ADDL2   #^X121FA, R0            ; calculate address of S0 vector table
entry
        JMP     (R0)                    ; make the system call and don't come
back this way
STACKOK:
        PUSHL   AP                      ; give ENTER access to parameters
        CALLS   #2, ENTER               ; #2 because ENTER uses saved PC and
removes it from stack
        CALLG   (AP), (R0)              ; ENTER returns in R0 appropriate
address to make the system call
RETURN:
        PUSHL   R0                      ; save system service return code (R0) -
LEAVE reads this
        CALLS   #0, LEAVE               ; call trace function
        POPL    R0                      ; restore system service return code
        RET                             ; return to invoker of system service
 
        .END
----------------------------sstracem.mar--------------------------------
---------
        .TITLE  System Service Trace support routines
        .IDENT  /V01-000/
 
;++
; FACILITY:     System Service Tracing
;
; ABSTRACT:
;
;
; ENVIRONMENT:  VAX/VMS V5.4
;
; AUTHOR:       Gary Nebbett, CREATION DATE: 13th November, 1990
;
; MODIFIED BY:
;
;--
 
        .SUBTITLE DECLARATIONS
;
; INCLUDE FILES:
;
 
;
; MACROS:
;
 
;
; EQUATED SYMBOLS:
;
        BSIZE   = 4                     ; offset to buffer size value
        BUFFER  = 8                     ; offset to buffer descriptor
;
; OWN STORAGE:
;
        .PSECT  MEM_CODE       RD,NOWRT,PIC,SHR,BYTE,EXE
 
        .SUBTITLE P1ALLOC - allocate a buffer from the P1 region
;++
; FUNCTIONAL DESCRIPTION:
;
;       Allocate a buffer from the P1 region that will not be deleted at
;       image rundown.
;
;       The exact requirements of EXE$ALOP1PROC are not known;
;       the current invocation is modelled after other device
;       driver allocation routines - it seems to work, but it never
;       seems to return SS$_NORMAL but rather returns the address
;       of the allocated buffer plus one.
;
;
; CALLING SEQUENCE:
;
;       CALLS/CALLG
;
; INPUT PARAMETERS:
;
;       BSIZE - Size of buffer (in bytes)
;
; IMPLICIT INPUTS:
;
;       NONE
;
; OUTPUT PARAMETERS:
;
;       BUFFER - Address of buffer descriptor
;
; IMPLICIT OUTPUTS:
;
;       NONE
;
; COMPLETION CODES:
;
;       SS$_INSFMEM
;       SS$_NOPRIV
;       Address of allocated buffer + 1
;
; SIDE EFFECTS:
;
;       NONE
;
;--
 
 
        .ENTRY  P1ALLOC, ^M<R2,R3>
        MOVL    BSIZE(AP), R1           ; put buffer size in r1
        JSB     G^EXE$ALOP1PROC         ; invoke routine
        MOVL    BUFFER(AP), R3          ; setup access to buffer descriptor
parameter
        MOVL    R2, (R3)                ; return base address of buffer
        MOVL    R1, 4(R3)               ; return size of buffer
        RET                             ; return to caller
 
 
        .SUBTITLE P1FREE - return a buffer to the P1 region
;++
; FUNCTIONAL DESCRIPTION:
;
;       Return a buffer to the P1 region.
;
;       The exact requirements of EXE$DEAP1 are not known;
;       the current invocation is modelled after other device
;       driver deallocation routines.
;
;
; CALLING SEQUENCE:
;
;       CALLS/CALLG
;
; INPUT PARAMETERS:
;
;       BSIZE - Size of buffer (in bytes)
;       BUFFER - Address of buffer
;
; IMPLICIT INPUTS:
;
;       NONE
;
; OUTPUT PARAMETERS:
;
;       NONE
;
; IMPLICIT OUTPUTS:
;
;       NONE
;
; COMPLETION CODES:
;
;       NONE
;
; SIDE EFFECTS:
;
;       NONE
;
;--
 
 
        .ENTRY  P1FREE, ^M<R2>
        MOVL    BSIZE(AP), R1           ; put buffer size in r1
        MOVL    BUFFER(AP), R0          ; put buffer address in r0
        JSB     G^EXE$DEAP1             ; invoke routine
        RET                             ; return to caller
 
        .END
----------------------------sstrace.c-----------------------------------
---------
/*
 * AUTHOR:       Gary Nebbett, CREATION DATE: 13th November, 1990
 */
 
#include <descrip.h>
#include <psldef.h>
#include <ssdef.h>
#include <ctype.h>
#include <stdio.h>
#include <stat.h>
#include <varargs.h>
#include "ssinfo.h"
 
#pragma builtins
 
#define PHD$L_P1BR  120
 
globalvalue unsigned long P1SYSVECTORS;
globalref unsigned long CTL$GL_PHD;
globalref unsigned long MMG$GL_SPTBASE;
globalref struct ssinfo * CTL$GL_SITESPEC;
 
struct vector {
    unsigned char   opcode;
    unsigned char   mode;
    unsigned long   address;
};
 
struct mem {
    unsigned long   base;
    unsigned long   size;
};
 
 
static unsigned long cmkrnl();
static void check_vectors(), switch_ptes(), tidy();
static void setup_ssfile(), setup_ssinfo(), setup_ssload(), setup_ssvectors();
 
 
/*
 * This program uses many individual change mode calls so that its progress
 * can be monitored with a user mode debugger.
 *
 * However we must be very wary of debugger interaction - DEBUG also plays
 * with the P1 vector table. It would be very unwise to run DEBUG whilst
 * also tracing system calls.
 *
 * It is also unwise to delete the process whilst trace is running - there is
 * a risk of a "WSLXVANMAT, Working set list entry does not match VA"
 * bugcheck (because the memory occupied by the old table is locked in
 * the working set but is not mapped into the virtual address space).
 *
 * Output is currently always sent to TT: - it is possible to record
 * the output in a file by first doing a "$ set host /log".
 *
 * Be very careful about pausing the output produced by trace with XON/XOFF -
 * the process being traced might be holding a critical resource (such as
 * an XQP lock); pausing the output stops the process from doing anything
 * including releasing the resource.
 */
 
main(int argc, char **argv)
{
    struct ssinfo ssinfo;
 
    if (CTL$GL_SITESPEC) {
        printf("\ncleaning up previous session\n\n");
        tidy();
        exit(0);
    }
 
    if (argc != 2) {
        printf("Usage: %s <file>\n", argv[0]);
        exit(0);
    }
 
    memset(&ssinfo, 0, sizeof(ssinfo));
    memcpy(ssinfo.ss_filename, "TT:", strlen("TT:"));
 
    check_vectors();
 
    setup_ssload(&ssinfo, argv[1]);
    setup_ssfile(&ssinfo);
    setup_ssvectors(&ssinfo);
    setup_ssinfo(&ssinfo);
 
    switch_ptes(&ssinfo);
 
    return(SS$_NORMAL);
}
 
/* ----------------------------------------------------------------------- */
 
static unsigned long restore_ptes(), unlock_vec();
static unsigned long close_file(), clear_sitespec();
 
/*
 * Tidy up after a trace session.
 *
 * 1) Restore vector table virtual address mapping
 * 2) Unlock vector table memory and then free memory
 * 3) Close the file to which trace output was written
 * 4) Free memory into which we loaded trace code
 * 5) Free information block memory
 * 6) Clear CTL$GL_SITESPEC
 *
 * If an error occurs just report it but keep on freeing as many
 * resources as possible.
 */
 
static void tidy()
{
    unsigned long status;
    struct ssinfo *ssinfo;
 
    ssinfo = CTL$GL_SITESPEC;
 
    cmkrnl(restore_ptes);
 
    if (ssinfo->ss_vectors) {
        cmkrnl(unlock_vec, ssinfo, &status);
        if (status != SS$_WASSET && status != SS$_NORMAL)
            printf("Tidy unlock error %x\n", status);
 
        p1free(ssinfo->ss_vectors_size, ssinfo->ss_vectors);
    }
 
    if (ssinfo->ss_file) {
        cmkrnl(close_file, ssinfo->ss_file, &status);
        if (status != SS$_NORMAL)
            printf("Tidy file error %x\n", status);
    }
 
    if (ssinfo->ss_base)
        p1free(ssinfo->ss_base_size, ssinfo->ss_base);
 
    if (ssinfo->ss_info)
        p1free(ssinfo->ss_info_size, ssinfo->ss_info, &status);
 
    cmkrnl(clear_sitespec);
}
 
/* ----------------------------------------------------------------------- */
 
/*
 * We just obtain the page table entries for the first page of the P1 and S0
 * system service vector tables and return these to user mode.
 */
 
static unsigned long check_vec(struct valid_pte *p1pte, struct valid_pte
*s0pte)
{
    unsigned long *p1br;
    struct valid_pte *svapte;
 
    p1br = CTL$GL_PHD + PHD$L_P1BR;
    svapte = (((P1SYSVECTORS - 0x40000000) / 0x200) * 4) + *p1br;
    *p1pte = *svapte;
 
    svapte = MMG$GL_SPTBASE;
    *s0pte = *svapte;
 
    return(SS$_NORMAL);
}
 
/*
 * This user mode code reports whether P1 and S0 vector tables have
 * been separated from using the same physical memory.
 *
 * The check of the return status from sys$cmkrnl verifies that we
 * are suitably privileged.
 *
 * If there are not as many vector pages as we expect we quickly exit.
 *
 * If the memcmp test fails we report that differences already exist
 * between P1 and S0 tables.
 */
 
static void check_vectors()
{
    unsigned long status;
    struct valid_pte p1pte, s0pte;
    void *addr;
    int ok;
 
    addr = P1SYSVECTORS;
    ok = _PROBER(PSL$C_USER, NUMVEC * CELLSIZE, addr);
    if (!ok) {
        printf("fewer vector pages than expected\n");
        exit(0);
    }
 
    if (memcmp(addr, 0x80000000, NUMVEC * CELLSIZE)) {
        printf("differences exist between P1 and S0 tables\n");
        exit(0);
    }
 
    if ((status = cmkrnl(check_vec, &p1pte, &s0pte)) != SS$_NORMAL)
        lib$stop(status);
 
    if (p1pte.pfn != s0pte.pfn)
        printf("P1 and S0 tables already distinct\n");
}
 
/* ----------------------------------------------------------------------- */
 
/*
 * First make sure that the memory that will hold our modified vector
 * routines is paged aligned. Then set the PFN fields of the PTEs for
 * the P1 vector pages to have the same value as the PFN fields of the
 * pages holding our modified vector routines.
 *
 * We remember the original PTEs so that we can subsequently restore
 * them.
 */
 
static unsigned long modify_ptes(struct ssinfo *ssinfo)
{
    unsigned long *p1br, newpage;
    struct valid_pte *oldpte, *newpte;
    int pages;
 
    newpage = (ssinfo->ss_vectors + 511) & 0xfffffe00;
 
    p1br = CTL$GL_PHD + PHD$L_P1BR;
 
    oldpte = (((P1SYSVECTORS - 0x40000000) / 0x200) * 4) + *p1br;
    newpte = (((newpage - 0x40000000) / 0x200) * 4) + *p1br;
 
    for (pages = 0; pages < (NUMVEC / 64); pages++) {
        ssinfo->ss_saved_pte[pages] = *oldpte;
        (oldpte++)->pfn = (newpte++)->pfn;
    }
}
 
/*
 * Because the user mode information block has already been copied
 * to the P1 buffer, we must pass the address of the P1 buffer to
 * modify_ptes; we do things in this order so that the switch of
 * vector tables remains the last major operaion performed by the
 * program.
 */
 
static void switch_ptes(struct ssinfo *ssinfo)
{
    cmkrnl(modify_ptes, ssinfo->ss_info);
}
 
/*
 * Restore the vectors by setting the P1 vector table PTEs to contain
 * the PFNs we saved when we started tracing.
 */
 
static unsigned long restore_ptes()
{
    unsigned long *p1br;
    struct valid_pte *oldpte;
    int pages;
 
    p1br = CTL$GL_PHD + PHD$L_P1BR;
 
    oldpte = (((P1SYSVECTORS - 0x40000000) / 0x200) * 4) + *p1br;
 
    for (pages = 0; pages < NUMVECPAGES; pages++)
        (oldpte++)->pfn = CTL$GL_SITESPEC->ss_saved_pte[pages].pfn;
}
 
/* ----------------------------------------------------------------------- */
 
/*
 * Hand craft a vector of the form JSB #@XXXXXXXX.
 *
 * First copy the real vector table to our new table; this sets up the
 * entry mask fields.
 *
 * Next replace the remaining 6 bytes of each vector cell with our JSB
 * instruction.
 *
 * Finally there are 17 vector cells at an offset of 0x310 from the
 * start of the table which do not contain vectors - restore these from
 * the S0 table. Also restore cells at offsets 0x10 and 0x768 - these
 * are named sys$call_handl and sys$call_handl_jacket.
 */
 
static unsigned long copy_vec(struct ssinfo *ssinfo)
{
    struct vector vector;
    char *c, *page;
    int i;
 
    vector.opcode = 0x16;
    vector.mode = 0x9f;
    vector.address = ssinfo->ss_base;
 
    page = (ssinfo->ss_vectors + 511) & 0xfffffe00;
 
    memcpy(page, P1SYSVECTORS, CELLSIZE * NUMVEC);
 
    for (c = page + ENTRY_MASK_SIZE, i = 0; i < NUMVEC; c += CELLSIZE, i++)
        memcpy(c, &vector, sizeof(vector));
 
    memcpy(page + 0x010, 0x80000010, 0x8);
    memcpy(page + 0x768, 0x80000768, 0x8);
    memcpy(page + 0x310, 0x80000310, 0x58);
 
    return(SS$_NORMAL);
}
 
static unsigned long lock_vec();
 
/*
 * Replicate our hand crafted vector table entry over the entire
 * P1 vector table.
 *
 * If we have decided not to reuse the existing memory then:
 * allocate enough memory to hold the vector table and to allow
 * for aligning the vector table on a page boundary; finally
 * lock these newly allocated pages into the working set
 * (the real P1 vector pages are locked into the working set).
 */
 
static void setup_ssvectors(struct ssinfo *ssinfo)
{
    unsigned long status;
 
    status = p1alloc((NUMVEC * CELLSIZE) + 512, &(ssinfo->ss_vectors));
    if ((status & 1) == 0)
        lib$stop(status);
 
    cmkrnl(copy_vec, ssinfo);
 
    cmkrnl(lock_vec, ssinfo, &status);
    if (status != SS$_NORMAL)
        lib$stop(status);
}
 
/* ----------------------------------------------------------------------- */
 
/*
 * Lock the system service dispatch vectors into the working set.
 *
 * We do not currently check the return range.
 */
 
static unsigned long lock_vec(struct ssinfo *ssinfo, unsigned long *status)
{
    unsigned long block[2], result[2];
 
    block[0] = ssinfo->ss_vectors; block[1] = block[0] +
ssinfo->ss_vectors_size;
    *status = sys$lkwset(block, result, PSL$C_KERNEL);
    return(SS$_NORMAL);
}
 
/*
 * Unlock the system service dispatch vectors from the working set.
 */
 
static unsigned long unlock_vec(struct ssinfo *ssinfo, unsigned long *status)
{
    unsigned long block[2], result[2];
 
    block[0] = ssinfo->ss_vectors; block[1] = block[0] +
ssinfo->ss_vectors_size;
    *status = sys$ulwset(block, result, PSL$C_KERNEL);
    return(SS$_NORMAL);
}
 
/* ----------------------------------------------------------------------- */
 
static void fail(char *reason)
{
    perror(reason);
    exit(0);
}
 
/*
 * Copy the tracing code first into a user writable buffer. This prevents
 * problems with privileged mode access to file system primatives and makes
 * tidying up in the event of an error easier.
 */
 
static void get_ssload(char *file, struct mem *mem)
{
    FILE *f;
    void *c;
    int n;
    stat_t stats;
 
    if ((f = fopen(file, "r")) == 0)
        fail("fopen");
    if (fstat(fileno(f), &stats))
        fail("fstat");
    if ((c = malloc(stats.st_size)) == 0)
        fail("malloc");
    if ((n = fread(c, stats.st_size, 1, f)) != 1)
        fail("fread");
    fclose(f);
 
    mem->base = c;
    mem->size = stats.st_size;
}
 
unsigned long copy_ssload(struct ssinfo *ssinfo, char *user)
{
    memcpy(ssinfo->ss_base, user, ssinfo->ss_base_size);
    return(SS$_NORMAL);
}
 
/*
 * Copy tracing code from user writable buffer in P0 to P1 buffer.
 */
 
static void setup_ssload(struct ssinfo *ssinfo, char *loadfile)
{
    unsigned long status;
    struct mem usermem;
 
    get_ssload(loadfile, &usermem);
 
    status = p1alloc(usermem.size, &(ssinfo->ss_base));
    if ((status & 1) == 0)
        lib$stop(status);
 
    cmkrnl(copy_ssload, ssinfo, usermem.base);
}
 
/* ----------------------------------------------------------------------- */
 
/*
 * Assign supervisor mode channel to device on which logging has
 * been requested.
 */
 
unsigned long open_file(struct ssinfo *ssinfo, unsigned long *status)
{
    struct dsc$descriptor file;
 
    file.dsc$b_class = file.dsc$b_dtype = 0;
    file.dsc$w_length = strlen(ssinfo->ss_filename);
    file.dsc$a_pointer = ssinfo->ss_filename;
 
    *status = sys$assign(&file, &ssinfo->ss_file, PSL$C_SUPER, 0);
    return(SS$_NORMAL);
}
 
/*
 * Establish channel to the logging device from a privileged mode.
 */
 
static void setup_ssfile(struct ssinfo *ssinfo)
{
    unsigned long status;
 
    cmkrnl(open_file, ssinfo, &status);
    if (status != SS$_NORMAL)
        lib$stop(status);
}
 
/*
 * Deassign the supervisor mode channel on which we logged the system
 * service invocations.
 */
 
static unsigned long close_file(unsigned short chan, unsigned long *status)
{
    *status = sys$dassgn(chan);
    return(SS$_NORMAL);
}
 
/* ----------------------------------------------------------------------- */
 
unsigned long copy_ssinfo(struct ssinfo *ssinfo)
{
    CTL$GL_SITESPEC = ssinfo->ss_info;
    *CTL$GL_SITESPEC = *ssinfo;
    return(SS$_NORMAL);
}
 
/*
 * Copy the user mode writable copy of the information block to the
 * P1 page, and set CTL$GL_SITESPEC to point to the P1 page.
 */
 
static void setup_ssinfo(struct ssinfo *ssinfo)
{
    unsigned long status;
 
    status = p1alloc(sizeof(struct ssinfo), &(ssinfo->ss_info));
    if ((status & 1) == 0)
        lib$stop(status);
 
    cmkrnl(copy_ssinfo, ssinfo);
}
 
/*
 * Clear the per-process site specific longword.
 */
 
static unsigned long clear_sitespec()
{
    CTL$GL_SITESPEC = 0;
    return(SS$_NORMAL);
}
 
/* ----------------------------------------------------------------------- */
 
/*
 * Handle arguments lists for the sys$cmkrnl system service.
 */
 
static unsigned long cmkrnl(void (*func)(), unsigned long arg1, ...)
{
    unsigned long arg[13];
 
    va_count(arg[0]);
    if (arg[0] > 12) {
        printf("more than 12 arguments passed to cmkrnl\n");
        exit(0);
    }
    memcpy(&arg[1], &arg1, (arg[0] - 1) * sizeof (unsigned long));
 
    return sys$cmkrnl(func, arg);
}
----------------------------ssinfo.h------------------------------------
---------
#define NUMVEC              320
#define CELLSIZE            8
#define MAXVECPAGES         16
#define ENTRY_MASK_SIZE     2
 
#define NUMVECPAGES         (((NUMVEC * CELLSIZE) + 511) / 512)
 
struct valid_pte {
    unsigned pfn    : 21;
    unsigned win    : 1;
    unsigned x      : 1;
    unsigned owner  : 2;
    unsigned y      : 1;
    unsigned mod    : 1;
    unsigned prot   : 4;
    unsigned valid  : 1;
};
 
struct call_info {
    unsigned mbz    : 5;
    unsigned psw    : 11;
    unsigned mask   : 12;
    unsigned unused : 1;
    unsigned calls  : 1;
    unsigned align  : 2;
};
 
struct ssinfo {
    unsigned long       ss_base;
    unsigned long       ss_base_size;
    unsigned long       ss_vectors;
    unsigned long       ss_vectors_size;
    unsigned long       ss_info;
    unsigned long       ss_info_size;
    struct valid_pte    ss_saved_pte[MAXVECPAGES];
    unsigned short      ss_file;
    char                ss_filename[255];
};
 
 
 
 
 
 
 
 
 
 
From:   IN%"eru!hagbard!sunic!mcsun!cernvax!chx400!cgch!fizciba-geigy.ch!bnebga@
bl
   oom-beaco" 27-NOV-1990 06:11:40.97
To:     info-vax@kl.sri.com
Subj:   Tracing system services - question and temp. bug fix
Date: 27 Nov 90 10:59:21 GMT
From:  eru!hagbard!sunic!mcsun!cernvax!chx400!cgch!fizciba-geigy.ch!bnebga@bloom
   -beaco
 
Can anyone tell me what happens to the IPL as a result of a CHMK instruction?
Is it reasonable for code running at an elevated IPL to use the CHMK
instruction? I do not have a copy of the VAX architecture handbook.
 
The question arises in connection with the sytem service tracing program which
I recently posted. The system would crash with a reserved operand exception
when tracing the $crembx system service. An analysis of the system dump
indicated that an REI instruction had attempted to raise the IPL from 0 to 2; I
guess this is what caused the crash.
 
If IPL is preserved across a change mode trap I would guess that what causes
the crash is that a system service is invoked via the P1 table at raised IPL;
then one of the system services that trace invokes (perhaps $qio) sets IPL to
0; when we finally try to REI from the original system service call we find
that REI is trying to raise IPL. Is this plausible?
 
Appended to this message is a patch to disable tracing of system service calls
at elevated IPL and a few more notes on the behaviour of sstrace.
 
Gary Nebbett (/pn=gary.nebbett/ou=chcgbs30/@ciba-geigy.ch)
 
------------------------------------------------------------------------
-----------
************
File SSREADME.TXT;2
   28   sstrace does not trace user-written system services, or any other
system
   29   service implemented in a shareable image (like $MOUNT, some security
system
   30   services, etc).
   31
   32   sstrace uses EFN 0; if an application also uses EFN 0 without an IOSB
then the
   33   behaviour of the application may be affected. It is unlikely (hopefully)
that
   34   any DEC applications would be so foolish as to do this.
   35
   36   I CURRENTLY KNOW OF THREE IMPORTANT THINGS THAT YOU SHOULD BE WARNED
ABOUT WITH
******
File SSREADME.TXT;1
   28   I CURRENTLY KNOW OF THREE IMPORTANT THINGS THAT YOU SHOULD BE WARNED
ABOUT WITH
************
************
File SSREADME.TXT;2
   46      bugcheck will occur which will crash the system. It may be the case
that
   47      this will only occur if the process has, at some time in its life,
run the
   48      debugger (and hence also possesses a debugger created  version of the
vector
   49      table).
   50
******
File SSREADME.TXT;1
   38      bugcheck will occur which will crash the system.
   39
************
------------------------------------------------------------------------
-----------
************
File SSLOADG.MAR;2
   14   ; MODIFIED BY:  Gary Nebbett, 27th November, 1990
   15   ;                         Add check for current IPL - skip trace if not
zero
   16   ;
******
File SSLOADG.MAR;1
   14   ; MODIFIED BY:
   15   ;
************
************
File SSLOADG.MAR;2
   57   ;       A check for the current IPL level is also made; if the current
IPL is
   58   ;       not zero then the trace functions are skipped. This test was
added
   59   ;       after problems tracing the $crembx system service indicated that
an
   60   ;       REI instruction was trying to raise IPL from 0 to 2 and hence
causing
   61   ;       a reserved operand fault.
   62   ;
   63   ;
******
File SSLOADG.MAR;1
   56   ;
************
************
File SSLOADG.MAR;2
   96           MOVPSL  R1                      ; move PSL into R1
   97           EXTZV   #16, #5, R1, R0         ; extract the IPL from the PSL
   98           BNEQ    HIGHIPL                 ; only trace functions invoked
at IPL=0
   99           EXTZV   #22, #4, R1, R0         ; extract the current and
previous access modes from the PSL
  100           BNEQ    STACKOK                 ; only check for stack space if
current and previous mode = K
  101           PROBEW  #0, #512, -516(SP)      ; probe next 512 bytes of stack
for write access
  102           BNEQ    STACKOK                 ; if stack space is scarce do
not invoke trace function
  103   HIGHIPL:
  104           POPL    R0                      ; get saved return address -
will be in range of P1 vector table
******
File SSLOADG.MAR;1
   89           MOVPSL  R1                      ; move PSL into R1
   90           EXTZV   #22, #4, R1, R0         ; extract the current and
previous access modes from the PSL
   91           BNEQ    STACKOK                 ; only check for stack space if
current and previous mode = K
   92           PROBEW  #0, #512, -516(SP)      ; probe next 512 bytes of stack
for write access
   93           BNEQ    STACKOK                 ; if stack space is scarce do
not invoke trace function
   94           POPL    R0                      ; get saved return address -
will be in range of P1 vector table
************
 
 
