cobst.cpp 12.2 KB
Newer Older
1
/* #######################################################################
2
# Copyright (c) 2019-2020 COBOLworx Corporation
3 4 5 6 7 8 9 10 11 12 13
# 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.
14
#    * Neither the name of the COBOLworx Corporation nor the names of its
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#      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
// #define DUMPING
52

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
           const COB_PROGRAM_LABELS &program_labels,
92 93 94
           const COB_FIELDS &cob_fields,
           const COB_FIELD_ATTRIBUTES &cob_field_attributes,
           const COB_PIC_SYMBOLS &cob_pic_symbols,
95
           const VARIABLE_TREE &variable_tree,
96 97
           bool tack_on_python,
           bool tack_on_filename)
98
{
rdubner's avatar
rdubner committed
99
    PROFILER;
100 101
    /*  This routine creates the .sym.c file, which contains a global
        variable comprising the cross-reference information, followed
102
        by the magical construction that puts the cobcd.py script
103 104
        into the .debug_script section of the object file created by
        compiling .sym.c
105 106
    */

107
    string fname = params.cbl_filename.GetFandExt();
108 109
    stringstream ss;

110 111 112 113
    // Start off the output with the program section information:
    program_labels.FormatProgramInfo(ss);

    // Continue with the data variables information:
114
    variable_tree.FormatVariablesInfo(ss,cob_fields,cob_field_attributes,cob_pic_symbols);
115

116
    // Do the line/address information from the .text in the minimal form
117
    // used by cobcd.py to figure out which program a trap has occurred in.
118 119
    string current_program = "";

120 121 122 123 124 125
    // 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("");

rdubner's avatar
rdubner committed
126 127 128 129 130 131
    for(size_t i=0; i<fname.size(); i++) {
        if( fname[i] EQ '.' ) {
            fname[i] = '_' ;
        }
    }

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

    const int SEGMENT_LENGTH = 78;
135 136 137 138 139 140
    int walker = 0;
    int remaining = (int)s.length();
    while( remaining > SEGMENT_LENGTH ) {
        ss << "\"" << s.substr(walker,SEGMENT_LENGTH) << "\"" << endl;
        walker    += SEGMENT_LENGTH;
        remaining -= SEGMENT_LENGTH;
141
    }
142 143
    if( remaining ) {
        ss << "\"" << s.substr(walker) << "\"" << endl;
144 145
    }
    ss << ";" << endl << endl;
146
    params.symc << ss.str();
147

148
    ss.str("");
149
    bool in_copyright = true;
150
    // Copy over the Python script, line by line, getting rid of comments
151
    // that appear after the copyright notice
152
    char *py = new char[___python_cobcd_py_len+1];
153 154
    py[0] = '\0';
    size_t index=0;
155
    while(index < ___python_cobcd_py_len) {
156
        // Read the next line from the .h file
157
        string seg;
158 159
        while(index < ___python_cobcd_py_len) {
            char ch = ___python_cobcd_py[index++];
160 161 162 163 164 165
            if(ch EQ '\n') {
                break;
            }
            seg += ch;
        }
        size_t nfound_comment = seg.find("#");
166
        if( !in_copyright AND nfound_comment != string::npos ) {
167 168 169 170 171 172 173 174 175 176 177 178
            // 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());
179

180 181
            if( seg.find("EndOfCopyright") != string::npos ) {
                in_copyright = false;
182
            }
183 184 185
        }
    }

186 187
//    memcpy(py, ___python_cobcd_py,___python_cobcd_py_len);
//    py[___python_cobcd_py_len] = '\0';
188 189 190 191 192
    ss <<  py;
    ss << "\n";

    delete[] py;

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    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"
            );
        */
214

215
        s = ss.str();
216

217 218 219 220
        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\"";
221

222 223 224 225
        int char_count = 0;
        size_t i = 0;
        while( i < s.size() ) {
            if(char_count EQ 0) {
226
                params.symc << "\".ascii \\\"";
227 228 229
                char_count = 10 ;
            }
            if( char_count >= 120 ) {
230
                params.symc << "\"" << endl << "\"";
231 232 233 234 235
                char_count = 1;
                continue;
            }
            char ch = s[i++];
            if( ch EQ '\n' ) {
236
                params.symc << "\\\\n\\\"\\n\"" << endl;
237 238 239 240
                char_count = 0;
                continue;
            }
            if( ch EQ '\\' OR ch EQ '\"' ) {
241
                params.symc << "\\\\\\";
242 243
                char_count += 1;
            }
244
            params.symc << ch;
245 246 247
            char_count += 1;
        }

248 249 250
        params.symc << "\".byte 0\\n\"" << endl;
        params.symc << "\".popsection\\n\"" << endl;
        params.symc << ");" << endl;
251
    }
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276

    if(tack_on_filename) {

        /*  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:

         asm("
        .pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n
        .byte 1 \n
        .asciz \"cobcd.py\"\n
        .popsection \n
        ");

        */

        s = ss.str();

        params.symc << "asm(" ;
        params.symc << "\".pushsection \\\".debug_gdb_scripts\\\", \\\"MS\\\",@progbits,1\\n\"" ;
        params.symc << "\".byte 1 \\n\"" ;
        params.symc << "\".asciz \\\"cobcd.py\\\"\\n\"" ;
        params.symc << "\".popsection\\n\"" ;
        params.symc << ");" ;

        params.symc << endl;
277
    }
278

279 280 281
    return;
}

rdubner's avatar
rdubner committed
282 283
int
main(int argc, char *argv[])
284 285 286 287
{
    PROFILER;

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

294 295 296 297 298 299
    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;
300 301 302 303 304 305 306 307 308 309 310

    // 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.
311
    variable_tree.ReadFromFile(params.cbl_lst);
312
    variable_tree.BuildCanonicalName();
313
#if defined(DUMPING)
314
//    variable_tree.Dump();
315
#endif
316

317
    // Scan the .h files for working storage and local storage locations
318 319
    ScanAllDotHFiles(params.c_filename.Path(),
                     params.c_filename.GetFname(),
320 321 322 323 324 325
                     cob_pic_symbols,
                     cob_data,
                     cob_field_attributes,
                     cob_fields
                    );
    // Scan the .c file for program identification and linkage information.
326
    ScanForLinkage(params.c_file,
327 328 329 330 331
                   params.c_filename.GetFname(),
                   program_labels,
                   cob_data,
                   cob_fields
                  );
332 333 334 335 336

    // The f_/b_ cross reference is as complete as we know how to make it.
    // Scan cob_fields, updating the parent variables and building the lookup map
    cob_fields.FixLookup(cob_data);

337 338
#if defined(DUMPING)
    cout << endl;
rdubner's avatar
rdubner committed
339 340
    //program_labels.Dump();
    //cob_pic_symbols.Dump();
341
    cob_data.Dump();
rdubner's avatar
rdubner committed
342
    cob_field_attributes.Dump();
343 344 345
    cob_fields.Dump();
#endif
    // We now have a nice complete list of COB_DATA, COB_FIELD_ATTRIBUTES, COB_FIELDS
346 347

    // The most complete description of the COBOL variable identifiers is
348
    // found in variable_tree.  But as of right now, it knows nothing about
349 350 351 352
    // 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

353
    // The Consolidate() routine puts them together.
354

355
    variable_tree.Consolidate(cob_fields);
356 357 358 359
#if defined(DUMPING)
    variable_tree.Dump();
    variable_tree.DumpFlatList();
#endif
360 361 362
    // 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
363
    bool tack_on_python = params.insert_python;
364
    bool tack_on_filename = params.insert_filename;
365
#if defined(_WIN32)
366
    tack_on_python = false;
367
#endif
368 369
    CreateSymc(params,
               program_labels,
370 371 372
               cob_fields,
               cob_field_attributes,
               cob_pic_symbols,
373
               variable_tree,
374 375
               tack_on_python,
               tack_on_filename);
376 377
    return 0;
}