1. O que é um abend

Abend vem de ABnormal END — é quando o z/OS encerra um programa antes do normal por causa de um erro irrecuperável. No job output você vê a mensagem IEF450I JOB ABENDED e um código de abend que identifica a causa.

Existem dois tipos:

  • System abend (Sxxx) — detectado pelo hardware ou pelo sistema operacional. Ex: S0C7 (dado inválido em operação numérica)
  • User abend (Uxxx) — acionado pelo próprio programa ou por middleware. Ex: U4038 (erro de acesso DB2)

🦕 Analogia — abend é como o airbag do carro

O airbag não causa o acidente — ele dispara porque o acidente já aconteceu. O abend é o sistema detectando que algo errado ocorreu (um byte inválido, um ponteiro errado, falta de memória) e encerrando o programa antes que ele cause mais dano. O código do abend é o relatório do sensor que disparou.

2. Abends do sistema — códigos S

Os abends de sistema mais comuns em programas COBOL no z/OS:

CódigoNomeCausa típica em COBOL
S0C1Operation ExceptionExecução de dado como instrução — geralmente GOBACK/STOP RUN esquecido ou controle caindo além do fim da Procedure Division
S0C4Protection ExceptionAcesso a endereço de memória inválido — ponteiro nulo em CALL, subscript negativo ou muito alto em alguns contextos
S0C5Addressing ExceptionSubscript ou Reference Modification fora dos limites do campo
S0C7Data ExceptionCampo numérico (PIC 9) com espaços, letras ou caracteres inválidos em operação aritmética
S013DCB MismatchLRECL ou RECFM do arquivo no JCL diferente do declarado no FD do programa
S122Time Limit Exceeded (Cancel)Operador cancelou o job (ou job foi cancelado por política)
S222Job CancelledJob cancelado por operador ou pelo próprio sistema
S322CPU Time ExceededLoop infinito ou processamento muito demorado (ultrapassou TIME= do JOB)
S806Load Module Not FoundPrograma chamado via CALL dinâmico não encontrado no STEPLIB/JOBLIB
S878Out of MemoryPrograma alocou mais memória do que disponível na região
SB37Dataset FullArquivo de saída encheu — SPACE insuficiente no JCL
SD37Dataset Full (sem secondary)Arquivo encheu e não tem alocação secundária definida

S0C7 — o abend mais comum em COBOL

COBOL Causas e prevenção do S0C7
             * S0C7 ocorre quando você usa dado inválido em aritmética

             * CAUSA 1: campo numérico não inicializado
       01  WS-VALOR   PIC 9(09)V99.  *contém X'00' (LOW-VALUES) por padrão
           ADD 1 TO WS-VALOR       *S0C7 — X'00' não é válido como numérico

             * CAUSA 2: MOVE de alfanumérico com letras para numérico
           MOVE 'ABC' TO WS-VALOR   *'ABC' vira X'C1C2C3'
           ADD 1 TO WS-VALOR       *S0C7

             * CAUSA 3: campo vindo de arquivo com SPACES
             *  Registro lido: '12345     BBBB' — campo valor = '     ' (spaces)
           COMPUTE WS-TOTAL = WS-TOTAL + MV-VALOR  *S0C7

             * PREVENÇÃO: inicialize e valide antes de operar
           INITIALIZE WS-VALOR           *zera numericos, spaces em alfanum
           IF MV-VALOR IS NOT NUMERIC
               PERFORM 9000-DADO-INVALIDO
           ELSE
               ADD MV-VALOR TO WS-TOTAL
           END-IF

S013 — DCB Mismatch

COBOL S013 — LRECL diferente entre JCL e FD
      *--- No programa COBOL ---*
       FD  ARQ-MOVIMENTO
           RECORD CONTAINS 150 CHARACTERS.
       01  REG-MOVIMENTO    PIC X(150).

      *--- No JCL ---*
      * //DDMOVTO DD DSN=PROD.MOVIMENTO,DISP=SHR,LRECL=120  ← 120 ≠ 150 → S013

      * SOLUÇÃO: alinhar LRECL do JCL com RECORD CONTAINS do FD
      * //DDMOVTO DD DSN=PROD.MOVIMENTO,DISP=SHR,LRECL=150

3. Abends de usuário — códigos U

Abends U são gerados por software — middleware, subsistemas ou pelo próprio programa via CALL 'CEE3ABD' ou ABEND:

CódigoOrigem típicaSignificado
U0001–U0999Programa de aplicaçãoAbend explícito do próprio código — verifique a lógica da aplicação
U4038DB2SQLCODE não tratado — programa fechou sem fazer COMMIT ou ROLLBACK
U4039DB2Deadlock ou timeout de lock DB2
U1026CICSTransação CICS abortada — tarefa encerrada pelo sistema
U4093IMS/DBErro de acesso a banco IMS — status code não tratado
U0016SORT/DFSORTErro no SORT — geralmente espaço insuficiente para os work files
COBOL Gerando abend de usuário explicitamente
             * Forma portável via LE (Language Environment)
           CALL 'CEE3ABD' USING
               WS-ABEND-CODE     *PIC 9(04) COMP — código U que aparecerá
               WS-CLEANUP-FLAG   *PIC 9(04) COMP — 0=sem cleanup, 1=com
               WS-FC             *feedback code do LE

             * Forma alternativa: MOVE código e usar ILLOGIC no tratamento
             * Em muitos sistemas legados, usa-se simplesmente:
           MOVE 0016 TO RETURN-CODE
           STOP RUN   *encerra com RC=16 para o JCL tratar via COND

4. Lendo as mensagens do job

Quando um job aborta, as informações de diagnóstico aparecem no SYSOUT (normalmente na DD SYSOUT=* do step). Saiba onde olhar:

Sysout Mensagens típicas de abend no SYSOUT
  IEA995I SYMPTOM DUMP OUTPUT
    SYSTEM COMPLETION CODE=0C7  REASON CODE=00000001
    TIME=14.32.07  SEQ=01234  CPU=0000  ASID=00AB
    PSW AT TIME OF ERROR  078D1000  80F9C2B4
    FAILING INSTRUCTION ADDRESS: 00F9C2B4
    PROGRAM=CALCPARC   OFFSET=00000B4

  CEE3501I  THE FOLLOWING MESSAGES ARE FROM THE LANGUAGE ENVIRONMENT:

  CEE3207S  A data exception (system completion code=0C7) occurred at
            offset X'0000B4' in CALCPARC.
            The name of the failing routine is CALCPARC.
            The offset from the start of 2000-PROCESSA is X'0058'.

  IEF450I JOBNAME CALCJOB  - ABEND=S0C7  U0000  REASON=00000001

✅ Informações-chave para o diagnóstico

  • COMPLETION CODE — o código do abend (S0C7, S0C1 etc.)
  • PROGRAM — qual módulo estava executando quando abortou
  • OFFSET — deslocamento em bytes dentro do módulo (use o compilador listing para mapear no parágrafo)
  • FAILING INSTRUCTION ADDRESS — endereço de memória da instrução problemática

5. CEEDUMP — o relatório de erro do Language Environment

O CEEDUMP é o relatório de diagnóstico gerado automaticamente pelo Language Environment (LE) quando ocorre um abend. É muito mais legível do que um dump bruto (SYSUDUMP). Para habilitá-lo, defina a DD no JCL:

JCL DDs de diagnóstico no JCL
  //CALCSTEP EXEC PGM=CALCPARC
  //STEPLIB  DD DSN=PROD.LOADLIB,DISP=SHR
  //DDMOVTO  DD DSN=PROD.MOVIMENTO,DISP=SHR
  //DDSAIDA  DD DSN=PROD.RESULTADO,DISP=(NEW,CATLG),
  //            SPACE=(CYL,(1,1)),RECFM=FB,LRECL=60
  //SYSOUT   DD SYSOUT=*
  //CEEDUMP  DD SYSOUT=*      ← relatório do LE (recomendado)
  //SYSUDUMP DD SYSOUT=*      ← dump bruto de memória (opcional)
Sysout Exemplo de CEEDUMP — trecho relevante
  CEE3DMP  - - - - - - - - - - - Language Environment Dump - - - - - - -

  Condition Information for Active Routines
  Condition: CEE3207S Data exception at offset X'0B4' in CALCPARC

  Call Chain:
    DSA  Entry       E_SP Offset  Statement  Load Mod  Service
    ---- ----------  ---- ------  ---------  --------  -------
    0001 CALCPARC    0001 000000B4 2100       CALCPARC
    0002 CALCPARC    0001 00000068 2000       CALCPARC
    0003 CALCPARC    0001 00000030 0000       CALCPARC

  Storage Around PSW:
  ...

  Working Storage at time of abend:
  WS-VALOR    = 40404040404040404040  (espaços — campo não inicializado!)

O CEEDUMP mostra a call chain — a pilha de parágrafos ativos no momento do abend — e os valores dos campos de Working Storage. Com isso, você consegue identificar qual parágrafo chamou qual, e qual campo tinha valor inválido.

6. Debugging com DISPLAY

Na ausência de ferramenta de debug interativa, o DISPLAY é o recurso mais direto: imprime valores no SYSOUT enquanto o programa executa:

COBOL DISPLAY para diagnóstico
             * Forma básica — imprime no SYSOUT (DD SYSOUT do step)
           DISPLAY 'INICIANDO 2100-PROCESSA'
           DISPLAY 'MV-CPF   = ' MV-CPF
           DISPLAY 'MV-VALOR = ' MV-VALOR
           DISPLAY 'WS-TOTAL = ' WS-TOTAL

             * DISPLAY UPON — direciona para DD específica
           DISPLAY 'ERRO: CPF INVALIDO = ' WS-CPF
               UPON SYSOUT           *SYSOUT padrão
           DISPLAY 'DEBUG: REG = ' REG-ENTRADA
               UPON CONSOLE          *console do operador

             * Estratégia de fence — imprime antes e depois do ponto suspeito
           DISPLAY '>>> ANTES DO ADD'
           DISPLAY '    MV-VALOR HEX = ' MV-VALOR
           ADD MV-VALOR TO WS-TOTAL   *linha suspeita do S0C7
           DISPLAY '<<< DEPOIS DO ADD'
           DISPLAY '    WS-TOTAL = ' WS-TOTAL

             * Mostrar conteúdo em hexa via MOVE para campo exibível
       01  WS-HEX-DISPLAY   PIC X(20).
           MOVE MV-VALOR TO WS-HEX-DISPLAY
           DISPLAY 'CONTEUDO RAW: ' WS-HEX-DISPLAY

💗 Para iniciantes — DISPLAY não aparece no terminal

O DISPLAY em batch escreve na DD SYSOUT do step — você vê a saída no output do job no SPOOL (ISPF opção 3.8 ou SDSF). Não é um print interativo como em linguagens modernas. Se o programa abortou antes do DISPLAY ser executado, você não verá a mensagem. Use DISPLAYs anteriores ao ponto suspeito como "confirmação de que chegou aqui".

7. Técnicas de diagnóstico passo a passo

Um método estruturado para investigar um abend:

Processo Roteiro de diagnóstico de abend
  PASSO 1 — Identifique o código do abend
    → Leia a mensagem IEF450I no SYSOUT
    → Anote: código (ex: S0C7), programa, offset

  PASSO 2 — Localize no fonte usando o listing do compilador
    → O compilador gera um listing com mapa de offsets
    → Procure o offset no listing para saber a linha COBOL exata
    → Opção OFFSET ou LIST no compilador Enterprise COBOL

  PASSO 3 — Leia o CEEDUMP ou SYSUDUMP
    → Call chain: qual parágrafo chamou qual
    → Valores dos campos no momento do abend
    → Identifique o campo com valor inválido

  PASSO 4 — Adicione DISPLAYs e execute novamente
    → Imprima o campo suspeito ANTES da instrução que falhou
    → Confirme o valor inválido
    → Rastreie de onde esse valor veio

  PASSO 5 — Identifique a raiz do problema
    → O campo tinha valor inválido desde a leitura do arquivo?
    → Foi corrompido por um MOVE errado?
    → A inicialização estava faltando?
    → O arquivo de entrada tem um registro com formato diferente?

  PASSO 6 — Corrija e valide
    → Adicione validação IS NUMERIC antes da operação
    → Inicialize campos antes de usar
    → Verifique o layout do arquivo de entrada

Usando o listing do compilador para localizar o offset

JCL Compilando com opções de diagnóstico
  //COMPILE  EXEC PGM=IGYCRCTL,
  //  PARM='OFFSET,LIST,MAP,XREF,SOURCE'
  //          ↑      ↑    ↑   ↑     ↑
  //       offset  código mapa xref fonte
  //       no lst  objeto vars     completo
  //SYSPRINT DD SYSOUT=*    ← listing aqui
  //SYSIN    DD DSN=PROD.SOURCE(CALCPARC),DISP=SHR
Listing Trecho do listing com offsets — localiza o abend
  LineID  Offset  Verb        Source
  ------  ------  ----------  ----------------------------------------
   00145  0000A8  PERFORM     PERFORM 2100-ATUALIZA-SALDO
   00150  0000B0  MOVE        MOVE MV-CPF TO CLI-CPF
   00151  0000B4  ADD         ADD MV-VALOR TO WS-TOTAL   ← OFFSET B4 → aqui!

✅ Offset no listing = localização exata do abend

O offset X'0B4' do CEEDUMP corresponde ao offset 0000B4 do listing. É a linha ADD MV-VALOR TO WS-TOTAL — confirma que MV-VALOR tinha conteúdo inválido. Agora você sabe exatamente onde investigar. Peça ao seu ambiente o SYSPUNCH ou SYSLIST do compilador com a opção OFFSET sempre que precisar depurar.

8. Prevenindo abends comuns

Validação de campos numéricos antes de operar

COBOL IS NUMERIC — validação defensiva
             * IS NUMERIC verifica se o campo contém dígitos válidos
             * para PIC 9: dígitos 0-9
             * para PIC S9: dígitos + sinal válido
           IF MV-VALOR IS NOT NUMERIC
               DISPLAY 'ERRO: MV-VALOR INVALIDO = ' MV-VALOR
               ADD 1 TO WS-QTD-ERROS
               MOVE 'E' TO SA-STATUS
           ELSE
               ADD MV-VALOR TO WS-TOTAL
           END-IF

             * IS ALPHABETIC, IS ALPHABETIC-LOWER, IS ALPHABETIC-UPPER
           IF WS-TIPO IS NOT ALPHABETIC
               PERFORM 9000-TIPO-INVALIDO
           END-IF

INITIALIZE garante estado limpo

COBOL Inicialização defensiva de áreas de trabalho
             * Inicialize áreas de trabalho antes de usar
       1000-INICIALIZA.
           INITIALIZE WS-AREA-TRABALHO
                      WS-CONTADORES
                      WS-ACUMULADORES
             * INITIALIZE zera PIC 9 e coloca SPACES em PIC X
             * Elimina o X'00' (LOW-VALUE) que causa S0C7

             * Para campos que leram do arquivo, valide antes de usar
           READ ARQ-ENTRADA
               AT END SET FIM-ARQUIVO TO TRUE
           END-READ
           IF NOT FIM-ARQUIVO
               IF MV-VALOR IS NUMERIC
                   PERFORM 2000-PROCESSA
               ELSE
                   PERFORM 9100-DADO-INVALIDO
               END-IF
           END-IF

Verificar FILE STATUS sempre após OPEN

COBOL Verificação defensiva de FILE STATUS
       1100-ABRE-ARQUIVOS.
           OPEN INPUT  ARQ-ENTRADA
           IF WS-FS-ENT NOT = '00'
               DISPLAY 'ERRO OPEN ENTRADA: FS='  WS-FS-ENT
               MOVE 16 TO RETURN-CODE
               STOP RUN
           END-IF

           OPEN OUTPUT ARQ-SAIDA
           IF WS-FS-SAI NOT = '00'
               DISPLAY 'ERRO OPEN SAIDA: FS=' WS-FS-SAI
               CLOSE ARQ-ENTRADA
               MOVE 16 TO RETURN-CODE
               STOP RUN
           END-IF.

9. Exemplo completo — diagnóstico de S0C7

Cenário real: o job CALCJOB abortou com S0C7 no programa CALCPARC. Veja o processo completo de diagnóstico:

Sysout PASSO 1 — Mensagem de abend no SYSOUT
  IEA995I SYMPTOM DUMP OUTPUT
    SYSTEM COMPLETION CODE=0C7
    PROGRAM=CALCPARC  OFFSET=000000B4

  CEE3207S Data exception at offset X'B4' in CALCPARC
           Offset from 2100-ATUALIZA-SALDO: X'0058'
Listing PASSO 2 — Localização no listing do compilador
  Offset  Stmt  Source
  0000AC  148   PERFORM 2100-ATUALIZA-SALDO
  0000B0  149   MOVE MV-CPF TO CLI-CPF
  0000B4  150   ADD MV-VALOR TO WS-TOTAL-GERAL   ← ponto do abend
CEEDUMP PASSO 3 — Valor do campo no CEEDUMP
  Working Storage Variables at time of abend:
  MV-VALOR  offset 0023  PIC S9(11)V99  COMP-3
  Contents: 4040404040404040  ← X'40' = espaço em EBCDIC
  Expected: valid packed decimal digits
COBOL PASSO 4 — DISPLAYs adicionados para confirmar
       2100-ATUALIZA-SALDO.
           DISPLAY 'DEBUG 2100 - MV-CPF   = ' MV-CPF
           DISPLAY 'DEBUG 2100 - MV-VALOR = ' MV-VALOR
           DISPLAY 'DEBUG 2100 - MV-TIPO  = ' MV-TIPO
           ADD MV-VALOR TO WS-TOTAL-GERAL   *linha do S0C7

             * Saída no SYSOUT:
             * DEBUG 2100 - MV-CPF   = 12345678901
             * DEBUG 2100 - MV-VALOR =            (espaços!)
             * DEBUG 2100 - MV-TIPO  = C
             * → MV-VALOR está vazio. O arquivo tem um registro sem valor.
COBOL PASSO 5 e 6 — Correção aplicada
       2100-ATUALIZA-SALDO.
                 * Validação defensiva antes de operar
           IF MV-VALOR IS NOT NUMERIC
               DISPLAY 'AVISO: MV-VALOR INVALIDO CPF=' MV-CPF
                       ' VALOR=' MV-VALOR
               ADD 1 TO WS-QTD-REJEITADOS
               EXIT PARAGRAPH
           END-IF
           ADD MV-VALOR TO WS-TOTAL-GERAL
           ADD 1         TO WS-QTD-PROCESSADOS.

🟣 Para quem já programa — COBTEST e ferramentas interativas

O IBM Enterprise COBOL oferece o COBTEST (Debug Tool / z/OS Debugger) — um debugger interativo que permite definir breakpoints, inspecionar campos em tempo real e executar passo a passo sem precisar recompilar com DISPLAYs. Exige compilar com a opção TEST e ter o z/OS Debugger licenciado. Em ambientes com Rational Developer for System z (RDz) ou IBM Developer for z/OS (IDz), o debug visual fica ainda mais acessível. Pergunte ao time de infraestrutura se essa ferramenta está disponível — ela poupa horas de diagnóstico em casos complexos.