diff --git a/cobc/cobc.c b/cobc/cobc.c index b3a52303c..8007ddf67 100644 --- a/cobc/cobc.c +++ b/cobc/cobc.c @@ -2788,6 +2788,8 @@ cobc_def_dump_opts (const char *opt, const int on) } else { cb_flag_dump = COB_DUMP_NONE; } + if (cb_flag_dump) + cb_flag_symbols = 1; return; } @@ -2823,6 +2825,8 @@ cobc_def_dump_opts (const char *opt, const int on) } else { cb_flag_dump ^= dump_to_set; } + if (cb_flag_dump) + cb_flag_symbols = 1; cobc_free (p); } @@ -3256,6 +3260,7 @@ process_command_line (const int argc, char **argv) cb_flag_c_line_directives = 1; cb_flag_c_labels = 1; #endif + cb_flag_symbols = 1; #ifdef COB_DEBUG_FLAGS COBC_ADD_STR (cobc_cflags, " ", cobc_debug_flags, NULL); #endif @@ -3267,6 +3272,7 @@ process_command_line (const int argc, char **argv) cb_flag_stack_extended = 1; cb_flag_stack_check = 1; cb_flag_memory_check = CB_MEMCHK_ALL; + cb_flag_symbols = 1; cobc_wants_debug = 1; break; @@ -4198,6 +4204,9 @@ process_command_line (const int argc, char **argv) cb_flag_trace = 1; cb_flag_source_location = 1; } + if (cb_flag_trace) { + cb_flag_symbols = 1; + } /* If C debug, never strip output */ if (cb_source_debugging) { @@ -8937,6 +8946,8 @@ finish_setup_compiler_env (void) if (getenv ("COBC_GEN_DUMP_COMMENTS")) { cb_wants_dump_comments = 1; + /* Disable "new" symbol table if requesting dump comments */ + cb_flag_symbols = 0; } } diff --git a/cobc/cobc.h b/cobc/cobc.h index 73f3d7a23..63c29f8c1 100644 --- a/cobc/cobc.h +++ b/cobc/cobc.h @@ -426,16 +426,6 @@ extern int cb_ml_tree_id; extern int cb_flag_functions_all; extern int cb_flag_dump; -#define COB_DUMP_NONE 0x0000 /* No dump */ -#define COB_DUMP_FD 0x0001 /* FILE SECTION -> FILE DESCRIPTION */ -#define COB_DUMP_WS 0x0002 /* WORKING-STORAGE SECTION */ -#define COB_DUMP_RD 0x0004 /* REPORT SECTION */ -#define COB_DUMP_SD 0x0008 /* FILE SECTION -> SORT DESCRIPTION */ -#define COB_DUMP_SC 0x0010 /* SCREEN SECTION */ -#define COB_DUMP_LS 0x0020 /* LINKAGE SECTION */ -#define COB_DUMP_LO 0x0040 /* LOCAL-STORAGE SECTION */ -#define COB_DUMP_ALL (COB_DUMP_FD|COB_DUMP_WS|COB_DUMP_RD|COB_DUMP_SD|COB_DUMP_SC|COB_DUMP_LS|COB_DUMP_LO) - extern int cb_unix_lf; diff --git a/cobc/codegen.c b/cobc/codegen.c index f32391606..a6e4a7ffb 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -296,6 +296,8 @@ static void output_param (cb_tree, int); static void output_field_no_target (cb_tree); static void output_funcall (cb_tree); static void output_report_summed_field (struct cb_field *); +static struct cb_field * real_field_founder (const struct cb_field *f); +static void add_field_cache (struct cb_field *f01); static void output_trace_info (cb_tree, const enum cob_statement); static void output_source_reference (cb_tree, const enum cob_statement); @@ -308,6 +310,42 @@ static void output_perform_once (struct cb_perform *); /* Local functions */ +static void +count_all_fields (struct cb_field *p) +{ + struct cb_field *f, *f01; + cb_tree l; + /* Exclude internal registers (those have level 0 + in GC4 and are thus "automaticaly" excluded) + as well as typedefs */ + if (p->flag_internal_register || p->flag_is_typedef) { + return; + } + if (p->storage == CB_STORAGE_REPORT) { + f01 = real_field_founder (p); + if (!f01->flag_base) { + add_field_cache (f01); + } + } + if (p->sister) { + count_all_fields (p->sister); + } + if (p->children) { + count_all_fields (p->children); + } + p->flag_sym_emitted = 0; + + if (p->storage == CB_STORAGE_REPORT + || p->level == 1 + || p->level == 77) { /* Make sure cob_field is emitted */ + p->count++; + for (l = p->index_list; l; l = CB_CHAIN (l)) { + f = CB_FIELD_PTR (CB_VALUE (l)); + f->count++; + } + } +} + static struct cb_field * cb_code_field (cb_tree x) { @@ -1029,6 +1067,48 @@ out_odoslide_size (struct cb_field *fld) out_odoslide_fld_size (fld, fld); } +static void +add_field_cache (struct cb_field *f01) +{ + struct base_list *bl; + if (!f01->flag_base) { + if (f01->index_type == CB_INT_INDEX) { + bl = cobc_parse_malloc (sizeof (struct base_list)); + bl->f = f01; + bl->curr_prog = excp_current_program_id; + bl->next = local_base_cache; + local_base_cache = bl; + } else if (!f01->flag_external && !f01->flag_local_storage) { + if (!f01->flag_local || f01->flag_is_global) { + bl = cobc_parse_malloc (sizeof (struct base_list)); + bl->f = f01; + bl->curr_prog = excp_current_program_id; + if (f01->flag_is_global + || current_prog->flag_file_global) { + bl->next = base_cache; + base_cache = bl; + } else { + bl->next = local_base_cache; + local_base_cache = bl; + } + } else { + if (current_prog->flag_global_use) { + output_local ("unsigned char\t\t*%s%d = NULL;", + CB_PREFIX_BASE, f01->id); + output_local ("\t/* %s */\n", f01->name); + output_local ("static unsigned char\t*save_%s%d;\n", + CB_PREFIX_BASE, f01->id); + } else { + output_local ("unsigned char\t*%s%d = NULL;", + CB_PREFIX_BASE, f01->id); + output_local ("\t/* %s */\n", f01->name); + } + } + } + f01->flag_base = 1; + } +} + static void output_base (struct cb_field *f, const cob_u32_t no_output) { @@ -2007,6 +2087,310 @@ output_debugging_fields (struct cb_program *prog) } } +static int num_symtab = 0; +static int sym_storage = 255; +static int sym_comma = 0; +static int sym_1st_file = 0; +static void +emit_comma () +{ + if (sym_comma) { + sym_comma = 0; + output (","); + output_newline (); + } +} + +static void +emit_one_sym (struct cb_field *f) +{ + struct cb_field *fp; + int is_indirect,idx; + unsigned int offset; + + if (f->flag_is_returning) /* Non static so cannot be in symbol table */ + return; + if (!output_target) + f->symtab = num_symtab++; + emit_comma (); + output ("/*%4d*/ {",f->symtab); + if (f->flag_indexed_by + || (f->flag_external && f->level == 1)) { + output (" 0, 0"); + } else { + output ("%4d",f->parent?f->parent->symtab:0); + output (",%4d",f->sister?f->sister->symtab:0); + } + if (f->flag_filler) + output(",NULL"); + else + output (",\"%s\"", f->name); + fp = real_field_founder (f); + is_indirect = SYM_ADRS_PTR; + offset = f->offset; + if (chk_field_variable_address (f)) { + is_indirect = SYM_ADRS_VARY; + output (",NULL"); + offset = 0; + } else + if (fp->flag_item_based) { + output (",&%s%d", CB_PREFIX_BASE, fp->id); + } else + if (fp->storage == CB_STORAGE_LINKAGE) { + if (f->flag_any_numeric + || f->flag_any_length) { + output (",&%s%d", CB_PREFIX_FIELD, f->id); + offset = 0; + is_indirect = SYM_ADRS_FIELD; + } else + if (f->flag_cob_field) { + output (",&%s%d.data", CB_PREFIX_FIELD, f->id); + offset = 0; + } else + if (fp->flag_cob_field) { + output (",&%s%d.data", CB_PREFIX_FIELD, fp->id); + } else { + output (",&%s%d", CB_PREFIX_BASE, fp->id); + } + } else + if (fp->storage == CB_STORAGE_LOCAL) { + output (",&cob_local_save"); + } else + if (fp->flag_external) { + output (",&%s%d", CB_PREFIX_BASE, fp->id); + } else + if (f->flag_cob_field) { + output (",&%s%d.data", CB_PREFIX_FIELD, f->id); + offset = 0; + } else + if (fp->flag_cob_field) { + output (",&%s%d.data", CB_PREFIX_FIELD, fp->id); + } else + if (f->flag_indexed_by + || f->flag_local) { + output (",&%s%d", CB_PREFIX_BASE, f->id); + offset = 0; + is_indirect = SYM_ADRS_DATA; + } else + if (f->children + && f->children->flag_cob_field + && f->children->offset == 0) { + output (",&%s%d.data", CB_PREFIX_FIELD, f->children->id); + } else { + is_indirect = SYM_ADRS_DATA; + output (",%s%d", CB_PREFIX_BASE, fp->id); + } + output (","); + output_attr (cb_build_field_reference (f, NULL)); + output (",0"); /* NOT is_file */ + output (",%d",is_indirect); + if (f->level < 8) + output (",\t\t%02d",f->level); + else + output (",\t\t%2d",f->level); + output (",%d",f->storage); + output (",%d",f->children?1:0); + if (sym_1st_file) { + sym_1st_file = 0; + output(",0"); + } else { + output (",%d",f->redefines?1:0); + } + output (",%d",f->depending?1:0); + for (idx=0, fp = f; fp; fp = fp->parent) { + if (fp->occurs_max > 1) + idx++; + } + output (",%d",idx); + output (",00"); /* Unused bits */ + output (", %d",offset); + output (",%d",f->size); + if (f->depending) { + fp = cb_code_field (f->depending); + output (",%d", fp->symtab); + } else { + output(",0"); + } + output (",%d",f->occurs_max>1?f->occurs_max:0); + if (is_indirect == SYM_ADRS_VARY) + output (",00"); + else + output (", %d",f->offset); + output ("}"); + sym_comma = 1; +} + +static void +emit_field_indexes (struct cb_field *f) +{ + cb_tree l; + struct cb_field *fp; + + for (l = f->index_list; l; l = CB_CHAIN (l)) { + fp = CB_FIELD_PTR (CB_VALUE (l)); + if (fp->flag_sym_emitted) + continue; + fp->flag_sym_emitted = 1; + emit_one_sym (fp); + } +} + +static void +emit_record_indexes (struct cb_field *f) +{ + while ( f != NULL ) { + if (f->index_list != NULL) + emit_field_indexes (f); + if (f->children != NULL) { + emit_record_indexes (f->children); + } + f = f->sister; + } + return; +} + +static const char *sectname[] = { + "CONSTANT","FILE","WORKING-STORAGE", + "LOCAL","LINKAGE","SCREEN", + "REPORT","COMMUNICATION"}; +static void +emit_symtab (struct cb_field *f) +{ + /* Exclude internal registers (those have level 0 + in GC4 and are thus "automaticaly" excluded) + as well as typedefs */ + if (f->flag_internal_register || f->flag_is_typedef) { + return; + } + if (!f->flag_sym_emitted + && f->level >= 1 + && f->level != 66 + && f->level != 78 + && f->level != 88) { + f->flag_sym_emitted = 1; + if (f->storage != sym_storage) { + emit_comma (); + output_line ("/* %s */",sectname[f->storage]); + sym_storage = f->storage; + } + if (f->level == 1 || f->level == 77) { + emit_field_indexes (f); + emit_record_indexes (f->children); + } + emit_one_sym (f); + } + if (f->children) { + emit_symtab (f->children); + } + if (f->sister) { + emit_symtab (f->sister); + } +} + +static void +emit_mod_symtab (struct cb_program *prog) +{ + struct cb_file *fl; + cb_tree l; + struct cb_field *f; + char wrk[64]; + num_symtab = 0; + sym_comma = 0; + sym_storage = 255; + for (l = prog->file_list; l; l = CB_CHAIN (l)) { + fl = CB_FILE(CB_VALUE (l)); + if (!fl->record) continue; + sprintf(wrk,"%s %s",fl->organization != COB_ORG_SORT ? "FD" : "SD",fl->name); + emit_comma (); + if (sym_storage != CB_STORAGE_FILE) { + sym_storage = CB_STORAGE_FILE; + output_line ("/* FILE */"); + } + output ("/*%4d*/ {",num_symtab++); + output ("%4d",0); + output (",%4d",fl->record->sister?fl->record->sister->symtab:0); + output (",\"%s\"",wrk); + output (",&%s%s",CB_PREFIX_FILE, fl->cname); + output (",NULL,1,1,\t\t00,%d,0,0,0,0,0,0,0,0",CB_STORAGE_FILE); + output ("}"); + sym_comma = 1; + sym_1st_file = 1; + for (f = fl->record->sister; f; f = f->sister) { + emit_symtab (f); + } + } + for (f = prog->working_storage; f; f = f->sister) { + emit_symtab (f); + } + for (f = prog->screen_storage; f; f = f->sister) { + emit_symtab (f); + } + for (f = prog->report_storage; f; f = f->sister) { + emit_symtab (f); + } + for (f = prog->local_storage; f; f = f->sister) { + emit_symtab (f); + } + for (f = prog->linkage_storage; f; f = f->sister) { + emit_symtab (f); + } +} + +/* + * Clear the symbol emited flag + */ +static void +clear_symtab (struct cb_field *f) +{ + struct cb_field *fp; + cb_tree l; + f->flag_sym_emitted = 0; + for (l = f->index_list; l; l = CB_CHAIN (l)) { + fp = CB_FIELD_PTR (CB_VALUE (l)); + fp->flag_sym_emitted = 0; + } + if (f->children) { + clear_symtab (f->children); + } + if (f->sister) { + clear_symtab (f->sister); + } +} + +static void +clear_mod_symtab (struct cb_program *prog) +{ + struct cb_file *fl; + cb_tree l; + struct cb_field *f; + + num_symtab = 0; + sym_comma = 0; + sym_storage = 255; + for (l = prog->file_list; l; l = CB_CHAIN (l)) { + fl = CB_FILE(CB_VALUE (l)); + if (!fl->record) continue; + for (f = fl->record->sister; f; f = f->sister) { + clear_symtab (f); + } + } + for (f = prog->working_storage; f; f = f->sister) { + clear_symtab (f); + } + for (f = prog->local_storage; f; f = f->sister) { + clear_symtab (f); + } + for (f = prog->linkage_storage; f; f = f->sister) { + clear_symtab (f); + } + for (f = prog->screen_storage; f; f = f->sister) { + clear_symtab (f); + } + for (f = prog->report_storage; f; f = f->sister) { + clear_symtab (f); + } +} + /* LOCAL-STORAGE pointer */ static void @@ -2015,7 +2399,8 @@ output_local_storage_pointer (struct cb_program *prog) if (prog->local_storage && local_mem) { output_local ("\n/* LOCAL storage pointer */\n"); output_local ("unsigned char\t\t*cob_local_ptr = NULL;\n"); - if (prog->flag_global_use) { + if (current_prog->flag_global_use + || cb_flag_symbols) { output_local ("static unsigned char\t*cob_local_save = NULL;\n"); } } @@ -2334,7 +2719,10 @@ output_emit_field (cb_tree x, const char *cmt) if (!(f->report_flag & COB_REPORT_REF_EMITTED)) { int i; + if (f->flag_cob_field) + return; f->report_flag |= COB_REPORT_REF_EMITTED; + f->flag_cob_field = 1; if (f->step_count < f->size) { f->step_count = f->size; } @@ -2386,14 +2774,6 @@ output_local_field_cache (struct cb_program *prog) return; } - /* Switch to local storage file */ - output_target = prog->local_include->local_fp; - if (prog->flag_recursive) { - output_local ("\n/* Fields for recursive routine */\n"); - } else { - output_local ("\n/* Fields (local) */\n"); - } - local_field_cache = list_cache_sort (local_field_cache, &field_cache_cmp); for (field = local_field_cache; field; field = field->next) { @@ -2408,10 +2788,13 @@ output_local_field_cache (struct cb_program *prog) output_emit_field (cb_build_field_reference (f, NULL), NULL); needs_comment = 0; } else { + f->flag_cob_field = 1; output ("static cob_field %s%d\t= ", CB_PREFIX_FIELD, f->id); output_field (field->x); } } else { + if (!prog->flag_recursive) { + f->flag_cob_field = 1; } output ("static cob_field %s%d\t= ", CB_PREFIX_FIELD, f->id); output ("{"); output_size (field->x); @@ -2430,6 +2813,40 @@ output_local_field_cache (struct cb_program *prog) output_newline (); f->report_flag |= COB_REPORT_REF_EMITTED; } +} + +static void +output_local_fields (struct cb_program *prog) +{ + cb_tree l; + struct cb_field *f; + + /* Switch to local storage file */ + output_target = prog->local_include->local_fp; + if (prog->flag_recursive) { + output_local ("\n/* Fields for recursive routine */\n"); + } else { + output_local ("\n/* Fields (local) */\n"); + } + + output_local_field_cache (prog); + + /* Output variable size/location parameters */ + for (l = prog->parameter_list; l; l = CB_CHAIN (l)) { + f = cb_code_field (CB_VALUE (l)); + if (!f->flag_field + && (chk_field_variable_size (f) + || chk_field_variable_address (f))) { + f->flag_cob_field = 1; + output ("static cob_field %s%d\t= ", CB_PREFIX_FIELD, f->id); + output ("{"); + output ("0, NULL, "); + output_attr (cb_build_field_reference (f, NULL)); + output ("}; /* %s */",f->name); + output_newline (); + } + + } /* Output report writer special fields */ if (prog->report_storage) { @@ -2453,6 +2870,26 @@ output_local_field_cache (struct cb_program *prog) } output_local ("\n/* End of fields */\n\n"); + + if (cb_flag_symbols + && prog->prog_type == 0 + && !prog->flag_recursive) { + FILE *svout = output_target; + int max; + output_target = NULL; + emit_mod_symtab (prog); + max = num_symtab; + output_target = svout; + clear_mod_symtab (prog); + output_line ("/* Symbol table for %s */",prog->orig_program_id); + output_line ("static cob_symbol %s_sym_tab [] = {",prog->program_id); + emit_mod_symtab (prog); + emit_comma (); + output_line (" {%4d,%4d,NULL,NULL,NULL,0,0,0,0}",0,0); + output_line ("};"); + output_line ("static unsigned int %s_num_sym = %d;",prog->program_id,max); + output_newline (); + } /* Switch to main storage file */ output_target = cb_storage_file; } @@ -2476,7 +2913,7 @@ output_nonlocal_field_cache (void) output_storage ("\n/* PROGRAM-ID : %s */\n", prev_prog); } - + field->f->flag_cob_field = 1; output ("static cob_field %s%d\t= ", CB_PREFIX_FIELD, field->f->id); if (!field->f->flag_local) { @@ -7094,6 +7531,10 @@ output_call (struct cb_call *p) output (");"); output_newline (); + if (current_prog->local_storage + && cb_flag_symbols) { + output_line ("cob_local_save = cob_local_ptr;"); + } if (except_id > 0) { output_line ("if (unlikely((cob_glob_ptr->cob_exception_code & 0x%04x) == 0x%04x))", @@ -8427,7 +8868,8 @@ output_trace_info (cb_tree x, const enum cob_statement stmnt) if (!cb_old_trace) { if (cb_flag_traceall) { - output_line ("cob_trace_statement (%s);", stmnt_enum); + output_line ("if ((module->flag_debug_trace & COB_MODULE_READYTRACE))"); + output_line (" cob_trace_statement (%s);", stmnt_enum); } } else { output_prefix (); @@ -9701,23 +10143,6 @@ output_ml_generate_init (struct cb_ml_generate_tree *tree) /* Handle REPORTs */ -static void -compute_report_rcsz (struct cb_field *p) -{ -#if 0 /* already checked: doesn't happen */ - if (p == NULL) { - return; - } -#endif - if (p->sister) { - compute_report_rcsz (p->sister); - } - if (p->children) { - compute_report_rcsz (p->children); - } - p->count++; -} - /* Report data definition */ /* Individual fields of the report(s) */ @@ -11220,8 +11645,9 @@ output_module_init_function (struct cb_program *prog) opt |= COB_MODULE_DEBUG; } #endif - output_line ("module->flag_debug_trace = %d;", opt); + output_line ("module->flag_debug_trace |= %d;", opt); } + output_line ("module->flag_dump_sect = 0x%02X;", cb_flag_dump); output_line ("module->flag_dump_ready = %u;", cb_flag_dump ? 1 : 0); output_line ("module->xml_mode = %u;", cb_xml_parse_xmlss); output_line ("module->module_stmt = 0;"); @@ -11804,8 +12230,6 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) if (prog->prog_type == COB_MODULE_TYPE_PROGRAM) { output_line ("/* CANCEL callback */"); output_line ("if (unlikely(entry < 0)) {"); - output_line ("\tif (entry == -10)"); - output_line ("\t\tgoto P_dump;"); output_line ("\tif (entry == -20)"); output_line ("\t\tgoto P_clear_decimal;"); output_line ("\tgoto P_cancel;"); @@ -11851,6 +12275,15 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) } output_line ("module->cob_procedure_params = cob_procedure_params;"); output_newline (); + if (cb_flag_symbols + && prog->prog_type == 0 + && !prog->flag_recursive) { + output_line ("module->num_symbols = %s_num_sym;",prog->program_id); + output_line ("module->module_symbols = %s_sym_tab;",prog->program_id); + } else { + output_line ("module->num_symbols = 0;"); + output_line ("module->module_symbols = NULL;"); + } #if 0 /* RXWRXW USERFUNC */ if (prog->prog_type == COB_MODULE_TYPE_FUNCTION) { @@ -11943,7 +12376,8 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) output_line ("/* Allocate LOCAL storage */"); output_line ("cob_local_ptr = cob_malloc (%dU);", local_mem); - if (prog->flag_global_use) { + if (prog->flag_global_use + || cb_flag_symbols) { output_line ("cob_local_save = cob_local_ptr;"); } } @@ -11983,7 +12417,8 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) for (l = prog->global_list; l; l = CB_CHAIN (l)) { output_line ("if (unlikely(entry == %d)) {", CB_LABEL (CB_VALUE (l))->id); - if (local_mem) { + if (local_mem + && cb_flag_symbols) { output_line ("\tcob_local_ptr = cob_local_save;"); } for (l2 = parameter_list; l2; l2 = CB_CHAIN (l2)) { @@ -12314,7 +12749,8 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) output_line ("if (cob_local_ptr) {"); output_line ("\tcob_free (cob_local_ptr);"); output_line ("\tcob_local_ptr = NULL;"); - if (current_prog->flag_global_use) { + if (current_prog->flag_global_use + || cb_flag_symbols) { output_line ("\tcob_local_save = NULL;"); } output_line ("}"); @@ -12361,7 +12797,8 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) CB_PREFIX_STRING, lookup_string (string_buffer)); } else { - output_line ("cob_trace_exit (%s%d);", + output_line ("if ((module->flag_debug_trace & COB_MODULE_READYTRACE))"); + output_line (" cob_trace_exit (%s%d);", CB_PREFIX_STRING, lookup_string(excp_current_program_id)); } output_newline (); @@ -12681,10 +13118,13 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list) output_line ("initialized = 1;"); output_line ("goto P_ret_initialize;"); - output_newline (); - output_line ("P_dump:"); - output_dump_code (prog, parameter_list); - output_line (" return 0;"); + /* Keep old dump for compatibility */ + if (cb_wants_dump_comments) { + output_newline (); + output_line ("P_dump:"); + output_dump_code (prog, parameter_list); + output_line (" return 0;"); + } output_newline (); /* Set up CANCEL callback code */ @@ -13612,6 +14052,36 @@ output_header (const char *locbuff, const struct cb_program *cp) } } +/* Symbol Table requested so make sure all 01/77 symbols have cob_field */ +static void +emit_base_symbols (struct cb_program *prog) +{ + struct cb_file *fl; + struct cb_field *f; + cb_tree l; + if (cb_flag_symbols) { + for (l = prog->file_list; l; l = CB_CHAIN (l)) { + fl = CB_FILE(CB_VALUE (l)); + if (!fl->record) continue; + for (f = fl->record->sister; f; f = f->sister) { + count_all_fields (f); + } + } + for (f = prog->working_storage; f; f = f->sister) { + count_all_fields (f); + } + for (f = prog->local_storage; f; f = f->sister) { + count_all_fields (f); + } + for (f = prog->linkage_storage; f; f = f->sister) { + count_all_fields (f); + } + for (f = prog->screen_storage; f; f = f->sister) { + count_all_fields (f); + } + } +} + void codegen (struct cb_program *prog, const char *translate_name) { @@ -13690,6 +14160,16 @@ codegen_init (struct cb_program *prog, const char *translate_name) globext_cache = NULL; field_cache = NULL; + { + struct cb_program *cp; + for (cp = prog; cp; cp = cp->next_program) { + struct cb_program *xp = current_prog; + current_prog = cp; + emit_base_symbols (cp); + current_prog = xp; + } + } + strftime (timestamp_buffer, (size_t)COB_MINI_MAX, "%b %d %Y %H:%M:%S", ¤t_compile_tm); @@ -13858,7 +14338,7 @@ codegen_internal (struct cb_program *prog, const int subsequent_call) } rep = CB_REPORT_PTR (CB_VALUE(l)); if (rep) { - compute_report_rcsz (rep->records); + count_all_fields (rep->records); } } } @@ -13886,7 +14366,7 @@ codegen_internal (struct cb_program *prog, const int subsequent_call) } output_local_base_cache (); - output_local_field_cache (prog); + output_local_fields (prog); /* Report data fields */ if (prog->report_storage) { diff --git a/cobc/flag.def b/cobc/flag.def index 4850daa60..9bb3ca007 100644 --- a/cobc/flag.def +++ b/cobc/flag.def @@ -143,6 +143,9 @@ CB_FLAG (cb_flag_traceall, 1, "traceall", _(" -ftraceall generate trace code\n" " * scope: executed SECTION/PARAGRAPH/STATEMENTS")) +CB_FLAG (cb_flag_symbols, 1, "symtab", + _(" -fsymtab build symbol table for dump/trace/debug")) + CB_FLAG (cb_flag_syntax_only, 1, "syntax-only", _(" -fsyntax-only syntax error checking only; don't emit any output")) diff --git a/cobc/tree.h b/cobc/tree.h index 5fb72a3fb..9fbfca06e 100644 --- a/cobc/tree.h +++ b/cobc/tree.h @@ -933,6 +933,8 @@ struct cb_field { enum cb_storage storage; /* Storage section */ enum cb_usage usage; /* USAGE */ + unsigned int symtab; /* Position in cob_symbol table */ + /* Flags */ unsigned char flag_base; /* Has memory allocation */ unsigned char flag_external; /* EXTERNAL */ @@ -991,6 +993,8 @@ struct cb_field { unsigned int flag_sync_left : 1; /* SYNCHRONIZED LEFT */ unsigned int flag_sync_right : 1; /* SYNCHRONIZED RIGHT */ unsigned int flag_internal_register : 1; /* Is an internally generated register */ + unsigned int flag_sym_emitted: 1; /* cob_symbol was emitted */ + unsigned int flag_cob_field : 1; /* Had cob_field emitted */ unsigned int flag_is_typedef : 1; /* TYPEDEF */ unsigned int flag_picture_l : 1; /* Is USAGE PICTURE L */ unsigned int flag_comp_1 : 1; /* Is USAGE COMP-1 */ diff --git a/libcob/common.c b/libcob/common.c index eef27ffc1..71ea87a64 100644 --- a/libcob/common.c +++ b/libcob/common.c @@ -1438,6 +1438,44 @@ cob_set_signal (void) #endif } +/* Used by cob_set_dump_signal (triggered with symbols generated with -fdump) to catch abort while dumping */ +void +cob_set_dump_signal (void *hndlr) +{ +#if defined(HAVE_SIGACTION) && !defined(_WIN32) + int k; + sigset_t sigs; + struct sigaction sa; + struct sigaction osa; + + if (hndlr == NULL) + hndlr = (void*)SIG_DFL; + + (void)sigemptyset(&sigs); + /* Unblock signals to allow catch of another abort during dump */ + for (k = 0; k < NUM_SIGNALS; k++) { + if (signals[k].for_dump) { + (void)sigaddset(&sigs, signals[k].sig); + } + } + (void)sigprocmask(SIG_UNBLOCK, &sigs, NULL); + + memset (&sa, 0, sizeof (sa)); + memset (&osa, 0, sizeof (osa)); + sa.sa_handler = (void(*)(int))hndlr; + + /* Establish signals to catch and continue */ + for (k = 0; k < NUM_SIGNALS; k++) { + if (signals[k].for_dump) { + (void)sigemptyset (&sa.sa_mask); + (void)sigaction (signals[k].sig, &sa, NULL); + } + } +#else + COB_UNUSED (hndlr); +#endif +} + /* ASCII Sign - Reading and undo the "overpunch"; * Note: if used on an EBCDIC machine this is actually _not_ an overpunch * but a replacement! @@ -2980,13 +3018,31 @@ cob_nop (void) void cob_ready_trace (void) { + cob_module *mod; + int k; + const int MAX_ITERS = 10240; + cobsetptr->cob_line_trace = 1; + /* FIXME: this is overkill - it should only be set in the current program + and within the start code for each ENTRY be set */ + for (k = 0, mod = COB_MODULE_PTR; mod && k < MAX_ITERS; mod = mod->next, k++) { + mod->flag_debug_trace |= COB_MODULE_READYTRACE; + } } void cob_reset_trace (void) { + cob_module *mod; + int k; + const int MAX_ITERS = 10240; + cobsetptr->cob_line_trace = 0; + /* FIXME: with the change above only the current program and its calers need + to be reset here */ + for (k = 0, mod = COB_MODULE_PTR; mod && k < MAX_ITERS; mod = mod->next, k++) { + mod->flag_debug_trace &= ~COB_MODULE_READYTRACE; + } } unsigned char * @@ -3254,6 +3310,11 @@ cob_module_global_enter (cob_module **module, cob_global **mglobal, COB_MODULE_PTR->statement = STMT_UNKNOWN; cobglobptr->cob_stmt_exception = 0; + if (cobsetptr->cob_line_trace) + COB_MODULE_PTR->flag_debug_trace |= COB_MODULE_READYTRACE; + else + COB_MODULE_PTR->flag_debug_trace &= ~COB_MODULE_READYTRACE; + return 0; } @@ -3268,6 +3329,7 @@ void cob_module_leave (cob_module *module) { COB_UNUSED (module); + cob_get_source_line (); /* Pop module pointer */ COB_MODULE_PTR = COB_MODULE_PTR->next; } @@ -10685,6 +10747,215 @@ cob_get_dump_file (void) #endif } +static const char *sectname[] = { + "CONSTANT","FILE","WORKING-STORAGE", + "LOCAL","LINKAGE","SCREEN", + "REPORT","COMMUNICATION"}; +static unsigned char sectdump[] = { + 0, COB_DUMP_FD, COB_DUMP_WS, COB_DUMP_LO, COB_DUMP_LS, + COB_DUMP_SC, COB_DUMP_RD, COB_DUMP_RD}; +#define SYM_MAX_IDX 8 +static int sym_idx = 0; +static int sym_sub [SYM_MAX_IDX]; +static int sym_size[SYM_MAX_IDX]; + +static jmp_buf save_sig_env; +static void +catch_sig_jmp (int sig) +{ + longjmp(save_sig_env, sig); +} + +void +cob_sym_get_field (cob_field *f, cob_symbol *sym, int k) +{ + int j; + f->size = sym[k].size; + f->attr = sym[k].attr; + if (sym[k].is_indirect == SYM_ADRS_PTR) { + memcpy (&f->data, sym[k].adrs, sizeof(void*)); + /* + * If field has not yet been referenced, the address will be NULL + * Scan up to parent and use that base address plus 'roffset' + * If the field had been referenced the field address will be set + * and 'offset' will be ZERO + */ + for (j = k; f->data == NULL; j = sym[j].parent) { + if (sym[j].parent == 0) { /* Base of COBOL Record */ + memcpy (&f->data, sym[j].adrs, sizeof(void*)); + if (f->data != NULL) + f->data += sym[k].roffset; + return; + } + } + if (f->data != NULL) + f->data += sym[k].offset; + } else if (sym[k].is_indirect == SYM_ADRS_FIELD) { + memcpy (f, sym[k].adrs, sizeof(cob_field)); + } else { + f->data = sym[k].adrs; + if (f->data != NULL) + f->data += sym[k].offset; + } +} + +int +cob_sym_get_occurs (cob_symbol *sym, int k) +{ + cob_field d0; + int occmax; + if (sym[k].has_depend) { + cob_sym_get_field (&d0, sym, sym[k].depending); + occmax = cob_get_int (&d0); + if (occmax > sym[k].occurs) + occmax = sym[k].occurs; + } else { + occmax = sym[k].occurs; + } + return occmax; +} + +static void cob_dump_table ( cob_symbol *sym, int k); +static void +cob_dump_sub ( cob_symbol *sym, int k, int sub) +{ + cob_field f0; + int j; + + sym_sub [sym_idx-1] = sub; + cob_sym_get_field (&f0, sym, k); + cob_dump_field ( sym[k].level, sym[k].name?sym[k].name:"FILLER", + &f0, 0, sym_idx, + sym_sub [0], sym_size [0], + sym_sub [1], sym_size [1], + sym_sub [2], sym_size [2], + sym_sub [3], sym_size [3], + sym_sub [4], sym_size [4], + sym_sub [5], sym_size [5], + sym_sub [6], sym_size [6], + sym_sub [7], sym_size [7]); + if (sym[k].is_group) { + for (j = k+1; sym[j].parent == k; j++) { + if (sym[j].occurs > 1) { + cob_dump_table (sym, j); + if ((j = sym[j].sister) == 0) + break; + j--; + } else { + cob_dump_sub (sym, j, sub); + } + } + } +} + +static void +cob_dump_table ( cob_symbol *sym, int k) +{ + int j, occmax; + + occmax = cob_sym_get_occurs (sym, k); + sym_size [sym_idx++] = sym[k].size; + for (j=0; j < occmax; j++) + cob_dump_sub (sym, k, j); + sym_size [--sym_idx] = 0; +} + +static void +cob_dump_symbols (cob_module *mod) +{ + static int skipgrp; + static cob_symbol *skpsym; + int j, k, sect; + cob_symbol *sym; + cob_field f0; + char msg[80]; + FILE *fp; + cob_file *fl; + + fp = cob_get_dump_file (); + sect = 255; + sym = mod->module_symbols; + mod->flag_debug_trace |= COB_MODULE_DUMPED; + + fprintf (fp, _("Dump Program-Id %s from %s compiled %s"), + mod->module_name, mod->module_source, mod->module_formatted_date); + fputc ('\n', fp); + for (k = 0; k < mod->num_symbols; k++) { + if (sym[k].is_redef) { + j = k; + while (j < mod->num_symbols + && sym[j].is_redef + && sym[j].sister ) { + k = j; + j = sym[j].sister; + } + continue; + } + if (sym[k].section == 0 + || !(mod->flag_dump_sect & sectdump[sym[k].section])) + continue; + if (sect != sym[k].section) { + sect = sym[k].section; + if (!sym[k].is_file) + cob_dump_output (sectname[sect]); + } + if (sym[k].is_file) { + memcpy (&fl, sym[k].adrs, sizeof(void*)); + cob_dump_file (sym[k].name, fl); + continue; + } + skipgrp = 0; + cob_sym_get_field (&f0, sym, k); + cob_set_dump_signal ((void *)catch_sig_jmp); + if (setjmp (save_sig_env) != 0) { + skipgrp = 1; + while (sym[k].parent > 0) + k = sym[k].parent; + if (skpsym == &sym[k]) + goto skipsym; + skpsym = &sym[k]; + sprintf (msg," >>>> Dump of %s aborted! <<<< !!", + sym[k].name?sym[k].name:"FILLER"); + cob_dump_output (msg); + } else if (sym[k].occurs > 1) { + for (sym_idx = 0; sym_idx < SYM_MAX_IDX; sym_idx++) + sym_sub [sym_idx] = sym_size [sym_idx] = 0; + sym_idx = 0; + cob_dump_table ( sym, k); + if (sym[k].is_group) + skipgrp = 1; + } else { + cob_dump_field ( sym[k].level, sym[k].name?sym[k].name:"FILLER", &f0, 0, 0); + } + if (skipgrp) { +skipsym: + if (sym[k].sister) { + k = sym[k].sister; + } else { + while (++k < mod->num_symbols + && sym[k].level > 1 + && sym[k].level != 77); + } + k--; + } else if (f0.data == NULL) { + if (sym[k].sister) { + k = sym[k].sister - 1; + continue; + } else if (k+1 < mod->num_symbols + && sym[k].section != sym[k+1].section) { + continue; + } else if (sym[k].level == 1 + || sym[k].level == 77) { + break; + } + } + } + sprintf (msg, "END OF DUMP - %s", mod->module_name); + cob_dump_output (msg); + fputc ('\n', fp); + fflush (fp); +} + static void cob_dump_module (char *reason) { @@ -10755,15 +11026,10 @@ cob_dump_module (char *reason) } k = 0; for (mod = COB_MODULE_PTR; mod; mod = mod->next) { - if (mod->module_cancel.funcint) { - int (*cancel_func)(const int); - cancel_func = mod->module_cancel.funcint; - - fprintf (fp, _("Dump Program-Id %s from %s compiled %s"), - mod->module_name, mod->module_source, mod->module_formatted_date); - fputc ('\n', fp); - (void)cancel_func (-10); - fputc ('\n', fp); + if (mod->module_symbols + && mod->num_symbols > 0 + && !(mod->flag_debug_trace & COB_MODULE_DUMPED)) { + cob_dump_symbols (mod); } if (mod->next == mod || k++ == MAX_MODULE_ITERS) { diff --git a/libcob/common.h b/libcob/common.h index c01965eff..3e26d2c69 100644 --- a/libcob/common.h +++ b/libcob/common.h @@ -1128,6 +1128,36 @@ typedef union __cob_fld_union { } cob_fld_union; #endif +/* Symbol table structure; Used for dump & debugging */ + +typedef struct __cob_symbol { + unsigned int parent; /* Index to parent cob_symbol */ + unsigned int sister; /* Index to sister cob_symbol */ + char *name; /* Field name, NULL means FILLER */ + void *adrs; /* Pointer to data pointer */ + const cob_field_attr *attr; /* Pointer to attribute */ + + unsigned int is_file:1; /* 'data' points to FILE pointer */ + unsigned int is_indirect:2;/* 'data' points to the field's pointer */ +#define SYM_ADRS_DATA 0 /* 'adrs' is direct address of field data */ +#define SYM_ADRS_PTR 1 /* 'adrs' is address of address of field data */ +#define SYM_ADRS_FIELD 2 /* 'adrs' is address of complete cob_field */ +#define SYM_ADRS_VARY 3 /* 'adrs' varys due to prior DEPENDING ON */ + unsigned int level:7; /* Level number */ + unsigned int section:3; /* SECTION of program */ + unsigned int is_group:1; /* Field was Group item */ + unsigned int is_redef:1; /* Field has REDEFINES */ + unsigned int has_depend:1;/* Field has DEPENDING ON */ + unsigned int subscripts:5;/* Field requires N subscripts */ + unsigned int unused:11; + + unsigned int offset; /* Offset in record, May be ZERO for LINKAGE fields */ + unsigned int size; /* Field size */ + unsigned int depending; /* Index to DEPENDING ON field */ + unsigned int occurs; /* Max number of OCCURS */ + unsigned int roffset; /* Original Offset within record */ +} cob_symbol; + /* Representation of 128 bit FP */ typedef struct __cob_fp_128 { @@ -1265,8 +1295,18 @@ typedef struct __cob_module { #endif #define COB_MODULE_TRACE 2 #define COB_MODULE_TRACEALL 4 - - unsigned char unused[1]; /* Use these flags up later, added for alignment */ +#define COB_MODULE_READYTRACE 8 +#define COB_MODULE_DUMPED 16 + unsigned char flag_dump_sect; /* Which SECTIONS to dump */ +#define COB_DUMP_NONE 0x00 /* No dump */ +#define COB_DUMP_FD 0x01 /* FILE SECTION -> FILE DESCRIPTION */ +#define COB_DUMP_WS 0x02 /* WORKING-STORAGE SECTION */ +#define COB_DUMP_RD 0x04 /* REPORT SECTION */ +#define COB_DUMP_SD 0x08 /* FILE SECTION -> SORT DESCRIPTION */ +#define COB_DUMP_SC 0x10 /* SCREEN SECTION */ +#define COB_DUMP_LS 0x20 /* LINKAGE SECTION */ +#define COB_DUMP_LO 0x40 /* LOCAL-STORAGE SECTION */ +#define COB_DUMP_ALL (COB_DUMP_FD|COB_DUMP_WS|COB_DUMP_RD|COB_DUMP_SD|COB_DUMP_SC|COB_DUMP_LS|COB_DUMP_LO) unsigned int module_stmt; /* Position of last statement executed as modulated source line @@ -1292,6 +1332,8 @@ typedef struct __cob_module { #define COB_XML_XMLNSS 1 /* similar to XMLPARSE(XMLNSS) Micro Focus, IBM may be different (_very_ likely for error codes); but the main difference is to "COMPAT" */ + unsigned int num_symbols; /* Number of symbols in table */ + cob_symbol *module_symbols; /* Array of module symbols */ struct cob_frame_ext *frame_ptr; /* current frame ptr, note: if set then cob_frame in this module is of type "struct cob_frame_ext", otherwise "struct cob_frame" */ @@ -1633,12 +1675,15 @@ struct cobjmp_buf { /*******************************/ /* Functions in common.c */ +COB_EXPIMP void cob_set_dump_signal (void *); COB_EXPIMP const char* cob_get_sig_name (int); COB_EXPIMP const char* cob_get_sig_description (int); COB_EXPIMP void print_info (void); COB_EXPIMP void print_info_detailed (const int); COB_EXPIMP int cob_load_config (void); COB_EXPIMP void print_runtime_conf (void); +COB_EXPIMP void cob_sym_get_field (cob_field *f, cob_symbol *sym, int k); +COB_EXPIMP int cob_sym_get_occurs (cob_symbol *sym, int k); COB_EXPIMP void cob_set_exception (const int); COB_EXPIMP int cob_last_exception_is (const int);