はじめに
アプリケーションを開発/修正する際には、コードを実際に動かしてみてトライ&エラーを繰り返すということはよくある話です。その際にデバッガーを使ってコードをステップ実行させたり、稼働中の変数の状態を確認したりすることは有用です。
ここでは、Eclipseのツールからデバッガーを使ってz/OS上のアプリケーション(COBOL)を動かしてみます。
当記事ではWazi Developer for Eclipse(V1.1.0)を使ってみた時の内容を記載します。
関連記事
Eclipseを使用したメインフレーム・アプリケーション開発 - (1)概要
Eclipseを使用したメインフレーム・アプリケーション開発 - (2)z/OS基本操作
Eclipseを使用したメインフレーム・アプリケーション開発 - (3)ソース編集
Eclipseを使用したメインフレーム・アプリケーション開発 - (4)ソース管理ツール/ビルドツール連携
Eclipseを使用したメインフレーム・アプリケーション開発 - (5)デバッガーの利用
全体像
ざっくりとしたデバッガーの利用イメージは上の図の通りです。ホスト上でDebugger機能を導入構成しておき、Eclipse側ではデバッグ情報を受け取るデーモン(Debug UI Daemon)を準備しておいて、Eclipse上でデバッグ(ステップ実行など)を行います。
ここでz/OS Debuggerというのはz/OS上で稼働するデバッグ機能を提供するコンポーネントを表しています。IBMさんのプロダクトは相変わらず製品体系や名前が分かりにくいものが多いですね。
IBM z/OS Debugger, IBM Debug for z/OS, IBM Debug for z Systemsなど少しずつ表記にゆらぎがあったりします。この機能は単体製品として提供されているものもありますし、IBM Developer for z/OS や IBM Wazi Developer for Red Hat CodeReady Workspacesなどに含まれて提供されていたりします。Continuous Deliveryなのでまたそれがさらにややこしい...。
ここではz/OS Debuggerと表記しますが、いずれにしても有償製品に付属しているデバッガー機能を指します。
z/OS Debuggerはずいぶん前から提供されている機能で、3270端末エミュレーター(PCOMなど)をUIとしてデバッグするようなこともできますが、ここではEclipseをUIとして考えているので、画面をリモート(ここではEclipse)に飛ばす、"リモート・デバッグ"と呼ばれるやり方にフォーカスします。また、デバッグ対象のアプリケーションも言語環境やミドルウェア(バッチ、CICS、IMSなど)によってもやり方は変わってくるのですが、とりあえずここではシンプルなCOBOLバッチのケースを試してみます。
※ここで注意が必要なのは、z/OS側からPC上のEclipseに対してTCPのコネクションを張る必要があるということです。z/OSのネットワークの構成としてそのような方向のコネクション確立が許されていないケースもあるのでその場合は別途考慮が必要です(後述)。
参考
IBM z/OS Debugger の概要
What's new in IBM z/OS Debugger V15.0
Installation of IBM Developer for z Systems and IBM Debug for z Systems
Announcement Letter - IBM Application Delivery Foundation for z/OS 3.3 and IBM Developer for z/OS Enterprise Edition 15.0 expand IDE choices to include support for Red Hat CodeReady Workspaces and move to Eclipse Photon 4.8 in alignment with IBM Explorer for z/OS Aqua 3.2
IBM Debug for z/OS
構成(事前準備)
今回はIBM Wazi Developer for Red Hat CodeReady Workspacesを使った場合の例を示します。この製品はOpenShift上で稼働するz/OSエミュレーターが提供されていますが、はじめからz/OS Debuggerの構成もされた状態となっています。
z/OS側
z/OS側の構成はここでは詳細は割愛します。基本はドキュメントの記述に従って構成してください。
参考: z/OS Debugger
ここでは、IBM Wazi Developer for Red Hat CodeReady WorkspacesV1.1.0のSandboxでデフォルトで提供されているz/OS Debuggerの構成をそのまま使用します。
Eclipse側
Debug UI Daemonの有効化
デバッグ・パースペクティブ - デバッグ・ビューから、以下のアイコンをクリックして、"Start listening on port: 8001"を選択します。
アイコンが緑色に変わればOKです。これで、Debug UI Daemonが有効化され、8001番ポートでListenしている状態になります。
ビジュアル・デバッグの有効化
ついでにビジュアル・デバッグ機能を有効化しておきます。デバッグ・パースペクティブで、以下のアイコンをクリックし、"ビジュアル・デバッグを有効にする"を選択します。
アイコン上の斜線が消えればOKです。
SSHポートフォワードの設定
今回、ホストは実際のz/OSではなくWaziというオープンシフト上で稼働するz/OSエミュレーターを使用する想定です。この環境は、z/OSから外部へのTCP/IP接続が制限されているのでそのままではデバッガーのセッションが張れません。そこで、今回はSSHポートフォワードの設定を行っておくことにします。
※z/OSからPCへのTCPコネクション確立が可能な環境であれば当設定は不要です。
事前にSSHのトンネルを作っておくことで、z/OS側のDebuggerからローカルの18001ポートに接続するとそれがPC側の8001番ポートにフォワードされるようにしておきます。
SSHポートフォワードを行うので、当然のことながらz/OS側にはSSHサーバーを立てておく必要があります。
Windowsからsshコネクションを張るにはsshクライアントが必要ですが、WSL(Windows Subsystem for Linux)を使うのが手っ取り早いと思いますので、ここではWSLからsshコマンドを使うことにします。
(teratermなどでも可です。参考: SSH転送(ポートフォワード) )
WSLの端末から以下のコマンドを実行しておきます。
$ ssh -p 31175 -N -f -R 18001:localhost:8001 -o 'StrictHostKeyChecking no' -o 'ServerAliveInterval=60' -o 'ServerAliveCountMax=3' TAGUCHI@OCPW01
-R 18001:localhost:8001
という指定が、リモート(z/OS側)の18001ポートをlocalhostの8001ポートにフォワードすることを意味しています。
※複数ユーザーで同一z/OSに接続してデバッグ実行する場合は、z/OS側でListenするポート番号(ここでは18001)がバッティングしないよう、ユーザーごとにポート番号を使い分けるなど考慮が必要です。
使用例
サンプルCOBOLプログラム準備
COBOLソース作成
単純なCOBOLソースを準備します。
ソース: HELLO1
***************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO1.
ENVIRONMENT DIVISION.
*****************************************************************
DATA DIVISION.
*****************************************************************
WORKING-STORAGE SECTION.
*****************************************************************
*
01 SYSTEM-DATE-AND-TIME.
05 CURRENT-DATE.
10 CURRENT-YEAR PIC 9(2).
10 CURRENT-MONTH PIC 9(2).
10 CURRENT-DAY PIC 9(2).
05 CURRENT-TIME.
10 CURRENT-HOUR PIC 9(2).
10 CURRENT-MINUTE PIC 9(2).
10 CURRENT-SECOND PIC 9(2).
10 CURRENT-HNDSEC PIC 9(2).
*****************************************************************
PROCEDURE DIVISION.
*****************************************************************
000-MAIN.
DISPLAY "***** Begin *****".
ACCEPT CURRENT-DATE FROM DATE.
ACCEPT CURRENT-TIME FROM TIME.
DISPLAY 'SAM1 STARTED DATE = ' CURRENT-MONTH '/'
CURRENT-DAY '/' CURRENT-YEAR ' (mm/dd/yy)'.
DISPLAY ' TIME = ' CURRENT-HOUR ':'
CURRENT-MINUTE ':' CURRENT-SECOND.
DISPLAY "HELLO WORLD!".
DISPLAY "***** End *****".
GOBACK .
コンパイル/リンク
コンパイル/リンク用JCL
//HELCOM JOB ,NOTIFY=&SYSUID,
// MSGCLASS=H,MSGLEVEL=(1,1),REGION=0M
//*****************************************************************
// SET HLQ='TAGUCHI' *TSO USER ID
// SET CMPLLIB='IGY630.SIGYCOMP' *COMPILER LIBRARY
// SET LINKLIB='CEE.SCEELKED' *LINK LIBRARY
// SET SPACE1='SYSALLDA,SPACE=(CYL,(1,1))' *SPACE ALLOCATION
// SET SPACE2='SYSALLDA,SPACE=(CYL,(1,1))' *SPACE ALLOCATION
//*
//***************************
//* *
//* COMPILE HELLO1 **
//* *
//***************************
//*
//CMPLHEL1 EXEC PGM=IGYCRCTL,PARM='LIST,MAP,NODYN,TEST(SOURCE)'
//STEPLIB DD DISP=SHR,DSN=&CMPLLIB
//SYSIN DD DISP=SHR,DSN=&HLQ..SAMPLE.COBOL(HELLO1)
//SYSLIB DD DISP=SHR,DSN=&HLQ..SAMPLE.COBCOPY
//SYSLIN DD DISP=OLD,DSN=&HLQ..SAMPLE.OBJ(HELLO1)
//SYSPRINT DD SYSOUT=*
//SYSMDECK DD UNIT=&SPACE1
//SYSUT1 DD UNIT=&SPACE1
//SYSUT2 DD UNIT=&SPACE1
//SYSUT3 DD UNIT=&SPACE1
//SYSUT4 DD UNIT=&SPACE1
//SYSUT5 DD UNIT=&SPACE1
//SYSUT6 DD UNIT=&SPACE1
//SYSUT7 DD UNIT=&SPACE1
//SYSUT8 DD UNIT=&SPACE1
//SYSUT9 DD UNIT=&SPACE1
//SYSUT10 DD UNIT=&SPACE1
//SYSUT11 DD UNIT=&SPACE1
//SYSUT12 DD UNIT=&SPACE1
//SYSUT13 DD UNIT=&SPACE1
//SYSUT14 DD UNIT=&SPACE1
//SYSUT15 DD UNIT=&SPACE1
//*
//***************************
//* *
//* LINK HELLO1 *
//* *
//***************************
//*
//LINKHEL1 EXEC PGM=IEWL,REGION=3000K
//SYSLMOD DD DISP=SHR,DSN=&HLQ..SAMPLE.LOAD
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD UNIT=&SPACE2
//SYSLIB DD DISP=SHR,DSN=&LINKLIB
// DD DISP=SHR,DSN=&HLQ..SAMPLE.LOAD
//OBJ DD DISP=SHR,DSN=&HLQ..SAMPLE.OBJ
//SYSLIN DD *
INCLUDE OBJ(HELLO1)
NAME HELLO1(R)
/*
デバッグを行うためにコンパイル・オプションとしてTEST(SOURCE)
を追加してコンパイル/リンクします。
参考: COBOL プログラムでの TEST または NOTEST コンパイラー・サブオプションの選択
実行用JCL準備
実行用JCL
//HELRUN2 JOB ,NOTIFY=&SYSUID,
// MSGCLASS=H,MSGLEVEL=(1,1),REGION=0M
//*****************************************************************
// SET HLQ='TAGUCHI' *TSO USER ID
// SET CMPLLIB='IGY630.SIGYCOMP' *COMPILER LIBRARY
// SET LINKLIB='CEE.SCEELKED' *LINK LIBRARY
// SET SPACE1='SYSALLDA,SPACE=(CYL,(1,1))' *SPACE ALLOCATION
// SET SPACE2='SYSALLDA,SPACE=(CYL,(1,1))' *SPACE ALLOCATION
//*
//*************************
//* RUN HELLO1
//*************************
//HELLO1 EXEC PGM=HELLO1
//STEPLIB DD DSN=EQAF00.SEQAMOD,DISP=SHR
// DD DSN=&HLQ..SAMPLE.LOAD,DISP=SHR
//CEEOPTS DD *
TEST(,,,TCPIP&localhost%18001:*)
//*
//SYSOUT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//*
デバッグを行うために、ランタイム・オプションとしてCEEOPTS DDにてTEST(,,,TCPIP&localhost%18001:*)
を追加しています。ここで指定しているlocalhost%18001
はDebug UI DaemonがListenしているアドレス+ポートです。今回はポートフォワード設定をしているので、localhostの18001番ポートを指定しています。
また、STEPLIBにてデバッガーのライブラリ(EQAF00.SEQAMOD)をロードモジュールのライブラリより上位にコンカチしています。
参考:
z/OS Debugger を開始する方法の選択
例: TEST ランタイム・オプション
Language Environment®内で始動される プログラムのための z/OS Debugger の始動
Debug実行
実際にDebugを行ってみます。
プログラム実行
上で準備したTESTランタイムオプション付きJCLをSubmitします。
以下のメッセージが出るので"切り替え"をクリックしてデバッグ・パースペクティブに切り替えます。
デバッグセッションでの操作
デバッグ・パースペクティブに切り替えると、デバッグ対象のソースが表示されてステップ実行などが行えるようになります。変数の状態や、ビジュアル・デバッグ・ビューにてプログラムの構造などを確認しながらデバッグを行うことができます。
おわりに
ここではシンプルなCOBOLバッチをVSCodeでデバッグする例を示しました。言語、コンパイラのバージョン、実行環境(CICS,IMS,...)などによって、準備の仕方などが異なってきますが、ここで示した例をベースとして必要な設定等を拡張していけばよいと思います。