From: MILORD::BISHOP "Richard Bishop ... dtn 381-1554, m/s ZKO3-4/U08, cube 4V14 03-Apr-1997 0909" 3-APR-1997 09:23:07.86 To: @DISTLIST:OPENVMS CC: BISHOP Subj: SDA extensions - now fully supported Ever been using SDA and found something it wouldn't do for you? In the past, you had a choice: - Ask the SDA developer to add your desired capability - Hack together a solution (possibly by directing SDA output to a file, then post-processing that file in some way) - Try to understand how to write an SDA extension by studying assorted listings of SDA modules, CLUE, etc. - Get around the problem another way (perhaps adding diagnostic code to the running system that records data that can be analyzed more easily later.) Now we offer a new choice: - Write an SDA extension using a documented, supported interface! Yes, that's right! The Raven release of OpenVMS Alpha, beginning with X6EA-FT1, includes a cleanup of the existing undocumented interface for SDA extensions, allowing anyone to write their own extension, tailored to answer their own particular need. There's only one limitation: support is only provided for SDA extensions written in C. Support for SDA extensions written in C comes in several parts: - Header files in SYS$LIBRARY:SYS$LIB_C.TLB: SDA_FLAGSDEF.H SDA_OPTDEF.H SDA_CIODEF.H SDA_MSGDEF.H SDA_ROUTINES.H The first three provide bit definitions for the arguments and returned values of many of the SDA routines that can be called from extensions. The fourth one defines the returned condition codes from other routines. The last one provides prototypes of all the callable routines, and contains #include statements for the other four, so that it is the only one that needs to be explicitly specified. - An example C program, SYS$EXAMPLES:MBX$SDA.C, that demonstrates calls of all the available routines and shows how an SDA extension should be compiled and linked. - A new image, SYS$SYSTEM:SDA_DEBUG.EXE. This is a copy of SDA.EXE, linked /DEBUG (SDA.EXE itself being linked /NOTRACEBACK to allow it to be installed with privileges). This new image will allow SDA extensions to be debugged. - The existing object file SYS$LIBRARY:SDA_EXTEND_VECTOR.OBJ is replaced by a module of the same name in SYS$LIBRARY:VMS$VOLATILE_PRIVATE_INTERFACES.OLB. Also added to this library is the module SDAMSG, providing a pointer to the SDA messages, which are in SYS$MESSAGE:PRGDEVMSG.EXE. - A new chapter in the Alpha SDA manual to guide a system programmer through the steps needed to create their own SDA extension. The changes that have been made to provide a clean C-callable interface should have little effect on any existing extensions written against the undocumented interface (since those were all written in Bliss or Macro), so if you own one of those, there are no changes that HAVE to be made to work with the new SDA. But there's one change we recommend, and two changes that will affect you when you want to build your extension against a Raven result disk: 1. Where you set up SDA$EXTEND_VERSION, you currently have to provide a pair of 16-bit words containing one and zero respectively, e.g.: sda$extend_version:: .word 1,0 or: GLOBAL sda$extend_version : VECTOR [2,WORD] PRESET ([0] = 1, [1] = 0); You should replace this definition with a single 32-bit longword containing the constant SDA_FLAGS$K_VERSION: $sda_flagsdef ; From LIB.MLB sda$extend_version:: .long SDA_FLAGS$K_VERSION or: LIBRARY 'sys$library:lib'; GLOBAL sda$extend_version : LONG INITIAL (SDA_FLAGS$K_VERSION); 2. Today, the existing return codes from the callable SDA routines are only available on a result disk; they are not shipped. Also, they all have names of the form MSG$_FOOBAR. Some existing extensions may have lifted these definitions from result disks in the past, or hardcoded their values in source or in linker options files, but there is no longer any need to do so. The following changes have been made: - All SDA message codes now have names of the form SDA$_FOOBAR - They are built into all flavors of LIB (LIB.MLB, LIB.REQ, LIB.R64, SYS$LIB_C.TLB), so they ship. - The object file that provides the pointer to the message texts in SYS$MESSAGE:PRGDEVMSG.EXE now ships in the object library SYS$LIBRARY:VMS$VOLATILE_PRIVATE_INTERFACES.OLB, so it is accessible to extensions that want to signal SDA message codes. 3. The file SYS$LIBRARY:SDA_EXTEND_VECTOR.OBJ is replaced by a module of the same name in SYS$LIBRARY:VMS$VOLATILE_PRIVATE_INTERFACES.OLB, so link procedures will need to be changed. In your link command, you need to replace: alpha$library:sda_extend_vector.obj by: alpha$library:vms$volatile_private_interfaces/library Attached to this message is an outline of the information that will go into that new chapter in the SDA manual. We need your feedback on this before it even goes to field test, so if you have a pet feature that you've always wanted SDA to provide, now's your opportunity. Please send your comments to any or all of us: Richard Bishop (MILORD::BISHOP) OpenVMS Alpha SDA project leader Christian Moser (EEMELI::MOSER) CLUE$SDA maintainer and SDA extensions expert (& the one that did the work to provide this C-callable interface for SDA extensions) John Hurst (JARETH::JHURST) SDA Technical Writer In particular, please give feedback on: - How easy/hard it is to write an SDA extension based on this description; - Clarity of build instructions; - How well the prototypes in SDA_ROUTINES.H fit the real-life uses (for example, is VOID_PQ better than CHAR_PQ or UINT64 in any given instance). Note: In prototypes and examples, variable and routine names are in lower case. In headings and text, they're in upper case. This is intentional. In the manual, we will be using different fonts for these names so the distinction between them and the surrounding text will be clear without upcasing them. Thanks, Richard. PS: I've posted this announcement and the attached description in STAR::SYSNOTES #2164. SDA EXTENSIONS ============== 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: - 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 " and "FORMAT UCB" to obtain the address of the nonpaged pool structure. - Invoke the SDA command "EXAMINE
;" to display the contents of the data in the new nonpaged pool structure as a series of hexadecimal longwords. - Manually decode the contents of the data structure from this hexadecimal dump. An extension to SDA 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. General Description ------------------- The following discussion uses an example SDA extension that provides 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 our 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; SDA$EXTEND_VERSION, the address a longword that contains the version of the interface used (in the format of major/minor ident), allowing 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 of course 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
" to demonstrate this. It is recommended that if the extension is invoked with no arguments, it should do no more than display a simple announcement message, or prompt for input. This will assist in the debugging of the extension, as described below. Creating an extension --------------------- (a) Compiling and linking an SDA extension The user-written module must be written in DEC C (minimum V5.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 + alpha$library:sys$lib_c /library $ link /share - mbx$sda.obj, - alpha$library:vms$volatile_private_interfaces /library, - sys$input /option symbol_vector = (sda$extend=procedure) symbol_vector = (sda$extend_version=data) Note 1: It is recommended that the qualifier /INSTRUCTION=NOFLOAT be included on the compile command line if floating point instructions are not actually needed. Note 2: The "+ ALPHA$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 ALPHA$LIBRARY:SYS$LIB_C.TLB. Note 3: If the user-written extension needs to signal SDA condition codes, or output their text with $PUTMSG, the qualifier /INCLUDE=SDAMSG should be added to the parameter ALPHA$LIBRARY:VMS$VOLATILE_PRIVATE_INTERFACES /LIBRARY. (b) Invoking an SDA extension The SDA extension can then be invoked as follows: $ define mbx$sda sys$disk:[]mbx$sda $ analyze /system SDA> mbx summary SDA> mbx
(c) 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 (This is recommended, as 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: void sda$extend ( int *transfer_table, struct dsc$descriptor_s *cmd_line, SDA_FLAGS sda_flags) Where: transfer_table is the address of the vector table in the base image. The user-written routine SDA$EXTEND must copy this to SDA$EXTEND_VECTOR_TABLE_ADDR before any SDA routines can be called. cmd_line is the address of the descriptor of the command line as entered by the user, less the name of the extension. So if "SDA> MBX" or "SDA> DO MBX" is entered, the command line is a zero length string. If the command "SDA> MBX 80102030" is entered, the command line is " 80102030" (the separating space is not stripped.) sda_flags This structure only has two bits defined: 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. (If neither bit is set, then SDA was activated with the ANALYZE/CRASH_DUMP command.) 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, it will not be possible to call any of the routines described below. Any attempts to call the routines will receive a status return of SDA$_VECNOTINIT. (For routines defined not to return a status, this value can only be found by examining R0.) It is recommended that the next statement 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 will output 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 This condition handler can be established as follows: lib$establish (sda$cond_handler); Note 4: The error condition, signal array and register dump are output directly to SYS$OUTPUT and/or SYS$ERROR, and will not be 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 #include sda_routines 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; } Debugging an extension ---------------------- In addition to the "after-the-fact" information provided by the condition handler, it is possible to 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, SDA extensions can be debugged, as follows: - Compile your extension /DEBUG/NOOPT and link it /DEBUG - Define logical names for SDA and the extension, and invoke SDA - At the initial DBG> prompt, type GO - At the initial SDA> prompt, invoke the extension with no arguments - At the next prompt (either from SDA or the extension), return control to Debug - Use Debug commands to set breakpoints, etc., in the extension and then type GO - Invoke the extension, providing the necessary arguments For example: $ cc /debug /noopt mbx$sda + alpha$library:sys$lib_c /library $ link /debug /share - mbx$sda.obj, - alpha$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> go ... SDA> mbx MBX commands: 'MBX SUMMARY' and 'MBX
' SDA> ^C DBG> set image mbx$sda DBG> set language c DBG> set break /exception DBG> go SDA> mbx summary ... SDA> mbx
... %DEBUG-I-DYNMODSET, setting module MBX$SDA %SYSTEM-E-INVARG, invalid argument ... DBG> 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, 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, etc. (and which is 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 - etc. The full list of available routines is: SDA$ADD_SYMBOL SDA$GETMEM SDA$ALLOCATE SDA$INSTRUCTION_DECODE SDA$DBG_IMAGE_INFO SDA$NEW_PAGE SDA$DEALLOCATE SDA$PARSE_COMMAND SDA$DISPLAY_HELP SDA$PRINT SDA$ENSURE SDA$READ_SYMFILE SDA$FORMAT SDA$REQMEM SDA$FORMAT_HEADING SDA$SET_ADDRESS SDA$GET_ADDRESS SDA$SET_HEADING_ROUTINE SDA$GET_BLOCK_NAME SDA$SET_LINE_COUNT SDA$GET_BUGCHECK_MSG SDA$SKIP_LINES SDA$GET_CURRENT_PCB SDA$SYMBOL_VALUE SDA$GET_HEADER SDA$SYMBOLIZE SDA$GET_HW_NAME SDA$TRYMEM SDA$GET_IMAGE_OFFSET SDA$TYPE SDA$GET_INPUT SDA$VALIDATE_QUEUE SDA$GET_LINE_COUNT The details of all these routines follow. But there are some points to be aware of in using them: 1. There are three different routines available to read the contents of memory locations in the dump: SDA$TRYMEM, SDA$GETMEM, and SDA$REQMEM. They are used as follows: 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. It should therefore be used directly when inaccessibility of the location being read is an expected situation which the caller of SDA$TRYMEM will handle 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 will print out a warning message, but does not abort the SDA command in progress. It should therefore be used when inaccessibility of the location being read is unexpected, but 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 will print out an error message, abort the SDA command in progress and return to the "SDA>" prompt. It should therefore be used when inaccessibility of the location being read is unexpected, and will prevent the command currently being executed from continuing. The caller of SDA$REQMEM will not resume if an error occurs. 2. Only use 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 , , , and the FAO directives that create them. Use the FAO directive !AF when contents of memory returned by SDA$TRYMEM, etc., are being displayed directly, since 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. 3. Only use 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 only deallocate it 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. 4. 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, since 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 */ specifying the address of interest in the dump, and void *dest /* 32-bit pointer */ specifying the address in local storage to which the dump contents are to be copied. SDA$ADD_SYMBOL Definition Adds a symbol to SDA's local symbol table. Format void sda$add_symbol ( char *symbol_name, uint64 symbol_value); Arguments symbol_name = address of symbol name string (zero-terminated) symbol_value = symbol value Condition Values Returned None 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. Example sda$add_symbol ("MBX", 0xFFFFFFFF80102030); This call defines the symbol MBX to the hexadecimal value FFFFFFFF80102030. SDA$ALLOCATE Definition Allocate dynamic memory. Format void sda$allocate ( uint32 size, void **ptr_block); Arguments size = size of block to allocate (in bytes) ptr_block = address of longword to receive address of block Condition Values Returned None. If no memory is available, the error will be signaled and the SDA session aborted. Description The requested memory is allocated and the address returned. Note: This is the only supported mechanism for allocation of dynamic memory. [See also SDA$DEALLOCATE] Example PCB *local_pcb; ... sda$allocate (PCB$C_LENGTH, (void *)&local_pcb); This call will allocate a block of heap storage for a copy of a PCB, and store its address in the pointer LOCAL_PCB. SDA$DBG_IMAGE_INFO Definition Displays a list of activated images together with their virtual address ranges, for debugging purposes. Format void sda$dbg_image_info (); Arguments None Condition Values Returned None Description A list of the images currently activated, with their start and end addresses, is displayed. This is provided as a debugging aid for SDA extensions. Example sda$dbg_image_info (); SDA will output the list of images in the following format: Current VMS Version: "X6DX-FT1" Process Activated Images: Start VA End VA Image Name 00010000 000301FF SDA 00032000 00177FFF SDA$SHARE 7B508000 7B58BFFF DECC$SHR 7B2D8000 7B399FFF DPML$SHR 7B288000 7B2C9FFF CMA$TIS_SHR 7B698000 7B6D9FFF LBRSHR 0021A000 0025A3FF SCRSHR 00178000 002187FF SMGSHR 7B1E8000 7B239FFF LIBRTL 7B248000 7B279FFF LIBOTS 80C140D0 80C23120 SYS$BASE_IMAGE 80C036B8 80C05288 SYS$PUBLIC_VECTORS 002C6000 002D31FF PRGDEVMSG 002D4000 002DA9FF SHRIMGMSG 002DC000 002DFFFF DECC$MSG 00380000 003E03FF MBX$SDA SDA$DEALLOCATE Definition Deallocate and free dynamic memory. Format void sda$deallocate ( void *ptr_block, uint32 size); Arguments ptr_block = starting address of block to be freed size = size of block to deallocate (in bytes) Condition Values Returned None. If an error occurs, it will be signaled and the SDA session aborted. Description The specified memory is deallocated. Note: This is the only supported mechanism for deallocation of dynamic memory. [See also SDA$ALLOCATE] Example PCB *local_pcb; ... sda$deallocate ((void *)local_pcb, PCB$C_LENGTH); This call will deallocate the block of length PCB$C_LENGTH whose address is stored in the pointer LOCAL_PCB. SDA$DISPLAY_HELP Definition Display online help. Format void sda$display_help ( char *library_desc, char *topic_desc); Arguments library = address of library filespec topic = address of of topic name (both arguments to be specified as zero-terminated ASCII strings) Condition Values Returned None Description Help from the specified library is displayed on the given topic Example sda$display_help ("SYS$HELP:SDA", "HELP"); This call will produce the following output at the terminal: HELP The System Dump Analyzer (SDA) allows you to inspect the contents of memory as saved in the dump taken at crash time or as exists in a running system. You can use SDA interactively or in batch mode. You can send the output from SDA to a listing file. You can use SDA to perform the following operations: Assign a value to a symbol Examine memory of any process Format instructions and blocks of data Display device data structures Display memory management data structures Display a summary of all processes on the system Display the SDA symbol table Copy the system dump file Send output to a file or device Read global symbols from any object module Search memory for a given value You can obtain help on any of the following topics by typing HELP : ATTACH Execute_Command Operation SET CPU_Context EXIT Process_Context SHOW COPY Expressions READ SPAWN DEFINE FORMAT REPEAT Symbols EVALUATE HELP SEARCH VALIDATE EXAMINE Initialization Topic? SDA$ENSURE Definition Ensure sufficient space on the current output page. Format void sda$ensure ( uint32 lines); Arguments lines = number of lines to fit on page Condition Values Returned None Description This routine will check and make sure that the number of lines specified will fit on the current page, otherwise it will issue a page break. Example sda$ensure (5); This call will ensure that there are five lines left on the current page, and output a page break if not. SDA$FORMAT Definition Displays the formatted contents of a data structure. Format void sda$format ( VOID_PQ struct_addr, __optional_params); Arguments struct_addr = the address in the system dump of the data structure to be formatted options = flags: none - use structure type from the xxx$B_TYPE field of the structure (default) SDA_OPT$M_FORMAT_TYPE - use the structure type given in struct_prefix SDA_OPT$M_FORMAT_PHYSICAL - indicates that struct_addr is a physical address instead of a virtual address struct_prefix = address of structure name string (zero-terminated) Condition Values Returned None Description This routine displays the formatted content of a data structure which begins at the address specified. If no symbol prefix is passed, then SDA tries to find the symbols associated with the block type specified in the block-type byte of the data structure. Example PCB *local_pcb; PHD *local_phd; ... sda$format (local_pcb); sda$format (local_phd, SDA_OPT$M_FORMAT_TYPE, "PHD"); The first call will format the structure whose system address is held in the variable LOCAL_PCB, determining the type from the type byte of the structure. The second call will format the structure whose system address is held in the variable LOCAL_PHD, using PHD symbols. SDA$FORMAT_HEADING Definition Format a new page heading. Format void sda$format_heading ( char *ctrstr, __optional_params); Arguments ctrstr = address of control string (zero-terminated ASCII string) prmlst = (optional) FAO parameters. All arguments after the control string are copied into a quadword parameter list as used by $FAOL_64. Condition Values Returned None. If the $FAOL_64 call issued by SDA$FORMAT_HEADING fails, an empty string will be used as the page heading. Description This routine prepares and saves the page heading to be used whenever SDA$NEW_PAGE is called. Nothing is output until SDA$NEW_PAGE is next called, or a page break is necessary because the current page is full. Example char hw_name[64]; ... sda$get_hw_name (hw_name, sizeof(hw_name)); sda$format_heading ( "SDA Extension Commands, system type !AZ", &hw_name); sda$new_page (); This example will produce the following heading: SDA Extension Commands, system type DEC 3000 Model 400 ------------------------------------------------------ SDA$GET_ADDRESS Definition Gets the address value of the current memory location. Format void sda$get_address ( VOID_PQ *address); Arguments address = location to store the current 64-bit memory address Condition Values Returned None Description Returns the current address being referenced by SDA (location ".") Example VOID_PQ current_address; ... sda$get_address (¤t_address); This call will store SDA's current memory location in the long pointer CURRENT_ADDRESS. SDA$GET_BLOCK_NAME Definition Returns the name of a structure, given its type and/or subtype Format void sda$extend_get_block_name ( uint32 block_type, uint32 block_subtype, char *buffer_ptr, uint32 buffer_len); Arguments block_type = block type (usually extracted from xxx$b_type field) block_subtype = block subtype (ignored if the given block type has no subtypes) buffer_ptr = address of buffer to save block name buffer_len = length of buffer to receive block name Condition Values Returned None Description Given the block type and/or subtype of a structure, this routine returns the name of the structure. If the structure type is one that has no subtypes, the given subtype is ignored. If the structure type is one that has subtypes, and the subtype is given as zero, the name of the block type itself is returned. If an invalid type or subtype (out of range) is given, an empty string is returned. Example char buffer[32]; ... sda$get_block_name (0x6F, 0x20, buffer, sizeof (buffer)); if (strlen (buffer) == 0) sda$print ("Block type: no named type/subtype"); else sda$print ("Block type: !AZ", buffer); This example will produce the output: Block type: VCC_CFCB SDA$GET_BUGCHECK_MSG Definition Get the text associated with a bugcheck code Format void sda$get_bugcheck_msg ( uint32 bugcheck_code, char *buffer_ptr, uint32 buffer_size); Arguments bugcheck_code = the bugcheck code to look up buffer_ptr = address of buffer to save bugcheck message buffer_size = size of buffer to put message in Condition Values Returned None Description Gets the string representing the bugcheck code passed as the argument. The bugcheck message string is passed in the buffer (represented as a pointer and length) as a zero-terminated ASCII string. Example char buffer[128]; ... sda$get_bugcheck_msg (0x108, buffer, sizeof(buffer)); sda$print ("Bugcheck code 108 (hex) ="); sda$print ("!_\"!AZ\"", buffer); This example will produce the following output: Bugcheck code 108 (hex) = "DOUBLDALOC, Double deallocation of swap file space" SDA$GET_CURRENT_PCB Definition Get the PCB address of the "SDA current process" currently selected. Format void sda$get_current_pcb ( PCB **pcbadr); Arguments pcbadr = location in which to store the current PCB address Condition Values Returned None Description The PCB address of the process currently selected by SDA is returned in the specified location. Example PCB *current_pcb; ... sda$get_current_pcb ( ¤t_pcb ); This call will store the dump address of the PCB of the process currently being referenced by SDA in the pointer CURRENT_PCB. SDA$GET_HEADER Definition Returns pointers to the dumpfile header and the errorlog buffer together with the size of those data structures. Format void sda$get_header ( DMP **dmp_header, uint32 *dmp_header_size, void **errlog_buf, uint32 *errlog_buf_size); Arguments dmp_header = location in which to store the address of the copy of the dumpfile header held by SDA dmp_header_size = location in which to store the size of the dumpfile header errlog_buf = location in which to store the address of the copy of the errorlog buffer held by SDA errlog_buf_size = location in which to store the size of the errorlog buffer Condition Values Returned None Description This routine returns the addresses and sizes of the dump header and error logs read by SDA when the dumpfile was opened. If this routine is called when the running system is being analyzed with ANALYZE/SYSTEM, then (1) the address and size of SDA's dump header buffer will be be returned, but the header will contain zeroes, and (2) zeroes will be returned for the address and size of SDA's error log buffer. Example DMP *dmp_header; uint32 dmp_header_size; char *errlog_buffer; uint32 errlog_buffer_size; ... sda$get_header (&dmp_header, &dmp_header_size, (void **)&errlog_buffer, &errlog_buffer_size); This call will store the address and size of SDA's copy of the dumpfile header in DMP_HEADER and DMP_HEADER_SIZE, and store the address and size of SDA's copy of the error log buffers in ERRLOG_BUFFER and ERRLOG_BUFFER_SIZE, respectively. SDA$GET_HW_NAME Definition Returns the full name of the hardware platform where the dump was written. Format void sda$get_hw_name ( char *buffer_ptr, uint32 buffer_len); Arguments buffer_ptr = address of buffer to save HW name buffer_len = length of buffer to receive HW name Condition Values Returned None Description Gets the string representing the platform hardware name and puts it in the buffer passed as the argument as a zero-terminated ASCII string. Example char hw_name[64]; ... sda$get_hw_name (hw_name, sizeof(hw_name)); sda$print ("Platform name: \"!AZ\"", hw_name); This example will produce output of the form: Platform name: "DEC 3000 Model 400" SDA$GET_IMAGE_OFFSET Definition Maps a given virtual address onto an image or execlet. Format COMP_IMG_OFF sda$get_image_offset ( VOID_PQ va, VOID_PQ img_info, VOID_PQ subimg_info, VOID_PQ offset); Arguments va = virtual address of interest img_info = pointer to return addr of LDRIMG or IMCB block subimg_info = pointer to return addr of ISD_OVERLAY or KFERES offset = pointer to address to return offset from image Condition Values Returned The status returned indicates the type of image if a match was found. SDA_CIO$V_VALID - set if image offset was found SDA_CIO$V_PROCESS - set if image was an activated image SDA_CIO$V_SLICED - set if the image is sliced SDA_CIO$V_COMPRESSED - set if activated image contains compressed data sections SDA_CIO$V_ISD_INDEX - index into ISD_LABELS table (only for LDRIMG execlets) SDA_CIO$V_xxx flags set: img_info type: subimg_info type: valid LDRIMG n/a valid && sliced LDRIMG ISD_OVERLAY valid && process IMCB n/a valid && process && sliced IMCB KFERES_SECTION Description Given a virtual address, this routine finds in which image it falls and returns the image information and offset. The loaded image list is traversed first to find this information. If it is not found, then the activated image list of the currently selected process is traversed. If still no success, then the resident installed images are checked. Example VOID_PQ va = (VOID_PQ)0xFFFFFFFF80102030; COMP_IMG_OFF sda_cio; int64 img_info; int64 subimg_info; int64 offset; ... sda_cio = sda$get_image_offset (va, &img_info, &subimg_info, &offset); For an example of code that interprets the returned COMP_IMG_OFF structure, see the supplied example program, SYS$EXAMPLES:MBX$SDA.C. SDA$GET_INPUT Definition Reads input commands. Format int sda$get_input ( char *prompt, char *buffer, uint32 buflen); Arguments prompt = address of prompt string (zero-terminated ASCII string) buffer = address of buffer to store command buflen = maximum length of buffer Condition Values Returned Status returned is either: SS$_NORMAL - successful completion RMS$_EOF - user hit Description The command entered will be returned as a zero-terminated string. The string is not upcased. No input, generated by simply pressing or will return a null string. Example int status; char buffer[128]; ... status = sda$get_input ( "MBX> ", buffer, sizeof (buffer) ); This call will prompt the user for input with "MBX> " and store the response in buffer. SDA$GET_LINE_COUNT Definition Get the number of lines currently printed on the current page. Format void sda$get_line_count ( uint32 *line_count); Arguments line_count = the number of lines printed on current page Condition Values Returned None Description The number of lines that have been printed so far on the current page is returned. Example uint32 line_count; ... sda$get_line_count (&line_count); This call will copy the current line count on the current page of output to the location LINE_COUNT. SDA$GETMEM Definition Read dump memory and signal warning if inaccessible Format int sda$getmem ( VOID_PQ start, void *dest, int length, __optional_params); Arguments start = starting virtual address in dump dest = return buffer address length = length of transfer physical = 0: is a virtual address (the default) 1: is a physical address Condition Values Returned SDA$_SUCCESS - successful completion SDA$_NOREAD - ) SDA$_NOTINPHYS - ) The data is inaccessible for some reason. Others - ) If a failure status code is returned, it will have already been signaled as a warning. Description This routine transfers an area from the memory in the dump file to the caller's return buffer. It performs the necessary address translation to locate the data in the dump file. SDA$GETMEM will signal a warning and return an error status if the data is inaccessible. [See also SDA$REQMEM and SDA$TRYMEM] Example int status; PCB *current_pcb; PHD *current_phd; ... status = sda$getmem ((VOID_PQ)¤t_pcb->pcb$l_phd, ¤t_phd, 4); This call will return the contents of the PCB$L_PHD field of the PCB whose dump address is in the pointer CURRENT_PCB to the pointer CURRENT_PHD. SDA$INSTRUCTION_DECODE Definition Translates one Alpha machine instruction into the assembler string equivalent. Format int sda$instruction_decode ( void *istream_ptr, char *buffer, uint32 buflen); Arguments istream_ptr = address of the pointer which points to the i-stream in a local buffer buffer = address of a string buffer into which to store the output assembler string buflen = maximum size of the string buffer Condition Values Returned Status returned is either: SS$_NORMAL - successful completion SS$_BADPARAM - any of the following failures: output buffer too small invalid register invalid opcode class/format could not translate instruction Description Translates an Alpha machine instruction into the assembler string equivalent. Alpha instructions are always 4 bytes long. The instruction stream must first be read into local memory and then the address of a pointer to the local copy of the instruction stream is passed to the routine. For every successful translated instruction, the pointer is automatically updated to point to the next instruction. The output assembler string is zero-terminated and in case of a failure a null string is returned. Example int status; VOID_PQ va = (VOID_PQ)0xFFFFFFFF80102030; uint32 instruction; uint32 *istream = &instruction; char buffer[64]; ... sda$reqmem (va, &instruction, 4); status = sda$instruction_decode (&istream, buffer, sizeof (buffer)); This example will read the instruction at dump location VA and decode it, putting the result into BUFFER. Pointer ISTREAM will be incremented (to the next longword). SDA$NEW_PAGE Definition Begins a new page of output Format void sda$new_page (); Arguments None Condition Values Returned None Description This routine will cause a new page to be written and will output the page heading (established with SDA$FORMAT_HEADING) and the current sub-heading (established with SDA$SET_HEADING_ROUTINE). Example sda$new_page (); This call will output a page break and display the current page heading and sub-heading (if any). SDA$PARSE_COMMAND Definition Parse and execute a SDA command line. Format void sda$parse_command ( char *cmd_line, __optional_params); Arguments cmd_line = address of a valid SDA command line (zero-terminated) options = flags SDA_OPT$K_PARSE_DONT_SAVE - means 'do not save this command' (the default) SDA_OPT$K_PARSE_SAVE - indicates to 'save this command' (i.e. can be recalled with KP0) Condition Values Returned None. Any errors that occur during the parsing or execution of the specified command are signaled. Description Not every SDA command has a callable extension interface. For example, to change the process context from within SDA you would pass the command string 'SET PROC/IND=xx' to this parse command routine. Abbreviations are allowed. Example sda$parse_command ("SHOW ADDRESS 80102030"); This call will produce the following output: FFFFFFFF.80102030 is an S0/S1 address Mapped by Level-3 PTE at: FFFFFFFD.FFE00408 Mapped by Level-2 PTE at: FFFFFFFD.FF7FF800 Mapped by Level-1 PTE at: FFFFFFFD.FF7FDFF8 Mapped by Selfmap PTE at: FFFFFFFD.FF7FDFF0 Also mapped in SPT window at: FFFFFFFF.FFDF0408 The "SHOW ADDRESS" command will not be recorded as the most recent command for use with the KP0 key or the REPEAT command. SDA$PRINT Definition Format and print a single line. Format int sda$print ( char *ctrstr, __optional_params ); Arguments ctrstr = address of a zero-terminated control string prmlst = (optional) FAO parameters. All arguments after the control string are copied into a quadword parameter list as used by $FAOL_64. Condition Values Returned Status returned is one of: SDA$_SUCCESS - successful completion SDA$_CNFLTARGS - more than twenty FAO parameters given Other - returned from the $PUT issued by SDA$PRINT (the error will also have been signaled). If the $FAOL_64 call issued by SDA$PRINT fails, a blank line will be output. Description Format and print a single line. This will normally be output to the terminal, unless the SDA commands SET OUTPUT or SET LOG have been used to redirect or copy the output to a file. Example char buffer[32]; ... sda$get_block_name (0x6F, 0x20, buffer, sizeof (buffer)); sda$print ("Block type: !AZ", buffer); This example will output the following line: Block type: VCC_CFCB SDA$READ_SYMFILE Definition Read symbols from a given file. Format int sda$read_symfile ( char *filespec, uint32 options, __optional_params ); Arguments filespec = address of file or directory specification from which to read the symbols (zero-terminated ASCII string) options = indicate type of symbol file and logging flags SDA_OPT$M_READ_FORCE - read/force SDA_OPT$M_READ_IMAGE - read/image SDA_OPT$M_READ_SYMVA - read/symva SDA_OPT$M_READ_RELO - read/relo SDA_OPT$M_READ_EXEC - read/exec [] SDA_OPT$M_READ_NOLOG - /nolog, suppress count of symbols read SDA_OPT$M_READ_FILESPEC - or given SDA_OPT$M_READ_NOSIGNAL - return status, without signaling errors relocate_base = base address for symbols (non-sliced symbols) symvect_va = symb vector addr (symbols are offsets into sym vector) symvect_size = size of symbol vector loaded_img_info = addr of $LDRIMG data structure with execlet info Condition Values Returned Status returned is one of: SDA$_SUCCESS - successful completion SDA$_CNFLTARGS - No filename given and SDA_OPT$M_READ_EXEC not set Others errors will be signaled and/or returned, exactly as though the equivalent SDA READ command had been used. Use HELP/MESSAGE for explanations. Description Read symbols from a given file to add symbol definitions to the working symbol table by reading GST entries. The file is usually a symbol file (.STB) or an image (.EXE). If SDA_OPT$M_READ_EXEC is specified in the options, then the filespec is treated as a directory specification, where symbol files and/or image files for all execlets may be found (à la READ/EXECUTIVE). If no directory specification is given, the logical name SDA$READ_DIR is used. Note that when SDA reads symbol files and finds routine names, the symbol name that matches the routine name is set to the address of the procedure descriptor. A second symbol name, the routine name with "_C" appended, is set to the start of the routine's prologue. Example sda$read_symfile ("SDA$READ_DIR:SYSDEF", SDA_OPT$M_READ_NOLOG); The symbols in SYSDEF.STB are added to SDA's internal symbol table, and the number of symbols found is not output to the terminal. SDA$REQMEM Definition Read dump memory and signal an error if inaccessible Format int sda$reqmem ( VOID_PQ start, void *dest, int length, __optional_params); Arguments start = starting virtual address in dump dest = return buffer address length = length of transfer physical = 0: is a virtual address (the default) 1: is a physical address Condition Values Returned SDA$_SUCCESS - successful completion Any failure will be signaled as an error and the current command will be aborted. Description This routine transfers an area from the memory in the dump file to the caller's return buffer. It performs the necessary address translation to locate the data in the dump file. SDA$REQMEM will signal a error and abort the current command if the data is inaccessible. [See also SDA$GETMEM and SDA$TRYMEM] Example VOID_PQ address; uint32 instruction; ... sda$symbol_value ("EXE_STD$ALLOCATE_C", (uint64 *)&address); sda$reqmem (address, &instruction, 4); This example will read the first instruction of the routine EXE_STD$ALLOCATE into the location INSTRUCTION. SDA$SET_ADDRESS Definition Stores a new address value as the current memory address ("."). Format void sda$set_address ( VOID_PQ address); Arguments address = address value to store in current memory location Condition Values Returned None Description The specified address becomes SDA's current memory address (the predefined SDA symbol "."). Example sda$set_address ((VOID_PQ)0xFFFFFFFF80102030); This call will set SDA's current address to FFFFFFFF.80102030. SDA$SET_HEADING_ROUTINE Definition Set the current heading routine to be called after each page break. Format void sda$set_heading_routine ( void (*heading_rtn) ()); Arguments heading_rtn = address of routine to be called after each new page Condition Values Returned None Description When SDA begins a new page of output (either because SDA$NEW_PAGE was called, or because the current page is full), it will output two types of heading. The first is the page title, and is set by calling the routine SDA$FORMAT_HEADING. This is the title that is included in the index page of a listing file when a SET OUTPUT command is issued. The second heading is typically for column headings, and since this can vary from display to display, a routine must be written for each separate heading. By calling SDA$SET_HEADING_ROUTINE to specify a user- written routine, the routine will be called each time SDA begins a new page. To stop the routine being invoked each time SDA begins a new page, either call SDA$FORMAT_HEADING to set a new page title, or call SDA$SET_HEADING_ROUTINE and specify the routine address as NULL. If the column headings need to be output during a display (i.e. in the middle of a page), and then be re-output each time SDA begins a new page, call the user-written routine directly the first time, then call SDA$SET_HEADING_ROUTINE to have it be called automatically thereafter. Example void mbx$title (void) { sda$print ("Mailbox UCB ..."); sda$print (" Unit Address ..."); sda$print ("------------------------"); return; } ... sda$set_heading_routine (mbx$title); ... sda$set_heading_routine (NULL); This example will set the heading routine to the routine MBX$TITLE, and later clear it. The routine will be called if any page breaks are generated by the intervening code. SDA$SET_LINE_COUNT Definition Set the number of lines currently printed on the current page. Format void sda$set_line_count ( uint32 line_count); Arguments line_count = the number of lines printed on current page Condition Values Returned None Description The number of lines that have been printed so far on the current page is set to the given value. Example sda$set_line_count (5); This call will set SDA's current line count on the current page of output to 5. SDA$SKIP_LINES Definition This routine will output a specified number of blank lines. Format void sda$skip_lines ( uint32 lines); Arguments lines = number of lines to skip Condition Values Returned None Description The specified number of blank lines are output. Example sda$skip_lines (2); This call will cause two blank lines to be output. SDA$SYMBOL_VALUE Definition Get the 64-bit value of a specified symbol. Format int sda$symbol_value ( char *symb_name, uint64 *symb_value); Arguments symb_name = zero-terminated string containing symbol name symb_value = address to receive symbol value Condition Values Returned SDA$_SUCCESS - symbol found SDA$_BADSYM - symbol not found Description A search through SDA's symbol table is made for the specified symbol. If found, its 64-bit value is returned. Example int status; VOID_PQ address; ... status = sda$symbol_value ("EXE_STD$ALLOCATE_C", (uint64 *)&address); This call will return the start address of the prologue of routine EXE_STD$ALLOCATE to location ADDRESS. SDA$SYMBOLIZE Definition Convert a value to a symbol name and offset. Format int sda$symbolize ( uint64 value, char *symbol_buf, uint32 symbol_len); Arguments value = value to be translated symbol_buf = address of buffer to return string into symbol_len = maximum length of string buffer Condition Values Returned Status returned is either: SS$_NORMAL - successful completion SS$_BUFFEROVF - buffer too small, string truncated SS$_NOTRAN - no symbolization for this value (null string returned) Description This routine accepts a value and returns a string which contains a symbol and offset corresponding to that value. First the value is checked in the symbol table. If no symbol can be found (either exact match or up to 0xFFF less than the specified value), the value is then checked to see if it falls within one of the loaded or activated images. Example VOID_PQ va = VOID_PQ(0xFFFFFFFF80102030); char buffer[64]; ... status = sda$symbolize (va, buffer, sizeof(buffer)); sda$print ("FFFFFFFF.80102030 = \"!AZ\""; This example will output the following: FFFFFFFF.80102030 = "EXE$WRITE_PROCESS_C+00CD0" SDA$TRYMEM Definition Read dump memory and return error status (without signaling) if inaccessible Format int sda$trymem ( VOID_PQ start, void *dest, int length, __optional_params); Arguments start = starting virtual address in dump dest = return buffer address length = length of transfer physical = 0: is a virtual address (the default) 1: is a physical address Condition Values Returned SDA$_SUCCESS - successful completion SDA$_NOREAD - ) SDA$_NOTINPHYS - ) The data is inaccessible for some reason. Others - ) Description This routine transfers an area from the memory in the dump file to the caller's return buffer. It performs the necessary address translation to locate the data in the dump file. SDA$TRYMEM will not signal any warning or errors. It returns the error status if the data is inaccessible. [See also SDA$GETMEM and SDA$REQMEM] Example int status; DDB *ddb; ... status = sda$trymem (ddb->ddb$ps_link, ddb, DDB$K_LENGTH); if ($VMS_STATUS_SUCCESS (status)) sda$print ("Next DDB is successfully read from dump"); else sda$print ("Next DDB is inaccessible"); This example attempts to read the next DDB in the DDB list from the dump. SDA$TYPE Definition Format and type a single line to SYS$OUTPUT Format int sda$type ( char *ctrstr, __optional_params); Arguments ctrstr = address of a zero-terminated control string prmlst = (optional) FAO parameters. All arguments after the control string are copied into a quadword parameter list as used by $FAOL_64. Condition Values Returned Status returned is one of: SDA$_SUCCESS - successful completion SDA$_CNFLTARGS - more than twenty FAO parameters given Other - returned from the $PUT issued by SDA$TYPE (the error will also have been signaled). If the $FAOL_64 call issued by SDA$TYPE fails, a blank line will be output. Description Format and print a single line to the terminal. This is unaffected by the use of the SDA commands SET OUTPUT or SET LOG. Example int status; ... status = sda$type ("Invoking SHOW SUMMARY to output file..."); This example will display the message "Invoking SHOW SUMMARY to output file..." to the terminal. SDA$VALIDATE_QUEUE Definition Validate queue structures. Format void sda$validate_queue ( VOID_PQ queue_header, __optional_params ); Arguments queue_header = address to start search from options = flags to indicate type of queue none - defaults to double-linked longword queue SDA_OPT$M_QUEUE_SELF - self-relative queue SDA_OPT$M_QUEUE_QUADLINK - quadword queue SDA_OPT$M_QUEUE_SINGLINK - single-linked queue SDA_OPT$M_QUEUE_LISTQUEUE - display queue elements for debugging Condition Values Returned None. If an error occurs, it will be signaled by SDA$VALIDATE_QUEUE. Description This routine can be used to validate the integrity of double-linked, single-linked or self-relative queues either with longword or quadword links. If you specify the option SDA_OPT$M_LISTQUEUE the queue elements are displayed for debugging purposes. Otherwise a one-line summary will indicate how many elements were found and whether the queue is intact. Example int64 temp; int64 *queue; ... sda$symbol_value ("EXE$GL_NONPAGED", &temp); temp += 4; sda$reqmem ((VOID_PQ)temp, &queue, 4); sda$validate_queue (queue, SDA_OPT$M_QUEUE_SINGLINK); This sequence will validate the nonpaged pool free list, and will output a message of the form: Queue is zero-terminated, total of 204 elements in the queue