Este artigo reúne tudo que aprendemos na trilha em um programa real e completo: lê um arquivo de registros de clientes, valida campos, conta registros por tipo e gera um relatório de sumário. Pelo caminho, veremos as macros de diagnóstico SNAP e ABEND, como interpretar um dump de Assembler e dicas práticas para quem vai trabalhar com código legado.
1. Especificação do programa
O programa SUMREC01 processa um arquivo de clientes com registros de 80 bytes:
- Lê cada registro do dataset SYSIN
- Identifica o tipo pelo campo TIPO (posição 1, 1 byte):
C=corporativo, P=pessoa física, X=cancelado
- Conta registros por tipo e o total
- Ao final, grava um relatório de sumário em SYSPRINT
- Retorna RC=0 se OK, RC=8 se erro de I/O, RC=12 se dado inválido
2. Estrutura e layout de dados
Layout do registro de entrada (80 bytes):
Posição 1 (1 byte) TIPO: C=corp, P=pf, X=cancel
Posição 2-11 (10 bytes) CODCLI: código do cliente
Posição 12-51 (40 bytes) NOMCLI: nome do cliente
Posição 52-80 (29 bytes) RESTANTE: demais campos
Layout da linha de relatório (133 bytes, FBA):
Posição 1 (1 byte) ASA: controle de formulário
Posição 2-132 (131 bytes) texto do relatório
3. Código completo anotado
* SUMREC01 — Sumarizador de registros de clientes
SUMREC01 CSECT
* ── PRÓLOGO ──────────────────────────────────────────
STM R14,R12,12(R13)
BALR R12,0
USING *,R12
ST R13,SAVAREA+4
LA R13,SAVAREA
* ── INICIALIZAR CONTADORES ───────────────────────────
SR R2,R2 R2 = contador corporativos
SR R3,R3 R3 = contador PF
SR R4,R4 R4 = contador cancelados
SR R5,R5 R5 = contador total
* ── ABRIR ARQUIVOS ───────────────────────────────────
OPEN (ENTRADA,(INPUT),SAIDA,(OUTPUT))
TM ENTRADA+48,X'10'
BZ ERROPEN
* ── LOOP DE LEITURA ──────────────────────────────────
RDLOOP GET ENTRADA,INREC
A R5,=F'1' Total++
* Classificar por tipo
CLI INREC,C'C' Corporativo?
BE ECORP
CLI INREC,C'P' Pessoa física?
BE EPF
CLI INREC,C'X' Cancelado?
BE ECANC
B EINVAL Tipo desconhecido
ECORP A R2,=F'1' Corporativos++
B RDLOOP
EPF A R3,=F'1' PF++
B RDLOOP
ECANC A R4,=F'1' Cancelados++
B RDLOOP
* Tipo inválido — gravar mensagem e setar RC=12
EINVAL MVC ERRMSG(10),INREC Copia início do registro
WTO 'SUMREC01: TIPO INVALIDO ENCONTRADO'
LA R15,12
ST R15,RCFINAL
B RDLOOP
* ── FIM DO ARQUIVO ───────────────────────────────────
FIMFILE BAL R10,RELATORIO Gerar relatório
CLOSE (ENTRADA,,SAIDA)
* ── EPÍLOGO ──────────────────────────────────────────
L R13,SAVAREA+4
LM R14,R12,12(R13)
L R15,RCFINAL Return Code
BR R14
* ── SUBROTINA: GERAR RELATÓRIO ────────────────────────
RELATORIO DS 0H
* Linha 1 — cabeçalho
MVI OUTREC,C'1' ASA: nova página
MVC OUTREC+1(30),=CL30'SUMREC01 - SUMARIO DE CLIENTES'
PUT SAIDA,OUTREC
* Linha 2 — corporativos (converter R2 para texto)
MVI OUTREC,C' '
MVC OUTREC+1(132),OUTREC
MVC OUTREC+1(15),=CL15'CORPORATIVOS: '
CVD R2,WORKDBL R2 → packed decimal em WORKDBL
UNPK WORK8(8),WORKDBL+4(4) Unpacked → zona decimal
OI WORK8+7,X'F0' Fix last digit sign
MVC OUTREC+16(8),WORK8
PUT SAIDA,OUTREC
* Linha 3 — PF (mesmo padrão)
MVI OUTREC,C' '
MVC OUTREC+1(132),OUTREC
MVC OUTREC+1(15),=CL15'PESSOA FISICA: '
CVD R3,WORKDBL
UNPK WORK8(8),WORKDBL+4(4)
OI WORK8+7,X'F0'
MVC OUTREC+16(8),WORK8
PUT SAIDA,OUTREC
* Linha 4 — total
MVI OUTREC,C' '
MVC OUTREC+1(132),OUTREC
MVC OUTREC+1(15),=CL15'TOTAL: '
CVD R5,WORKDBL
UNPK WORK8(8),WORKDBL+4(4)
OI WORK8+7,X'F0'
MVC OUTREC+16(8),WORK8
PUT SAIDA,OUTREC
BR R10 Retorna ao chamador (FIMFILE)
* ── ERRO DE OPEN ─────────────────────────────────────
ERROPEN WTO 'SUMREC01: ERRO AO ABRIR ARQUIVO'
LA R15,8
B SAIRCOD
SAIRCOD L R13,SAVAREA+4
LM R14,R12,12(R13)
BR R14
* ── DCBs ─────────────────────────────────────────────
ENTRADA DCB DSORG=PS,MACRF=(GM),DDNAME=SYSIN,
RECFM=FB,LRECL=80,BLKSIZE=800,
EODAD=FIMFILE
SAIDA DCB DSORG=PS,MACRF=(PM),DDNAME=SYSPRINT,
RECFM=FBA,LRECL=133,BLKSIZE=1330
* ── DADOS ────────────────────────────────────────────
SAVAREA DS 18F
INREC DS CL80
OUTREC DS CL133
ERRMSG DS CL10
WORKDBL DS D Doubleword para CVD
WORK8 DS CL8 Área de trabalho numérica
RCFINAL DC F'0' Return Code inicial = 0
END SUMREC01
4. SNAP e diagnóstico de dumps
Quando um programa Assembler falha com ABEND, o z/OS pode gerar um dump — uma imagem da memória no momento do abend. A macro SNAP permite gerar um dump parcial em pontos específicos do código para debug:
Configuração para SNAP (precisa de DCB própria):
SNAP DCB=SNAPDCB, Dataset onde o dump vai
PDATA=(REGS), Inclui registradores
ID=1 Identificador do snap
SNAPDCB DCB DSORG=PS,MACRF=(W),DDNAME=SNAPDD,
RECFM=VBA,LRECL=125,BLKSIZE=1632
No JCL:
//SNAPDD DD SYSOUT=*
Como ler um dump de Assembler:
1. PSW (Program Status Word) — mostra o endereço onde o abend ocorreu
2. Registradores no momento do abend (R0-R15)
3. Mapa de memória — identificar DCBs, buffers, savearea
4. Usar o listing do assembler para mapear endereço → instrução
O listing do assembler (PARM='OBJECT,NODECK,XREF(SHORT)' gera o listing no SYSPRINT) é essencial para debug: ele mostra o endereço de cada instrução, o endereço de cada label e a expansão de cada macro.
5. Dicas para código legado
| Situação | O que verificar |
| ABEND S0C1 (operação inválida) |
Dado não-numérico em instrução aritmética; ponteiro inválido; branch para endereço errado |
| ABEND S0C4 (proteção de armazenamento) |
Acesso a área de memória sem autorização; R13 corrompido; savearea sobrescrita |
| ABEND S0C7 (exceção de dados) |
Campo packed decimal (P) com conteúdo inválido (não-numérico) |
| ABEND S322 (time exceeded) |
Loop infinito; espera por recurso; processamento maior que o esperado |
| ABEND S806 (módulo não encontrado) |
Nome de módulo errado; STEPLIB ou JOBLIB não inclui a biblioteca |
💡 Preservação de registradores em código legado
Código Assembler antigo frequentemente usa registradores como R10, R11 para múltiplos fins ao longo do programa. Antes de modificar qualquer subrotina existente, mapeie quais registradores o código usa como base registers adicionais, quais são usados como ponteiros de dados e quais são usados como registradores de trabalho. Uma mudança inocente que altera R11 pode corromper o endereçamento de uma seção inteira do programa.
6. Próximos passos
Com a base desta trilha, você já consegue ler e modificar programas Assembler legados. Os tópicos avançados para continuar:
| Tópico | Para que serve |
| AMODE/RMODE (31-bit / 64-bit) | Programas que acessam memória acima de 16MB / 2GB |
| SVCs e macros de sistema | Chamadas diretas ao z/OS — DYNALLOC, ENQ/DEQ, STORAGE |
| Programas reentrantes | Código que pode ser executado simultaneamente por múltiplos usuários |
| Assembler em CICS | Comandos EXEC CICS em módulos Assembler |
| Instruções SIMD (z14+) | Operações vetoriais para processamento em massa de dados |