|
HP OpenVMS systems documentation |
Previous | Contents | Index |
The null frame procedure descriptor built by a compiler provides information about a procedure with no frame. The size of the descriptor is 16 bytes (defined by PDSC$K_NULL_SIZE).
The fields defined in the null frame descriptor are illustrated in Figure 3-7 and described in Table 3-5.
Figure 3-7 Null Frame Procedure Descriptor (PDSC) Format
Field Name | Contents | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
PDSC$W_FLAGS |
The PDSC descriptor flag bits <15:0> are defined as follows:
|
||||||||||||||||||||
PDSC$V_FUNC_RETURN |
A 4-bit field <11:8> that describes which registers are used for
the function value return (if there is one) and what format is used for
those registers.
Table 5-4 lists and describes the possible encoded values of PDSC$V_FUNC_RETURN. |
||||||||||||||||||||
PDSC$W_SIGNATURE_OFFSET | A 16-bit signed byte offset from the start of the procedure descriptor. This offset designates the start of the procedure signature block (if any). A 0 in this field indicates that no signature information is present. Note that in a bound procedure descriptor (as described in Section 3.6.4), signature information might be present in the related procedure descriptor. A 1 in this field indicates a standard default signature. An offset value of 1 is not otherwise a valid offset because both procedure descriptors and signature blocks must be quadword aligned. | ||||||||||||||||||||
PDSC$Q_ENTRY | The absolute address of the first instruction of the entry code sequence for the procedure. |
Except for null-frame procedures, a procedure is an active procedure while its body is executing, including while any procedure it calls is executing. When a procedure is active, it may handle an exception that is signaled during its execution.
Associated with each active procedure is an invocation context, which consists of the set of registers and space in memory that is allocated and that may be accessed during execution for a particular call of that procedure.
When a procedure begins to execute, it has no invocation context. The initial instructions that allocate and initiallize its context, which may include saving information from the invocation context of its caller, are termed the procedure prologue. Once execution of the prologue is complete, the procedure is said to be active.
When a procedure is ready to return to its caller, the instructions that deallocate and discard the procedure's invocation context (which may include restoring state of the caller's invocation context that was saved during the prologue), are termed a procedure epilogue. A procedure ceases to be active when execution of its epilogue begins.
A procedure may have more than one prologue if there are multiple entry points. A procedure may also have more than one epilogue if there are multiple return points. One of each will be executed during any given invocation of the procedure.
Some procedures, notably null frame procedures (see Section Section 3.4.6), never have an invocation context of their own and are said to execute in the body of their caller. A null frame procedure has no prologue or epilogue, and consists solely of body instructions. Such a procedure never becomes current or active in the sense that its handler may be invoked.
A call stack (for a thread) consists of the stack of invocation contexts that exists at any point in time. New invocation contexts are pushed on that stack as procedures are called and invocations are popped from the call stack as procedures return.
The invocation context of a procedure that calls another procedure is
said to precede or be previous to the invocation context of the called
procedure.
3.5.1 Current Procedure
The current procedure is the active procedure whose execution began most recently; its invocation context is at the top of the call stack. Note that a procedure executing in its prologue or epilogue is not active, and hence cannot be the current procedure. Similarly, a null frame procedure cannot be the current procedure.
In this calling standard, R29 is the frame pointer (FP) register that defines the current procedure.
Therefore, the current procedure must always maintain in FP one of the following pointer values:
At any point in time, the FP value can be interpreted to find the procedure descriptor for the current procedure by examining the value at 0(FP) as follows:
By examining the first quadword of the procedure descriptor, the procedure type can be determined from the PDSC$V_KIND field.
The following code is an example of how the current procedure descriptor and procedure type can be found:
LDQ R0,0(FP) ;Fetch quadword at FP AND R0,#7,R28 ;Mask alignment bits BNEQ R28,20$ ;Is procedure descriptor pointer LDQ R0,0(R0) ;Was pointer to procedure descriptor 10$: AND R0,#7,R28 ;Do sanity check BNEQ R28,20$ ;All is well ;Error - Invalid FP 20$: AND R0,#15,R0 ;Get kind bits ;Procedure KIND is now in R0 |
IF PDSC$V_KIND is equal to PDSC$K_KIND_FP_STACK, the current procedure has a stack frame.
If PDSC$V_KIND is equal to PDSC$K_KIND_FP_REGISTER, the current procedure is a register frame procedure.
Either type of procedure can use either type of mechanism to point to
the procedure descriptor. Compilers may choose the appropriate
mechanism to use based on the needs of the procedure involved.
3.5.2 Procedure Call Tracing
Mechanisms for each of the following functions are needed to support procedure call tracing:
This section describes the data structure mechanisms. The routines that
support these functions are described in Section 3.5.3.
3.5.2.1 Referring to a Procedure Invocation from a Data Structure
When referring to a specific procedure invocation at run time, a procedure invocation handle, shown in Figure 3-8, can be used. Defined by constant LIBICB$K_INVO_HANDLE_SIZE, the structure is a single-field longword called HANDLE. HANDLE describes the invocation handle of the procedure.
Figure 3-8 Procedure Invocation Handle Format
To encode a procedure invocation handle, follow these steps:
Note that a procedure invocation handle is not defined for a null frame procedure.
So you can distinguish an invocation of a register frame procedure that calls another register frame procedure (where the called procedure uses no stack space and therefore has the same base register value as the caller), the register number that saved the return address is included in the invocation handle of a register frame procedure. Similarly, the number 3110 in the invocation handle of a stack frame procedure is included to distinguish an invocation of a stack frame procedure that calls a register frame procedure where the called procedure uses no stack space. |
The context of a specific procedure invocation is provided through the use of a data structure called an invocation context block. The minimum size of the block is 528 bytes and is system defined using the constant LIBICB$K_INVO_CONTEXT_BLK_SIZE. The size of the last field (LIBICB$Q_SYSTEM_DEFINED[n]) defined by the host system determines the total size of the block.
The fields defined in the invocation context block are illustrated in Figure 3-9 and described in Table 3-6.
Figure 3-9 Invocation Context Block Format
Field Name | Contents | ||||||||
---|---|---|---|---|---|---|---|---|---|
LIBICB$L_CONTEXT_LENGTH | Unsigned count of the total length in bytes of the context block; this represents the sum of the lengths of the standard-defined portion and the system-defined section. | ||||||||
LIBICB$R_FRAME_FLAGS |
The procedure frame flag bits <24:0> are defined as follows:
|
||||||||
LIBICB$B_BLOCK_VERSION | A byte that defines the version of the context block. Because this block is currently the first version, the value is set to 1. | ||||||||
LIBICB$PH_PROCEDURE_DESCRIPTOR | Address of the procedure descriptor for this context. | ||||||||
LIBICB$Q_PROGRAM_COUNTER | Quadword that contains the current value of the procedure's program counter. For interrupted procedures, this is the same as the continuation program counter; for active procedures, this is the return address back into that procedure. | ||||||||
LIBICB$Q_PROCESSOR_STATUS | Contains the current value of the processor status. | ||||||||
LIBICB$Q_IREG[ n] | Quadword that contains the current value of the integer register in the procedure (where n is the number of the register). | ||||||||
LIBICB$Q_FREG[ n] | Quadword that contains the current value of the floating-point register in the procedure (where n is the number of the register). | ||||||||
LIBICB$Q_SYSTEM_DEFINED[ n] | A variable-sized area with locations defined in quadword increments by the host environment that contains procedure context information. These locations are not defined by this standard. |
A thread can obtain its own context or the current context of any
procedure invocation in the current stack call (given an invocation
handle) by calling the run-time library functions defined in
Section 3.5.3.
3.5.2.4 Walking the Call Stack
During the course of program execution, it is sometimes necessary to walk the call stack. Frame-based exception handling is one case where this is done. Call stack navigation is possible only in the reverse direction (in a latest-to-earliest or top-to-bottom sequence).
To walk the call stack, perform the following steps:
Compilers are allowed to optimize high-level language procedure calls in such a way that they do not appear in the invocation chain. For example, inline procedures never appear in the invocation chain.
Make no assumptions about the relative positions of any memory used for
procedure frame information. There is no guarantee that successive
stack frames will always appear at higher addresses.
3.5.3 Invocation Context Access Routines
A thread can manipulate the invocation context of any procedure in the
thread's virtual address space by calling the following run-time
library functions.
3.5.3.1 LIB$GET_INVO_CONTEXT
A thread can obtain the invocation context of any active procedure by using the following function format:
LIB$GET_INVO_CONTEXT(invo_handle, invo_context) |
Argument | OpenVMS Usage | Type | Access | Mechanism |
---|---|---|---|---|
invo_handle | invo_handle | longword (unsigned) | read | by value |
invo_context | invo_context_blk | structure | write | by reference |
Arguments:
invo_handle
Handle for the desired invocation. |
|
invo_context
Address of an invocation context block into which the procedure context of the frame specified by invo_handle will be written. |
Function Value Returned:
status
Status value. A value of 1 indicates success; a value of 0 indicates failure. |
If the invocation handle that was passed does not represent any procedure context in the active call stack, the value of the new contents of the context block is unpredictable. |
A thread can obtain the invocation context of a current procedure by using the following function format:
LIB$GET_CURR_INVO_CONTEXT(invo_context) |
Argument | OpenVMS Usage | Type | Access | Mechanism |
---|---|---|---|---|
invo_context | invo_context_blk | structure | write | by reference |
Argument:
invo_context
Address of an invocation context block into which the procedure context of the caller will be written. |
Function Value Returned:
Zero. This is to facilitate use in the implementation of the C language unwind setjmp or longjmp function (only). |
A thread can obtain the invocation context of the procedure context preceding any other procedure context by using the following function format:
LIB$GET_PREV_INVO_CONTEXT(invo_context) |
Argument | OpenVMS Usage | Type | Access | Mechanism |
---|---|---|---|---|
invo_context | invo_context_blk | structure | modify | by reference |
Argument:
invo_context
Address of an invocation context block. The given invocation context block is updated to represent the context of the previous (calling) frame. The LIBICB$V_BOTTOM_OF_STACK flag of the invocation context block is set if the target frame represents the end of the invocation call chain or if stack corruption is detected. |
Function Value Returned:
status
Status value. A value of 1 indicates success. When the initial context represents the bottom of the call stack, a value of 0 is returned. If the current operation completed without error, but a stack corruption was detected at the next level down, a value of 3 is returned. |
Previous | Next | Contents | Index |