MVS TOOLS AND TRICKS OF THE TRADE AUGUST 2000 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. THE CVT - THE BACKBONE OF MVS My approach to understanding computers might be termed "outside-in". I'll explain it to you, and I'm sure most of you will agree why such an approach is needed and practical. You can begin by trying to remember what your feelings were, when you first started doing systems programming work. If your experience was like mine, it was something like this: When we entered this field, we were suddenly immersed into a complicated mess that already existed, and it was our job to learn as much as was necessary to survive. The reason for that is very simple, when you think about it. Computer knowledge is a lot of other people's work, thinking, and debugging. All of this occurred in the past. Once somebody built an operating system, or a utility, or any program written for any purpose, all subsequent people became users of that operating system, utility or program. In other words, even though most of us are called "programmers", we're really the "users" of other people's programs, most of the time. There's nothing wrong with that. So why are we called "programmers" and why are the other people (the "real users") called "users"? The answer is because we ADD to the existing computing program base, and the "users" don't. We write more programs, to build on top of what's already there. Or we install new packages, to create a new, enhanced programming base on our computing system, for the other people, the real users, to use. At this point, I can explain what I mean by "outside-in". It simply means that when I'm trying to understand something in computing, first I try and see what it does. I use it. I get the feel of the screens and the outputs. I see what it does to the data files. I give it one "test drive", and then another, and another, until I understand the externals of what it does. That's what the "outside" is. What's the "in"? It's this. After I see how the program, or package, or tool works, I try and find out what makes it tick--WHY it works. For that, I have to look into its internal structure, and as much as is possible in a semi-OCO world, into its programming. I reason as follows: "It DOES work, so something it does, has to MAKE it work. It has to make the computer do this stuff in a step-by-step manner, the same way a building is constructed out of its component parts." Then, realizing that the entire picture may be very complicated, I start trying to find a way to begin. In other words, I start by looking for a small piece of the mechanism that I CAN understand. It's like trying to break into a house that you're locked out of. (In our case, as in the case of a locksmith, it's legal to do this.) You look for a loose door, or an open window, so you can get inside. That's the "in". What relevance does all this have to today's subject? Today, I'm going to tell you how to start looking inside MVS. I'm going to show you a window that you can climb in, so you can start looking around. This window is called the CVT, or Communication Vector Table. Once you know what the CVT is, and where it is, you're already looking at MVS from the inside, and not from the outside. WHAT IS THE CVT? The Communication Vector Table (as its name actually tells you if you understand IBM-ese) is a huge collection of pointers to a lot of seemingly miscellaneous locations. Its contents is described by a macro called CVT, which is in SYS1.MACLIB. At the beginning of the CVT macro, IBM actually provides a short explanation as to what the CVT is for. This explanation says: "The CVT provides the means by which non-nucleus-resident routines may refer to information in the nucleus of the control program. It contains addresses of other control blocks and tables used by the control program routines." Basically, this means that as far as any users of the MVS operating system are concerned, the CVT is the backbone and spinal cord of MVS. How does a program get to the CVT? There are two pointers to the CVT in low storage. The primary pointer is at virtual location hex 10, or decimal 16. The second pointer, far less well-known, is at virtual location hex 4C, or decimal 76. Sometimes, if the system is crippled for some reason, the second location to get to the CVT might be available, even though the main location at x'10' is damaged. It's an extra measure of system security, and it's nice to know about. What's in the CVT? You can find out, by reading the comments in the CVT macro. If you're like me, and you've tried doing that, you'll probably have the same reaction that I did. You'd be overwhelmed by the fact that you don't understand very much. Trust me, that reaction is natural and normal. There's a simple reason for it. In order to understand all the pointers in the CVT, you have to understand practically all of MVS, because that's what's being pointed to. So instead of being disappointed, you should really be happy. Why? Because you've gotten in through the door, and you're now inside this "mansion of many rooms", that is the MVS operating system. You've even got a key to most of the rooms. Now, you can start exploring the inside. USING POINTERS TO GET ALMOST ANYWHERE IN MVS The CVT, with its prefix and its extensions, can be likened to a "room full of address pointers". Practically every 4 bytes of the CVT is a pointer to a different virtual storage address. So, if you're sitting in a room full of address pointers, the next logical question is: How do you use them? The answer is: Most of the time, you use the LOAD instruction (abbreviated "L" in an assembler program). The action of the LOAD instruction is very simple. You point the LOAD instruction at a four-byte location in storage, and give LOAD the name of a general register (which holds 4 bytes). LOAD then puts whatever 4 bytes of hex values that are at the storage location, into the general purpose register. It's very simple. Just for the record, I'll mention that the opposite of the LOAD instruction is the STORE ("ST") instruction, which puts the 4-byte contents of a general purpose register into four bytes of storage. Using LOAD, you don't just have to use the four bytes of storage that it's directly pointing at. You can also use any four bytes you choose, at a displacement up to 4095 bytes forward from the location you're pointing at. (I'm keeping it elementary here, and I'm not mentioning how to use an index register in LOAD.) Why is the LOAD instruction excellently suited for following chains of pointers? Because it allows you to jump from one location in the computer to another, very simply. It also accounts for small displacements off the storage location it is referring to. I'll try and explain this a little better. Most of the information that the MVS operating system uses, is stored in moderate-sized chunks of bytes that are together in one location. These are termed "control blocks". The main control block that is used by any program which uses the MVS operating system, is the CVT. An address in the CVT might point to the beginning of another control block, which contains more address pointers to other control blocks. Finally, after following a chain of pointers, you can arrive at the MVS information you are looking for. It goes the other way, too. Any information that the designers of MVS want you to use, is almost always pointed to by chains of addresses in control blocks, and it is almost never referred to by a direct storage location. Therefore, to get to any information you want in MVS, there exists some chain of control block pointers which leads there. And almost always, the place to start the search is the CVT. So it comes out, that if you want most information in an MVS system, you have to ask about the chain of pointers, starting from the CVT, that has to be followed, in order to get there. And in an assembler program, following a chain of pointers is done by the LOAD instruction. For example, if you're running a program from TSO, and you want the program to find out your TSO userid, you ask where the TSO userid is, and then you ask how to get there. I'll give you an answer. One place the TSO userid is, is in a control block called the PSCB, in a field called PSCBUSER, that is 0 bytes off the beginning of the PSCB control block, for 7 bytes. Question now is, how do you get to the PSCB? Answer is: You start from the CVT, which is pointed to from virtual location x'10' in low core. Then you point to the TSCB-ASCB words, which is at a location for 4 bytes at 0 bytes off the beginning of the CVT. At 4 bytes off that location, is a pointer to your TCB (Task Control Block). At x'B4' off the beginning of the TCB is a pointer to the JSCB (Job Step Control Block). And at x'108' off the beginning of the JSCB, is the pointer to the location of the PSCB. This all looks very complicated, but it isn't really, because whenever you want the PSCB, you always go there the same way. And when you do it with a succession of LOAD instructions in an assembler program, it's only a succession of 5 instructions. In a program, that's very very simple. So if you want to get to the PSCB, you always do it the same way, as follows: Pick a work register you're not using right now, in the program. Say it's Register 3 (called R3). To get the address of the CVT, just LOAD R3 with the numeric value x'10'. Then LOAD R3 with the value in storage that is 0 bytes off R3 to get to the TCB-ASCB words. Then LOAD R3 again with 4 bytes off R3 to get to the TCB. Then LOAD R3 again with x'B4' bytes off R3 to get to the JSCB. And finally, you LOAD R3 again with x'108' bytes off R3 to get the storage address of the beginning of the PSCB. Finally, you can move the 7 bytes that are at the location R3 now points to (your TSO userid), to wherever you want. In a program, it's just LOAD, LOAD, LOAD, LOAD, LOAD. Please see Figure 1 for what the actual instructions look like. Each piece of MVS information has its own address. A large number of the MVS quantities and values can be reached in this way. And once you, as a programmer, have gotten to the stage of understanding this fact, you're now WAY inside MVS. You're not outside it anymore. WHAT'S LEFT? So what's left for you to do? Accumulate information! MVS is a very large operating system, and it does thousands of different things in its normal operation. If you want to write a program that interacts with one of the things MVS does, you have to know where MVS keeps the information that particular function is dealing with. You have to find out how to get there, and once there, you have to know what you're allowed to do. If you're only doing inquiries, and you're not trying to change anything, you can go practically anywhere, and copy the information off. If you're trying to change one of MVS's functions, you have to be mighty careful. But at least you can now start looking, and start doing things. At this point (if you're fairly new to MVS internals), you're a lot farther along than you were, before you started reading this column. Many working MVS assembler utilities can be found in the enormous, free CBT Tape collection that is available online, at www.cbttape.org , and you can examine the different coding examples, so you can see how they are able to access the system information they need. I wish you the best of luck in your endeavors, and I'm looking forward to seeing you again next month. * * * * * * * * * * * * * * * * * * * * * * * Figure 1. Example of running a chain of address pointers from the CVT. We want our TSO program to find out the userid it is running under. That information is located in a control block called the PSCB, and the PSCB is pointed to, by a chain of 4-byte addresses which starts with the CVT. Here's how our program gets there, using a succession of LOAD instructions into general register 3. --- SNIP --- RUNCHAIN L R3,16 POINT TO CVT. ADDR IS IN LOW STORAGE L R3,0(,R3) POINT TO TCB/ASCB WORDS, "0" OFF CVT L R3,4(,R3) POINT TO TCB, "4" OFF TCB/ASCB WORDS L R3,X'B4'(,R3) POINT TO JSCB. X'B4' OFF CURRENT TCB L R3,X'108'(,R3) POINT TO PSCB. X'108' OFF THE JSCB * ----- Now you're there. R3 contains the address of the PSCB * ----- control block. MVC MSGLINE+13(7),0(R3) MOVE USERID IN FROM 0 OFF THE PSCB * AND PLACE IT INTO THE MESSAGE. TPUT MSGLINE,L'MSGLINE DISPLAY THE WHOLE MESSAGE ON THE TUBE --- SNIP --- MSGLINE DC CL20'MY USERID IS ' DEFINE LINE FOR MESSAGE --- SNIP ---