k%Writing SDA Extensions.

Writing SDA Extensions


6Previous6 | Contents


2These components are now described in more detail.4

3.1 Analysis mode



'SDA can be invoked in one of two modes:



=Not all SDA commands apply to both modes. For example, SDA's GSHOW CPU or SHOW HEADER commands are *allowed only when examining a system dump.

DYour extension may provide such commands as well - or, in contrast, 5commands which are useful on the running system only.

‰On Alpha, you may use the callback SDA$EXTEND_ON_CURRENT_SYSTEM. This callback returns F1, if the current (running) system is analyzed, else it returns 0. On DVAX, however, the callback doesn't exist. You may use the following "MACRO-32 routine as a replacement:

SYM: .ascid  /EXE$GL_ABSTIM/ SEC: .float  1.0  8      .entry  SDA$EXTEND_ON_CURRENT_SYSTEM,^m<r2>       pushal  SYM +      calls   #1,g^sda$extend_symbol_value       movl    (r1),r2       pushal  SEC       calls   #1,g^lib$wait       pushal  SYM +      calls   #1,g^sda$extend_symbol_value       movzbl  #1,r0       cmpl    (r1),r2       bneq    10$       decb    r0 
10:   ret 


GThis routine obtains the value of the system cell EXE$GL_ABSTIM twice, Fwhile waiting one second between the accesses. This cell contains the Dnumber of seconds since last reboot; its value is incremented every Fsecond. Of course, this occurs on the running system only; in a dump, Fthe value at the time of the crash is frozen and never changes. So if Gthe values still are the same after waiting a second, a system dump is 7analyzed and 0 (on_current_system = false) is returned.





Note

EIf you must decide between running system and system dump, call this Eroutine once as part of the extension's initialization and store the Hresult in a global variable. Whenever you must decide, check the global Hvariable only. Otherwise, every check would delay command execution for &one second.



AThere is another thing you should consider when a system dump is Hanalyzed: the dump may exist partially only. This may occur when it was Ewritten to the primary page file or it was written to the designated Hdump file, but the dump file was too small to store the entire dump. In Fthis case, some data may not be available although system cells point Dto it. Also keep in mind that you may work with a dump written by a different system.





Note

@It is strongly recommended that you use only SDA callbacks when Eaccessing system cells or addresses where system cells point to. The Ecallbacks check that the requested data is available and valid, and, Dwhen analyzing a system dump, the data is taken from the dump file. 

2

3.2 Output mode



GOutput of SDA command is usually written to screen, but can be sent to Da file as well (with the SET OUTPUT or SET ELOG commands). SDA callbacks ensure that the output of your Fextension is written at the place where the user expects it. For this Ereason, avoid using standard I/O commands provided by your language, -always use the appropriate callbacks instead.

COutput created by SET OUTPUT is written in a well Gformatted, printable form. In addition, a table of contents is created Hat the top of the output file. User-supplied commands or error messages Aare not included here. The output width is always 132 characters '(suitable for print on a line printer).

EIn contrast, output created by SET LOG contains all >SDA output in an unformatted, as-is form. As the command name Gindicates, the output created with this command is a complete log of a Cparticular SDA session (or part of a session), including all error Emessages and user-supplied commands. The output width corresponds to Bthe terminal width; if a logfile with the same name exists from a Aprevious session, new output is appended at the end of this file.

HUnfortunately, current SDA versions provide no way to determine whether Goutput is sent to screen or to a file (or to obtain the current output @device's width) - this would allow an extension to display more Ginformation when longer lines would be available. For this reason, you Gshould always assume a screen width of 80 characters. Avoid to display :longer lines, this may produce confusing output on screen.>

3.3 Process and CPU context



AWhen displaying process data structures or examining per-process Haddresses, SDA always makes references to the current process. The initial current process is:



CYou can use the SET PROCESS command to select and Gchange the current process. From within your extension, you can change ƒthe current process by using the SDA$EXTEND_PARSECOMMAND callback. This callback Gexecutes any SDA command; by specifying the above command with a valid 9process index (or PID), you can access any process' data.

DWhenever you want to display per-process data or access per-process Eaddress space, you should always reference only the Gamount of data you're willing to display in a single line. Always keep Gin mind that the current process may have changed between two calls of Gyour extension. This occurs when the screen becomes full, SDA displays Eits Press RETURN for more prompt, and the user enters a new DSET PROCESS command. Currently, there is no way to Bnotify your extension from a current process change. You must use >callbacks whenever you want to reference per-process data and Haddresses; only the callbacks ensure that data about the actual current process is returned.

FWhen the subject of analysis is an uniprocessor system, SDA's context Cis solely process context. In the case of symmetric multiprocessor E(SMP) systems, there are more than one CPU; the one which caused the Gsystem to crash (which becomes the current CPU), and up to 31 Bother CPU's. Each of these CPU's may have a current process; when Gchanging CPU context, process context may change as well. In addition, .some SDA commands affect the current CPU only.





Note

ECPU context is available on SMP systems only, and only when a system Gdump is analyzed. On the running system, the current CPU is always the >CPU which your process executes on.



FIn general, the notes for process context in the sentence above apply Efor CPU context as well. Entering a SET CPU command Gmay change the process context implicitly. In addition, when examining ACPU-specific data (from the per-CPU database), keep in mind that Areferences to this data may become invalid due to a previous CPU context change.

FIn addition to the commands described above, there are some other SDA Bcommands which may cause a process or CPU context change. See the CSystem Dump Analyzer (VAX/Alpha) Utility manuals for more information.6

3.4 Current address



DSDA provides the dot (.) as current address indicator when <used in commands which accepts address specifications, e.g. 5EXAMINE, FORMAT or DVALIDATE. The current address is always set by the :last EXAMINE, FORMAT or BVALIDATEcommand. For example, if the user enters HEXAMINE 10000, 10000 becomes the current address. This Haddress may be referenced later by supplying the dot (.) in place of an address.

9SDA provides two callbacks to access the current address:



FThere is one situation where these callbacks may be very useful: when Cparsing and evaluating SDA expressions. Assume, in your extension, Gthere is a command which accepts an address as parameter. To behave in Fthe usual SDA way, your command should not accept a hexadecimal value Honly, but a standard SDA expression, including logical and arithmetical 6operators, parentheses and previously defined symbols.

GSDA provides no callback for expression evaluation. However, using the 3above callbacks, you can do this the following way:



DThe following code example shows this way in more detail. Given the Gaddress of a null-terminated string containing a valid SDA expression, Cthe C routine comp_expr() computes and returns the binary Cresult. The code assumes that initialization work (as described in NSection 2.3.1) was already done.

  E#include <string.h>                   /* strxxx() functions */ I#include <tpadef.h>                   /* TPA parser definitions */   rvoid SDA$EXTEND_GET_ADDRESS(),        /* Get current address */ (1)@     SDA$EXTEND_SET_ADDRESS(),        /* Set current address */ ;     SDA$EXTEND_PARSECOMMAND();       /* Command parser */    int comp_expr(char *expression) { ; char cmdbuf[132];                    /* Command buffer */  @ int oldaddr,                         /* Old current address */ :     result;                          /* Binary result */  u struct tpadef tpa;                   /* TPA (parser) structure */ (2) s strcpy(cmdbuf,"EXA ");               /* Command is 'EXAMINE' */ (3) t strcat(cmdbuf,str);                  /* Append our expression */ (4) j strcat(cmdbuf,";0");                 /* Append ';0' */ (5) x SDA$EXTEND_GET_ADDRESS(&oldaddr);    /* Save current address. */ (6) q tpa.tpa$l_count = TPA$K_COUNT0;      /* 8 addit. longwords */ (7) B tpa.tpa$l_options = TPA$M_ABBREV;    /* Abbreviations allowed */  D tpa.tpa$l_stringcnt = strlen(cmdbuf);/* Command length in bytes */  C tpa.tpa$l_stringptr = (int) cmdbuf;  /* Command string address */  v SDA$EXTEND_PARSECOMMAND(&tpa);       /* Now execute command */ (8) p SDA$EXTEND_GET_ADDRESS(&result);     /* Obtain result */ (9) t SDA$EXTEND_SET_ADDRESS(oldaddr);     /* Restore old address. */ (10) : return result;                       /* Return result */ }  




    
  1. EThis makes the callbacks known as functions to the C compiler. Since Hthere are no includes or other external declarations for SDA callbacks, @it is up to you to declare them in a way your compiler requires.
  2. EThis defines the parser block for the VMS table-driven (TPA) parser. }SDA$EXTEND_PARSECOMMAND must be called with the address of this block. The Cstructure and the following TPA$xxx literals are defined in module ;$TPADEF. A detailed description of the table-driven parser A(LIB$TPARSE/LIB$TABLE_PARSE) can be found in the RTL Library (LIB$) manual.
  3. EWe want to execute an EXAMINE command. Since we set Hthe TPA$M_ABBREV bit later (which allows us to abbreviate commands), we 6can write 'EXA' ('EX' would be ambiguous with 'EXIT').
  4. 7The given expression is appended to the command string.
  5. AWe append ;0. This means 'examine the given Haddress and display null bytes'. It causes EXAMINE to suppress any Goutput. Otherwise, we would get displayed the result of the expression.
  6. EWe must save the initial current address since it will be changed by Eour EXAMINE command. Once the new current address (the result of our 4expression) is obtained, we can restore the old one.
  7. EFill in the structure for the parser. The structure consists of nine Clongwords where only the first four (shown in the example) must be Ginitialized. The remaining longwords are used to store internal parser Gstates. The 'options' longword contains parsing options; we will allow Habbreviated commands here (otherwise, we had to write 'EXAMINE' instead of 'EXA').
  8. @Invoke the parser. If the expression was spelled incorrectly or Gcontains unknown symbols, the parser signals an exception, causing SDA Eto abort our routine, display an error message and print its SDA> Dprompt. You can declare a condition handler to avoid this situation B(see Section 3.5).
  9. DObtain the current address again, this time, it contains our result.
  10. 6Restore the old current address and return the result.


FNote that SDA interprets the '/' as division sign in its expressions. <For this reason, you cannot supply qualifiers following SDA Gexpressions. If you use CDL (Command Definition Language) and Gthe corresponding CLI$ routines, the expression parameter or qualifier Evalue should be declared as value(type= $end_of_line) which Aprevents DCL from parsing the expression (and, if the expression Dcontains characters like '@' or '*', returning a syntax error). You Cshould notify your users that qualifiers, if any, must be supplied Gimmediately after the command verb (this is the same for most SDA commands).H

3.5 Condition handling and interrupts



EMost SDA callbacks do not return a status value, instead, in case of Herrors, they signal a condition. Unless otherwise changed, this results Ein the invocation of SDA's condition handler which is established by Fdefault. The condition handler examines the reason for the condition, Adisplays the appropriate error message and - in case of errors - Gperforms an unwind. This causes the routine, wherein the condition was Asignaled, to abort and to return to SDA's main command loop (see |SDA$EXTEND_HANDLER for a detailed description of SDA's condition handler).

HIn most cases, this is a good practice. You can write your code simply; Dthere is no need to check return states (in fact, many callbacks do Hnot return any state). If your code is executed until its end, Fyou can assume that all involved callbacks had executed successfully. DIn contrast, in case of errors, you can assume that the appropriate Hmessages were already displayed on screen and the condition was handled %correctly by SDA's condition handler.

DIn some situations, however, it may be useful to establish your own vcondition handler. Consider the example in Section 3.4, wherein SDA's @current address location is used in conjunction with the parser Gcallback and the EXAMIME command to compute numerical For logical expressions. When the parser detects an error, it signal a Bcondition. EXAMINE is not executed in this case, Dleaving the current address unchanged. If, however, a syntactically Ccorrect, but otherwise invalid address is given, the parser forces Eexecution of EXAMINE which computes the expression, Hchanges the current address, and, since the address is invalid, signals Can exception. This causes your routine to abort before the initial current address can be restored.

DBy declaring a condition handler, you can avoid this situation. The Acondition handler restores the current address and resignals the Econdition, passing control to SDA's condition handler. In this case, Gthe longword holding the saved current address must be declared global (in C, outside of any function):

Jint G_addr_changed,                /* 1 if current address was changed */ ?    G_curr_addr;                   /* Saved current address */  int my_handler() { J if (G_addr_changed)                   /* Was current address changed? */  { =  SDA$EXTEND_SET_ADDRESS(G_curr_addr); /* Yes, restore it */  :  G_addr_changed = 0;                  /* OK, restored */  } @ return SS$_RESIGNAL;                  /* Resignal condition */ } 


?This code fragment shows the condition handler which should be Festablished as part of the extension's initialization work. It checks 9whether the current address was changed (if our internal EEXAMINE command was executed), and, if so, restores Fthe address. In the get_expr() routine, the change flag must be set accordingly:

   .   .   .G SDA$EXTEND_GET_ADDRESS(&G_curr_addr);  /* Save current address */  D G_addr_changed = 1;                    /* Force handler restore */  F SDA$EXTEND_PARSECOMMAND(&tpa);         /* Now execute command */    .   .   .B SDA$EXTEND_SET_ADDRESS(G_curr_addr);   /* Restore old address */  D G_addr_changed = 0;                    /* Clear handler restore */    .   .   .


HWithout the change flag, the current address would be restored whenever Aa condition occurs - even in the case, that no address was saved Epreviously. By the way: i prefer to prefix all global variables with 0'G_' - this makes easy to recognize their scope.

FSDA's condition handler is provided as callback; you can establish it Ein your program or call it from your own handler. This allows you to Ddisplay error messages like SDA does, but prevents you from loosing 6control over the execution flow in case of conditions.

EThere is another thing you should be aware of: there is no guarantee Dthat your routines are executed entirely. Due to SDA's behaviour of Dreprompting for a new command whenever the screen becomes full, the Huser may invoke a command of your extension, display some data, but may Genter another command before yours has completed. For this reason, you Ashould be careful when allocating resources at the begin of your Fcommand and returning them at the end (for example, virtual memory or locks).

CIt is highly recommended that you allocate all required resources, Dperform all work and free them before the first line of data is Ddisplayed. Never allocate resources beyond your routines or as @part of the extension initialization. Since there is no 'state' <maintained by SDA for this purpose, your extension (and its Ginitialization routine) may and may invoked many times from within the Bsame SDA session; uncontrolled resource allocation can cause your /extension to fail and the SDA session to abort.4

3.6 Override mode



FOn Alpha, with OpenVMS V7.0 and higher, when analyzing a system dump, DSDA can be invoked in override mode. This mode can be used Hwhen SDA would reject otherwise the dump stored in the dump file (since Eit is either incomplete or contains invalid data in the header). You 2tell SDA to run in override mode by supplying the B/OVERRIDE qualifier. SDA uses a different prompt $(SDA>>) to indicate that mode.

GOnly few commands are available in this mode; in general, all commands Eaccessing memory are not available. Override mode is mainly Cused to repair a corrupted dump file. It provides a MODIFY CDUMP command which allows you to change every byte, word, Flongword or quadword in the dump. Once the dump file is repaired, SDA can be invoked in the usual way.

GFrom the programmers point of view, callbacks accessing data in memory Dor from the dumpfile are not available. If you try to invoke one of Cthese callbacks in override mode, the error SDA$_MEMNOTACC (memory ?locations not accessible) is returned. This affects mainly the following callbacks:

   SDA$EXTEND_FORMAT    SDA$EXTEND_GETMEM64    SDA$EXTEND_GET_CURRECT_PCB    SDA$EXTEND_GET_IMAGE_OFF    SDA$EXTEND_REQMEM64    SDA$EXTEND_TRYMEM64 !   SDA$EXTEND_VALIDATE_QUEUE[64] 


HSDA provides no way to tell an extension whether is invoked in override Gmode. You may, however, find out this yourself: try to get data at the >base S0 address (FFFFFFFF80000000) as part of the extension's Finitialization. This address always exists in a dump; if you Ereceive the above error, you're running in override mode and are not Gable to access and display data from memory. Since most extensions are Huseless in override mode, you should display an appropriate message and terminate.8

3.7 Callback routines



HAs described earlier, callback routines are provided by SDA to Dmake some work easier and let our extension behave in a SDA-conform Gmanner. There are 28 callbacks on VAX and 36 callbacks on Alpha (44 on BAlpha V7 due its 64-bit support); some of the Alpha callbacks not Gavailable on VAX can be written easily by yourself; see the example of ²SDA$EXTEND_ON_CURRENT_SYSTEM in Section 3.1. Some others are Alpha-specific and @therefore not available on VAX. For every callback described in {Appendix B, information is given whether it exists on VAX and Alpha, Gor on Alpha only. In addition, some callbacks have different arguments pon VAX and Alpha; this is described in Appendix B as well.

HSince callbacks are internal routines in the SDA.EXE image, a shareable Gimage containing transfer vectors to these routines is provided, which Fyour extension must be linked against (on Alpha, it's an object file; wsee Appendix A). You must initialize a location in the shareable Eimage with the base address of the routine pointer array in SDA.EXE; @this address is passed as first argument to your extension (see vSection 2.2.2.1). If you do not so, invoking a callback results in an access violation.

ENot all callbacks confirm to the OpenVMS calling standard in the way Cthat they are called as procedures or pass a return status back to Gtheir caller. In addition, some callbacks expect and/or return data in Hprocessor registers. If your programming language does not allow direct Gaccess to processor registers, you must provide jackets which Einvoke the appropriate callback and copy the data from the processor Aregisters into locations where you can access it. If a jacket is Hrequired for a callback, a MACRO-32 example is given in its description Din Appendix B.

yTable 3-1 contains an overview about all callbacks, the SDA modules vin which they are defined, and the calling conventions. Table 3-2 Dcontains all callbacks, sorted by purpose, and a short description. FNote that the common name prefix SDA$EXTEND_ is omitted in the tables for the reason of shortness.





Note

CSDA callbacks may be invoked from user or supervisor mode only. In Fgeneral, unless required for protection purposes, an extension should Dnot run at higher-privileged processor modes. If it does, it should Creturn to user mode as fast as possible.





.)=  ' ! "                                                                                                                                                                                                                                            
Table 3-1 SDA Callbacks
Routine name Module RetStat Notes
 ADD_SYMBOL SYMBOLS  yes¹
 ALLOCATE SYMBOLS yes  Requires jacket routine
 DEALLOCATE SYMBOLS yes
 DISPLAY_HELP  SDA_EXTEND  yes¹
ENSURE  SDA_EXTEND  no
FORMAT SYMBOLS  yes¹
 FORMAT_SUBHEADING INDEX  no
GETMEM MAPPING yes ²
 GET_ADDRESS  SDA_EXTEND  no ³
 GET_BUGCHECK_MSG  SDA_EXTEND  no  Alpha only
 GET_CURRENT_PCB  SDA_EXTEND  no Alpha V7.0 and higher only
 GET_DYN_INFO  SDA_EXTEND  no  Alpha only
 GET_HEADER  SDA_EXTEND  no  Alpha only
 GET_HW_NAME  SDA_EXTEND  no  Alpha only
 GET_IMAGE_OFF  SDA_EXTEND yes  Alpha only
 GET_INPUT  SDA_EXTEND yes
 GET_LINE_COUNT  SDA_EXTEND  no Alpha V7.0 and higher only
HANDLER HANDLER  no
 LIB$INS_DECODE  EVAX_DECODE yes  Alpha only
 NEW_PAGE MAIN  no
 ON_CURRENT_SYSTEM  SDA_EXTEND yes  Alpha only
 PARSECOMMAND  SDA_EXTEND yes
PRINT MAIN  yes¹
 PRINT_COLUMN_VALUE MAIN yes " Must be called as subroutine
 PRINT_COLUMNS MAIN  no
 READ_SYMFILE  SDA_EXTEND yes
REQMEM MAPPING yes ²
 SET_ADDRESS  SDA_EXTEND  no ³
 SET_HEADING INDEX  no
 SET_HEADING_ROUTINE  SDA_EXTEND  no  Alpha only
 SET_LINE_COUNT  SDA_EXTEND  no Alpha V7.0 and higher only
 SKIP_LINES MAIN  no
 SYMBOLIZE SYMBOLS  no
 SYMBOL_VALUE SYMBOLS yes  Requires jacket routine
 TRANSLATE_ADDRESS SYMBOLS yes " Must be called as subroutine
 TRANSLATE_BITS SYMBOLS  yes¹
TRYMEM MAPPING yes ²
TYPE  SDA_EXTEND  yes¹
 VALIDATE_QUEUE  SDA_EXTEND yes ³



>¹Returns always success (low bit set), signals any error.
D²On OpenVMS Alpha V7.0 and higher, this routine accepts 64-bit Gaddresses and therefore was renamed to include the '64' postfix (e.g., GSDA$EXTEND_GETMEM was renamed to SDA$EXTEND_GETMEM64).
D³On OpenVMS Alpha V7.0 and higher, this routine accepts 32-bit Faddresses only, but has a corresponding routine for 64-bit support as ;well. This routine has the '64' postfix in its name (e.g., -SDA$EXTEND_GET_ADDRESS for 32-bit addresses, ?SDA$EXTEND_GET_ADDRESS64 for 64-bit addresses)



G  " # &                                                                                                                                                                                                                                             
Table 3-2 SDA Callbacks - Purpose
Purpose Callback Description
$ Formatting and displaying data  DISPLAY_HELP - Display online help from a help library
ENSURE  Ensure that/ n lines of data can be displayed
 FORMAT_SUBHEADING # Format and display subheaders
 GET_INPUT  Get a line of input
 NEW_PAGE ' Insert a <FF>; clear screen
PRINT ' Format and display a line of data
PRINT64 # Format and display 64bit data
 PRINT_COLUMNS $ Print columns of data (tables)
 PRINT_COLUMN_VALUE & Print a single value in a column
 SET_HEADING  Set heading line
 SET_HEADING_ROUTINE * Establish a routine to print headers
 SKIP_LINES $ Insert one or more empty lines
TYPE ' Format and display a line of data
TYPE64 $ Format and display 64-bit data
$ Decoding and symbol processing  ADD_SYMBOL Add symbol to symbol table
FORMAT & Decode and format data structure
 LIB$INS_DECODE  Decode 21x64 instruction
 READ_SYMFILE  Read symbol table file
 SYMBOLIZE  Symbolize numeric value
 SYMBOL_VALUE  Obtain symbol value
 TRANSLATE_ADDRESS " Translate value into address
 TRANSLATE_BITS ! Translate bitmask to string
. Interfaces to SDA routines and locations  ALLOCATE  Allocate virtual memory
 DEALLOCATE  Deallocate virtual memory
HANDLER  SDA's condition handler
 GET_ADDRESS  Obtain current address
 GET_ADDRESS64 # Obtain current 64-bit address
 GET_LINE_COUNT ! Obtain current line counter
 SET_ADDRESS  Set current address
 SET_ADDRESS64 Set current 64-bit address
 SET_LINE_COUNT ! Change current line counter
 PARSECOMMAND # Parse and execute SDA command
 Accessing memory GETMEM $ Access memory, signal warnings
 GETMEM64 + Access 64-bit memory, signal warnings
REQMEM " Access memory, signal errors
 REQMEM64 ) Access 64-bit memory, signal errors
TRYMEM " Access memory, do not signal
 TRYMEM64 ) Access 64-bit memory, do not signal
 VALIDATE_QUEUE ) Validate absolute or relative queue
 VALIDATE_QUEUE64  Validate 64-bit queue
$ System and context information  GET_BUGCHECK_MSG  Get bugcheck message
 GET_CURRENT_PCB Get PCB of current process
 GET_DYN_INFO ' Get info about dynamic data codes
 GET_HEADER  Get dump file header
 GET_HW_NAME  Get hardware name
 GET_IMAGE_OFFSET " Get offsets in sliced images
 ON_CURRENT_SYSTEM - Check for system dump or running system



T

Appendix A
Linking and debugging your extension



FOnce you have coded your extension in your favorite language and have Bsuccessfully compiled it, you must create a shareable image. This Fshareable image must be either copied into directory SYS$SHARE or you mdefine a logical name which points to it (see Section 2.1). This Fchapter explains how to link your extension on VAX and Alpha (this is :slightly different) and contains some hints for debugging.5

A.1 Linking on VAX



DOn VAX, your extension is built by linking the following components:

 




6Previous- | Next6 | Contents