Studio:SCL Pragmas

From STRIDE Wiki
(Redirected from SCL Pragmas)
Jump to: navigation, search

Introduction

The SCL pragmas are designed to allow annotation of C language constructs in such a way as to identify and define messages, function calls, and trace points so that they can be transparently intercepted and remoted. Some pragmas are necessary because C language constructs lack important interface details; other pragmas are necessary because they allow STRIDE to better represent information to the user, or allow STRIDE to take advantage of increased opportunities for efficiency. Lastly, some pragmas simply make it easier for users to adopt STRIDE without changing existing source code.

Pragmas are used to elaborate all of the following areas:

  • The set of messages and functions within the application that are candidates for interception and remoting.
  • Use of pointers. Pointer-related ambiguities include memory ownership, data directions, and pointers that point to a sequence of elements rather than to a single element.
  • The convention of using null-terminated strings in C. When a pointer is declared as ”char *”, it must be further elaborated as pointing to a single character or a series of characters ending in NULL.
  • Pointers to functions. Functions whose addresses are passed as parameters must be identified.
  • Pointers to data which should be treated by STRIDE as ”void*” rather than its declared type. This may be necessary because of self-referential data structures or efficiency concerns.
  • Unions. The discriminant (if any) must be identified; the relationship between active union members and discriminant values must be prescribed.
  • Convenience pragmas to constrain the allowable values of a data item.
  • Convenience pragmas to allow STRIDE to treat a data item as if it was defined to be of another type.
  • Pragmas to allow STRIDE to identify certain structures, such as v-tables, used in C programs to simulate C++ inheritance and virtual function mechanisms.
  • The STRIDE-defined constructs known as trace points.
  • The special constructs known as conformant arrays (also known as variable length arrays).

The SCL Wizard streamlines and simplifies working with pragmas by allowing you to quickly capture interfaces and accurately qualify payloads and types. See the Online Help installed with STRIDE for more information on the SCL Wizard.

Remotable Interfaces

SCL includes pragmas used to identify remotable messages or functions. Only messages or functions identified with these pragmas are remotable candidates. These remotable candidates are also referred to as interfaces. Almost all other pragmas operate on, or depend upon, the set of interfaces identified as remotable.

By far, the most important aspect of a remotable interface is the memory layout of the data that is passed from message sender or function caller. Most pragmas allow the data format to be described in detail. Throughout the STRIDE documentation, the data exchanged for a given instance of a message or function is referred to as the payload.

Since STRIDE represents communication via both messaging and function calls, the terms user and owner are used to identify the sender/receiver of a message or the caller/callee of a function, respectively. Within a message, the user is the agent sending the message and owner is the agent that receives the message. Within a function call, the user is the caller and the owner is the callee.

Payloads

The data passed between user and owner is referred to as a payload. Not all messages or functions contain a payload. Consider the function

void f(void);

This function has no return value and no parameters; thus it has no payload.

Message Payloads

Message payloads are defined by a C datatype. For example, we may have message ERROR that has an associated structure containing the error code and a string. The relevant C language declarations might be:

#define ERROR_MSG  23  // the message id for ERRROR
     
// The structure for the message data.
typedef struct _ErrorMessagePayload {
  int        errorCode; 
  char[100]  text;
} ErrorMessagePayload;

Messages payloads are typically passed by reference (but can also be passed by value). Assuming the message payload above is passed by reference we can depict the memory layout of the entire message payload as follows:

Message payload.gif


Note that in this instance, the payload actually consists of two distinct memory blocks, a pointer and the structure pointed to. The distinct blocks in a payload are referred to as the payload blocks. Note also that the blocks form a tree structure, with each contiguous memory block representing a node in the tree. This illustrates a more general concept: the payload blocks form a network, and that network must be a tree (i.e., it starts with a node designated as the root, and all other nodes are reachable from the root. There cannot be cycles).

Within a two-way message, the structure of data passed in each direction may be different. For this reason, payloads must be further defined according to whether they are passed from user to owner or owner to user. Payloads passed from user to owner are called Command Payloads. Payloads passed from owner to user are called Response Payloads.

Function Payloads

Functions are much like two-way messages in that data can be passed from user (caller) to the owner (callee) at the time of the call, and the owner (callee) may pass data back to the user (caller) at the time of the return. As with message payloads, the data passed from user to owner is referred to as the Command Payload and the data passed from owner to user is referred to as the Response Payload.

A Command Payload is constructed from the formal parameters of a function, and is a synthesized C structure. The members of the structure correspond to the formal parameters of the function (both the order and types of the members correspond exactly).

The Response Payload for a function is constructed from the return value of a function. Below is an example of the Command and Response Payload memory layout for a simple function Error():

// The structure for the message data.
typedef struct _ErrorMessagePayload {
  int        errorCode; 
  char[100]  text;
} ErrorMessagePayload; 
     
int Error(ErrorMessagePayload *pPayload, BOOL bPopupMessage);
Command payload.gif

Pragmas

The SCL pragmas are listed here, categorized by function:

Test Units

Capture

Qualification

Trace

Notes

  • The hash (#) symbol that begins the pragma directive must be the first non-white-space character on the line containing the pragma, e.g. #pragma.
  • Compilers typically issue warnings, but not errors, for unrecognized pragmas. An SCL-compliant compiler is required to automatically define the _SCL symbol. It is recommended that a header file using SCL pragmas include the following conditional compile statement wrapped around the pragma definitions:
#ifdef _SCL

  //... pragma definitions
     
#endif // #ifdef _SCL
  • The use of packed pragmas may result in structure alignment issues when communicating with the target platform.
  • STRIDE pragmas should be added to header (.h) files. Although such pragmas could be added to implementation (.c/cpp) files it is not recommended because it may lead to linkage problems when integrating the generated IM code in to your application.

See Also

  • Refer to the SCL Wizard section of the STRIDE Online Help for information on how to create SCL pragmas.