Operating System - OpenVMS
1820095 Members
3488 Online
109608 Solutions
New Discussion

Re: System Service Interception on OpenVMS

 
JohnRD
Visitor

System Service Interception on OpenVMS

Hi,

 

Does anyone know if DEC/Compaq/HP produced any documentation about the System Service Interception API on OpenVMS Alpha?

 

If so, where or how I can get a copy of the document(s)?

 

Thanks

 

John

17 REPLIES 17
John McL
Trusted Contributor

Re: System Service Interception on OpenVMS

I'm sure that John Gillings will give you the details but conceptually it's pretty simple - just provide a new function with the same name as the system service function, and within that new function do a LIB$FIND_IMAGE_SYMBOL to activate the image and locate the sys service function, then call it.

 

In your own function you can add whatever diagnostics or monitoring that you want to add.  Also you can step into your own function from the debugger and get full access whereas with the system service images it's not so easy. 

 

Hein van den Heuvel
Honored Contributor

Re: System Service Interception on OpenVMS

 

Hmm,

 

What problem are you trying to solve, or just curios?

 

Ever heard about Google? Wonderful invention! Try it some day?!

it leads me to: http://h71000.www7.hp.com/openvms/journal/v8/ssi.pdf

Of course it helps knowing that that existed, having talked to Ruth about it :-)

 

And what about $ HELP  SET PROC /SSLOG and $ HELP **bleep**/SSLOG.

[edit: stupid computers (programmers).... I'll let you analyze as to why it bleeb my perfectly honorable reply ]

 

Now if you experiemnt with that, I recommend to SPAWN first, then try.

When I last used it it was not entirely stable.

 

I also received the following text and code from Harmut B, some 5 years ago.

See below.

 

Hope this helps,

Hein.

 

----------------------- Hartmut --------------------------------------------------------

 

If you want to use just ssi$declare_intercept.

I append a small example, which I tested on I64/V8.3-1H1.

The SSI_BLOCK is filled like

static SSI_BLOCK ssi_block = {
       0, 0,
       SSI$C_LENGTH, DYN$C_MISC, DYN$C_SSI_BLOCK,
       SSI$K_VERSION_QUAD_LIST, 0,
       pre, post};

So you will get into your pre() and post() for all system services, once you successfully called the declare routine.

To do processing just for one system service, you need to check against its declared address, as in starlet.h or for example with a "extern int sys$asctim();". Once in your pre() or post() this system service address is in ps_ssadr.

You can make the call to ssi$declare_intercept from your main image. If you don't have control over main, you can place the call in an init routine in a shareable image and let it call during the image initialization via the lib$initialize mechanism.

On Alpha, if your shareable image is not activated with main, that is SYS$SSISHR is not activated with main, then you can't intercept system service calls from main (and all the shareable images it depends on).

Yes, you should be able to do the same with replacing a few system services. You should also be able to use a single generic replacement routine. There you check the passed ps_ssadr against you list and call the original system service as passed in ss_ssadr. I didn't try that, so far, and therefore don't have an example.

You just link against the SYS$SSISHR, that's all.

That's my understanding, it may be incomplete or not 100% correct, but I hope it helps to get you started or even going.

 

 

 

#include <pdscdef.h>
#include <ssdef.h>
#include <ssidef.h>
#include <starlet.h>
#include <stdio.h>
#include <dyndef.h>

#include <descrip.h>

static char timbuf[32] ;
static $DESCRIPTOR (timbuf_d, timbuf) ;
static short int timlen ;

static int preasctim;
static int postss;

static void pre(int *arg_list, int (*ss_ssadr)(), SSI_PDSC *ps_ssadr, int retadr, SSI_BLOCK *ssi_block_ptr) {
	if ((int(*)())ps_ssadr==sys$asctim)
		preasctim++;}
static void post() {postss++;}

static SSI_BLOCK ssi_block = {
	0, 0, SSI$C_LENGTH, DYN$C_MISC, DYN$C_SSI_BLOCK, SSI$K_VERSION_QUAD_LIST, 0,
	pre, post};

main() {
	int status;
	printf ("preasctim: %d, postss: %d\n", preasctim, postss);
	status= ssi$declare_intercept (&ssi_block);
	if (status!=SS$_NORMAL)
		printf ("status: 0x%x\n", status);
	else {
		printf ("hello ssi\n");
		sys$asctim (&timlen,&timbuf_d,0,0);
		printf ("time: %.*s\n", timlen, timbuf) ;
		fsync (fileno (stdout));
		printf ("preasctim: %d, postss: %d\n", preasctim, postss);
	}
}

 

JohnRD
Visitor

Re: System Service Interception on OpenVMS

Thanks for the responses.

 

I am experimenting with SSI in order to capture the system calls issued by an old application.

 

I had already found using Google the journals on the subject written by John Gillings and Ruth Goldenberg. Though they are extremely interesting, they did not provide enough practical information since I am not an OpenVMS internals guru.

 

Ruth did mention at the end of her journal "For information on the use of SSI, please check HP OpenVMS System Documentation home page for forthcoming documentation", but I have not yet been successful in finding this information.

H.Becker
Honored Contributor

Re: System Service Interception on OpenVMS

>>> to capture the system calls issued by an old application
 
Do you want to count the calls for one or all system services? You probably want to capture what your application directly calls and not what the RTLs call on behalf of the application. You probably have a linker map or can generate one, so you know the system services from the map file. If you don't have the objects to link the application, you can use XPD to get the names. But then, you can't use ssi, because you have to link your application with an object or shareable image which provides your ssi stuff.  
 
This is what  XPD shows when analyzing itself:
$ mc []xpd xpd.exe
eXternal Procedure and Data list (Alpha), version 1.5
CMA$TIS_SHR:
offset 0x100 maps to CMA$TIS_VMSERRNO_GET_ADDR, type is procedure
offset 0xe0 maps to CMA$TIS_ERRNO_GET_ADDR, type is procedure
DECC$SHR -> SYS$SHARE:DECC$SHR_EV56:
offset 0x2710 maps to DECC$STRLEN, type is procedure
...
offset 0x4f0 maps to DECC$GA_STDERR, type is data
offset 0x4e0 maps to DECC$GA_STDOUT, type is data
LIBOTS:
offset 0x1b0 maps to OTS$MOVE, type is procedure
SYS$PUBLIC_VECTORS:
offset 0x830 maps to SYS$PARSE, type is procedure

John Gillings
Honored Contributor

Re: System Service Interception on OpenVMS

I've been able to intercept system services using ssi$declare_interrupt.

 

On Alpha V8.3, I was only able to get the intercepts to work with RUN/DEBUG (something to do with getting SYS$SSISHR activated).

 

A few things to look out for. You need to be very careful of recursion. Anything that directly or indirectly invokes a system service from inside the pre or post routine could put you into a recursion loop. You can use a simple static flag in both pre and post routines so they only act on first level calls.

 

pre(args...)
static busy

  if not busy then 
    busy=true
      do stuff here...
    busy=false
  endif

end

 

I was able to do I/O from the protected code. Counters showed thousands of other invokations even for trivially simple programs (there appears to be some kind of polling from DEBUG)

 

You can detect specific system services by looking at the PDSC address and comparing with the global symbol (as shown in Hein/Hartmut's the C example). However, I couldn't find a simple way to identify an arbitrary incoming service call. There are obvious brute force mechanisms, but for the huge volume of calls you're likely to get, the lookup needs to be fast.

 

I was trying to create a generic routine to dump the name and argument list of all system services called. The simplest mechanism I can think of is to dump name/PDSC pairs, based on a shareable image /NAMES list from SYS$PUBLIC_VECTORS, then dump the PDSC of each call, along with the argument list, then post process the listings to resolve the addresses into names.

 

Use SSI$DECLARE_REPACEMENT PDSC_Of_Target,YourRoutine

 

to substitute routines (but beware, this is non-trivial!)

A crucible of informative mistakes
H.Becker
Honored Contributor

Re: System Service Interception on OpenVMS

>>> On Alpha V8.3, I was only able to get the intercepts to work with RUN/DEBUG (something to do with getting SYS$SSISHR activated).

 

Works for me on Alpha and V8.3. I'm just an unpriv guest there, so I have no idea about the ECOs installed. The linker has to resolve the ssi$declare_interrupt, so you very likely linked with sys$ssishr.exe. 
 
$ mc []xpd ssi.exe
eXternal Procedure and Data list (Alpha), version 1.5
SYS$SSISHR:
offset 0x10 maps to SSI$DECLARE_INTERCEPT, type is procedure
offset 0x140 maps to SYS$ASCTIM, type is procedure
DECC$SHR -> SYS$SHARE:DECC$SHR_EV56:
offset 0x7b0 maps to DECC$MAIN, type is procedure
offset 0x46e0 maps to DECC$GXPRINTF, type is procedure
offset 0x2000 maps to DECC$EXIT, type is procedure
offset 0x15f0 maps to DECC$FILENO, type is procedure
offset 0x31b0 maps to DECC$FSYNC, type is procedure
offset 0x3a20 maps to DECC$$SHELL_HANDLER, type is procedure
offset 0x4e0 maps to DECC$GA_STDOUT, type is data
 
Do you get an error message, maybe when activating the main image? 
John Gillings
Honored Contributor

Re: System Service Interception on OpenVMS

No errors, status is normal, just no execution of the pre and post routines. Example:

 

$ run/nodebug ssi
 ELAPSED:    0 00:00:00.00  CPU: 0:00:00.00  BUFIO: 0  DIRIO: 0  FAULTS: 0
Declare: 00000001 Pre: In 00000000 Act 00000000  Post Out 00000000 act 00000000


$ run/debug ssi

         OpenVMS Alpha Debug64 Version V8.3-016

%DEBUG-I-INITIAL, Language: AMACRO, Module: SYS$MISCDEF

DBG> go
SSI_PRE 25-MAY-2012 11:53:39.35 SS: 820EBC60 PDSC: 001A08C0 From: 810CC14C Args:   7   00000000 00000080 00000000 00000000 00000000
00000000 00000000
SSI_PRE 25-MAY-2012 11:53:39.35 SS: 82101290 PDSC: 0019F540 From: 810CC184 Args:   1   00000000
SSI_PRE 25-MAY-2012 11:53:39.35 SS: 820EBC60 PDSC: 001A08C0 From: 810CC14C Args:   7   00000000 00000080 00000000 00000000 00000000
00000000 00000000
SSI_PRE 25-MAY-2012 11:53:39.35 SS: 82101290 PDSC: 0019F540 From: 810CC184 Args:   1   00000000
SSI_PRE 25-MAY-2012 11:53:39.35 SS: 82100EF0 PDSC: 0019F420 From: 810CBBD4 Args:  11   00000000 7AD639C0 00000000 7AD639B8 00000000
7AD639B8 00000000 7AD639E8 00000000 00000000 00000000
SSI_PRE 25-MAY-2012 11:53:39.35 SS: 82131AB0 PDSC: 001A0110 From: 810C20C4 Args:   1   00000000
 ELAPSED:    0 00:00:00.00  CPU: 0:00:00.00  BUFIO: 2  DIRIO: 0  FAULTS: 0
Declare: 00000001 Pre: In 00000033 Act 00000006  Post Out 00000033 act 00000006
%DEBUG-I-EXITSTATUS, is '%SYSTEM-S-NORMAL, normal successful completion'
DBG>

 

Here are the routines (hopefully my macros are self evident)

 

Main routine

        .ENTRY Start,^M<>
          CALL SSI_START
          MOVL R0,DeclareStat
            CALL LIB$INIT_TIMER
            CALL LIB$SHOW_TIMER
          CALL SSI_STOP
        MessageOut <<Declare: !XL Pre: In !XL Act !XL  Post Out !XL act !XL> #DeclareStat #In #ActIn #Out #ActOut>
        RET

PRE routine

        .ENTRY SSI_PRE,^M<R2,R3>
        arglist args ssadr dsc retadr blk
          INCL In
          BLBS Recur,PRESkip
            MOVL #1,Recur
            INCL ActIn
              CALL FormatArgs AllArgs @args_arg(AP)
              MessageOut <<SSI_PRE !%D SS: !XL PDSC: !XL From: !XL Args: !3UL !AS> -
                                   ##0 #ssadr_arg(AP) #dsc_arg(AP) #retadr_arg(AP) #@args_arg(AP) AllArgs>
            CLRL Recur
          PRESkip: RET

 

 

This obviously has something to do with activation of SYS$SSISHR, but I don't understand the mechanism. I'd guess that most of the time this would be a diagnostic tool, so running under DEBUG would be fairly normal.

 

Not sure what XPD is, here's what IMAGETREE has to say about the image

 

$ @imagetree []ssi.exe
SSI, executable V1 RWD,RWD,R,
  SYS$SSISHR, shareable(%X'01',%X'0003E8',MATEQU) X-20 build:XBCA-0080070058 RWED,RWED,RE,RE
   Installed Open Hdr Shared Prot Lnkbl
    SYS$BASE_IMAGE, shareable(%X'56',%X'703EFE',MATEQU) ALPHA XBCA-N2O build:XBCA-0080070099 RWED,RWED,RE,RE
  SYS$SSISHR references 1 image
  LIBRTL, shareable(%X'01',%X'000001',MATLEQ) X01-001 build:XBCA-0080070005 RWED,RWED,RE,RE
   Installed Open Hdr SharAddr Lnkbl Resid
    SYS$PUBLIC_VECTORS, shareable(%X'13',%X'0064E6',MATEQU) X-123 build:XBCA-0080070058 RWED,RWED,RE,RE
     Installed
  LIBRTL references 1 image
  LIBOTS, shareable(%X'01',%X'000003',MATLEQ) LIBOTS V1.5-00 build:XBC4-0080060000 RWED,RWED,RE,RE
   Installed Open Hdr SharAddr Lnkbl Resid
    SYS$PUBLIC_VECTORS (repeat)
  LIBOTS references 1 image
SSI references 3 images

 

 

A crucible of informative mistakes
H.Becker
Honored Contributor

Re: System Service Interception on OpenVMS

XPD is part of the VMS Objects and Image Tool set. For an image, it lists external procedures and data.

 

I can't see why your code doesn't work with /nodebug. From the output of your IMAGETREE, SYS$SSISHR is linked with your main image, so it is activated with main and it is correctly installed as a protected shareable image.  SYS$SSISHR has init code, which has to run. But I don't see what would prevent that from running especially with /nodebug. The obvious difference is Macro32 vs. C, but that should not cause the different behavior. At least when I modify my example to avoid the CRTL dependency, it still works as expected.
JohnRD
Visitor

Re: System Service Interception on OpenVMS

I have created a shareable executable linked with SYS$SSISHR, and have managed to intercept system services such as  SYS$ASCTIM issued from COBOL, but I have found that the RMS system services such as SYS$CONNECT and SYS$RMS_CONNECT are not being intercepted.

 

Is it not possible to intercept the RMS system services?

 

By the way, I am currently restricted and struggling with an Alpha running V7.3-2.

H.Becker
Honored Contributor

Re: System Service Interception on OpenVMS

I know, it doesn't help, but it works for me (on OpenVMS V8.3, node EISNER, AlphaServer DS20 500 MHz). I took the Example 3-1 "Use of the Create, Open, and Close Services" from http://h71000.www7.hp.com/doc/731final/4523/4523pro_002.html, changed my example to count sys$connect and created a shareable image with image initialization out of it; I linked the RMS example against it an ran it: the shown count is two.

 

Sorry, I don't have the time (but you can hire me any time :-) to do more testing and I don't have the same environment as you have: I have no idea why it doesn't work for you and V7.3-2.

John Gillings
Honored Contributor

Re: System Service Interception on OpenVMS

FWIW,

   I worked out an ugly way to translate system service PDs into names. I use a macro to build a table of value pairs (PD,descriptor address), like this:

 

        .PSECT Table,RD,WRT,NOEXE,QUAD
MaxTbl: .LONG 0
K_MaxTbl=0
SymTbl:
        .MACRO RTN nam
           .PSECT Const
           .ALIGN QUAD
           S%EXTRACT(0,30,nam): .ASCID /'nam'/
           .PSECT Table
           .ADDRESS 'nam'
           .ADDRESS S%EXTRACT(0,30,nam)
           K_MaxTbl=K_MaxTbl+1
        .ENDM RTN
RTN SYS$QIOW
RTN SYS$CLI
RTN SYS$ADJSTK
RTN SYS$ADJWSL
RTN SYS$ALCDNP
...

 The list of routine names is taken from SYS$SSISHR entry points. At run time, the table is sorted on PD value at initialisation. To determine a system service name do a binary search for the PD value, which gives the address of the string descriptor.

 

Regarding JohnRD's question about RMS services. I see a curious behaviour. If I link against SYS$SSISHR without DEBUG and just RUN the image I catch those system services which the image calls directly. Here's the beginning and end of a run of Hein's "STRINGS" program running against itself:

 

SSI 30-MAY-2012 08:38:35.54 SYS$OPEN     From: 00030A98 AP:   1  00000000
SSI 30-MAY-2012 08:38:35.54 SYS$CONNECT  From: 00030AC4 AP:   1  00000000
SSI 30-MAY-2012 08:38:35.54 SYS$GET      From: 00030B64 AP:   1  00000000
STRINGS
SSI 30-MAY-2012 08:38:35.54 SYS$GET      From: 00030B64 AP:   1  00000000
SYS$SSISHR_001
LIBRTL_001
LIBOTS_001
SSI 30-MAY-2012 08:38:35.54 SYS$GET      From: 00030B64 AP:   1  00000000
SSI 30-MAY-2012 08:38:35.54 SYS$GET      From: 00030B64 AP:   1  00000000

...

DSC$K_CLASS_S
DSC$K_DTYPE_T
START
SSI 30-MAY-2012 08:38:35.60 SYS$GET      From: 00030B64 AP:   1  00000000
SSI_FINDENTRY
SSI_FIXTABLE
SSI_STOP
SSI_FORMATARGS
SSI_START
SSI_POST
SSI_PRE
SSI 30-MAY-2012 08:38:35.60 SYS$GET      From: 00030B64 AP:   1  00000000
SSI 30-MAY-2012 08:38:35.60 SYS$CLOSE    From: 00030AF4 AP:   1  00000000
SSI Pre: In 000004E3 Act 000001A1  Post: Out 000004E3 act 000001A1

 

 

 Notice that the output lines (written with LIB$PUT_OUTPUT) don't trigger any traces for the services they obviously call. Also note the counters on the final line. Exactly the same program, run under DEBUG

 

         OpenVMS Alpha Debug64 Version V8.3-016

%DEBUG-I-INITIAL, Language: AMACRO, Module: .MAIN.

DBG> go
SSI 30-MAY-2012 08:35:50.57 SYS$CLI      From: 810BE254 AP:   1  00000000
SSI 30-MAY-2012 08:35:50.57 SYS$OPEN     From: 00030A48 AP:   1  00000000
SSI 30-MAY-2012 08:35:50.57 SYS$CONNECT  From: 00030A68 AP:   1  00000000
SSI 30-MAY-2012 08:35:50.57 SYS$GET      From: 00030AEC AP:   1  00000000
SSI 30-MAY-2012 08:35:50.57 SYS$PUT      From: 810C20C4 AP:   1  00000000
STRINGS
SSI 30-MAY-2012 08:35:50.57 SYS$GET      From: 00030AEC AP:   1  00000000
SSI 30-MAY-2012 08:35:50.57 SYS$PUT      From: 810C20C4 AP:   1  00000000
SYS$SSISHR_001
SSI 30-MAY-2012 08:35:50.57 SYS$PUT      From: 810C20C4 AP:   1  00000000
LIBRTL_001
SSI 30-MAY-2012 08:35:50.57 SYS$PUT      From: 810C20C4 AP:   1  00000000
LIBOTS_001
SSI 30-MAY-2012 08:35:50.57 SYS$GET      From: 00030AEC AP:   1  00000000
SSI 30-MAY-2012 08:35:50.57 SYS$GET      From: 00030AEC AP:   1  00000000

...


SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
DSC$K_CLASS_S
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
DSC$K_DTYPE_T
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
START
SSI 30-MAY-2012 08:35:52.18 SYS$GET      From: 00030AEC AP:   1  00000000
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_FINDENTRY
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_FIXTABLE
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_STOP
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_FORMATARGS
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_START
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_POST
SSI 30-MAY-2012 08:35:52.18 SYS$PUT      From: 810C20C4 AP:   1  00000000
SSI_PRE
SSI 30-MAY-2012 08:35:52.18 SYS$GET      From: 00030AEC AP:   1  00000000
SSI 30-MAY-2012 08:35:52.18 SYS$CLOSE    From: 00030A8C AP:   1  00000000
SSI Pre: In 000063CD Act 000018F2  Post: Out 000063CD act 000018F2
%DEBUG-I-EXITSTATUS, is '%SYSTEM-S-NORMAL, normal successful completion'

 

Now we see the SYS$PUTs from LIB$PUT_OUTPUT and the counters are much higher. I guess it depends on when the fixups are done how the SSI effects calls from lower level shareable images. It explains my earlier observation that I got no output, as my test program in that case had no direct system service calls. Could be seen as a feature.

 

My next puzzle is why the arguments of the RMS services are all 0! Also, DEBUG issues a constant stream of $SETIMR/$WAITFR pairs. I need to work out a simple way to recognise and bypass system service calls originating from DEBUG. The from address should help, but it's non-trivial!

A crucible of informative mistakes
John Gillings
Honored Contributor

Re: System Service Interception on OpenVMS

Proof of concept.

 

I added a bypass in the PRE routine for "from" address within a particular range.

Running the under DEBUG and using SHOW IMAGE to find the start and end addresses for the DEBUG image and manually DEPOSIT those values into the range check.

I can now set a break point to the active section of the PRE address without sending DEBUG into a recursion loop.

 

Next step is to find a reasonably clean way to automatically detect the DEBUG image and set the range...

 

Using this trick with DEBUG I was able to confirm that the argument list SSI gets for the RMS services is indeed count=1 fiist arg=0. Not sure why.

A crucible of informative mistakes
H.Becker
Honored Contributor

Re: System Service Interception on OpenVMS

>>> I guess it depends on when the fixups are done how the SSI effects calls from lower level shareable images.

 
I'm not sure what you mean by that. Fixups are always done at the same time and the same way. Fixups are "fixed": VMS has early binding. In other words, you can't get any different results from the same fixups running at different times. Or put it another way, if you have a "low level shareable image" linked against sys$public_vectors, you can't fix it up against sys$ssishr.
John Gillings
Honored Contributor

Re: System Service Interception on OpenVMS

>> Or put it another way, if you have a "low level shareable image" linked against sys$public_vectors, you can't fix it up against sys$ssishr

 

Fair enough, but that doesn't explain the observation.  How are we catching system service calls from low level shareable images? Here's the result matrix:

 

Image                    Image Liked

Run              /NODEBUG          /DEBUG

/NODEBUG         Direct Only       All Calls

/DEBUG           All Calls         All Calls

 

Note that in all cases the image itself is linked against SYS$SSISHR (has to be to resolve the calls to DECLARE_INTERCEPT).

 

My evidence for "All Calls" is I'm catching SS calls with FROM addresses in LIBRTL.

 

JG>
JG> macro/noopt/deb strings+[-]util/lib
JG> link strings+ssishr/opt

First run, LINK/NODEBUG RUN/NODEBUG. Only one direct call was caught.

JG> run strings
SSI 31-MAY-2012 07:56:25.74 SYS$GETTIM   From: 00030B14 AP:   1  00000000
Please enter filename:
SSI Pre: In 00000003 Act 00000001  Post: Out 00000003 act 00000001


Second run LINK/NODEBUG RUN/DEBUG. Direct and indirect calls caught. The
block of calls from SYS$CLI to SYS$GET are from LIB$GET_FOREIGN. Note that 
the LIBRTL addresses are in S0 space - so they're from the resident image.

JG> run/debug strings
%DEBUG-I-NOGLOBALS, some or all global symbols not accessible

         OpenVMS Alpha Debug64 Version V8.3-016

%DEBUG-I-INITIAL, Language: AMACRO, Module: STRINGS

DBG> go
SSI 31-MAY-2012 07:56:54.89 SYS$GETTIM   From: 00030B14 AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$CLI      From: 810BE254 AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$SETAST   From: 810BEA14 AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$READ_THR From: 810BEA2C AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$OPEN     From: 810BEB68 AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$CONNECT  From: 810BEC94 AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$SETAST   From: 810BEDD4 AP:   1  00000000
SSI 31-MAY-2012 07:56:54.89 SYS$GET      From: 810BF1E4 AP:   1  00000000
Please enter filename: Exit
SSI Pre: In 00000025 Act 00000008  Post: Out 00000025 act 00000008
%DEBUG-I-EXITSTATUS, is '%RMS-E-EOF, end of file detected'
DBG> set image librtl
DBG> examine 810BE254
%DEBUG-E-INVPD, procedure descriptor at 00000000000E3198 is not valid.
LIB$GET_FOREIGN\LIB$GET_FOREIGN\%LINE 545:              LDL             R5,#X0020(FP)
DBG> exit


Third run LINK/DEBUG RUN/NODEBUG direct and indirect calls caught.

JG> link/debug strings+ssishr/opt
JG> run/nodeb strings
SSI 31-MAY-2012 07:57:13.40 SYS$GETTIM   From: 00030B14 AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$CLI      From: 810BE254 AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$SETAST   From: 810BEA14 AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$READ_THR From: 810BEA2C AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$OPEN     From: 810BEB68 AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$CONNECT  From: 810BEC94 AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$SETAST   From: 810BEDD4 AP:   1  00000000
SSI 31-MAY-2012 07:57:13.40 SYS$GET      From: 810BF1E4 AP:   1  00000000
Please enter filename: Exit
SSI Pre: In 00000025 Act 00000008  Post: Out 00000025 act 00000008
%RMS-E-EOF, end of file detected


Fourth run LINK/DEBUG RUN/DEBUG direct and indirect calls caught.


JG> run/debug strings

         OpenVMS Alpha Debug64 Version V8.3-016

%DEBUG-I-INITIAL, Language: AMACRO, Module: STRINGS

DBG> go
SSI 31-MAY-2012 07:57:29.17 SYS$GETTIM   From: 00030B14 AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$CLI      From: 810BE254 AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$SETAST   From: 810BEA14 AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$READ_THR From: 810BEA2C AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$OPEN     From: 810BEB68 AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$CONNECT  From: 810BEC94 AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$SETAST   From: 810BEDD4 AP:   1  00000000
SSI 31-MAY-2012 07:57:29.17 SYS$GET      From: 810BF1E4 AP:   1  00000000
Please enter filename: Exit
SSI Pre: In 00000025 Act 00000008  Post: Out 00000025 act 00000008
%DEBUG-I-EXITSTATUS, is '%RMS-E-EOF, end of file detected'
DBG> set image librtl
DBG> examine 810BE254
%DEBUG-E-INVPD, procedure descriptor at 00000000000E3198 is not valid.
LIB$GET_FOREIGN\LIB$GET_FOREIGN\%LINE 545:              LDL             R5,#X0020(FP)

 

Note that the LIBRTL calls are coming from S0 space, so they're the RESIDENT image  (ShareAddr!). How are we catching those, and why does it depend on /DEBUG?

 

Here's what the call stack looks like inside SSI_PRE when called through LIBRTL

 

DBG> show calls
 module name    routine name     line           rel PC           abs PC
 SHARE$SIMPLE                               000000000000098C 000000000003098C
 SHARE$SYS$SSISHR                           0000000000010C64 000000000018CC64
 SHARE$SYS$SSISHR                           0000000000011884 000000000018D884
*LIB$GET_INPUT  DO_GET           1851       0000000000000548 FFFFFFFF810BEB68
----- the above looks like a null frame in the same scope as the frame below
*LIB$GET_INPUT                                             ?                ?
*LIB$GET_INPUT  LIB$GET_INPUT
                                 1569       000000000000020C FFFFFFFF810BE82C
----- the above looks like a null frame in the same scope as the frame below
*LIB$GET_INPUT                                             ?                ?
%DEBUG-E-INVPD, procedure descriptor at 00000000000E3198 is not valid.
*LIB$GET_FOREIGN
                LIB$GET_FOREIGN
                                  601       0000000000000294 FFFFFFFF810BE414
----- the above looks like a null frame in the same scope as the frame below
*LIB$GET_FOREIGN                                           ?                ?
 SHARE$SIMPLE                               0000000000000AF8 0000000000030AF8
                                            FFFFFFFF8038BDD4 FFFFFFFF8038BDD4

 

(Another ugly hack to work out where DEBUG is... I'm using LIB$FIND_IMAGE_SYMBOL to locate both symbols exported from the DEBUG shareable image. I've determined their offsets from the beginning and end of the image and hard coded them as constants. At run time, I add (or subtract) the offsets from both symbols, sanity check that both symbols yield the same results and use the resulting range to exclude FROM addresses from processing in the PRE routine. This is obviously dependent on the version of DEBUG)

A crucible of informative mistakes
H.Becker
Honored Contributor

Re: System Service Interception on OpenVMS

>>> Note that the LIBRTL calls are coming from S0 space, so they're the RESIDENT image  (ShareAddr!). How are we catching those, and why does it depend on /DEBUG?

 

I no longer have access to the sources so I can't read the real documentation.  I re-read Ruth's paper on ssi and she proves me wrong, fixups aren't always fixed :-(

 

If the main image was linked with SYS$SSISHR.EXE or linked /DEBUG, the image activator activates SYS$SSISHR.EXE before doing any fixups. Once it has been activated, the image activator fixes up references to SYS$PUBLIC_VECTORS.EXE symbols using the SYS$SSISHR.EXE symbol vector instead. This means that services can be intercepted only from images activated with and after SYS$SSISHR.EXE.

 

However, that didn't match what I saw, so far, but wait ...

 

Usually LIBRTL is installed /resident and /share=addr. So it seems a reasonable assumption that "coming from S0" means, it also uses shared address data. But in general /resident is independent of shared address data. So the asumption is not always true. Shared address data means sharing the linkage sections and pre-applying fixups during INSTALLation of the image. As you show, you can intercept system services from LIBRTL: either you have a private and modified copy of the shared address data in P0 or /DEBUG does some magic. It seems to be the first.

 

$ cc ssi+sys$share:sys$lib_c/lib
$ link/notraceback ssi,tt:/opt
sys$share:sys$ssishr/share
 Exit 
$ r ssi
preasctim: 0, postss: 0
hello ssi
time: 31-MAY-2012 11:37:21.80
preasctim: 1, postss: 1
$ r ssi/debug
preasctim: 0, postss: 0
hello ssi
time: 31-MAY-2012 11:37:25.39
preasctim: 1, postss: 5
$

$

$ def/user librtl sys$share:librtl.exe;
$ r ssi
preasctim: 0, postss: 0
hello ssi
time: 31-MAY-2012 12:01:00.60
preasctim: 1, postss: 5

 

It seems that the image activator can't change the shared data of the installed images and didn't bother to tell us about it. I miss the real documentation, here. Also, if you run /DEBUG you get private copies of all the P1 sections, including the shared data.  You can verify that from SDA and you will also see that code is still in S0 space.

JohnRD
Visitor

Re: System Service Interception on OpenVMS

What are the chances of HP ever publishing the documentation on SSI?

John Gillings
Honored Contributor

Re: System Service Interception on OpenVMS

>What are the chances of HP ever publishing the documentation on SSI?

 

  If no one formally asks for it, ZERO. HP is a very metrics driven culture. The days of people being able to do things just because it's the right thing to do are long gone. Everything must have a measurable payoff.

 

Even if you formally ask, I think it's a long shot. The folk who actually know this stuff are also long gone :-(

 

That said, here's another (tiny) piece of the puzzle. It looks to me like the argument list passed to the PRE action routine is an array of QUADWORDS, not a VAX type argument list (longwords). That explains my puzzle of the 0 arguments to RMS services. Interpreting the argument list as quadwords gives more plausible values.

 

Please lodge a formal request for the documentation against your HP services contract.

A crucible of informative mistakes