Debug entry control blocks created by custom communication packages on z/TPF

With greater frequency, IBM® z/Transaction Processing Facility, Enterprise Edition (z/TPF) customers are implementing custom communication packages to communicate between systems or drive traffic into z/TPF, for example TN3270 support or proprietary protocols. The z/TPF debugger offers a range of solutions for debugging entry control blocks, or ECBs. Three features have been implemented to help debug ECBs created by custom communication packages.

Joshua B. Wisniewski (, Senior Software Engineer, IBM

Photo of Joshua B. WisniewskiJoshua Wisniewski is a senior software engineer at IBM in Poughkeepsie, New York.

17 April 2013


IBM® z/Transaction Processing Facility, Enterprise Edition (z/TPF), Version 1.1 (5748-T15), is a high-performance operating system specifically designed to provide high availability for demanding, high-volume, real-time transaction processing for business-critical applications. z/TPF runs on IBM® zSeries® servers, which offer an infrastructure for transaction processing with high quality-of-service demands.

The z/TPF debugger is a remote debugger for the z/TPF operating system running on zSeries servers where the GUI debugger client is located on the user's workstation in the Eclipse-based TPF Toolkit (see Figure 1). As a remote debugger, the user must register the conditions that an entry control block (ECB) must meet to start a debugger session. The z/TPF debugger provides several types of registration, including the option to register by module name (any entry to an executable), function (a specific entry point to an executable), SVC macro execution, system error, CTEST, and others. Additional registration functions serve to filter ECBs even further, such as registering a conditional expression or a TPF terminal called trace-by-terminal registration.

Figure 1. Standard remote debugging environment
flowchart, comms code calling TBT candidate code

The trace-by-terminal feature enables you to limit debugging to ECBs created by a specific communications protocol (via the terminal), such as a Line Number Interchange Address Terminal Address (LNIATA), TCP/IP address, or logical unit (LU). If a wild card is specified for the LNIATA, all ECBs will be candidates for debugging regardless of their input origin. However, if a terminal is specified, only ECBs created by that terminal will be candidates for starting the debugger. This determination is typically made immediately after the ECB is created in the internal z/TPF communications code before the application code is executed. As such, ECBs created through custom communication packages might not be marked by the system as trace-by-terminal candidates and subsequently, trace-by-terminal debugger registration entries may not start the debugger when the user thinks it should. In Figure 2, notice that the trace-by-terminal candidate determination is missing from the diagram.

Figure 2. Remote debugging environment with custom communication package environment
flowchart, custom comms code calling application

z/TPF general service tpf_flag_for_debug

APAR PJ39617 introduced the z/TPF general service tpf_flag_for_debug to externalize the marking of an ECB as a candidate for trace-by-terminal debugging. As Figure 3 shows, in your custom communications package, after your ECBs are set up and just before executing your application code, you can call the tpf_flag_for_debug system service to mark potential ECBs as candidates for trace-by-terminal debugging. The tpf_flag_for_debug system service will inspect your ECB in relation to the registered debugger sessions on your system and mark the ECBs that are candidates. This is accomplished by calling the tpf_flag_for_debug system service. Listing 2 is an example of how to call tpf_flag_for_debug in assembler code.

Listing 1. Code to call tpf_flag_for_debug in assembler code
CPROC RETURN=void,tpf_flag_for_debug,(i)    
SGR R2,R2  // zero out register two
CALLC tpf_flag_for_debug(R2)
Figure 3. Remote debugging environment with custom communication package environment with trace-by-terminal determination
flowchart, custom comms code calling TBT code

The trace-by-terminal candidate determination routine depends on the communication settings in your ECB following z/TPF system conventions. For example, an ECB type indicating that the ECB was created by of a TCP/IP socket must have the field EBROUT in the ECB set as a valid TCP/IP socket descriptor. However, some custom communication packages might be using additional fields to identify the terminal, which will, in effect, break the z/TPF system conventions. The CDBX_DebuggerTBTRegistrationTerminalUserExit was implemented to circumvent the use of system conventions in determining trace-by-terminal candidates.

CDBX_DebuggerTBTRegistration TerminalUserExit

APAR PJ40974 introduced the CDBX_DebuggerTBTRegistrationTerminalUserExit user exit to allow you to tell the system what terminal should be used for a given ECB when evaluating if a matching debugger registration session is registered on the system. This user exit enables you to inspect your ECB, determine the appropriate terminal type and return it in the return structure provided.

Using this user exit for TN3270 support

Let's return to the previous example and expand upon it to see how this user exit could be used to implement TN3270 support.

The CDBX_DebuggerTBTRegistrationTerminalUserExit user exit could inspect the ECB type flag to see if the ECB was created by a TCP/IP socket. A custom TN3270 field in the ECB that was set up by the customer communications package could be inspected to discern whether this ECB was created by way of a TN3270 terminal. If so, the value in EBROUT can be treated as the LNIATA value to register.

Listing 2 is an example of the code that could be implemented in the CDBX_DebuggerTBTRegistrationTerminalUserExit user exit.

Listing 2. CDBX_DebuggerTBTRegistrationTerminalUserExit user exit code example
//TN3270 support example
if(ecbptr()->ce1flg == CFFSOCK)                                        
   //perform some test to see if this is a TN3270 terminal created ECB
   if(ecbptr()->ce1TN3270Flag ==  TRUE)
      //copy pseudo LNIATA into the LNIATA to return
      term->Terminal.LNIATA = ecbptr()->ebrout;
      term->TerminalType = lniata;
Figure 4. Remote debugging environment with custom terminal determination
flowchart, TBT code calling custom terminal code

Using tpf_flag_for_debug and this user exit together

The tpf_flag_for_debug system service and CDBX_DebuggerTBTRegistrationTerminalUserExit user exit can be used together to implement a seamless solution for using the z/TPF debugger trace-by-terminal functionality. If we continue the TN3270 example, end users will be using your TN3270 support, thinking in terms of using a particular LNIATA. They will be able to register the debugger for that LNIATA without understanding that your custom communication package is calling the tpf_flag_for_debug system service and returning the pseudo LNIATA by way of the CDBX_DebuggerTBTRegistrationTerminalUserExit user exit.

Figure 5. Remote debugging environment with custom communication package environment with trace-by-terminal determination and custom terminal determination
custom comms calling TBT and custom terminal code

Abstract terminals

In essence, using the tpf_flag_for_debug system service and CDBX_DebuggerTBTRegistrationTerminalUserExit user exit abstracts the terminal from how the application ECB was really created. Further, the distinctions made by the use of these two functions affects only which debugger registration entries can be used for the debugging of the application ECB. No other system function will be affected by these designations. Therefore, this function can be used creatively by custom communication packages.

For example, suppose that your shop does not use LU terminals but you do have a custom communications package that embeds the user's ID in an ECB work area or data level. The CDBX_DebuggerTBTRegistrationTerminalUserExit user exit could be used to determine that this ECB was created by your custom communication package, to extract the user's ID from the ECB, and then to return the user's ID as the LU terminal. Further, your custom communications package calls the tpf_flag_for_debug system service to appropriately mark ECBs as candidates for trace-by-terminal debugging. In this way, users who want to debug ECBs started by your custom communication package can register their user IDs as the LU and debug only applications that they initiate.

User-defined registration: The ultimate solution

However, there are many scenarios in z/TPF environments where these solutions will not work efficiently or at all. z/TPF is a high-performance transaction system, so thousands of ECBs might be started per second in a given program, and you might need to debug only one specific ECB (for example, the one ECB out of a thousand with 0 on data level 1). Or perhaps your system has a proprietary communication package that requires the user to register multiple pieces of information. Or maybe you need to debug a particular location in code where a set of conditions occur, such as a single entry point transaction application where a query is performed on a particular account number. The user-defined registration support was designed to solve all of these problems in a fully customizable debugger registration solution.

The user-defined registration support enables you to define several conditions:

  • Conditions to test
  • The location in your application code where the test for the conditions will occur
  • How the test for these conditions will be performed
  • When to start the debugger at that exact location in your application code

In other words, you can tell the debugger exactly when and where you need debugger sessions to start without relying on any built-in registration tests in the debugger (function, system error, conditions, terminals, and so forth), even in the middle of your code. Further, the user-defined registration framework is implemented in a performance sensitive manner such that the customizations can be included in production code, thereby maintaining high-value test points in your application indefinitely without affecting performance. Assembler and C/C++ user-defined registration frameworks are provided. As Figure 6 illustrates, the user-defined registration is triggered directly from the application.

Figure 6. Remote debugging environment with user-defined registration
flowchart, app code calling user-defined reg code

Define conditions to test

The TPF Toolkit uses an XML file for the user to define the names of the conditions to register. The names of the conditions are shown to the user in the registration entry (filter). The user can enter comparison values to test against the conditions in the ECBs that are candidates for debugging.

To create a user-defined registration type, you first need to modify the TPF Toolkit install directory\Config\TPFSHARE\Debug Registration\customDebugRegTypes.xml file (change words in italics to your information) to define the names of the conditions (parameters) to be tested. The parameter fields are used to define the name of each condition to test. The name field is the name that will be shown to the user representing this registration type. The ID is this registration type's unique registration type ID, which is used to tie together the XML definition and how the conditions will be tested.

Listing 3 is an example of a MyRegistration type in customDebugRegTypes.xml file.

Listing 3. Example of a MyRegistration type
	<parameter>User Id</parameter>
	<parameter>Message Type</parameter>

After restarting the TPF Toolkit, the new registration type will appear in the list of registration types. The names of the conditions will be shown to the user with a text box for the user to provide the comparison value. See Figure 7.

Figure 7. User-defined registration: New registration type with comparison values entered by user
GUI, user Id=MyId Type=Query EBROUT=010000 i=2000

Define where to test the conditions

The next thing that you need to do is to modify your application to call the test program with the conditions in your application to be tested against the comparison values registered by the user. First, modify your makefile to include the CDBX user exit module in your LIBS:


Next, you need to include the user-defined registration header file to have the performance macro, struct, and etc definitions:

#include <tpf/c_udrt.h>

Next, modify your application code at the location where the tests need to be performed. The first line of this block of code uses the performance-sensitive macro tpf_UserDefRegTypPerfCheck to see whether a given user-defined registration type is actively registered on the system. Notice the use of id 101. This is the value of the <id> tag used in the XML file in the TPF Toolkit in the previous step.

Now define an instance of the tpf_UserDefRegTypStruct structure and populate it with the registration type ID, a resolving function (in this example, you'll just use the user exit provided), and the comparison values to be passed as parameters. In this example, notice that you did not fill in parm1 (User ID) and parm3 (EBROUT), because these conditions will be extracted from the ECB.

Lastly, you call tpf_UserDefRegTypHandler.

Listing 4. Code to call tpf_UserDefRegTypHandler
     struct tpf_UserDefRegTypStruct temp = {0};
     temp.udrt_id = 101;
     temp.udrt_funcptr = (tpf_UserDefRegTypUserExit *)cdbxud_user_exit;
     temp.udrt_parm2 = (void*)reqType;
     temp.udrt_parm4 = (void*)&i;

Build and load your application code. Because the user-defined registration code is contained within a block that is encapsulated by the performance-sensitive macro, this code can be left in your production-level code for test points that can be used in the future.

Define how to test the conditions

As mentioned in the previous step, the code that performs the test of the conditions will be implemented in the existing user exit code in cdbxud.c. The sample code for this is shown in Listing 4. This code (function cdbxud_user_exit) is called for each registration entry of type MyRegistration (id 101). The contents of the UDRT_ptr (the state of the executing ECB) are compared to the contents of tbu_entry (the comparison values registered by the user as stored in the debugger registration entries). As shown in Listing 5, for conditions parm1 and parm3 (User Id and EBROUT), you can compare the registered comparison values to data found in the ECB. The parameters are passed as void pointers so that your code must know how to interpret the comparison values, such as using functions like atoi, sscanf, and so on. If a registration entry matches the state of an ECB, rc is set equal to TRUE to indicate to the debugger that a debugger session should be started.

Listing 5. Testing the conditions to determine whether a debugger session should be started
     case 101:                                                                  //PJ36059
       {                                                                        //PJ36059
          if(0 != strncmp((char*)&ecbptr()->ebw000,
          if(0 != strncmp((char*)UDRT_ptr->udrt_parm2,
          unsigned int lniata = 0;
          if(1 != sscanf((char*)tbu_entry->itbp_udrt_parmValue[2],"%x",&lniata))
          if(ecbptr()->ebrout != lniata)
          if(*((int *)UDRT_ptr->udrt_parm4) !=
          rc = TRUE;
       }                                                                        //PJ36059

Build and load your CDBX.

Using user-defined registration

Register your user-defined debugger registration entry as you would for other registration types and then run your application. When the debugger is notified by your condition-testing code (cdbxud.c) that a debugger session should be started, the debugger will stop the application at the next line of code following the code snippet in your application that passed in the state of the application.

Figure 8. User-defined registration: Application stopped immediately after test point
debugger GUI editor shows source code highlighted

Larger view of Figure 8.


The z/TPF debugger provides several different registration features and options. The tpf_flag_for_debug system service and CDBX_DebuggerTBTRegistrationTerminalUserExit user exit can be used to enable standard z/TPF debugger trace-by-terminal features to work for ECBs created by custom communications packages. The z/TPF debugger user-defined registration support is the ultimate debugger registration solution for custom communications packages. You can use it to address a myriad of possible debugger registration requirements.



Get products and technologies



developerWorks: Sign in

Required fields are indicated with an asterisk (*).

Need an IBM ID?
Forgot your IBM ID?

Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.


All information submitted is secure.

Dig deeper into Rational software on developerWorks

Zone=Rational, WebSphere, DevOps
ArticleTitle=Debug entry control blocks created by custom communication packages on z/TPF