Mainframe COBOL Decoder
| Field | Value |
|---|---|
| Type | Skill Resource |
| Source | ~/.copilot/skills/architecture/references/discovery/mainframe-cobol.md |
| Description | Not specified |
Source Content
Mainframe COBOL Decoder
A field guide for reading z/OS COBOL batch systems — the language, the record layouts, the job control, and the file systems underneath. Read this before phase 2 when the platform family is mainframe.
Contents
- The stack in one paragraph
- COBOL program structure: the four divisions
- Level numbers, PIC, and USAGE (how to read a field)
- REDEFINES and OCCURS (the two layout traps)
- Copybooks: the real data model
- The PROCEDURE DIVISION verbs that carry logic
- JCL: how batch actually runs
- Datasets and VSAM
- DB2 and IMS on the mainframe
- Schedulers and the nightly batch cycle
- Abends: when the clues are in the failure
- File-extension cheat sheet
The stack in one paragraph
A mainframe (IBM Z running z/OS) runs work two ways: batch — programs launched by JCL that read and write datasets — and online — interactive transactions under CICS or IMS (CICS has its own decoder, references/cics-online.md). The programs are usually COBOL; the record layouts they share live in copybooks; the data lives in sequential datasets or VSAM, and increasingly in DB2. Understanding a mainframe system is mostly: read the copybooks (data), read the COBOL (rules), and read the JCL (what runs when).
The four divisions
Every COBOL program has four divisions, always in this order. Skim them in order and you know the program’s shape before its logic:
IDENTIFICATION DIVISION
Names the program (PROGRAM-ID). Sometimes carries author/date comments that hint at age and purpose.
ENVIRONMENT DIVISION
Maps the program’s logical files to physical datasets. The SELECT … ASSIGN TO … clauses in FILE-CONTROL tell you which files the program uses and whether they are sequential, indexed (VSAM KSDS), or relative. This is half of the “what data does it touch” answer.
DATA DIVISION
The layouts. Three sections matter:
- FILE SECTION — an
FD(file description) per file, each with its record layout (often aCOPYof a copybook). - WORKING-STORAGE SECTION — the program’s variables, constants, flags, and tables. Business thresholds and magic numbers live here.
- LINKAGE SECTION — parameters passed in from a caller (or from CICS/JCL
PARM). This is the program’s input contract.
PROCEDURE DIVISION
The logic — organized into paragraphs and sections that are run with PERFORM. This is where the rules are; read it against the data model, not cold.
Level numbers, PIC, and USAGE
A COBOL field is described by a level number, a name, and a PICTURE (PIC) clause. Read three things per field: how it nests, its type, and how it is stored.
Level numbers show nesting. 01 is a top-level record; 05, 10, 15 nest under it (a group and its sub-fields). Two special levels:
88— a condition name: a named value test, e.g.88 CLAIM-APPROVED VALUE 'A'. These are gold — they name business states in plain English. Harvest every88.77— a standalone scalar (no sub-fields).
PIC gives type and size:
| PIC symbol | Means |
|---|---|
9 | A numeric digit (PIC 9(5) = 5 digits) |
X | Any character (PIC X(30) = 30 chars) |
A | Alphabetic only |
S | Signed (leading S, e.g. S9(7)) |
V | Implied decimal point (S9(7)V99 = 7 digits, 2 decimals, no stored dot) |
Z, ,, ., $, -, / | Edit characters — display formatting only, for report fields |
USAGE gives physical storage — and this is where reverse-engineering goes wrong if ignored:
| USAGE | Storage | Note |
|---|---|---|
DISPLAY (default) | One byte per digit/char, as text | Easy to read raw |
COMP-3 / PACKED-DECIMAL | Packed decimal — two digits per byte + sign nibble | Extremely common for money; raw bytes are unreadable without decoding |
COMP / COMP-4 / BINARY | Binary integer (2/4/8 bytes) | Byte order matters |
COMP-1 / COMP-2 | Single/double floating point | Rare in business code |
A PIC S9(7)V99 COMP-3 amount is 5 bytes of packed decimal representing a signed number with two implied decimals — not a 12-character string. Decode rules and the signed-overpunch trap are in references/data-model-extraction.md.
REDEFINES and OCCURS
Two clauses let one layout mean several things. Both are traps for automated extraction:
REDEFINES overlays a second layout on the same bytes. 05 FILLER PIC X(20) 05 PARSED REDEFINES FILLER … means those 20 bytes are read two ways depending on context. A field can be a date in one branch and a code in another. You must find which condition selects which view — that is a business rule, not just a layout note.
OCCURS makes an array/table: 05 MONTH-AMT PIC S9(7)V99 COMP-3 OCCURS 12. OCCURS … DEPENDING ON n makes it variable-length (the record size depends on a counter field), which means the layout is not fixed and offsets shift at runtime. Flag every OCCURS DEPENDING ON — it complicates any flat extract.
Copybooks: the real data model
A copybook is a shared fragment of DATA DIVISION code pulled in with COPY MEMBER.. It defines a record layout (or a set of constants) once and is reused by every program that touches that file. That makes copybooks the single best source of the data model — they are the schema the mainframe never wrote down as DDL.
Practical consequences for discovery:
- One copybook is usually one file/table’s record. Inventory the copybooks first; they enumerate the entities.
- The same copybook
COPY’d into many programs is a dependency signal: those programs all share that record and likely that responsibility. COPY … REPLACINGsubstitutes text at copy time (e.g. prefixing field names). The effective layout differs from the raw copybook — expand it mentally before trusting field names.
PROCEDURE DIVISION verbs
The verbs that carry business meaning (as opposed to plumbing):
| Verb | Meaning | Discovery note |
|---|---|---|
PERFORM | Call a paragraph/section (optionally in a loop) | The control flow; PERFORM … UNTIL is the main loop idiom |
MOVE | Copy/convert data between fields | Watch implicit type conversion and truncation |
COMPUTE / ADD/SUBTRACT/MULTIPLY/DIVIDE | Arithmetic | Where money and eligibility math live |
IF / EVALUATE | Branch / case (EVALUATE = switch) | EVALUATE often encodes a decision table |
READ / WRITE / REWRITE / DELETE | File I/O (REWRITE = update) | The CRUD verbs; check the file’s FD |
CALL | Invoke another program | Cross-program edges for the call graph |
STRING / UNSTRING / INSPECT | Text build/parse/scan | Parsing rules, formatting |
SORT / MERGE | In-program sort | Often a whole batch step in one verb |
GO TO | Unconditional jump | Legacy spaghetti signal; trace carefully |
Condition names (88 levels) turn cryptic tests into readable ones: IF CLAIM-APPROVED beats IF WS-STAT = 'A'. When you see them used, you have found named business states — put them straight into the rule catalog.
JCL
Job Control Language tells z/OS what programs to run, in what order, with which datasets. A JCL member is a job; a job has steps; each step runs a program (or a cataloged PROC). The three statement types:
//JOBNAME JOB …— the job card: name, accounting, class, priority.//STEPnn EXEC PGM=…(orEXEC PROC=…) — a step running a program or procedure.PARM=passes a parameter string to the program (itsLINKAGE).//ddname DD …— a data definition: connects a program’s internal file name to a real dataset (DSN=), with a disposition (DISP=(status,normal,abnormal)), or inline data (DD *).
What to extract from JCL:
- Step order and program calls — the batch flow within a job.
DDstatements — every dataset a step reads or writes (DISP=SHRread-shared,DISP=OLDexclusive,DISP=(NEW,CATLG)creates). This is the file-usage matrix’s raw material.COND/IF-THEN-ELSE— steps that run only if a prior step’s return code passes. This encodes error handling and conditional flow.- PROCs — cataloged, reusable JCL. A job that
EXECs a PROC hides its real steps in the PROC member; expand it. - Utilities —
IEBGENER(copy),IDCAMS(VSAM admin),DFSORT/SYNCSORT(sort/filter, sometimes doing real business transforms in the sort control cards).
Datasets and VSAM
Mainframe “files” are datasets, named hierarchically (PROD.CLAIMS.MASTER). The kinds you will meet:
Sequential (PS) and partitioned (PDS/PDSE)
A PS is a flat sequential file. A PDS/PDSE is a container of members (like a folder of files) — source code and JCL usually live in PDS members.
VSAM — the indexed file family
VSAM is how the mainframe did keyed/indexed data before DB2. Three organizations:
| VSAM type | Full name | Access pattern | COBOL sees it as |
|---|---|---|---|
| KSDS | Key-Sequenced Data Set | By unique key (like a primary-key table) | Indexed file |
| ESDS | Entry-Sequenced Data Set | In insertion order (like an append log) | Sequential file |
| RRDS | Relative Record Data Set | By record number (like an array) | Relative file |
KSDS is the common one — treat a KSDS as a single-table keyed store; its record layout is the copybook, its key is in the SELECT … RECORD KEY. An alternate index (AIX) on a KSDS is a secondary index — a second access path worth noting as a query the business needed. VSAM clusters are defined and loaded with IDCAMS (DEFINE CLUSTER).
DB2 and IMS
Two database options coexist with VSAM:
DB2 for z/OS
Relational, accessed by embedded SQL in COBOL: EXEC SQL … END-EXEC, precompiled. DCLGEN generates a copybook-like host-variable declaration from a table. When you see EXEC SQL, the data model for those tables is real SQL — get the DDL or catalog (SYSIBM.SYSTABLES, SYSCOLUMNS) and you have an authoritative schema, no reverse-engineering needed.
IMS
A hierarchical database (segments in a parent/child tree) accessed by DL/I calls (CALL 'CBLTDLI' …) rather than SQL, plus IMS/DC for online transactions. Rarer in new discovery but present in the oldest systems. If you see CBLTDLI/PCB/PSB, you are in IMS and the data model is a hierarchy, not tables — model it as nested entities.
Schedulers and the batch cycle
Batch jobs do not run themselves. A scheduler — Control-M, CA-7, or IBM TWS/OPC — triggers jobs on a clock and on dependencies (job B runs when job A ends OK and a file arrives). The scheduler definitions (not the JCL) hold the true nightly batch cycle: the order, the timing windows, and the “must finish before 6 AM” constraints that a migration must preserve. If you can get the scheduler export, it is worth more than any single program for understanding operational risk. Draw it as a job DAG — see references/mermaid-legacy-patterns.md.
Abends
A mainframe failure is an abend (abnormal end) with a system completion code. Two are worth recognizing during discovery because they reveal data assumptions:
- S0C7 — data exception: arithmetic on a field that does not contain valid packed/numeric data. Almost always bad or uninitialized
COMP-3data. Frequent S0C7s in the history mean the data has dirty values the rules must tolerate. - S0C4 — protection/addressing exception: often a bad index, subscript, or
OCCURSoverrun. Signals table-size assumptions.
Abend history (from job logs) is a free source of edge cases for phase 5 test generation.
File-extension cheat sheet
In an exported repo, classify by extension (confirm by the first division/statement):
| Extension(s) | It is a… |
|---|---|
.cbl, .cob, .cobol | COBOL program |
.cpy, .cpybk, .copy | Copybook (record layout / constants) |
.jcl, .job | JCL job |
.prc, .proc | Cataloged JCL procedure |
.pli, .pl1 | PL/I program (sibling language; similar role) |
.asm, .mlc | Assembler (HLASM) — low-level, rare but opaque |
.dbrm, .bind | DB2 bind artifacts |
.sql | SQL DDL/DML |
.bms | CICS map source (see references/cics-online.md) |
.rex, .rexx | REXX scripts (ops automation) |
When extensions are absent, the first line decides it: IDENTIFICATION DIVISION → COBOL; //… JOB → JCL; a bare record layout starting with a 01 level → copybook; EXEC SQL blocks → embedded DB2.