VSCodeを使用したメインフレーム・アプリケーション開発 - (5)デバッガーの利用

# はじめに
アプリケーションを開発/修正する際には、コードを実際に動かしてみてトライ&エラーを繰り返すということはよくある話です。その際にデバッガーを使ってコードをステップ実行させたり、稼働中の変数の状態を確認したりすることは有用です。
ここでは、VSCodeからデバッガーを使ってz/OS上のアプリケーション(COBOL)を動かしてみます。

## 関連記事
[VSCodeを使用したメインフレーム・アプリケーション開発 - (1)概要](https://qiita.com/tomotagwork/items/085b91098fce3aabaeaf)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (2)z/OS基本操作](https://qiita.com/tomotagwork/items/9496dbc121cc5bf17b29)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (3)ソース編集](https://qiita.com/tomotagwork/items/f4008d1ead61e8a263ae)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (4)ソース管理ツール/ビルドツール連携](https://qiita.com/tomotagwork/items/4bdd0b5a7284b5102d10)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (5)デバッガーの利用](https://qiita.com/tomotagwork/items/2ce806f5747bc72f9474)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (6)FTP経由での接続](https://qiita.com/tomotagwork/items/a2f82db16d18a8fd9d21)

# 全体像

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/2fdad2de-5ad8-c4c9-1efc-5ea673ede6d1.png)

ざっくりとしたデバッガーの利用イメージは上の図の通りです。ホスト上でDebugger機能を導入構成しておき、VSCode側にはデバッガーを利用するためのExtensionを導入しておいて、VSCode上でデバッグ(ステップ実行など)を行います。

ここで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としてデバッグするようなこともできますが、ここではVSCodeをUIとして考えているので、画面をリモート(ここではVSCode)に飛ばす、"リモート・デバッグ"と呼ばれるやり方にフォーカスします。また、デバッグ対象のアプリケーションも言語環境やミドルウェア(バッチ、CICS、IMSなど)によってもやり方は変わってくるのですが、とりあえずここではシンプルなCOBOLバッチのケースを試してみます。


参考: 
[IBM z/OS Debugger の概要](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=overview-zos-debugger)
[What's new in IBM z/OS Debugger V15.0 ](https://community.ibm.com/community/user/ibmz-and-linuxone/blogs/violaine-batthish1/2020/10/30/whats-new-in-ibm-zos-debugger-v150)
[Installation of IBM Developer for z Systems and IBM Debug for z Systems](https://community.ibm.com/community/user/ibmz-and-linuxone/blogs/blog-entry1/2016/12/02/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](https://www-01.ibm.com/common/ssi/cgi-bin/ssialias?subtype=ca&infotype=an&appname=iSource&supplier=897&letternum=ENUS220-425)
[IBM Debug for z/OS](https://www.ibm.com/products/debug-for-zos/details)


# 構成(事前準備)
今回はIBM Wazi Developer for Red Hat CodeReady Workspacesを使った場合の例を示します。この製品はOpenShift上で稼働するz/OSエミュレーターが提供されていますが、はじめからz/OS Debuggerの構成もされた状態となっています。

## z/OS側
z/OS側の構成はここでは詳細は割愛します。基本はドキュメントの記述に従って構成してください。
参考: [z/OS Debugger](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=components-zos-debugger)

ここでは、IBM Wazi Developer for Red Hat CodeReady WorkspacesV1.1.0のSandboxでデフォルトで提供されているz/OS Debuggerの構成を見てみます。
先に示した全体像の図にあるように、z/OS側では3つのコンポーネントを構成、稼働させておく必要があります。

### Debug Manager
参考:[デバッグ・マネージャーとの通信の有効化](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=users-enabling-communication-debug-manager)

Debug Managerはリモート・デバッグを行う際にVSCodeやEclipseなどのクライアントと通信を行う際に必要なコンポーネントです。

<details><summary><font color="blue">起動プロシージャー</font></summary><div>

```xxx:FEU.Z24B.PROCLIB(DBGMGR)
//*
//* Debug Manager
//*
//DBGMGR   PROC PRM=,                   * PRM=DEBUG TO START TRACING
//*BGMGR   PROC PRM=DEBUG,              * PRM=DEBUG TO START TRACING
//            LEPRM='RPTOPTS(ON)',
//            TZ='EST5EDT',
//            CLIENT=7397,
//*           CLIENT=4097,          * use for wazi_int_test
//            HOST=4040,
//            HLQ=EQAF00
//*
//DBGMGR   EXEC PGM=EQAZPCM,REGION=0M,TIME=NOLIMIT,
//            PARM=('&LEPRM ENVAR("TZ=&TZ")/&HOST &CLIENT &PRM')
//STEPLIB  DD DISP=SHR,DSN=&HLQ..SEQAAUTH
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//         PEND
//*
```

</div></details>

### Remote Debug Service
参考:[リモート・デバッグ・サービスのサポートの追加](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=users-adding-support-remote-debug-service)

Remote Debug Serviceはデバッグエンジンとクライアント(ここではVSCode)の間のプロキシーの役割を果たします。

<details><summary><font color="blue">起動プロシージャー</font></summary><div>

```xxx:FEU.Z24B.PROCLIB(EQARMTD)
//*
//* Remote Debug Service
//*
//EQARMTD  PROC SVRPATH='/usr/lpp/IBM/debug',
//         CFGDIR='/etc/debug',
//         WRKDIR='/var/debug',
//         ENVFILE='eqarmtd.env'
//         SET QUOTE=''''
//EXPORTS  EXPORT SYMLIST=*
//         SET SVRPATH=&QUOTE&SVRPATH&QUOTE
//         SET CFGDIR=&QUOTE&CFGDIR&QUOTE
//         SET WRKDIR=&QUOTE&WRKDIR&QUOTE
//         SET ENVFILE=&QUOTE&ENVFILE&QUOTE
//*---------------------------------------------------------
//* Start the Remote Debug Service
//*---------------------------------------------------------
//EQARMTD EXEC PGM=BPXBATSL,REGION=0M,TIME=NOLIMIT,
//  PARM='PGM /bin/sh &SVRPATH/remote-debug-service/bin/eqarmtd.sh'
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//STDENV   DD *,SYMBOLS=JCLONLY
EQARMTD_CFG_DIR=&CFGDIR
EQARMTD_WRK_DIR=&WRKDIR
EQARMTD_ENVFILE=&CFGDIR/&ENVFILE
EQARMTD_BASE=&SVRPATH/remote-debug-service
_BPXK_AUTOCVT=ON
/*
//        PEND
//*
```

</div></details>

<details><summary><font color="blue">環境変数ファイル</font></summary><div>

```xxx:/etc/debug/eqarmtd.env
# =============================================================================
# Remote Debug Service configurations
# =============================================================================


# ------------------------------------------------------------------------------
# Ports required to run the service:
#   'port_internal' must be specified
# And at least one of the following options must be specified:
#   'port_external_secured'
#   'allow_unsecured_remote_connections=true'
# ------------------------------------------------------------------------------

# Port number the service listens to for internal debug backend connections from
# the local z/OS machine. This port is mandatory. This port may be secured with
# AT-TLS if encryption of localhost-localhost connections is desired.
port_internal="7393"

# Allow the internal port number to also listen for unsecured incoming requests
# from remote debug clients. Uncomment this line to enable listening for unsecured
# remote connections on 'port_internal'.
#allow_unsecured_remote_connections="true"

# Port number the service listens to for secured incoming requests from remote
# debug clients. This port is encrypted by Java. Do not use AT-TLS to secure
# this port. Comment out this line to disable secured remote connections.
port_external_secure="7394"


# ------------------------------------------------------------------------------
# TLS keystore and password:
#   These values must be specified if 'port_external_secured' is specified
# ------------------------------------------------------------------------------

# Pathname of the keystore file where the server certificate is loaded
#keystoreFile="$EQARMTD_CFG_DIR/keystore.jks"
keystoreFile="/etc/zexpl/rseapikey.p12"

# Password to access the server certificate from the keystore file
keystorePass="ibmuser"

# The type of keystore file to be used for the server certificate. This value
# is for reference only. Only JKS keystore types are supported at this time
keystoreType="JKS"


# ------------------------------------------------------------------------------
# Other server config paths and files:
# ------------------------------------------------------------------------------

# Home directory of the 64-bit Java SDK
java_dir="/usr/lpp/java/J8.0_64"

# Working directory of the Remote Debug Service
eqarmtd_workdir="/var/debug/workspace"


# ------------------------------------------------------------------------------
# Diagnostic tracing of service and debug connections
# ------------------------------------------------------------------------------
#eqarmtd_logdir="/var/debug/logs"
#trace=true

# ------------------------------------------------------------------------------
# Low level tracing of Remote Debug Service application and debug connections
# ------------------------------------------------------------------------------
#detailedTraceOptions="/var/debug/trace.options"
#detailedTrace=true

# ------------------------------------------------------------------------------
# Headless Code coverage options
# ------------------------------------------------------------------------------
#headless_cc=true
#headless_cc_config=SharedServiceFiles/samples/eqahcc.env
IBM_JAVA_OPTIONS="-Xms256m -Xmx512m -Xquickstart -Xshareclasses:nonFatal"
IBM_JAVA_OPTIONS="$IBM_JAVA_OPTIONS -Xshareclasses:cacheDirPerm=0777 -Xscmx30m -Xshareclasses:cacheDir=/javasc/eqaprof,name=eqaprofcache"
IBM_JAVA_OPTIONS="$IBM_JAVA_OPTIONS -Xlp:objectheap:pagesize=1m,warn,pageable -Xlp:codecache:pagesize=1m,pageable"
```

</div></details>

### Debug Profile Service
※今回の手順では利用しないのでオプションです。アプリケーションの種類やデバッグ方法によって使用するケースがあります。

参考:[デバッグ・プロファイル・サービスと API のサポートの追加](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=users-adding-support-debug-profile-service-apis)

デバッガー利用の際は、どのモジュールをデバッグ対象として扱うか、といった情報をプロファイルとして管理します。Debug Profile Serviceは外部からプロファイルを管理するためのREST APIを提供してくれるので、このサービスを経由してVSCodeからプロファイルの管理が行えるようになります。


<details><summary><font color="blue">起動プロシージャー</font></summary><div>

```xxx:FEU.Z24B.PROCLIB(EQAPROF)
//*
//* Debug Profile Service
//*
//EQAPROF  PROC SVRPATH='/usr/lpp/IBM/debug',
//         CFGDIR='/etc/debug',
//         WRKDIR='/var/debug',
//         ENVFILE='eqaprof.env'
//         SET QUOTE=''''
//EXPORTS  EXPORT SYMLIST=*
//         SET SVRPATH=&QUOTE&SVRPATH&QUOTE
//         SET CFGDIR=&QUOTE&CFGDIR&QUOTE
//         SET WRKDIR=&QUOTE&WRKDIR&QUOTE
//         SET ENVFILE=&QUOTE&ENVFILE&QUOTE
//*---------------------------------------------------------
//* Start the Debug Profile Service
//*---------------------------------------------------------
//EQAPROF EXEC PGM=BPXBATSL,REGION=0M,TIME=NOLIMIT,
//  PARM='PGM /bin/sh &SVRPATH/tomcat/bin/catalina.sh run'
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//STDENV   DD *,SYMBOLS=JCLONLY
EQAPROF_CFG_DIR=&CFGDIR
EQAPROF_WRK_DIR=&WRKDIR
EQAPROF_ENVFILE=&CFGDIR/&ENVFILE
CATALINA_BASE=&SVRPATH/eqaProfile
_BPXK_AUTOCVT=ON
/*
//        PEND
//*
```

</div></details>

<details><summary><font color="blue">環境変数ファイル</font></summary><div>

```xxx:/etc/debug/eqaprof.env
# Debug Profile API Server configurations

# Ports required to run the server:

# Port number the server listens to for a shutdown command
port_shutdown="7391"
# Port number the server listens to for incoming http requests
port_http="7390"
# Port number the server listens to for incoming https requests
port_https="7392"

# TLS keystore and password:

# The pathname of the keystore file where the server certificate is loaded
keystoreFile="/etc/debug/keystore.p12"
# The password to access the server certificate from the keystore file
keystorePass="ibmuser"
# The type of keystore file to be used for the server certificate
keystoreType="PKCS12"

# Other server config paths and files:

# Context path of the URI. For example:
#   http://localhost:8180/context_path/profile/dtcn?region=cicsts54
context_path="/api/v1"

# Naming pattern used by the API for working with EQAUOPTS data sets
default_dsname="\&USERID.DLAYDBG.EQAUOPTS"

# Pathname of the configuration file containing the list of CICS region
# names and their associated DTCN ports
dtcn_ports="/etc/debug/dtcn.ports"

# Home directory of the 64-bit Java SDK
java_dir="/usr/lpp/java/J8.0_64"

# Pathname of the server log file
tomcat_outfile="/var/debug/logs/catalina.out"

# Server temp directory
tomcat_tmpdir="/var/debug/temp"

# Server working directory
tomcat_workdir="/var/debug/work"
CATALINA_OPTS="$CATALINA_OPTS -Xms256m -Xmx512m -Xquickstart -Xshareclasses:nonFatal"
CATALINA_OPTS="$CATALINA_OPTS -Xshareclasses:cacheDirPerm=0777 -Xscmx30m -Xshareclasses:cacheDir=/javasc/eqaprof,name=eqaprofcache"
CATALINA_OPTS="$CATALINA_OPTS -Xlp:objectheap:pagesize=1m,warn,pageable -Xlp:codecache:pagesize=1m,pageable"
```

</div></details>

Wazi Sandboxの構成は上の通りですが、VSCodeからSecureな接続(TLS通信)を行う場合、Debug Profile Serviceのサーバー証明書はデフォルトで自己署名証明書を使う構成になっています。VSCode側は自己署名されたサーバー証明書は受け付けられないようなので、サーバー証明書をCA証明書で署名したものに置き換えることにします。手順は以下参照。
参考: https://qiita.com/tomotagwork/items/52f66ab9c78b9d8b3131#debug-profile-service

## VSCode側

### Extensionのインストール
VSCodeからz/OS Debuggerを利用するためのExtensionとして、IBM Z Open Debugというものが提供されています。これは有償製品に付属のものなので、VSCodeのMarketplaceからはインストールできないようです。
Waziの場合、以下のサイトからライセンスに同意してダウンロード可能です。(vsixファイルとして提供)
https://ibm.github.io/mainframe-downloads/downloads.html

以下の2つのファイルが提供されるので、VSCodeから"VSIXからのインストール"でそれぞれインストールします。
zopendebug-1.1.0.vsix
zopendebug-profileui-1.1.0.vsix

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/6b5505e1-a780-4bef-bca0-0b7723b4e040.png)

### プロパティの設定
参考:[IBM Z Open Debug のセットアップ](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=code-setting-up-z-open-debug)
VSCodeのプロパティでIBM Z Open Debug用のプロパティを設定します。
ここでは、Debug Profile Service、Remote Debug Serviceに対する接続構成を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/673bd8f5-0d81-926b-62e3-a781849953da.png)

- **Connection Name**: Debug Profile Serviceのホスト名(IPアドレス)
- **Connection Port**: Debug Profile ServiceがListenしているポート(環境変数ファイルで設定されているport_http or port_https)
- **Context Root**: Debug Profile ServiceのContext Root (環境変数ファイルで設定されているcontext_path)
- **Secured**: 上でセキュアなポート(https)を指定した場合はチェックを入れる
- **User Name**: Remote Debug Service, Debug Profile Serviceに接続する際のユーザー

ここではWaziの環境を使用する前提としているので、環境変数ファイルで設定したポート番号と外部に公開されているポート番号が異なるので違う値をしているように見えますが、対応するポート番号を指定しているという想定です。
また、Debug Profile ServiceとはTLS通信を行う想定のため、ここではSecureなポートを使用します。
Connection NameはDebug Profile Serviceに接続する際のホスト名を指定しますが、TLS通信を行う場合はサーバー証明書作成時に指定したDNS.xのホスト名に合致する名前でアクセスする必要があります。(DNSに登録しておくか、hostsファイルで名前解決できるようにしておく必要があります。)
参考: [(3)サーバー証明書作成](https://qiita.com/tomotagwork/items/52f66ab9c78b9d8b3131#3%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E8%A8%BC%E6%98%8E%E6%9B%B8%E4%BD%9C%E6%88%90linux%E4%B8%8A%E3%81%A7%E3%81%AE%E6%93%8D%E4%BD%9C)

### launch.jsonファイル作成
参考:[アプリケーションのデバッグ](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=applications-debugging-your-application)
launch.jsonというファイルを作成し、Remote Debug Serviceに対する接続構成を行います。
デバッグの画面を開いて、"launch.jsonファイルを作成します"をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/154ed8d8-6e98-8822-ad58-060addd1a874.png)

ここではVSCode上にワークスペースを作成しているので、"ワークスペース"を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/af6a3398-b983-210d-b0da-5ede83e4451e.png)

"IBM Z Open Debug"を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/1434a540-8ac5-d85b-b309-ddd76d7448c2.png)

launch.jsonが作成されるので、以下のようにパラメータを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/ef017cc1-fbab-70db-d9d3-70f48e1ef143.png)
- **useConnectionDetailsFromSettings**: falseを指定
- **host**: Remote Debug Serviceのホスト名を指定
- **port**: Remote Deubg ServiceがListenしているポート番号を指定(環境変数ファイルのport_internal　or port_external_secure)
- **secure**: 上のポートでセキュアなポートを指定した場合はtrue、そうでない場合はfalse
- **ignoreCertificateErrors**: 証明書関連のエラーを無視する場合はtrueを指定。自己署名のサーバー証明書を受け入れる場合はtrueを指定する必要がある。
- **password**: デバッガーに接続するユーザー(上のプロパティで指定したユーザー)のパスワードを指定

ここで指定しているポートも、Waziを使っている想定なので、z/OS上でListenしているポート番号と、公開されているポート番号が異なるので、設定値とは違う番号を指定していますが、対応するポート番号を指定しているという想定です。
launch.configurations以下に、"request":"attach"と"request":"launch" という2つの構成を定義しますが、attachの方はデバッグセッションをリストする際のパラメーター、launchはデバッグセッションに接続する際のパラメーターです。使用例の方と合わせてみるとイメージが沸きやすいと思います。
Remote Debug ServiceとはTLS通信を行う想定のため、ここではSecureなポートを使用します。また、Remote Debug Serviceの構成としては自己署名のサーバー証明書が使われているのて、ignoreCertificateErrorsにtrueを設定しています。

### 証明書インポート
ここでは、Remote Debug Service、Debug Profile ServiceそれぞれとTLS通信する想定なので、PC上に証明書をインポートしておきます。ここではWindows10の例を示します。

#### Debug Profile Service接続用
※今回の手順では利用しないのでオプションです。アプリケーションの種類やデバッグ方法によって使用するケースがあります。
Debug Profile Serviceは、以下の手順でサーバー証明書を作成しなおしている想定です。
参考: https://qiita.com/tomotagwork/items/52f66ab9c78b9d8b3131#debug-profile-service
サーバー証明書に署名しているCA証明書(myCA.pem)を入手して、それをPC上に登録します。

コントロール・パネルからインターネットオプションを開き、コンテンツタブの証明書ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/02bffe51-1665-c8aa-b7dd-ca7172de7065.png)

信頼されたルート証明機関タブでインポート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/462fab8e-dda3-c85f-d121-69e857b8cb5e.png)

次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/891779a0-f9a9-5619-5c81-bc7689d004bf.png)

CA証明書(myCA.pem)を選択して次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/cf470084-f955-08c9-7525-b3568075b35e.png)

信頼されたルート証明機関を選択し次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/755ba927-3c0f-dc9a-5b61-97d6cbc37e28.png)

完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/5dbd2a07-787e-5308-2897-49aa2ae0cd2e.png)


#### Remote Debug Service接続用
Remote Debug Serviceは、自己署名のサーバー証明書を使っているので、それをエクスポートして入手しPC上に登録しておきます。

**(1)証明書エクスポート**/USS上での操作
以下のようにUSS上でkeytoolコマンドを実行し、証明書をエクスポートします。

```
TAGUCHI:/u/TAGUCHI: > keytool -export -keystore /etc/zexpl/rseapikey.p12 -alias rseapi -storetype JKS -file ~/rseapi.cer -rfc -storepass ibmuser
Certificate stored in file <rseapi.cer>
```

**(2)証明書のインポート**/PC上での操作
rseapi.cerをバイナリー・モードでPC上に転送します。
rseapi.cerを信頼されたルート証明機関としてPC上に登録します。手順は上のDebug Profile Serviceと同様。

# 使用例

## サンプルCOBOLプログラム準備

### COBOLソース作成

単純なCOBOLソースを準備します。

<details><summary><font color="blue">ソース: HELLO1</font></summary><div>

```cbl: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 .
```

</div></details>

### コンパイル/リンク

<details><summary><font color="blue">コンパイル/リンク用JCL</font></summary><div>

```jcl:HELCOMP
//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)
/*
```

</div></details>

デバッグを行うためにコンパイル・オプションとして`TEST(SOURCE)`を追加してコンパイル/リンクします。

参考: [COBOL プログラムでの TEST または NOTEST コンパイラー・サブオプションの選択](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=ccod-choosing-test-notest-compiler-suboptions-cobol-programs-1)

### 実行用JCL準備

<details><summary><font color="blue">実行用JCL</font></summary><div>

```jcl:HELRUN
//HELRUN  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(,,,RDS:*)
//*
//SYSOUT   DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//*
```

</div></details>

デバッグを行うために、ランタイム・オプションとしてCEEOPTS DDにて`TEST(,,,RDS:*)`を追加しています。また、STEPLIBにてデバッガーのライブラリ(EQAF00.SEQAMOD)をロードモジュールのライブラリより上位にコンカチしています。
<font color="red">ここではまだSubmitはしません。</font>

参考:
[z/OS Debugger を開始する方法の選択](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=session-choosing-method-methods-starting-zos-debugger)
[例: TEST ランタイム・オプション](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=string-example-test-runtime-options)
[Language Environment®内で始動される プログラムのための z/OS Debugger の始動](https://www.ibm.com/docs/ja/wdfrhcw/1.2.0?topic=szdbtp-starting-zos-debugger-programs-that-start-in-language-environment)

## Debugプロファイル準備
※今回の手順では利用しないのでオプションです。
デバッグ実行用JCLのランタイムオプションとして```TEST(,,,RDS:*)```を指定して実行する場合はこの手順は不要です。ランタイムオプションとして```TEST```のみを指定している場合、このDebugプロファイルを登録/アクティベートしておくことでデバッグ可能となります。

どのプログラムをデバッグするかをプロファイルとして登録しておきます。

VSCodeからCtrl + Shift + P でコマンドパレットを開いて、Debug: IBM Z Open Debug Profiles viewを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/ed9f6866-814d-d648-9e72-2a27e0053034.png)

Let's get startedをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/1c9cb54e-8f57-fb1e-6472-3cf5ee8a6b16.png)

Create Profileをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/d4f33be3-fb39-b68c-c294-498c9537e55f.png)

Batch, IMS, Db2を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/1c372b4f-b302-9bb5-ef7e-9b50204831a9.png)

以下のように指定
Name: HELLO
Load Module or DLL Name: HELLO*
その他はデフォルト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/246deeac-93bb-8606-e360-78a8ef226aef.png)

作成したHELLOというプロファイルをAcitiveにします。(パスワード聞かれたら入力します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/d81db4c1-055e-1682-93e8-ae6d1e5ff085.png)

## Debug実行
実際にDebugを行ってみます。

### 事前確認
待機中デバッグセッションを確認してみます。まだデバッグ対象のプログラムが実行されていないので以下のように表示されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/e9f91f9f-1915-117c-95e6-08d0ee75777c.png)

### プログラム実行
上で準備したTESTランタイムオプション付きJCLをSubmitします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/60da171e-c67a-1214-e08f-08d1af198d04.png)

JOBはACTIVEの状態となります。

### 待機中デバッグセッションの確認
再度デバッグ画面から、List parked IBM Z Open Debug sessionsを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/883e2788-ef58-457b-6145-66571a51cf90.png)
デバッグのアサイン待ちのプログラムがリストされるはずです。

### デバッグセッション接続
デバッグ画面からConnectします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/deed8ade-fe26-28f7-c4d5-d84a5c222817.png)

### デバッグ実行
デバッグセッションが接続され、ソースが表示されてステップ実行できるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/17cda886-8eb9-ec93-9724-3b9345fb2891.png)

# おわりに
ここではシンプルなCOBOLバッチをVSCodeでデバッグする例を示しました。言語、コンパイラのバージョン、実行環境(CICS,IMS,...)などによって、準備の仕方などが異なってきますが、ここで示した例をベースとして必要な設定等を拡張していけばよいと思います。