Newer
Older
# COBOLworx COBOL debugger
This extension provides source-level debugging of COBOL programs compiled with the GnuCOBOL COBOL compiler.
September 24, 2020
support@cobolworx.com
## Basic methodology
COBOL source code is compiled with the GnuCOBOL compiler. Debugging information and a gdb extension are added to the executable by the COBOLworx cbl-gdb routines. The resulting executable can be debugged directly by the [GNU Project Debugger `gdb`](https://www.gnu.org/software/gdb/).
That executable can also be debugged on the source-code level with this extension, which provides a VSC Debug Adapter that is aware of the COBOLworx extensions to gdb that make source-level debugging possible.
## Prerequisites: GnuCOBOL
In order to debug a COBOL program, it must first be compiled with the GnuCOBOL compiler. The compiler must be at least the 3.1.2 version; earlier versions will not work.
GnuCOBOL installation packages for Ubuntu, RedHat, and Windows can be found at [COBOLworx downloads](https://cobolworx.com/pages/downloads.html).
Those who prefer to build the GnuCOBOL compiler from source can download the latest version from [here](https://alpha.gnu.org/gnu/gnucobol/). The build sequence starts with `./configure`.
As an alternative you may build from developer source code, which is available in the [GnuCOBOL SVN repository](https://svn.code.sf.net/p/gnucobol/code/branches/gnucobol-3.x). The build sequence starts with `./autogen.sh`; for details see its `HACKING` file.
More information can be found at the [GnuCOBOL project site](https://www.gnu.org/software/gnucobol/).
## Prerequisites: COBOLworx cbl-gdb debugging extensions
As part of the compilation process, the cbl-gdb extensions need to be applied before the executable can be debugged using gdb and VSC.
Download and install the appropriate `COBOLworx GnuCOBOL Debugging Extensions package` from [COBOLworx downloads](https://cobolworx.com/pages/downloads.html) or from the [COBOLworx source repository](https://gitlab.cobolworx.com/COBOLworx/cbl-gdb).
Once the cbl-gdb extensions are installed, you compile COBOL code for debugging by replacing the `cobc` command with `cobcd`. So, when compiling `foo.cbl`, you enter the command `cobcd foo.cbl` instead of `cobc foo.cbl`.
## Installation
If you didn't install this extension from [Open VSX Registry](https://open-vsx.org/?search=COBOLworx) or the [Microsoft Visual Studio Code Marketplace](https://marketplace.visualstudio.com/vscode), then you probably downloaded a file named cbl-gdb-4.2.1.vsix, which is a Visual Studio Code extension package. You have a couple of options for loading the extension into VS code:
- From inside Visual Studio Code, use the Command Palette `(Ctrl+Shift+P)` to find "Extensions: Load extension from VSIX..." Select that, and point it at the .VSIX file.
- From the command line, execute `code --install-extension cbl-gdb-4.2.1.vsix`
## Additional extensions
There are a number of COBOL formatting extensions available at the [Open VSX Registry](https://open-vsx.org/?search=cobol) and [Microsoft's Visual Studio Code Marketplace](https://marketplace.visualstudio.com/vscode). We've found that `Enterprise COBOL for z/OS` seems to coexist with our Debugging Adapter, and does a reasonable job of formatting the COBOL source code.
## Additional configuration of Visual Studio Code.
Use the Command Palette `(Ctrl+Shift+P)` To search for `Settings`, or navigate to `File > Preferences > Settings` from the menu. Select the `User` tab, and then `User > Features > Debug`. Activate the `Allow Breakpoints Anywhere` option.
## Getting Started / Troubleshooting Guide
Were you to contact me for help getting this package running on your system, I would go through this series of steps to convince myself all the pieces were working correctly.
### Create a simple test program
Create an empty directory; I'm naming it `ctest`.
Create a text file CTEST.CBL
000001 IDENTIFICATION DIVISION.
000002 PROGRAM-ID. CTEST.
000003 DATA DIVISION.
000004 WORKING-STORAGE SECTION.
000005 01 D123 PIC 999 VALUE 123.
000006 PROCEDURE DIVISION.
000007 DISPLAY "Simple".
000008 DISPLAY "as".
000009 DISPLAY "one".
000010 DISPLAY "two".
000011 DISPLAY "three".
000012 DISPLAY D123.
000013 GOBACK.
000014 END PROGRAM CTEST.
```
### Verify that GnuCOBOL is the right version:
The shell command `cobc --version | head -n 1` should return one of
or greater.
### Verify that GnuCOBOL compiles ctest:
Execute the shell command `cobc -x CTEST.CBL && ./CTEST`
The resulting output should be
```
Simple
as
one
two
three
123
```
### Verify that the COBOLworx Debugging Extensions are in place:
Execute the shell command `cobcd -x CTEST.CBL && ./CTEST`
*Note that the `cobc` command has been replaced with the `cobcd` command.*
The displayed results should be the same as for `cobc`.
### Verify that gdb debugging works:
Execute the shell command `gdb -q CTEST`
The immediate output from GDB should look like this:
```
$ gdb -q CTEST
Reading symbols from CTEST...
Registering CPrint (Usage is "cprint <COBOL identifier>") [Version 4.18]
Registering CWatch (Usage is "cwatch <COBOL identifier>")
Registering CBreak (Usage is "cbreak <line number> <COBOL identifier> == <value>")
*It is important that the two lines indicating PRINT and CWATCH have been registered appear here. If they are missing, then the cbl-gdb package wasn't completely installed.*
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
Entering the following sequence of commands: `l, b 7, r, n, n, n, n, n, n, n` should produce this output:
```
$ gdb -q CTEST
Reading symbols from CTEST...
registering CPrint (Usage is "print <COBOL identifier>") [Version 2.9]
registering CWatch (Usage is "cwatch <COBOL identifier>")
(gdb) l
1 000001 IDENTIFICATION DIVISION.
2 000002 PROGRAM-ID. CTEST.
3 000003 DATA DIVISION.
4 000004 WORKING-STORAGE SECTION.
5 000005 01 D123 PIC 999 VALUE 123.
6 000006 PROCEDURE DIVISION.
7 000007 DISPLAY "Simple".
8 000008 DISPLAY "as".
9 000009 DISPLAY "one".
10 000010 DISPLAY "two".
(gdb) b 7
Breakpoint 1 at 0xf10: file CTEST.CBL, line 7.
(gdb) r
Starting program: /home/bob/projects/ctest/CTEST
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, CTEST_ (entry=0) at CTEST.CBL:7
7 000007 DISPLAY "Simple".
(gdb) n
Simple
8 000008 DISPLAY "as".
(gdb) n
as
9 000009 DISPLAY "one".
(gdb) n
one
10 000010 DISPLAY "two".
(gdb) n
two
11 000011 DISPLAY "three".
(gdb) n
three
12 000012 DISPLAY D123.
(gdb) n
123
13 000013 GOBACK.
(gdb) n
[Inferior 1 (process 9710) exited normally]
(gdb)
```
### Putting it all together
At this point, Visual Studio Code has been installed, and the VSC extension for the COBOLworx Debugging Extensions has been installed into VSC. GnuCOBOL 3.1.2 (or higher) has been installed and tested. The COBOLworx cbl-gdb debugging extensions have also been installed and tested.
We are now ready to demonstrate source-level debugging of COBOL with Visual Studio Code.
Change the working directory to your `ctest` folder.
Launch VSC with `code .`
Select the `Run` view. (From the menu, select View > Run. On a Linux system Ctrl+Shift+D will get you there.)
Because you do not already have a `.vscode` subdirectory, the Run view will offer you the opportunity to `create a launch.json file` Select it.
A `select environment` dropdown list will appear. Select `COBOLworx cbl-gdb GnuCOBOL debugging`. Your `launch.json` file will appear.
*Note: Save yourself some future inconvenience by changing the line*
"program": "${workspaceFolder}/${fileBasenameNoExtension}",
*to*
"program": "${workspaceFolder}/CTEST",
In the editor view, select the file `CTEST.CBL`.
Set a breakpoint on Line 7 `000007 DISPLAY "Simple".` by pressing the F9 key or clicking in the gutter to the left of the line of code.
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
*If you can't set a breakpoint (shown as a red dot to the left of the editor's line number) see the note up above about setting the Debug option* `Allow Breakpoints Anywhere`.
Launch the program with `Run > Start Debugging (F5)` from the menu, or press the `F5` key.
You will immediately get an error response: `Could not find the task 'make'`
Select `Configure Task`, and then choose the option `Create tasks.json file from template`, and then choose `Others Example to run an arbitrary external command`.
Edit your new `tasks.json` file to look like this:
```
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "cobcd -x CTEST.CBL"
}
]
}
```
Once that's done, go back to looking at the CTEST.CBL file in the editor view and press F5 again.
VSC will compile the CTEST.CBL program and use gdb to launch it, and it will trap at the breakpoint on Line 7. That will be indicated by a yellow pentagon surrounding the red breakpoint dot.
In the VARIABLES pane, you will see the variable 01-D123 and its contents.
You are now ready to start working with more complex COBOL programs.
## Advanced topic: Attaching to existing processes
If you are in the business of attaching to existing processes, we offer you a couple of choices.
If you used the default environment provided by this extension, the Debugging view has a dropdown selection in the `Run` selector: `Attach to COBOL process with cbl-gdb debugger`. When that is selected, a too-small data entry windows will appear with the text `Enter the PID of the process`. Replace that with the PID of your process, and the debugger will attach to it.
If you prefer a bit more control over what's going on, you can create your own "attach" configuration in the launch.json file. It might look like this:
```
"configurations": [
{
"name": "Attach to COBOL debugger",
"type": "cbl-gdb",
"request": "attach",
"cwd":"${workspaceFolder}",
"solibs":"${env:PRIM_LIBRARY_PATH}",
}
],
"inputs": [
{
"type": "promptString",
"description": "Enter the PID to attach to",
"default": ""
}
]
```
When you execute `Debug > Start Debugging (F5)` and choose `Attach to COBOL debugger`, you will be asked `Enter the PID to attach to`. You'll need to know the PID (perhaps the application will have been designed to tell you what its PID is, or you'll have found the PID through ps(1) or pgrep(1)
Take special note of the `"solibs"` variable. As described here it gets set from a global environment variable. It doesn't have to be set that way, but if the application involves dynamically-loaded shared libraries, the `"solibs"` variable somehow has to be set to a colon-separated list of folders that include the location of your libraries (assuming you have any, of course). If `"solibs"` isn't set, then the instance of gdb launched by Visual Studio Code won't be able to find the symbols for those libraries.
## Automatic display of variables
COBOL, particularly older code, sometimes has modules with hundreds, even thousands or tens of thousands of variables. To avoid uselessly filling the VSC Variables pane with thousands of variables, the COBOLworx extension attempts to analyze the code near the breakpoint to show you just the variables that seem relevant.
It does this through the `print ?` command. `print ?` examines a range of lines around where the program is currently stopped. That value currently defaults to +/- six lines.
The bottom of the DEBUG CONSOLE allows you to enter commands directly to GDB. You can use that command line to change the range of lines that are examined. `p/r` will respond with the current setting. `p/r N` will set the range to +/- N. `p/r 0` is valid; it sets the range to just the line you are stopped on. `p/r -1` sets the range to be the entire program.
## Command line variable display.
The cbl-gdb debugger tries to be helpful. If you type `cprint RECORD-COUNT` into the DEBUG CONSOLE command line, it'll look for a variable of that name. Failing that, it'll look for variables that contain "RECORD-COUNT" as part of their names.
This means you can use shortcuts: `cprint REC` will show you all variables containing "REC". This will, of course, give you "RECORD-COUNT". It can save a lot of time.
`cprint/h` generates a concise list of the COBOLworx `print` commands.
More information on using the cbl-gdb debugger can be found at the [COBOLworx knowledge base](https://cobolworx.com/pages/cbl-gdb-kb.html)
## Alternative display formats
The CBL-GDB debugger that VSC relies on has the ability to display variables in both hex and binary. Although there is no way to tell VSC to use those methods directly, you can invoke them in the command line field of the DEBUG CONSOLE
Entering `cprint/x custmas-ctr` displays the variable in hexadecimal. `cprint/b custmas-ctr` displays the variable in binary.
## "Break on variable change"
Visual Studio Code has no provision for activating GDB's "variable watch" feature, which allows for "break when a variable changes". You can activate that feature from the command line entry field in VSC's DEBUG CONSOLE. For example, entering `watch custmas-ctr` in that field will cause execution to break when that variable's data changes.
The results can be a little odd, because Visual Studio Code doesn't quite know what to do with a break that it didn't set itself. Recent versions of VSC put up an red announcement that "Exception has occurred". But you can make it work.
## Variable display when hovering
An extremely useful feature of VSC is that it has provisions for evaluating a variable's contents when the cursor is hovering over the name of the variable in the source code. However, it is not known how to implement this feature for COBOL debugging in VSC.
It is very common for COBOL variable names to include hyphens. But VSC treats hyphens as separators, so hovering over `custmas-ctr` will cause VSC to ask the debugging code to evaluate either `custmas` or `ctr`. Investigation has revealed no way of preventing VSC from parsing on hyphens
We won't say it can't be done, but we don't know how to do it.