System abend

S0C1: Operation exception

An S0C1 abend means the processor tried to run something that isn't a valid machine instruction. The program almost always got there by mistake, usually through a call to a subprogram that was never linked in or a branch to an address that was overwritten.

Also written as 0C1, SOC1, abend 0C1, system abend 0C1, operation exception.

What it means

Every machine instruction starts with an operation code. When the processor fetches an operation code it doesn't recognize, it raises an operation exception, program interrupt code 1, and z/OS ends the step with system completion code 0C1.

The bytes at the failure point usually aren't code at all, so the useful question is how the program got there.

One cause is different. Compilers such as Enterprise COBOL pick instructions according to the ARCH option, so a program compiled for a newer processor can contain instructions an older machine doesn't have. Those fail with S0C1 even though the code is correct.

Common causes

  • A CALL to a subprogram that wasn't resolved at link-edit time. The binder flagged the symbol as unresolved but saved the module as executable anyway, so the CALL branches to address zero.
  • An assembler program, or one built by an old compiler, did a GET or PUT on a file that never opened, usually because its DD statement is missing.
  • Storage was overwritten. A table that runs past its end, or a move into the wrong area, can destroy a saved return address or a branch table. When the program later branches through it, it lands on data.
  • An assembler routine ran off the end of its code into its constants or work areas because a branch or return was missing.
  • The program was compiled with an ARCH level higher than the processor it runs on supports.

How to find the problem

  1. Read the IEA995I symptom dump or the CEE3201S message. Note the PSW address, the instruction length (ILC), and the load module name and offset.
  2. If the PSW address is very low, such as 00000002, the program branched to zero. Check register 15 in the dump. If it's zero too, a CALL went to a routine that was never resolved, so look for unresolved symbols in the binder listing (IEW2454W or IEW2456E).
  3. Register 14 usually holds the return address of the last call. Map it back to the calling program's listing to see which CALL led to the failure.
  4. If the PSW points inside your program, subtract the ILC from the offset and find that spot in the compiler listing made with LIST or OFFSET. If the spot is in the middle of data, look for whatever overwrote the code or the branch address.
  5. Check that every DD statement the program uses is in the step. The IEF237I messages in the job log show which DD names were allocated.
  6. If the failing instruction looks valid, compare the ARCH option in the compiler listing with the processor the job ran on.

How to fix it

  • Link-edit the program again with the missing subprogram included, or with the right library in SYSLIB, and make the link step fail when a symbol is unresolved.
  • Add the missing DD statement, and check the result of every OPEN (the file status in COBOL) so a missing file is reported clearly.
  • Find and fix the storage overlay. In COBOL, compiling with SSRANGE in test catches table overruns as they happen.
  • Recompile with an ARCH level that matches the oldest processor the program must run on, including the disaster recovery site.

What it looks like

IEA995I SYMPTOM DUMP OUTPUT
  SYSTEM COMPLETION CODE=0C1  REASON CODE=00000001
   PSW AT TIME OF ERROR  078D1000   80000002  ILC 2  INTC 01
     NO ACTIVE MODULE FOUND
CEE3201S The system detected an operation exception (System Completion Code=0C1).
IEF450I INVRUN02 STEP010 - ABEND=S0C1 U0000 REASON=00000001

Questions

Why does an S0C1 show a PSW address of 00000002?

The program branched to address zero and the processor found zeros, which aren't a valid instruction. This almost always means a CALL to a subprogram whose address was never filled in because it wasn't linked into the load module.

Can a missing DD statement cause S0C1?

In assembler programs and programs built by older compilers, yes. Reading or writing a file that never opened can branch to a bad address. Current Enterprise COBOL reports the missing file as file status 35 on the OPEN instead.

How is S0C1 different from S806?

S806 means the system couldn't find a program to load at all, for example on a dynamic CALL. S0C1 means the program was already running and branched to something that isn't an instruction.