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ódigo | Nome | Causa típica em COBOL |
|---|---|---|
S0C1 | Operation Exception | Execução de dado como instrução — geralmente GOBACK/STOP RUN esquecido ou controle caindo além do fim da Procedure Division |
S0C4 | Protection Exception | Acesso a endereço de memória inválido — ponteiro nulo em CALL, subscript negativo ou muito alto em alguns contextos |
S0C5 | Addressing Exception | Subscript ou Reference Modification fora dos limites do campo |
S0C7 | Data Exception | Campo numérico (PIC 9) com espaços, letras ou caracteres inválidos em operação aritmética |
S013 | DCB Mismatch | LRECL ou RECFM do arquivo no JCL diferente do declarado no FD do programa |
S122 | Time Limit Exceeded (Cancel) | Operador cancelou o job (ou job foi cancelado por política) |
S222 | Job Cancelled | Job cancelado por operador ou pelo próprio sistema |
S322 | CPU Time Exceeded | Loop infinito ou processamento muito demorado (ultrapassou TIME= do JOB) |
S806 | Load Module Not Found | Programa chamado via CALL dinâmico não encontrado no STEPLIB/JOBLIB |
S878 | Out of Memory | Programa alocou mais memória do que disponível na região |
SB37 | Dataset Full | Arquivo de saída encheu — SPACE insuficiente no JCL |
SD37 | Dataset Full (sem secondary) | Arquivo encheu e não tem alocação secundária definida |
S0C7 — o abend mais comum em COBOL
* 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
*--- 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ódigo | Origem típica | Significado |
|---|---|---|
U0001–U0999 | Programa de aplicação | Abend explícito do próprio código — verifique a lógica da aplicação |
U4038 | DB2 | SQLCODE não tratado — programa fechou sem fazer COMMIT ou ROLLBACK |
U4039 | DB2 | Deadlock ou timeout de lock DB2 |
U1026 | CICS | Transação CICS abortada — tarefa encerrada pelo sistema |
U4093 | IMS/DB | Erro de acesso a banco IMS — status code não tratado |
U0016 | SORT/DFSORT | Erro no SORT — geralmente espaço insuficiente para os work files |
* 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:
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:
//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)
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:
* 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:
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
//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
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
* 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
* 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
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:
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'
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
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
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.
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.