V'0)Q
*
Municipality of the City of Vienna
%
Ing. Ferry Bolhár-Nordenkampf
%Writing SDA Extensions.

Writing SDA Extensions

1This manual explains how to write SDA extensions.

May 1996

&Revision Information:This is a new manual.

!OpenVMS Version:VMS V5.5 or higher

Manual Version:V1.0-03




<

Contents






Preface



EThis manual explains how to write SDA extensions. It is intended for Ethe system programmer who want to add new commands to SDA and extend Dits capabilities to format and display the contents of various data structures.

3This manual is divided into the following sections:

oChapter 1 contains a short introduction to SDA extensions. It 2explains the purpose and how they are implemented.

tChapter 2 explains in detail how extensions are activated. It also Hgives you some hints how to code the extension's initialization routine.

nChapter 3 explains in detail the SDA environment wherein the @extension runs and gives a first introduction to SDA's callback routines.

lAppendix A shows how to link and debug your extension.

uFinally, Appendix B contains a detailed description of all SDA extension callbacks.

HIt is assumed that the reader is familiar with the SDA utility and with Dthe VMS programming concepts. The following OpenVMS manuals contain 2information about these topics and may be helpful:



HThis manual was written and inspected carefully. You may find, however, Gsome errors or have comments and suggestions. Please feel free to mail Dto the author, any input is very appreciated. The E-mail address is:
Ing. Ferry Bolhár-Nordenkampf
E-mail: bol@adv.magwien.gv.at.

9And now: enjoy and good luck when writing your extension!





Note

2Addendum to this manual, release date 20-AUG-1997:

@As indicated in the OpenVMS V7.2 pre-release notes, writing SDA Fextensions becomes a supported task under OpenVMS Alpha V7.2 (it will @still remain unsupported on OpenVMS VAX). The names of callback Groutines may change and their behaviour may change as well, to confirm Hthe OpenVMS calling standard and to make the routines callable from any high-level language.

FIf you plan to write SDA extensions for OpenVMS Alpha V7.2 or higher, Gyou should read carefully the OpenVMS Alpha V7.2 Release Notes as well Eas the System Dump Analyzer (Alpha) Utility manual, version D7.2. However, if you write your extension for earlier OpenVMS Alpha Hversions, as well for OpenVMS VAX, this manual contains all information you need.

uA description of already known changes is given in Appendix C. 





L

Chapter 1
Introduction to SDA extensions



@Starting with VAX/VMS V5.5, SDA (System Dump Analyzer) Hsupports extensions to provide additional, product-specific or Acustomer-specific commands and to increase SDA's capabilities to Hinterpret and display various data structures. This manual explains how 7to write your own SDA extension tailored to your needs.

DWhen analyzing a dump file or the running system, you need intimate Gknowledge of data structures that are not known to SDA. For example, a Euser-written ACP (ancilliary control process) may allocate non-paged Cpool and record some data or place I/O buffers therein. Without an Dextension, the only way to examine this data is to create a hexdump Bwith the EXAMINE command and manually decode the contents of the dump.

EWith a SDA extension, you can make the format of the data structures Hand buffers known to SDA and provide a way to display their contents in -an interpreted, much more understandable way.

:DEC's TCP/IP Services for OpenVMS, also known as @UCX, is an example for a layered product which Eprovides its own SDA extension to display information about its data structures ¹.

6Another example (which exists on Alpha only) might be CCLUE(Crash Log Utility Extractor), which Hallows you to maintain system dump history logs and provides additional Ccommands to display more detailed information about OpenVMS system cells and data structures².

ESDA invokes an extension when the extension's name is entered at the FSDA> prompt. Once activated, SDA performs a small version check to Hensure that the command and data passing mechanism is still the one the >extension expects. SDA then passes control to the extension's Finitialization (or main) routine. The way SDA invokes an extension is Rdescribed in detail in Chapter 2.

HOnce the extension receives control, it may do some initialization work @and then execute the given user commands. These commands may be Esupplied either with the extension name at the SDA> prompt or the Dextension is activated without additional commands in which case it Gshould prompt for them. If the extension was activated with a command, Eit should execute the command and return control back to SDA. In the Clatter case, it should prompt for commands and execute them, until FEXIT was entered or [CTRL] [Z] Cwas typed. This is the usual behaviour of most VMS utilities which provide their own subcommands.

FThe extension should also provide online help, either with a built-in Htext, or better, by an external help library whose topics may be called with HELP.

wChapter 2 gives some hints how to build an extension 'skeleton' which tprovides the above functions and commands. Chapter 2 contains code examples as well.

FWhile activated, the extension operates in SDA's environment Aand may call SDA's extension callback routines, shorter ?callbacks. SDA provides over 20 callbacks for various Gpurposes: examining memory, validating queues, executing SDA commands, Fdisplaying data in various formats, and much more. Whenever possible, Gyou should use these callbacks instead of native commands or functions Gprovided by your language. This ensures that your extension behaves in Han usual manner. For example, in C, you could use the printf() Efunction to display data on the screen. If, however, the user enters HSDA's SET OUTPUT command, SDA writes further text into Ethe given output file whereas your extension still would continue to Hsend its data to the screen. For this reason, SDA provides callbacks to Fdisplay data. By using these callbacks, your extension sends its data always to the expected location.

GAnother reason for using callbacks is SDA's environment which Emay change from time to time. Let's assume that you want to access a Hcell in the process-control (P1) space. Most languages provide a way to Ddeclare the name of VMS cells as global symbols whose addresses are Asubstituted by the linker when linked against SYS$SYSTEM:SYS.STB H³. In the program, the cell may be further accessed like any other variable.

GThe P1 space, however, is process-specific. Every process contains its Gown, separate P1 space. There is no (easy) way for a program to access -the P1 (and P0) space of a different process.

HSDA provides the SET PROCESS command for this purpose. GThis will change SDA's process context; the specified process :becomes the current process. By convention, when Hprocess-specific data is addressed, it's always the data of the current Hprocess. For this reason, SDA provides routines, which, when a P0 or P1 Daddress is given, obtain the data from the current process' address Fspace. In addition, these routines allow you to access data from user Gmode which would be accessible otherwise from executive or kernel mode Bonly. Finally, the routines contain their own condition handlers, >preventing the system to crash when you specify an invalid or non-existent address.

gThe SDA environment is described further in Chapter 3.

@SDA extensions may be written in any high-level language (HLL). EHowever, not all callbacks confirm the OpenVMS calling standard. For Hexample, some routines return results in processor registers or must be Hcalled as subroutines, not as procedures. Unless your language provides Ba way to access processor register directly and call subroutines, Hjacket routines, mostly written in MACRO-32, must be provided. HThe purpose of a jacket routine is simple: it calls the appropriate SDA Ccallback in the required fashion and places the returned data in a Glocation where it can be accessed by the HLL. From the HLL, you invoke 9the jacket routine instead of the corresponding callback.

yAppendix A explains how to link and debug SDA extensions. Examples Hfor jackets are provided in the description of the appropriate callback.

uFinally, Appendix B contains a detailed description of all SDA Hextension callbacks as well tables giving an overview about them, their &purpose and their calling conventions.






Note

:

¹ UCX V3.2 or higher only.

F

² On VAX, CLUE exists as well, however, it Gis provided as external utility, invoked with the DCL command C$ MCR CLUE. Unlike Alpha, VAX CLUE provides no additional Adisplays and is used to create and maintain system dump logs and Dhistory files only.
The author of this manual wrote a CLUE SDA Aextension for OpenVMS VAX; it provides the same (and additional) Ginformation as its Alpha counterpart. If you're interested in obtain a @copy, please send a mail to bol@adv.magwien.gv.at.

H

³ or linked with /SYSEXE on Alpha.





U

Chapter 2
Extension activation and initialization



FThis chapter explains how extensions are activated and how SDA passes control to them.C

2.1 SDA Extension Implementation



FSDA extensions are implemented as shareable images, either located in Ethe directory SYS$SHARE or found by translating a logical name. When Hthe extension's name is entered at the SDA> prompt, SDA uses the RTL =routine LIB$FIND_IMAGE_SYMBOL to load the extension. See the ?description in the RTL Library (LIB$) manual for more ?information about this routine and the VMS run-time image load mechanism.

DBy convention, SDA extensions are named name $SDA, Ewhere name is the extension's name. For example, in case of FUCX, the extension would be named UCX$SDA. You may define this string Fas a logical name pointing to the actual shareable image, or (in this 4example) the image SYS$SHARE:UCX$SDA.EXE must exist.

BSDA tries to activate an extension whenever an unknown command is Hentered at the SDA> prompt. If the activation fails for some reason, SDA displays this message:

-%CLI-W-SYNTAX, error parsing 'name' 


CWhen you enter a command, SDA first looks in its table of built-in @commands. If the command (or a valid abbreviation) can be found Etherein, it is executed, instead of activating an extension with the Fsame name. For example, if you call your extension EXAM$SDA and enter ?EXAM, SDA assumes that an abbreviation of its GEXAMINEcommand was entered, not an extension name. In Gthis case, you must force SDA to interpret the given name as extension ;by specifying the undocumented DO command:

SDA> DO EXAM


DWith DO, when the activation fails, SDA displays a different message:

7%SDA-E-SUPPNOTINS, name support not installed 


4where name is the specified extension name.





Note

GThe above message may be confusing. SDA displays this message whenever Hit fails to activate the specified extension. This does not necessarily Fmean that the extension is not installed; the activation may fail for Cother reasons as well (e.g., ident mismatches with other shareable images).

BTo find out what causes the activation to fail, try to invoke the Fextension with the DCL command RUN. In most cases, you will receive a H%IMGACT-F-... message. This is an error message created by the Fimage activator and is also passed to LIB$FIND_IMAGE_SYMBOL as return Hstatus. In most cases, this message can help you to isolate the problem.

FAlso keep in mind that the activation fails when compilation warnings >were detected by the linker in one or more extension modules. 


;

2.2 Extension activation



qAs described in Section 2.1, extensions are activated by calling the HRTL routine LIB$FIND_IMAGE_SYMBOL. In addition to the shareable image's Bname, this routine requires a symbol name to load the image. This Csymbol must be included in the shareable image's symbol table when zlinking the extension (Appendix A describes how to compile and link ;your extension and how to build a symbol table). SDA calls <LIB$FIND_IMAGE_SYMBOL twice with the following symbol names:



FIf these symbols are not found in the shareable image's symbol table, Athe activation fails with one of the error messages described in 8Section 2.1.

ˇSection 2.2.1 and Section 2.2.2 describe the purpose and contents of these symbols in detail.M

2.2.1 Activation interface version check



@SDA $EXTEND _VERSION contains the address of a Alongword which holds the extension's activation version. This is Bnot the version of the extension; it just determines the Gversion of the activation interface. It consists of two parts, a major Gand minor version number. Before passing control to the extension, SDA @compares its own interface version with the one supplied by the @extension to ensure that the interfaces are compatible. Further activation occurs only if:



FFor example, if the SDA version number would be V1.2, the extension's Fnumber may be one of V1.2, V1.3, V1.4 ... V1.9, but not V1.0, V1.1 or V2.0.





Note

GThe version number of the SDA extension interface is still V1.0 in all Ecurrent VMS releases. It is recommended that your extension uses the Dsame version number. In the case of an activation interface change, Gthis will prevent your extension from being activated in an unexpected "manner.



?The following example shows how to set the version number in C:

+const int SDA$EXTEND_VERSION = 0x00000001; 


wSee Appendix A how to include the variable name in the shareable Gimage's symbol table. Note that the variable must be defined in global &scope (in C, outside of any function).M

2.2.2 Calling the initialization routine



ESDA $EXTEND contains the address of the extension's Ginitialization routine. Once the version check is performed, SDA calls Fthe extension at this address. The following two arguments are passed to this routine:



1These arguments are now described more in detail.

HNote that SDA does not expect a return value from the extension; if the &extension supplies one, it is ignored.?

2.2.2.1 Callback pointer



DThe first argument passed to the initialization routine is the base Eaddress of an array containing pointers to all callback routines. In @order to understand the use of this argument, you should become 'familiar with SDA's callback mechanism.

BCallbacks are internal SDA routines, located at various places in ;SYS$SYSTEM:SDA.EXE, the system dump analyzer (invoked with (ANALYZE/CRASH _DUMP or FANALYZE/SYSTEM). Since these addresses may vary from GVMS to VMS version, an array consisting of longword pointers is built. EEvery longword points to a callback routine in SDA.EXE. Although the Dbase address of this array, which is located itself in SDA.EXE, may Hchange in new VMS versions, the position of a particular routine within Bthe array never changes; new routines are added at the end of the Farray. In other words, the purpose of this array is very similar to a Htransfer vector in a shareable image. Note, however, that SDA.EXE is an <executable image which can't be used as input to the linker.

0The interface to SDA.EXE is the shareable image DSYS$SHARE:SDA_EXTEND_VECTOR.EXE ¹ which your extension must be Glinked against. This image contains jacket routines for every Dcallback in SDA.EXE. When you call one of these jacket routines, it Dfirst adds the array offset of the corresponding SDA routine to the Earray's base address. The resultant value is the absolute address of Cthe longword which points to the callback routine in SDA.EXE. This routine is then invoked.

GAll jacket routines expect the array's base address in global location FSDA $EXTEND _VECTOR _TABLE _ADDR. This is a writable 5longword in SYS$SHARE:SDA_EXTEND_VECTOR.EXE (VAX) or CSYS$SHARE:SDA_EXTEND_VECTOR.OBJ (Alpha). Before invoking the first Ccallback, you must fill this location with the array base address, Dwhich is passed as first argument to your extension. An example for this could be:

,int globalref SDA$EXTEND_VECTOR_TABLE_ADDR;  >void sda$extend(int array_addr, struct dsc$descriptor_s *cmd) { , SDA$EXTEND_VECTOR_TABLE_ADDR = array_addr;  . . .} 


BFrom this point, you can use all callbacks. They are described in AAppendix B.>

2.2.2.2 Command pointer



HThe second argument passed to the initialization routine is the address Fof a fixed-length string descriptor pointing to the specified command Gstring, if any was given. If no command was given, the length field of the descriptor contains 0.

HNote that the extension name (and a preceeding DO) were already removed from the string. For example, if

SDA> MYEXT SHOW ALL


Bwas entered, the string passed in this argument would be SHOW ALL.

pAs described in Chapter 1, the usual behaviour of an extension )providing its own commands is as follows:



GIt is up to the extension to parse the supplied command string. A good Eand easy way to do this are the CLI$ routines in conjunction with an Eobject module containing binary language definitions. This module is Hwritten in CDL (Command Definition Language) and compiled with nCDU (Command Definition Utility). See Section 2.3 for an example.






Note

D

¹ On Alpha, there is no shareable image, Hinstead, an object file SYS$SHARE:SDA_EXTEND_VECTOR.OBJ is provided for the same purpose.


>

2.3 Extension code examples



,This chapter contains some code examples of:



GAll relevant coding techniques in the following examples are described Ein the previous chapters. In the following examples, the extension's name becomes MYEXT.A

2.3.1 Initialization routine



:The following code fragment, written in C, may be used as sinitialization routine. It behaves as described in Section 2.2.2.2.

  K#include <cli$routines.h>          /* CLI$xxx routine definitions */ F#include <descrip.h>               /* Descriptor definitions */ K#include <rmsdef.h>                /* RMS$_xxx status definitions */ B#include <string.h>                /* strxxx() functions */ J#include <ssdef.h>                 /* SS$_xxx status definitions */   %typedef struct dsc$descriptor_s dsc;   /* SDA callback definitions. */  >void SDA$EXTEND_PRINT(),           /* Print a line of text */ 9     SDA$EXTEND_NEW_PAGE(),        /* Insert new page */ >     SDA$EXTEND_SKIP_LINES(),      /* Insert blank line(s) */ B     SDA$EXTEND_GET_INPUT();       /* Get a line from the user */  Lint globalref SDA$EXTEND_VECTOR_TABLE_ADDR; /* Callback array base addr. */  Cconst int SDA$EXTEND_VERSION = 0x00000001;  /* Activation vers. */  cint globalvalue MYEXT$CDL;          /* CDL Module */ (1) iint G_exit_flg;                     /* Global exit flag */ (2) >dsc* desc();                        /* Descriptor function */   </* ======== Initialization routine starts here. ======== */  *void sda$extend(int array_addr, dsc *cmd) { ; int status;                       /* CLI return status */  7 $DESCRIPTOR(prp,"MYEXT$SDA>" );   /* Our prompt */  ; /* First, store array base address in shareable image. */  , SDA$EXTEND_VECTOR_TABLE_ADDR = array_addr;  o if (cmd->dsc$w_length)            /* If command was given */ (3) { g  status = cli$dcl_parse(cmd,MYEXT$CDL);  /* Parse it */ (4) 0  /* If parsing was OK, execute the command. */  6  if (status == CLI$_NORMAL) status = cli$dispatch();  <  return;                          /* Return back to SDA *.  } 3 else                              /* Otherwise */  { g  SDA$EXTEND_NEW_PAGE();           /* Insert new page */ (5) !  /* Display welcome message. */  F  SDA$EXTEND_PRINT(desc("Welcome to MYEXT, my nice SDA extension!"));  :  SDA$EXTEND_SKIP_LINES(2);        /* Insert two lines */  D  /* Prompt for command - use SDA callback instead of LIB$GET_INPUT      to read the command. */  i  status = cli$dcl_parse(0,MYEXT$CDL,SDA$EXTEND_GET_INPUT, (6)9                         SDA$EXTEND_GET_INPUT,&prp);  o  while (status != RMS$_EOF)       /* Loop until EOF (CTRL-Z) */ (7)  { N   if (status == CLI$_NORMAL) status = cli$dispatch();  /* Execute command */  j   if (G_exit_flg) return;         /* If EXIT, terminate */ (8) M   status = cli$dcl_parse(0,MYEXT$CDL,SDA$EXTEND_GET_INPUT, /* Prompt for */ S                          SDA$EXTEND_GET_INPUT,&prp);       /* next command */   } 7  return;                          /* Return to SDA */  } }  


Notes to this example:

    
  1. DThe module MYEXT$CDL contains the definition of all known extension Gcommands. It was written in CDL (Command Definition Language) 3and built with SET COMMAND/OBJECT.
  2. AThis global location initially contains 0. It is set to 1 by the lextension's EXIT command (see Section 2.3.2).
  3. DThe length of the command given when the extension was activated is Htested. If the length is not 0, the extension was activated with one of its commands.
  4. DWe parse the command using the CDL module and dispatch to it. After this, we return back to SDA.
  5. HIf no command was given, we must prompt for one. First, let's clear the Ascreen and display a nice welcome message. This is done with SDA Hcallbacks. Given a null-terminated string, the function desc() Creturns a fixed-length descriptor pointing to this string. This is Arequired since most callbacks, when strings are supplied, expect pointers to descriptors.
  6. FPrompt for a command and parse it. In the arguments to CLI$DCL_PARSE, =we use SDA callbacks as prompt and read routines, instead of DLIB$GET_INPUT. This gives access to SDA's command recall buffer and predefined keys.
  7. FIf [CTRL] [Z] was typed, we can leave the loop. ;Otherwise, we execute the command and prompt for a new one.
  8. GThis location is set to 1 by the EXIT command. If so, 'we must leave the command loop as well.


2The code for the desc() function follows:

dsc *desc(char *str) {  static $DESCRIPTOR(x,"");   x.dsc$w_length = strlen(str);  x.dsc$a_pointer= str;   return &x; } 


BSince the descriptor must survive the function's exit, it must be declared as 'static' (in C).7

2.3.2 EXIT command



HIf the extension was invoked without a command, it must prompt for them Funtil the EXIT command is entered. As you can see in rthe code example in Section 2.3.1, this is indicated by setting the Hglobal variable G_exit_flag to 1. So the only thing we must do here is setting this variable:

void myext_exit() {  G_exit_flg = 1; } 


GIf your favorite language does not support global variables, you could Aindicate the execution of the EXIT command by a Especial return status. In the main command loop, you could check the Gstatus returned by CLI$DISPATCH and terminate the loop if this special status is encountered.7

2.3.3 HELP command



BEvery program which supports more than one command should provide Honline-help. Although you can give this help by a built-in text, a more Cfriendly and VMS-conform way is to provide a HELP Ccommand and a help text library. By entering HELP Dwithout a topic, the user receives a general help text, including a Hlist of all topics for which help is available. He may further select a *topic to obtain more information about it.

=You can create help text files with any text editor. You use ELIBRARY/HELP/CREATE to create your help library and ELIBRARY/HELP/INSERT to insert help topics into your ?library. See the Command Definition, Librarian and Message +Utilities manual for more information.

FThis is the code fragment of the HELP command in the command definition file:

$define verb HELP routine MYEXT_HELP 8parameter P1, prompt="Topic", value(type=$rest_of_line) 


And here comes the help routine:

#include <descrip.h>  int cli$get_value();   void SDA$EXTEND_DISPLAY_HELP();  void myext_help() {  char dcl_buf[120];   short len;   $DESCRIPTOR(dcl,dcl_buf);   $DESCRIPTOR(dcl_p1,"P1");   $DESCRIPTOR(lib,"MYEXT_HELP");  C cli$get_value(&dcl_p1,&dcl,&len);     /* Get topic */  ; dcl.dsc$w_length = len;               /* Update length */  B SDA$EXTEND_DISPLAY_HELP(&lib,&hlp);   /* Display help */ } 


GIn this example, the name of the help library is MYEXT_HELP. This must Fbe either a logical name pointing to the help library, or the library *is expected to be SYS$HELP:MYEXY_HELP.HLB.

DAs you can see, SDA even provides a callback to display online-help <which you should use instead of the appropriate VMS routine LBR$OUTPUT_HELP.


J

Chapter 3
Running in SDA's environment



=Once activated, the extension runs under control of SDA. SDA Cestablishes a default environment from which it interprets certain Fcommands. Your extension should behave exactly in the same manner, so Eit's important to understand in which environment you're running and how commands may be interpreted.

,SDA's environment consists of the following:

 




*Next6 | Contents