MVS TOOLS AND TRICKS OF THE TRADE April 1997 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. HARNESSING MACRO POWER - PART 2 Last month, we discussed the topic of turning system macros, which operate from within assembler programs, into utilites that we can use. This topic seems a bit daunting for many of us, and I must admit that toward the beginning of my career, when I wasn't so good at programming in assembler language, I was at something of a loss when shown a macro facility. I figured that I myself could never use the facility, because I felt dependent on someone else to write the programs for me. Today, I'd like to show you that even if you're only fair at assembler, you can still harness system macro facilities for yourself. I'll go into a little more detail as to the kind of things you can do in a program, and I'll give you another example to study. THE GBHABEND PROGRAM We'll start our discussion with an example of what my friend Gordon Hampton did with the ABEND macro. The ABEND macro is a system facility which ends a job and produces a system abend, killing all subsequent steps in the job stream, so they are not executed. Abends can have several types of codes. These are: system codes, user codes, and system code with reason code. Optionally, if a SYSUDUMP, SYSABEND, or SYSMDUMP ddcard is included in the JCL, a virtual storage dump is produced in the step. The value of the abend code is displayed in the JCL output for the job step. System abend codes are hex values, and they range from X'000' to X'FFF'. User abend codes have the same range, but they are expressed in decimal values from 0 to 4096. Reason codes that accompany system codes, can have the same range, expressed in decimal values from 0 to 4096. The GBHABEND program can invoke the ABEND macro to reproduce any of these abend codes, driven by a parm value. See Figure 1. An application program which ends abnormally or because of a programming error, in such a situation where the programmer did not provide an error routine, will often cause a system abend. Also, many operating system programs which end abnormally, do so via either the ABEND macro, or the service it invokes, SVC 13. However, some system utilities will almost never produce an abend under normal conditions, even if there is a severe error. The notable example of such a program is IDCAMS, the utility which handles VSAM files. At this point, we can see one practical use for Gordon's program. Suppose you have a multi-step job stream which involves the creation or manipulation of VSAM files. The success or failure of such a "VSAM" job step will involve a return code, rather than a system abend. If a certain job step is supposed to create an important VSAM file, and it fails, then instead of an abend, a return code of 12 will be issued by the job step. If you'd want to kill the rest of the job stream because of the step failure, one way would be to code a COND parameter on all subsequent job steps. Another way would be to code just one job step, invoking the GBHABEND program with a COND parameter on it, that would abend the rest of the job then and there. Figure 1 shows how this is done. Of course on newer systems, with IF-THEN-ELSE coding in the JCL, the same thing could also be accomplished, but the GBHABEND method works on all systems, old and new. Gordon had another use for his program. Since he could induce the ABEND macro to produce an abend with any code: system, user, or system with reason code, he could do simulations. For example, one could study the effect of a system or a user abend with a certain code, on a job stream, without having to actually execute the offending job step. One could merely execute the GBHABEND program with the proper parameters and reproduce the exact abend code in the job stream. To complete the simulation picture, one would have to write a program which produces a given condition code depending on a parm. This is extremely easy to write, and all of you can do so as an exercise. Just be sure to test your program out in a job stream, to make sure it works properly. The program should do as follows: Save the registers, then read the parm, which is pointed to by Register 1 plus 2. The length of the parm field is a halfword pointed to by Register 1 itself. If there is no parm, the program should do nothing. If there is a parm, once the EBCDIC value of the parm is extracted, you can pack it, and convert it to binary in a fullword of storage. Then return control to the caller, with all registers restored except for Register 15, which has been loaded from the fullword containing the binary value obtained from the parm. That's all there is to it. Source code for the GBHABEND program may be found on File 233 of the CBT MVS Utilities Tape, a large collection of free software which can be obtained through the NaSPA office. Optionally, this program can be downloaded from the Nascom bulletin board. GBHABEND is a practical and useful program for any installation to have. DISPLAYING HEX VALUES Nowadays, many system macros are designed to return binary tokens, codes, or similar types of values. It makes sense, that if we possessed a technique of displaying a binary value in a program, we could look at the output of all these macros, and possibly learn something about what these token values are. I have done this kind of work myself in a few programs that are publicly available. An example of code which does such hex displays is on File 247 of the CBT MVS Tape, and is a program called BCMLISY. BCMLISY is a TSO command which displays any TSO user's SYS1.BRODCAST messages. However, besides displaying the text of the messages alone, it also displays, for each message, the relative record address, in hex, of that message within the SYS1.BRODCAST dataset. I took the technique of displaying a hexadecimal value in readable numbers, from Bill Godfrey. Figure 2 displays the elements of the technique, and has snippets of code from the BCMLISY program, which accomplish the display. This display technique for hex values, is packaged as a macro. In order for the macro to function, a few other ingredients need to be coded into the program. All of these ingredients are shown in Figure 2. The macro is called HEX, and its operands are three. The first operand is the target area for the EBCDIC display bytes. This is twice the size of the hexadecimal original data. The second operand is the number of hex bytes to be expanded. The third operand is the hex source data. As Figure 2 shows, the HEX macro invokes the HEX subroutine that uses Registers 15, 0, and 1 as work registers, to expand one byte of hex into two bytes of display characters at a time. You can see exactly how this code works by looking at Figure 2. It remains for me to indicate, at this point, how the expanded data is to be displayed to a user of the program. If the program is a batch program, you can use QSAM PUT to print an output line of display. If the program is a TSO command, the TPUT or PUTLINE macros can be used to display the output at a terminal. PUTLINE is harder to use than TPUT, but PUTLINE results can be printed to a hardcopy device, whereas TPUT results cannot; they can only be sent directly to a terminal. A coding example of how to use PUTLINE can be found in the BCMLISY program from File 247 of the CBT Tape. The code and actual technique is the work of Bill Godfrey. The TSO/E Programming manual, I believe, spells out the directions for doing TSO output using PUTLINE, but you can also copy Bill Godfrey's code, which works fine. Bill Godfrey already did the work, and you don't have to knock your head against the manual to untangle what it says. What is the point of all of this, for our subject? You can now take any system macro in the books which can be induced to return a token value. Then you can write a simple program to invoke the macro under control of parameters that were externally supplied, either by a parm or by control cards. After that, you can use the hex display technique to display or print the results. This technique becomes a great diagnostic and learning tool. I've had to be brief this month, but I hope these techniques will prove of value in your work. I think that this idea of displaying the results of macro calls is a bit novel, and it can be very very useful. If you actually follow these ideas up, you can gain much system knowledge and you can profit very much. Good luck with your efforts. See you again next month. * * * * * * * * * * * * * * * * * * * * * * * Figure 1. How to use Gordon Hampton's GBHABEND program to abend a job step with any ABEND code you would like to specify. The parms you specify are fed by the program into the ABEND system macro, to produce the desired result. This is a clear example of a program which feeds the user's parameters into a system macro. Full format of the parms is as follows: SNNN - GIVES SYSTEM ABEND NNN. UNNNN - GIVES USER ABEND NNNN. NNNN - GIVES USER ABEND NNNN. RMMMNNN - GIVES SYSTEM ABEND MMM WITH REASON CODE NNN. If you don't follow this format you may get strange results. JCL to run is as follows: //BOOMSTEP EXEC PGM=GBHABEND,PARM=U1288,COND=(8,GT,PREVSTEP) //STEPLIB DD DISP=SHR,DSN=MY.STEPLIB //SYSABEND DD SYSOUT=* This will cause a user abend of 1288 on BOOMSTEP if PREVSTEP had a condition code of 8 or greater. If you don't want a dump to be produced, leave out the SYSABEND DD card. * * * * * * * * * * * * * * * * * * * * * * * Figure 2. Code to support the display of hexadecimal numbers in EBCDIC. This code was taken from the BCMLISY program whose source code is on File 247 of the CBT MVS Utilities Tape. I think the original author of the code is Bill Godfrey. Inline code is the HEX macro, which takes an n-byte hexadecimal field and expands it into a 2n-byte EBCDIC display field. Here are two separate invocations of the HEX macro, to expand two 3-byte hex numbers into 6-byte display format. HEX LINE+10,3,USDRBA Display 3-byte hex fields HEX LINE+18,3,USDEND in 6-byte EBCDIC fields. This is the supporting code for the HEX macro: First is the macro itself, followed by the byte-by-byte display expansion routine. MACRO &NAME HEX &TO,&LEN,&FROM &NAME STM 15,1,HEXSAVE LA 1,&FROM LA 0,&LEN LA 15,&TO BAL 4,HEX LM 15,1,HEXSAVE MEND HEX MVC 1(1,R15),0(R1) MOVE BYTE UNPK 0(3,R15),1(2,R15) UNPACK TR 0(2,R15),HEXTAB-240 LA R15,2(,R15) INCREMENT OUTPUT PTR LA R1,1(,R1) INCREMENT INPUT PTR BCT R0,HEX DECREMENT LENGTH, THEN LOOP MVI 0(R15),C' ' BLANK THE TRAILING BYTE BR R4 RETURN TO CALLER HEXTAB DC C'0123456789ABCDEF' TRANSLATE TABLE These are the data areas referred to by the above code. HEXSAVE DS 3F Register save for HEX macro USDRBA DS AL3 - RELATIVE BLOCK ADDRESS (RBA) OF FIRST * MESSAGE FOR THIS USERID (ZERO IF NONE) USDEND DS AL3 - RBA OF LAST MESSAGE FOR THIS USERID * (ZERO IF NONE)