HP OpenVMS Utility Routines Manual


Previous Contents Index


Chapter 21
Traceback Facility (TBK) Routines

The Traceback facility for HP OpenVMS I64 and Alpha systems is a debugging tool that provides information (symbolizations) about call stack PCs. In normal operation, when a process suffers a fatal unhandled exception, the operating system launches Traceback which sends to SYS$OUTPUT the complete call stack at the time of the exception. Applications can also directly use the Traceback facility to sequentially generate information for an individual call stack PC. In this case, the Traceback simply returns information to the caller, not to SYS$OUTPUT. This chapter describes this direct Traceback interface.

21.1 Introduction to TBK Routines

On I64 systems, the Traceback facility can be invoked at any time by using the TBK$I64_SYMBOLIZE routine. This routine uses a single data structure for its inputs and outputs. It can be called from User, Supervisor, or Executive mode.

Similarly, on Alpha systems, the Traceback facility can be invoked at any time using the TBK$ALPHA_SYMBOLIZE routine. This routine uses a single data structure for its inputs and outputs and it can be called from USER, SUPERVISOR, or EXCECUTIVE mode.

Section 21.2 provides sample programs showing how to use the TBK routines. Section 21.3 is a reference section that provides details about the TBK routines.

21.2 Using TBK Routines---Example

This section provides an example program containing three small subroutines to illustrate using the TBK$I64_SYMBOLIZE routine. The example program runs a test to exercise the I64 librtl call stack walking routines, the TRACE API, sys$unwind , and sys$unwind_goto_64 . It is presented in three parts with callout information that describes the processing:

21.2.1 TBK$I64_SYMBOLIZE Example---Part 1

The first part of the example defines the necessary call stack walking headers, TRACE API headers, local subroutines, and a subroutine exception handler.

Example 21-1 TBK$I64_SYMBOLIZE Example---Part 1

 
$ run/nodebug unwind4 
 
In subc_handler, ch_cnt = 1 
Call stack: 
image           module          routine                 line            PC 
UNWIND4         UNWIND4         subc_handler            27271           0000000000030650 
DECC$SHR        C$SHELL_HANDLER decc$$shell_handler     5566            FFFFF80208613E50 
DECC$SHR        C$SHELL_HANDLER decc$$shell_handler     0               FFFFFFFF803EC680 
DECC$SHR        C$SHELL_HANDLER decc$$shell_handler     0               FFFFFFFF803E00B0 
UNWIND4         UNWIND4         subc                    27409           00000000000310A0 
UNWIND4         UNWIND4         subb                    27200           0000000000030300 
UNWIND4         UNWIND4         suba                    27187           0000000000030200 
UNWIND4         UNWIND4         main                    27175           0000000000030140 
UNWIND4         UNWIND4         __main                  27171           00000000000300E0 
UNWIND4         UNWIND4         __main                  0               FFFFFFFF80B72C80 
 
Continue (versus exit)? [Y/N]: 
 
 /* 
  * NOTE: to compile include "/define=(__NEW_STARLET)". 
  */ 
 
 
#include <stdio.h> (1)
#include <stdarg.h> 
#include <starlet.h> 
#include <stddef.h> 
#include <ssdef.h> 
#include <descrip.h> 
 
 
/* librtl headers for call stack walking 
 */ 
 
#include <lib$routines.h> (2)
#include <libicb.h> 
 
/* trace headers for trace api 
 */ 
 
#include <tbkdef.h> (3)
#include <tbk$routines.h> 
 
/* some local subroutines 
 */ 
 
void suba (void); (4)
void subb (void); 
void subc (void); 
 
/* a subroutine exception handler 
 */ 
 
int subc_handler (unsigned long int *sigarg, unsigned long int *mecharg); (5)
unsigned long int a_cnt, b_cnt, c_cnt, ch_cnt; 
unsigned __int64 a_invo_handle, b_invo_handle, c_invo_handle; 
int status; 
 
int main () 
    { 
    suba (); 
 
    return 1; 
    } 
 
void suba () 
    { 
 
 

  1. This program runs a test to exercise the I64 librtl call stack walking routines, the TRACE API, sys$unwind , and sys$unwind_goto_64 .
  2. The necessary librtl call stack walking headers. LIBICB defines the invocation context block. LIB$ROUTINES defines the call stack walk function prototypes.
  3. The necessary TRACE API header files. TBKDEF defines the TRACE_API call parameter. TBK$ROUTINES defines the TRACE API function prototype.
  4. This code defines the local subroutines suba , subb , and subc .
  5. This code defines a subroutine exception handler.

21.2.2 TBK$I64_SYMBOLIZE Example---Part 2

The second part of the example issues librtl call stack walking calls for each of three subroutines, defines a pointer to a call stack walk invocation context block, defines storage for the return TRACE symbolizations and information, and defines storage and initializes the TRACE API parameter block.

Example 21-2 TBK$I64_SYMBOLIZE Example---Part 2

 
    /* Get routine a's invocation context handle, used in subc_handler 
     */ 
    status = lib$i64_get_curr_invo_handle (&a_invo_handle); (1)
 
    a_cnt++; 
    subb (); 
 
    a_cnt++; 
    subb (); 
    } 
 
    void subb () 
    { 
 
    /* Get routine b's invocation context handle, used in subc_handler 
     */ 
    status = lib$i64_get_curr_invo_handle (&b_invo_handle); (2)
 
    b_cnt++; 
    subc (); 
 
    b_cnt++; 
    subc (); 
 
    b_cnt++; 
    subc (); 
    } 
 
void subc () 
    { 
    lib$establish (subc_handler); 
 
    /* Get routine c's invocation context handle, used in subc_handler 
     */ 
    status = lib$i64_get_curr_invo_handle (&c_invo_handle); (3)
 
    /* Signal into subc_handler 
     */ 
    c_cnt++; 
    lib$signal (c_cnt); 
 
    c_cnt++; 
    lib$signal (c_cnt); 
    } 
 
int subc_handler (unsigned long int *sigarg, unsigned long int *mecharg) 
    { 
    int status, tbk_status=0, callstack_depth = 0; 
    unsigned int depth; 
    /* local pointer for the call stack walk invocation context block 
     */ 
    INVO_CONTEXT_BLK *myICB; (4)
 
    /* local storage for image, module, routine names, line number, and image 
     * and module base addresses returned by the trace api 
     */ 
    static char image [128], module [128], routine [128], inquire_continue [128]; 
    static struct dsc$descriptor_vs image_dsc = {125, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, &image[0]}; 
    static struct dsc$descriptor_vs module_dsc = {125, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, &module[0]}; 
    static struct dsc$descriptor_vs routine_dsc = {125, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, &routine[0]}; 
    unsigned int     list_line; 
    unsigned __int64 image_base_addr;          (5)
    unsigned __int64 module_base_addr;      
 
    /* Local storage and setup for the trace api parameter block 
     */ 
    unsigned __int64 symbolize_flags={0};   (6)
    TBK_API_PARAM params = { 
                TBK$K_LENGTH,   /* trace api parameter block length */ 
                0,              /* trace api parameter block type, MBZ */ 
                TBK$K_VERSION,  /* trace api parameter block length, MBZ */ 
                0,      /* reserved, MBZ */ 
                0,      /* pc, input */ 
                0,      /* fp, input, not used for I64 */ 
                0,      /* filename desc, output, not used here */ 
                0,      /* library module desc, output, not used here */ 
                0,      /* record number, output, not used here  */ 
                (struct _descriptor *)&image_dsc,       /* image descriptor, output */ 
                (struct _descriptor *)&module_dsc,      /* module descriptor, output */ 
                (struct _descriptor *)&routine_dsc,     /* routine_descriptor, output */ 
                &list_line,     /* compiler listing line number, output */ 
                0,      /* relative pc, output, not used here */ 
                &image_base_addr,       /* image base address, output */ 
                &module_base_addr,      /* module base address, output */ 
                0,      /* malloc routine, input */ 
                0,      /* free routine, input */ 
                &symbolize_flags,       /* symbolize flags, input */ 
                0,      /* reserved */ 
                0,      /* reserved */ 
                0};     /* reserved */ 
 
    if (*(sigarg+1) == SS$_UNWIND) 
        return SS$_CONTINUE; 
    else 
        ch_cnt++; 
 
    printf ("\nIn subc_handler, ch_cnt = %d\n", ch_cnt); 
    printf ("Call stack: \n"); 
 
    status = 1; 
 

  1. A librtl call stack walk call to get the suba subroutine's invocation context handle used in subc_handler .
  2. A librtl call stack walk call to get the subb subroutine's invocation context handle used in subc_handler .
  3. A librtl call stack walk call to get the subc subroutine's invocation context handle used in subc_handler .
  4. A pointer is defined to a call stack walk invocation context block.
  5. Storage is defined for the return TRACE symbolizaions and information, which includes local storage for image, module, routine names, line number, and image and module base addresses returned by the TRACE API.
  6. Local storage is defined for the TRACE API parameter block, which is initialized.

21.2.3 TBK$I64_SYMBOLIZE Example---Part 3

The third part of the example allocates and initializes the invocation context block and obtains the the context handler's current context. Subroutine subc signals into a frame-based handler ( subc_handler ), which walks the stack, calls TBK$I64_SYMBOLIZE to symbolize each frame's PC, and prints out the symbolizations.

Example 21-3 TBK$I64_SYMBOLIZE Example---Part 3

 
    /* Walk the call stack top to bottom, symbolize each frame's PC, and 
     * print out the symbolizations. 
     * 
     * First, create the invocation context block and get my (subc_handler's) 
     * current context. 
     */ 
    myICB = (INVO_CONTEXT_BLK *) lib$i64_create_invo_context ();   (1)
    lib$i64_get_curr_invo_context (myICB); 
 
    printf ("image       module     routine          line           PC\n"); 
 
    while (!(myICB->libicb$v_bottom_of_stack) &&   (2)
           ((status & 1) != 0)) 
        { 
        /* Use the PC from the call stack invocation context block. 
         */ 
        params.tbk$q_faulting_pc = (unsigned __int64) myICB->libicb$ih_pc; (3)
 
        /* Call trace to do the symbolizations. 
         */ 
        tbk_status = tbk$i64_symbolize (&params); (4)
 
        /* And print out results 
         */ 
        image [*((short *) image) + 2] = 0; 
        module [*((short *) module) + 2] = 0; 
        routine [*((short *) routine) + 2] = 0; 
        /* Print out the tbk$i64_symbolize info (with formating 
         * to align columns). 
         */ 
        if (*((short *) module) > 8) 
            { 
            if (*((short *) routine) > 8) 
                { 
                printf ("%s   %s    %s    %ld       %16.16LX\n", 
                        &image [2], 
                        &module [2], 
                        &routine [2], 
                        list_line, 
                        (unsigned __int64) myICB->libicb$ih_pc); 
                } 
            else 
                { 
                printf ("%s     %s      %s    %ld      %16.16LX\n", 
                        &image [2], 
                        &module [2], 
                        &routine [2], 
                        list_line, 
                        (unsigned __int64) myICB->libicb$ih_pc); 
                } 
            } 
        else 
            { 
            if (*((short *) routine) > 8) 
                { 
                printf ("%s       %s       %s      %ld      %16.16LX\n", 
                        &image [2], 
                        &module [2], 
                        &routine [2], 
                        list_line, 
                        (unsigned __int64) myICB->libicb$ih_pc); 
                } 
            else 
                { 
                printf ("%s       %s         %s         %ld      %16.16LX\n", 
                        &image [2], 
                        &module [2], 
                        &routine [2], 
                        list_line, 
                        (unsigned __int64) myICB->libicb$ih_pc); 
                } 
            } 
        /* Get the previous call frame. 
         */ 
        status = lib$i64_get_prev_invo_context (myICB);  (5)
        callstack_depth++; 
        } 
 
    /* Terminate the call stack walk and free up the memory that it used. 
     */ 
    lib$i64_prev_invo_end (myICB);  (6)
    lib$i64_free_invo_context (myICB); 
 
    /* Set up to unwind if we continue execution. 
     */ 
    switch (ch_cnt) 
        { 
        /* first, some sys$unwinds    (7)
         */ 
        case 1 : 
            status = sys$unwind (0, 0); 
            break; 
        case 2 : 
            depth = 0; 
            status = sys$unwind (&depth, 0); 
            break; 
        case 3 : 
            depth = 1; 
            status = sys$unwind (&depth, 0); 
            break; 
        case 4 : 
            depth = 2; 
            status = sys$unwind (&depth, 0); 
            break; 
 
        /* now, some sys$goto_unwinds 
         */ 
        case 5 : 
            status = sys$goto_unwind_64 (&c_invo_handle, 0, 0, 0); 
            break; 
        case 6 : 
            status = sys$goto_unwind_64 (&b_invo_handle, 0, 0, 0); 
            break; 
        case 7 : 
            status = sys$goto_unwind_64 (&a_invo_handle, 0, 0, 0); 
            break; 
 
        default : 
            break; 
        } 
 
    /* Continue (after unwinding) or exit?  Let the user decide. 
     */ 
    printf ("\nContinue (versus exit)? [Y/N]: "); 
    gets (inquire_continue); 
 
    if ((inquire_continue [0] == 'Y') || (inquire_continue [0] == 'y')) 
        return SS$_CONTINUE; 
    else 
        sys$exit (1); 
    } 
 
 

  1. To prepare for walking the call stack, the invocation context block is allocated and initialized, and the context handler's ( subc_handler ) current context is obtained.
  2. The call stack is walked from the current context, subc_handler , to the bottom of the stack.
  3. The essential call stack PC value is provided. On I64 systems, all the symbolization is based on a call stack frame's PC value.
  4. A call is made to the TRACE symbolize routine, TBK$I64_SYMBOLIZE, for the call frame's PC. This is the call to the TRACE API. The information is then printed out.
  5. The previous call frame context is obtained.
  6. Cleanup is performed and and memory used by the call stack walk is deallocated.
  7. Unwind is set up to continue program execution.

21.3 TBK Routines

This section describes the TBK routines. The TBK$I64_SYMBOLIZE routine is for use on I64 systems and the TBK$ALPHA_SYMBOLIZE routine is for use on Alpha systems.

TBK$I64_SYMBOLIZE

The TBK$I64_SYMBOLIZE routine attempts to symbolize a PC, returning as much symbolic representation for that location as was requested.

For information about the TBK symbolize routine for Alpha systems, see the information for TBK$ALPHA_SYMBOLIZE later in TBK$ALPHA_SYMBOLIZE.


Format

TBK$I64_SYMBOLIZE parameter_block


RETURNS


OpenVMS usage: cond_value
type: longword (unsigned)
access: write only
mechanism: by value

Longword condition value. Most utility routines return a condition value. Condition values that this routine can return are listed under Condition Values Returned.


Argument

parmeter_block


OpenVMS usage: TBK_API_PARAM
type: structure
access: modify
mechanism: by reference

Table 21-1 shows the values for TBK_API_PARAM (defined in TBKDEF).

Table 21-1 Values for TBK_API_PARAM
Field Size Description
TBK$W_LENGTH Word Input by value, structure length, must be TBK$K_LENGTH
TBK$B_TYPE Byte Input, MBZ
TBK$B_VERSION Byte Input by value, must be TBK$K_VERSION
TBK$L_RESERVEDA Longword Reserved for future use, MBZ
TBK$Q_FAULTING_PC Quadword Input by value, call stack frame PC
TBK$PQ_FILENAME_DESC 64-bit pointer Optional output by reference (I64 only), pointer (if not requested, MBZ) to a fixed-length string text descriptor. The descriptor must be set up with preallocated adequate buffer space. The descriptor is filled with the image file name. This can be a dynamic descriptor (rather than fixed-length), but only if the caller is in user mode.
TBK$PQ_
LIBRARY_MODULE_DESC
64-bit pointer Optional output, pointer (if not requested, MBZ) to a fixed-length string text descriptor. The descriptor must be set up with pre-allocated adequate buffer space. The descriptor is filled in with library module name if the image filename (see previous field) is a text library file. This can be a dynamic descriptor (rather than fixed length) but only if the caller is in user mode.
TBK$PQ_
RECORD_NUMBER
64-bit pointer Optional output, pointer (if not requested, MBZ) to a longword to be filled with the relevant image file record number.
TBK$PQ_IMAGE_DESC 64-bit pointer Optional output, pointer (if not requested, MBZ) to a fixed-length string text descriptor. The descriptor must be set up with preallocated adequate buffer space. The descriptor is filled in with the image name. This can be a dynamic descriptor (rather than fixed length), but only if the caller is in user mode.
TBK$PQ_MODULE_DESC 64-bit pointer Optional output, pointer (if not requested, MBZ) to a fixed-length string text descriptor. The descriptor must be set up with preallocated adequate buffer space. The descriptor is filled in with the module name.
TBK$PQ_ROUTINE_DESC 64-bit pointer Optional output, pointer (if not requested, MBZ) to a fixed-length string text descriptor. The descriptor must be set up with preallocated adequate buffer space. The descriptor is filled in with the routine name.
TBK$PQ_
LISTING_LINENO
64-bit pointer Optional output, pointer (if not requested, MBZ) to longword to be filled in with the line number (as show in the modules LIS file).
TBK$PQ_REL_PC 64-bit pointer Optional output, pointer (if not requested, MBZ) to quadword to be filled in with the relative PC. This can be an image or module relative PC.
TBK$PQ_ MALLOC_RTN 64-bit pointer Optional input, pointer (if not supplied, MBZ) address to a user-supplied malloc routine. Must be supplied when called from supervisor or executive mode (kernel mode is not supported).
TBK$PQ_ FREE_RTN 64-bit pointer Optional input, pointer (if not supplied, MBZ) address to a user-supplied free routine. Must be supplied when called from supervisor or executive mode (kernel mode not supported).
TBK$PQ_
SYMBOLIZE_FLAGS
64-bit pointer Optional input and output, pointer (if not supplied, MBZ) to TBK_SYMBOLIZE_FLAGS (quadword, see below). Used to control symbolization options and to return additional status.
TBK$Q_RESERVED0 Quadword Reserved for future use, MBZ.
TBK$Q_RESERVED1 Quadword Reserved for future use, MBZ.
TBK$Q_RESERVED2 Quadword Reserved for future use, MBZ.
TBK$V_
EXCEPTION_IS_FAULT
0 Adjusts the PC value used for symbolization for target frames that suffered a fault exception.
  All remaining bits Reserved, Must be initialized to zero.


Description

The TBK$I64_SYMBOLIZE routine attempts to symbolize a PC, that is, given a PC, this routine returns as much of the symbolic representation for that location that has been requested: image name, file name, module name, routine name, listing line number, file record number, and so on.

The degree of symbolization depends upon the images symbolic information. For best results, compile the images source modules with either traceback (the default) or debug information (/DEBUG) and link the image with either traceback (/TRACE) or debug (/DEBUG) information. If no symbolic information records exists within the image for the PC, then only partial symbolization is possible.

TBK$I64_SYMBOLIZE can be called by programs in user, supervisor, or executive mode. Calls from kernel mode are not allowed; calls when IPL is nonzero are not allowed.

Callers in supervisor or executive mode must supply routines that perform the equivilent of malloc and free operations that are legal for the given mode. (The C Run Time Library malloc and free routines are only supported in user mode.) Pointers to these user-written replacement routines are specified in the TBK$PQ_MALLOC_RTN and TBK$PQ_FREE_RTN fields.


Condition Values Returned

SS$_KERNELINV This API does not support kernel mode calls.
SS$_BADPARAM Incorrect TBK_API_PARAM length, type, or version.
SS$_INSFMEM Unable to allocate needed memory.
SS$_NORMAL Successful completion.
SS$_ACCVIO Unable to read from the TBK_API_PARAM block.

Other conditions indicate TRACE failures such as failure status from sys$crmpsc_file_64 on an I64 system.


Previous Next Contents Index