[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS System Analysis Tools Manual


Previous Contents Index


Chapter 10
SDA Extensions and Callable Routines

This chapter describes how to write, debug, and invoke an SDA Extension. This chapter also describes the routines available to an SDA Extension.

10.1 Introduction

When analysis of a dump file or a running system requires intimate knowledge of data structures that are not known to the System Dump Analyzer, the functionality of SDA can be extended by the addition of new commands into which the necessary knowledge has been built. Note that in this description, whenever a reference is made to accessing a dump file (ANALYZE/CRASH_DUMP), this also includes accessing memory in the running system (ANALYZE/SYSTEM).

For example, a user-written device driver allocates nonpaged pool and records additional data about the device there (logging different types of I/O, perhaps), and a pointer to the new structure is saved in the device-specific extension of the UCB. After a system crash, the only way to look at the data from SDA is to do the following:

  • Invoke the SDA command DEFINE to define a new symbol (for example, UCB$L_FOOBAR) whose value is the offset in the UCB of the pointer to the new structure.
  • Invoke the SDA commands "SHOW DEVICE <device>" and "FORMAT UCB" to obtain the address of the nonpaged pool structure.
  • Invoke the SDA command "EXAMINE <address>;<length>" to display the contents of the data in the new nonpaged pool structure as a series of hexadecimal longwords.
  • Decode manually the contents of the data structure from this hexadecimal dump.

An SDA extension that knows the layout of the nonpaged pool structure, and where to find the pointer to it in the UCB, could output the data in a formatted display that alerts the user to unexpected data patterns.

10.2 Description

The following discussion uses an example of an SDA extension that invokes the MBX command to output a formatted display of the status of the mailbox devices in the system. The source file, MBX$SDA.C, is provided in SYS$EXAMPLES.

An SDA extension consists of a shareable image, in this case MBX$SDA.EXE, either located in the directory SYS$LIBRARY or found by translating the logical name MBX$SDA. It contains two universal symbols: SDA$EXTEND, the entry point; and SDA$EXTEND_VERSION, the address of a longword that contains the version of the interface used (in the format of major/minor ident), which allows SDA to confirm it has activated a compatible extension. The image contains at least two modules: MBX$SDA, the user-written module that defines the two symbols and provides the code and data necessary to produce the desired formatted output; and SDA_EXTEND_VECTOR, which provides jackets for all of the callable SDA routines, and is found in SYS$LIBRARY:VMS$VOLATILE_PRIVATE_INTERFACES.OLB. The user-written portion can be split into multiple modules.

Whenever SDA receives an unrecognized command, like "SDA> MBX", it attempts to activate the shareable image MBX$SDA at the SDA$EXTEND entry point. If you choose a command name that matches the abbreviation of an existing command, SDA can be forced to activate the extension using the "DO" command. For example, if you had an SDA extension called VAL$SDA, you could not activate it with a command like "SDA> VAL" as SDA would interpret that as an abbreviation of its VALIDATE command. But VAL$SDA can be activated by issuing "SDA> DO VAL".

With or without the "DO" prefix, the rest of the command line is passed to the extension; it is up to the extension to parse it. The example extension MBX$SDA includes support for commands of the form "SDA> MBX SUMMARY" and "SDA> MBX <address>" to demonstrate this. If the extension is invoked with no arguments, it should do no more than display a simple announcement message, or prompt for input. This assists in the debugging of the extension, as described in Section 10.3.

Section 10.2.1 describes how to compile, link, and invoke an SDA extension, and describes what an SDA extension should contain.

10.2.1 Compiling and Linking an SDA Extension

The user-written module is only supported when written in HP C (minimum Version 5.2), following the pattern of the example extension, MBX$SDA.C. It should be compiled and linked using commands of the following form:


$cc mbx$sda + sys$library:sys$lib_c /library
$link /share - 
                mbx$sda.obj, - 
                sys$library:vms$volatile_private_interfaces /library, - 
                sys$input /option 
        symbol_vector = (sda$extend=procedure) 
        symbol_vector = (sda$extend_version=data)

Note

1. You can include the qualifier /INSTRUCTION=NOFLOAT on the compile command line if floating-point instructions are not needed.

2. The + SYS$LIBRARY:SYS$LIB_C /LIBRARY is not needed on the compile command line if the logical name DECC$TEXT_LIBRARY is defined and translates to SYS$LIBRARY:SYS$LIB_C.TLB.

3. If the user-written extension needs to signal SDA condition codes, or output their text with $PUTMSG, you should add the qualifier /INCLUDE=SDAMSG to the parameter SYS$LIBRARY:VMS$VOLATILE_PRIVATE_INTERFACES /LIBRARY .

10.2.2 Invoking an SDA Extension

You can invoke the SDA extension as follows:


$define mbx$sda sys$disk:[]mbx$sda
$analyze /system
SDA>mbx summary
SDA>mbx <address>

10.2.3 Contents of an SDA Extension

At a minimum, the user-written module must contain:

  • #include statements for DESCRIP.H and SDA_ROUTINES.H
  • The global variable SDA$EXTEND_VERSION, initialized as follows:


            int sda$extend_version = SDA_FLAGS$K_VERSION; 
    
  • The routine SDA$EXTEND (prototype follows)

Optionally, the user-written module may also contain the statement:


        #define __NEW_STARLET 

You should use this option because it provides type checking of function arguments and gives consistency in casing and naming conventions.

The entry point in the user-written module, SDA$EXTEND, is called as a routine with three arguments and no return value. The declaration is as follows:


        void sda$extend ( 
                int *transfer_table, 
                struct dsc$descriptor_s *cmd_line, 
                SDA_FLAGS sda_flags) 

The arguments in this code example have the following meanings:

Table 10-1 SDA$EXTEND Arguments
Line of Code Meaning
transfer_table Address of the vector table in the base image. The user-written routine SDA$EXTEND must copy this to SDA$VECTOR_TABLE (declared in SDA_ROUTINES.H) before any SDA routines can be called.
cmd_line Address of the descriptor of the command line as entered by the user, less the name of the extension. So, if you enter "SDA> MBX" or "SDA> DO MBX", the command line is a zero length string. If you enter the command "SDA> MBX 80102030", the command line is " 80102030" (the separating space is not stripped).
sda_flags Definition for the following four bits in this structure:
Bit Meaning
sda_flags.sda_flags$v_override Indicates SDA has been activated with the ANALYZE/CRASH_DUMP/OVERRIDE command
sda_flags.sda_flags$v_current Indicates SDA has been activated with the ANALYZE/SYSTEM command or was invoked from the kept debugger during an SCD session
sda_flags.sda_flags$v_target Indicates that SDA was invoked from the kept debugger during an SCD or SDD session or when analyzing a process dump
sda_flags.sda_flags$v_process Indicates SDA was activated with the ANALYZE/CRASH_DUMP command to analyze a process dump
sda_flags.sda_flags$v_ia64 Indicates that SDA is analyzing an Integrity server system or dump
None of the above bits set Indicates SDA was activated with the ANALYZE/CRASH_DUMP command to analyze an Alpha system dump
Other bits Reserved to HP:may be nonzero

The first executable statement of the routine must be to copy TRANSFER_TABLE to SDA$VECTOR_TABLE (which is declared in SDA_ROUTINES.H):


        sda$vector_table = transfer_table; 

If this is not done, you cannot call any of the routines described below. Any attempts to call the routines receive a status return of SDA$_VECNOTINIT. (For routines defined not to return a status, this value can be found only by examining the return value directly.)

The next statement should be one to establish a condition handler, as it is often difficult to track down errors in extensions such as access violations because the extension is activated dynamically with LIB$FIND_IMAGE_SYMBOL. A default condition handler, SDA$COND_HANDLER, is provided that outputs the following information in the event of an error:

  • The error condition
  • The VMS version
  • A list of activated images, with start and end virtual addresses
  • The signal array and register dump
  • The current call frame chain

You can establish this condition handler as follows:


 
        lib$establish (sda$cond_handler); 

Note

The error condition, signal array, and register dump are output directly to SYS$OUTPUT and/or SYS$ERROR, and are not affected by the use of the SDA commands SET OUTPUT and SET LOG.

Thus, a minimal extension would be:


        #define __NEW_STARLET 1 
        #include <descrip.h> 
        #include <sda_routines.h> 
 
        int sda$extend_version = SDA_FLAGS$K_VERSION; 
 
        void sda$extend (int *transfer_table, 
                         struct dsc$descriptor_s *cmd_line, 
                         SDA_FLAGS sda_flags) 
          { 
          sda$vector_table = transfer_table; 
          lib$establish (sda$cond_handler); 
 
          sda$print ("hello, world"); 
          return; 
          } 

10.3 Debugging an Extension

In addition to the "after-the-fact" information provided by the condition handler, you can debug SDA extensions using the OpenVMS Debugger. A second copy of the SDA image, SDA_DEBUG.EXE, is provided in SYS$SYSTEM. By defining the logical name SDA to reference this image, you can debug SDA extensions as follows:

  • Compile your extension /DEBUG/NOOPT and link it /DEBUG or /DSF.
  • Define logical names for SDA and the extension, and invoke SDA.
  • Type SET BREAK START_EXTENSION at the initial DBG> prompt, and then type GO.
  • Invoke the extension at the SDA> prompt.
  • When Debug prompts again, use Debug commands to set breakpoints, and so on, in the extension and then type GO.
  • Invoke the extension, providing the necessary arguments.

An example of the preceding steps is as follows:


 
        $ cc /debug /noopt mbx$sda + sys$library:sys$lib_c /library 
        $ link /debug /share - 
                mbx$sda.obj, - 
                sys$library:vms$volatile_private_interfaces /library, - 
                sys$input /option 
        symbol_vector = (sda$extend=procedure) 
        symbol_vector = (sda$extend_version=data) 
        $ ! 
        $ define mbx$sda sys$disk:[]mbx$sda 
        $ define sda sda_debug 
        $ analyze /system 
        ... 
        DBG> set break start_extension 
        DBG> go 
        ... 
        SDA> mbx 
        break at routine START\START_EXTENSION 
        ... 
        DBG> set image mbx$sda 
        DBG> set language c 
        DBG> set break /exception 
        DBG> go 
        MBX commands: 'MBX SUMMARY' and 'MBX <address>' 
        SDA> mbx summary 
        ... 
        SDA> mbx <address> 
        ... 
        %DEBUG-I-DYNMODSET, setting module MBX$SDA 
        %SYSTEM-E-INVARG, invalid argument 
        ... 
        DBG> 

10.4 Callable Routines Overview

The user-written routine may call SDA routines to accomplish any of the following tasks:

  • Read the contents of memory locations in the dump.
  • Translate symbol names to values and vice-versa, define new symbols, and read symbol table files.
  • Map an address to the activated image or executive image that contains that address.
  • Output text to the terminal, with page breaks, page headings, and so on (or output to a file if the SDA commands SET OUTPUT or SET LOG have been used).
  • Allocate and deallocate dynamic memory.
  • Validate queues/lists.
  • Format data structures.
  • Issue any SDA command.

Note the following points before using the callable routines described here:

  • The following three routines are used to read the contents of memory locations in the dump:
    • SDA$TRYMEM is called from both SDA$GETMEM and SDA$REQMEM as the lower-level routine that actually does the work. SDA$TRYMEM returns success/failure status in R0, but does not signal any errors. Use it directly when you expect that the location being read might be inaccessible. The caller of SDA$TRYMEM handles this situation by checking the status returned by SDA$TRYMEM.
    • SDA$GETMEM signals a warning when any error status is returned from SDA$TRYMEM. Signaling a warning prints out a warning message, but does not abort the SDA command in progress. You should use this routine when you expect the location to be read to be accessible. This routine does not prevent the command currently being executed from continuing. The caller of SDA$GETMEM must allow for this by checking the status returned by SDA$GETMEM.
    • SDA$REQMEM signals an error when any error status is returned from SDA$TRYMEM. Signaling an error prints out an error message, aborts the SDA command in progress, and returns to the "SDA>" prompt. You should use this routine when you expect the location to be read to be accessible. This routine prevents the command currently being executed from continuing. The caller of SDA$REQMEM does not resume if an error occurs.
  • You should use only the routines provided to output text. Do not use printf() or any other standard routine. If you do, the SDA commands SET OUTPUT and SET LOG will not produce the expected results. Do not include control characters in output (except tab); in particular, avoid <CR>, <LF>,<FF>, and the FAO directives that create them. Use the FAO directive !AF when contents of memory returned by SDA$TRYMEM, and so on, are being displayed directly, because embedded control characters will cause undesirable results. For example, displaying process names or resource names that contain particular control characters or escape sequences can lock up the terminal.
  • You should use only the routines provided to allocate and deallocate dynamic memory. Do not use malloc() and free(). Where possible, allocate dynamic memory once, the first time the extension is activated, and deallocate it only if it needs to be replaced by a larger allocation. Because SDA commands can be interrupted by invoking another command at the "Press return for more" prompt, it is very easy to cause memory leaks.
  • Some routines expect 32-bit pointers, and others expect 64-bit pointers. At first this not may appear to be logical, but in fact it is. All code and data used by SDA and any extensions must be in P0 or P1 space, as SDA does not need to (and does not) use P2 space for local data storage. However, addresses in the system dump (or running system, in the case of ANALYZE/SYSTEM) are 64-bit addresses, and SDA must provide access to all locations in the dump.
    So, for example, the first two arguments to the routine SDA$TRYMEM are:


     
            VOID_PQ start   /* 64-bit pointer */ 
    


            void *dest      /* 32-bit pointer */ 
    

    They specify the address of interest in the dump and the address in local storage to which the dump contents are to be copied.
  • Common Bitmask Block (CBB) routines, SDA$CBB_xxx, are designed for use with local copies of the CBB structures that describe the CPUs in use in a system. The CBB structures are assumed to be at least CBB$K_STATIC_BLOCK bytes in length. The definitions of the various CBB constants and field names used by these routines can be found in CBBDEF.H in SYS$LIBRARY:SYS$LIB_C.TLB.
    The set of routines is not intended to be an exhaustive set of all possible CBB-related operations, but it provides those operations known to be needed. The routines might not work as expected with CBB structures that are set up for any purpose other than to describe CPUs.

10.5 Routines

The following sections describe the SDA extension callable routines.


SDA$ADD_SYMBOL

Adds a symbol to SDA's local symbol table.

Format

void sda$add_symbol (char *symbol_name, uint64 symbol_value);


Arguments

symbol_name


OpenVMS usage char_string
type character string
access read only
mechanism by reference

Address of symbol name string (zero-terminated).

symbol_value


OpenVMS usage quadword_unsigned
type quadword (unsigned)
access read only
mechanism by value

The symbol value.

Description

SDA maintains a list of symbols and the corresponding values. SDA$ADD_SYMBOL is used to insert additional symbols into this list, so that they can be used in expressions and during symbolization.

Condition Values Returned

None  

Example


sda$add_symbol ("MBX", 0xFFFFFFFF80102030); 
      

This call defines the symbol MBX to the hexadecimal value FFFFFFFF80102030.


SDA$ALLOCATE

Allocates dynamic memory.

Format

void sda$allocate (uint32 size, void **ptr_block);


Arguments

size


OpenVMS usage longword_unsigned
type longword (unsigned)
access read only
mechanism by value

Size of block to allocate (in bytes).

ptr_block


OpenVMS usage address
type longword (unsigned)
access write only
mechanism by reference

Address of longword to receive address of block.

Description

The requested memory is allocated and the address returned. Note that this is the only supported mechanism for allocation of dynamic memory.

Related Routine

SDA$DEALLOCATE


Condition Values Returned

None  

If no memory is available, the error is signaled and the SDA session aborted.


Example


PCB *local_pcb; 
... 
sda$allocate (PCB$C_LENGTH, (void *)&local_pcb); 
      

This call allocates a block of heap storage for a copy of a PCB, and stores its address in the pointer LOCAL_PCB.


SDA$CBB_BOOLEAN_OPER

Performs a Boolean operation on a pair of CBBs.

Format

int sda$cbb_boolean_oper (CBB_PQ input_cbb, CBB_PQ output_cbb, int operation);


Arguments

input_cbb


OpenVMS usage address
type CBB structure
access read only
mechanism by reference

The address of the first (input) CBB structure.

output_cbb


OpenVMS usage address
type CBB structure
access read/write
mechanism by reference

The address of the second (output) CBB structure.

operation


OpenVMS usage longword
type longword (unsigned)
access read only
mechanism by value

The desired operation from the following list:
CBB$C_OR The logical sum of the two CBBs is performed and the result (B = A | B) is written to the output CBB.
CBB$C_BIC The logical product with complement of the two CBBs is performed and the result (B = B & ~A) is written to the output CBB.

Description

The desired Boolean operation is performed on the two CBB structures, and the result is written to the second (output) structure.

Condition Values Returned

SS$_BADPARAM The number of valid bits in the input and output CBBs is different.
SS$_WASCLR All bits in the resulting output CBB are clear.
SS$_WASSET At least one bit in the resulting output CBB is set.

Example


int status; 
extern CBB active_set, 
       configure_set; 
CBB inactive_set; 
sda$cbb_copy (&configure_set, &inactive_set); 
status = sda$cbb_boolean_oper (&active_set, &inactive_set, CBB$C_BIC); 
if (status == SS$_WASSET) 
    sda$print ("There are inactive CPUs in the system"); 
      

This example shows how the set of active CPUs and the set of configured CPUs can be manipulated to create a set of inactive CPUs.


SDA$CBB_CLEAR_BIT

Clears the specified bit in a CBB.

Format

int sda$cbb_clear_bit (CBB_PQ cbb, int bit);


Arguments

cbb


OpenVMS usage address
type CBB structure
access read/write
mechanism by reference

The address of the CBB structure to be modified.

bit


OpenVMS usage longword
type longword (unsigned)
access read only
mechanism by value

The bit in the CBB to be cleared. If the bit number is -1, clears all bits.

Description

The specified bit (or all bits) in the CBB is cleared.

Condition Values Returned

SS$NORMAL Successful completion
SS$BADPARAM The bit number is out of range

Example


int status; 
extern int next; 
extern CBB active_set; 
status = sda$cbb_clear_bit (&active_set, next); 
if (!(status & 1)) 
    sda$print ("Bad CPU specified: !XL", next); 
      

This example shows how a bit in a CBB is cleared.


SDA$CBB_COPY

Copies the contents of one CBB to another.

Format

int sda$cbb_copy (CBB_PQ input_cbb, CBB_PQ output_cbb);


Arguments

input_cbb


OpenVMS usage address
type CBB structure
access read only
mechanism by reference

The address of the CBB structure to be copied.

output_cbb


OpenVMS usage address
type CBB structure
access write only
mechanism by reference

The address of the CBB structure to receive the copy.

Description

The specified CBB is copied.

Condition Values Returned

None  

SDA$CBB_FFC

Locates the first clear bit in a CBB.

Format

int sda$cbb_ffc (CBB_PQ cbb, int start_bit);


Arguments

cbb


OpenVMS usage address
type CBB structure
access read only
mechanism by reference

The address of the CBB structure to be searched.

start_bit


OpenVMS usage longword
type longword (unsigned)
access read only
mechanism by value

The first bit in the CBB to be checked.

Description

The CBB structure is searched, starting at the specified bit, for a clear bit.

Condition Values Returned

bit_number If a clear bit is found, its bit number is returned. If no clear bit is found (all bits from start_bit to cbb->cbb$l_valid_bits are set), then the number of valid bits is returned.

Example


int bit; 
extern int start; 
extern CBB active_set; 
bit = sda$cbb_ffc (&active_set, start); 
if (bit >= active_set.cbb$l_valid_bits) 
    sda$print ("No clear bits in active set"); 
else 
    sda$print ("First clear bit in active set = !XL", bit); 
      

This example shows how the next clear bit in a CBB can be located.


SDA$CBB_FFS

Locates the first set bit in a CBB.

Format

int sda$cbb_ffs (CBB_PQ cbb, int start_bit);


Arguments

cbb


OpenVMS usage address
type CBB structure
access read only
mechanism by reference

The address of the CBB structure to be searched.

start_bit


OpenVMS usage longword
type longword (unsigned)
access read only
mechanism by value

The first bit in the CBB to be checked.

Description

The CBB structure is searched for a set bit, starting at the specified bit.

Condition Values Returned

bit_number If a set bit is found, its bit number is returned. If no set bit is found (all bits from start_bit to cbb->cbb$l_valid_bits are clear), then the number of valid bits is returned.

Example


int bit; 
extern int start; 
extern CBB active_set; 
bit = sda$cbb_ffs (&active_set, start); 
if (bit >= active_set.cbb$l_valid_bits) 
      sda$print ("No set bits in active set"); 
else 
      sda$print ("First set bit in active set = !XL", bit); 
      

This example shows how the next set bit in a CBB can be located.


SDA$CBB_INIT

Initializes a CBB structure to a known state.

Format

void sda$cbb_init (CBB_PQ cbb);


Argument

cbb


OpenVMS usage address
type CBB structure
access read only
mechanism by reference

The address of the CBB structure to be initialized.

Description

The fields of the CBB that describe its layout are initialized as necessary for a CPU CBB. The actual bitmask is zeroed.

Condition Values Returned

None  

SDA$CBB_SET_BIT

Sets the specified bit in a CBB.

Format

int sda$cbb_set_bit (CBB_PQ cbb,int bit);


Arguments

cbb


OpenVMS usage address
type CBB structure
access read/write
mechanism by reference

The address of the CBB structure to be modified.

bit


OpenVMS usage longword
type longword (unsigned)
access read only
mechanism by value

The bit in the CBB to be set. If the bit number is -1, set all bits.

Description

The specified bit (or all bits) in the CBB is set.

Condition Values Returned

SS$NORMAL Successful completion.
SS$BADPARAM The bit number is out of range.

Example


int status; 
extern int next; 
extern CBB active_set; 
status = sda$cbb_set_bit (&active_set, next); 
if (!(status & 1)) 
    sda$print ("Bad CPU specified: !XL", next); 
      

This example shows how a bit in a CBB is set.


SDA$CBB_TEST_BIT

Tests the specified bit in a CBB.

Format

int sda$cbb_test_bit (CBB_PQ cbb,int bit);


Arguments

cbb


OpenVMS usage address
type CBB structure
access read only
mechanism by reference

The address of the CBB structure to be tested.

bit


OpenVMS usage longword
type longword (unsigned)
access read only
mechanism by value

The bit in the CBB to be tested.

Description

The specified bit in the CBB is tested and its value returned.

Condition Values Returned

SS$_WASSET The specified bit was set.
SS$_WASCLR The specified bit was clear.
SS$_BADPARAM The bit number is out of range.

Example


int status; 
extern int next; 
extern CBB active_set; 
status = sda$cbb_test_bit (&active_set, next); 
if (!(status & 1)) 
    sda$print ("Bad CPU specified: !XL", next); 
else if (status == SS$_WASSET) 
    sda$print ("CPU !XL was set", next); 
else 
    sda$print ("CPU !XL was clear", next); 
      

This example shows how a bit in a CBB is tested.


Previous Next Contents Index