cobst.cpp 11 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* #######################################################################
# Copyright (c) 2019-2020 Symas Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in
#      the documentation and/or other materials provided with the
#      distribution.
#    * Neither the name of the Symas Corporation nor the names of its
#      contributors may be used to endorse or promote products derived
#      from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
############################################################################ */

31
32
33
#include <iostream>
#include <string>
#include <fstream>
rdubner's avatar
rdubner committed
34
#include <map>
35
36
#include <sstream>
#include <iomanip>
rdubner's avatar
rdubner committed
37
#include <string.h>
38
39
40
41
42
#include "csv.h"
#include "params.h"
#include "input_scan.h"
#include "profiler.h"
#include "vartree.h"
43
#include "cobcd_py.h"
44
45
46
47
48
49
50

#define EQ ==
#define AND &&
#define OR ||

using namespace std;

51
52
//#define DUMPING

rdubner's avatar
rdubner committed
53
54
void
scan_test(const string &filename)
55
56
57
{
    PROFILER;
    ifstream ifs;
rdubner's avatar
rdubner committed
58
    ifs.open(filename.c_str(),ifstream::in);
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    FILE *f = fopen(filename.c_str(),"r");

    string input;
    int nlines;
    nlines = 0;
    LAPTIME;
    for(;;) {
        getline(ifs,input);
        if(ifs.eof()) {
            break;
        }
        nlines += 1;
    }
    LAPTIME;
    cout << nlines << endl;
    LAPTIME;

    char ach[2048];
    nlines = 0;
    while(fgets(ach,sizeof(ach),f)) {
        nlines += 1;
    }
    LAPTIME;
    cout << nlines << endl;


    ifs.close();
    fclose(f);
}

89
90
static void
CreateSymc(PARAMETERS &params,
91
92
           const COB_PROGRAM_LABELS &program_labels,
           const VARIABLE_TREE &variable_tree,
93
           bool tack_on_python)
94
{
95
96
    /*  This routine creates the .sym.c file, which contains a global
        variable comprising the cross-reference information, followed
97
        by the magical construction that puts the cobcd.py script
98
99
        into the .debug_script section of the object file created by
        compiling .sym.c
100
101
    */

102
    string fname = params.c_filename.GetFname();
103
    stringstream ss_tab;
104
105
    stringstream ss;

106
107
108
109
110
111
    // Start off the output with the program section information:
    program_labels.FormatProgramInfo(ss);

    // Continue with the data variables information:
    variable_tree.FormatVariablesInfo(ss);

112
    // Do the line/address information from the .text in the minimal form
113
    // used by cobcd.py to figure out which program a trap has occurred in.
114
115
    string current_program = "";

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    // At this point, ss contains a potentially huge literal string.
    // We're going to bust it up into smaller pieces.

    string s = ss.str();
    ss.str("");

    ss << "char VARIABLE_STRING_" << Upper(fname) << "[]=" << endl;

    const int SEGMENT_LENGTH = 78;
    while(s.length() > SEGMENT_LENGTH) {
        ss << "\"" << s.substr(0,SEGMENT_LENGTH) << "\"" << endl;
        s = s.substr(SEGMENT_LENGTH);
    }
    if( s.length() ) {
        ss << "\"" << s << "\"" << endl;
    }
    ss << ";" << endl << endl;
rdubner's avatar
rdubner committed
133
    *params.symc << ss.str();
134

135
    ss.str("");
136
    bool in_copyright = true;
137
    // Copy over the Python script, line by line, getting rid of comments
138
    // that appear after the copyright notice
139
    char *py = new char[___python_cobcd_py_len+1];
140
141
    py[0] = '\0';
    size_t index=0;
142
    while(index < ___python_cobcd_py_len) {
143
        // Read the next line from the .h file
144
        string seg;
145
146
        while(index < ___python_cobcd_py_len) {
            char ch = ___python_cobcd_py[index++];
147
148
149
150
151
152
            if(ch EQ '\n') {
                break;
            }
            seg += ch;
        }
        size_t nfound_comment = seg.find("#");
153
        if( !in_copyright AND nfound_comment != string::npos ) {
154
155
156
157
158
159
160
161
162
163
164
165
            // There is a pound sign, which is the Python comment signal
            size_t nfound_quote = seg.find_first_of("'\"");
            if( nfound_quote > nfound_comment ) {
                seg = seg.substr(0,nfound_comment);
                seg = RTrim(seg);
            }
        }

        if( !Trim(seg).empty() ) {
            seg += '\n';
            size_t t = strlen(py);
            strcpy(py+t,seg.c_str());
166

167
168
            if( seg.find("EndOfCopyright") != string::npos ) {
                in_copyright = false;
169
            }
170
171
172
        }
    }

173
174
//    memcpy(py, ___python_cobcd_py,___python_cobcd_py_len);
//    py[___python_cobcd_py_len] = '\0';
175
176
177
178
179
    ss <<  py;
    ss << "\n";

    delete[] py;

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    if(tack_on_python) {

        /*  As per https://sourceware.org/gdb/current/onlinedocs/gdb/dotdebug_005fgdb_005fscripts-section.html,
            we are going to format that string in a way that reflects this example:

            #include "symcat.h"
            #include "gdb/section-scripts.h"
            asm(
            ".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n"
            ".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n"
            ".ascii \"gdb.inlined-script\\n\"\n"
            ".ascii \"class test_cmd (gdb.Command):\\n\"\n"
            ".ascii \"  def __init__ (self):\\n\"\n"
            ".ascii \"    super (test_cmd, self).__init__ (\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n"
            ".ascii \"  def invoke (self, arg, from_tty):\\n\"\n"
            ".ascii \"    print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n"
            ".ascii \"test_cmd ()\\n\"\n"
            ".byte 0\n"
            ".popsection\n"
            );
        */
201

202
        s = ss.str();
203

rdubner's avatar
rdubner committed
204
205
206
207
        *params.symc << "asm(" << endl;
        *params.symc << "\".pushsection \\\".debug_gdb_scripts\\\", \\\"MS\\\",@progbits,1\\n\"" << endl;
        *params.symc << "\".byte 4\\n\"" << endl;
        *params.symc << "\".ascii \\\"gdb.inlined-script\\\\n\\\"\\n\"";
208

209
210
211
212
        int char_count = 0;
        size_t i = 0;
        while( i < s.size() ) {
            if(char_count EQ 0) {
rdubner's avatar
rdubner committed
213
                *params.symc << "\".ascii \\\"";
214
215
216
                char_count = 10 ;
            }
            if( char_count >= 120 ) {
rdubner's avatar
rdubner committed
217
                *params.symc << "\"" << endl << "\"";
218
219
220
221
222
                char_count = 1;
                continue;
            }
            char ch = s[i++];
            if( ch EQ '\n' ) {
rdubner's avatar
rdubner committed
223
                *params.symc << "\\\\n\\\"\\n\"" << endl;
224
225
226
227
                char_count = 0;
                continue;
            }
            if( ch EQ '\\' OR ch EQ '\"' ) {
rdubner's avatar
rdubner committed
228
                *params.symc << "\\\\\\";
229
230
                char_count += 1;
            }
rdubner's avatar
rdubner committed
231
            *params.symc << ch;
232
233
234
            char_count += 1;
        }

rdubner's avatar
rdubner committed
235
236
237
        *params.symc << "\".byte 0\\n\"" << endl;
        *params.symc << "\".popsection\\n\"" << endl;
        *params.symc << ");" << endl;
238
    }
239
240
241
    return;
}

rdubner's avatar
rdubner committed
242
243
int
main(int argc, char *argv[])
244
245
246
247
248
249
250
251
252
{
    PROFILER;

    // Decode the command line for our purposes.
    PARAMETERS params = GetParameters(argc, argv);
    if(!params.quiet) {
        cout << "cobst version " << VERSION << endl;
    }

253
254
255
256
257
258
259
    COB_PROGRAM_LABELS   program_labels;
    VARIABLE_TREE        variable_tree;
    COB_PIC_SYMBOLS      cob_pic_symbols;
    COB_DATA             cob_data;
    COB_FIELD_ATTRIBUTES cob_field_attributes;
    COB_FIELDS           cob_fields;
    DATA_DESCRIPTIONS    data_description;
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

    string source = params.basename;
    const string GLOBAL = "GLOBAL";
    const string LOCAL = "LOCAL";
    const string MAIN = "MAIN";

    // We embark on a multi-step process, where we scan a number of
    // different files separately.  This is a bit like putting a jigsaw
    // puzzle together.

    // One of the files generated by GnuCOBOL is named .cbl.lst.  This is
    // a listing of the COBOL program, with the PROCEDURE division sort of
    // normalized.  We're interested in the last part of the file, which has
    // a normalized rendition of the parsed STORAGE sections.  We read that
    // in, and build a COBOL identifier tree based on the various storage
    // sections and the COBOL 77 01 02 03 data heirarchy.
rdubner's avatar
rdubner committed
276
    variable_tree.ReadFromFile(*params.cbl_lst);
277
    variable_tree.BuildCanonicalName();
278
279
280
#if defined(DUMPING)
    //variable_tree.Dump();
#endif
281

282
    // Scan the .h files for working storage and local storage locations
283
284
    ScanAllDotHFiles(params.c_filename.Path(),
                     params.c_filename.GetFname(),
285
286
287
288
289
290
291
                     cob_pic_symbols,
                     cob_data,
                     cob_field_attributes,
                     cob_fields
                    );

    // Scan the .c file for program identification and linkage information.
rdubner's avatar
rdubner committed
292
    ScanForLinkage(*params.c,
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
                   params.c_filename.GetFname(),
                   program_labels,
                   cob_data,
                   cob_fields
                  );
#if defined(DUMPING)
    cout << endl;
    program_labels.Dump();
    cob_pic_symbols.Dump();
    cob_data.Dump();
    cob_field_attributes.Dump();
    cob_fields.Dump();
#endif
    // We now have a nice complete list of COB_DATA, COB_FIELD_ATTRIBUTES, COB_FIELDS
    // Flatten them down into the composite table:
308

309
310
311
312
    data_description.Flatten(cob_fields,cob_field_attributes,cob_pic_symbols,cob_data);
#if defined(DUMPING)
    data_description.Dump();
#endif
313
314

    // The most complete description of the COBOL variable identifiers is
315
    // found in variable_tree.  But as of right now, it knows nothing about
316
317
318
319
    // where those variables can be found in the assembly output.
    // data_description has some COBOL/assembler cross references, but it is
    // incomplete, because it doesn't have the canonical COBOL names

320
    // The Consolidate() routine puts them together.
321

322
323
324
325
326
    variable_tree.Consolidate(data_description);
#if defined(DUMPING)
    variable_tree.Dump();
    variable_tree.DumpFlatList();
#endif
327
328
329
    // Create the .sym.c file that will be compiled and linked into the
    // executable, providing the text that will become the executable's
    // .debug_gdb_scripts section
330
331
#if defined(_WIN32)
    bool tack_on_python = false;
332
#else
333
    bool tack_on_python = true;
334
#endif
335
336
337
338
    CreateSymc(params,
               program_labels,
               variable_tree,
               tack_on_python);
339
340
    return 0;
}