!+ ! NAME ! CMAP_TESTOR -- Handles parsing of the map file ! ! DESCRIPTION ! This module is the guts of the check_map software ! in that it parses the map file searching for PSECT ! errors an undefined symbol errors. ! ! RETURN VALUE ! CHKMAP_OKAY - for clean map file ! CHKMAP_BADMAP - for errors in map file ! ! HISTORY ! 4-8-88 Bauer Initial implementation. ! 4-19-88 Bauer Revamped undefined symbols report so that it contains ! more info - namely the module name AND the file in which ! the referenced symbol was undefined. ! !- MODULE CMAP$TESTOR IDENT 'V1.0'; ! ! Set definitions ! SET digit ( '0' .. '9' ); SET hex_digit ( '0' .. '9' OR 'a' .. 'f' OR 'A' .. 'F' ); SET alpha ( 'a'.. 'z' OR 'A'..'Z' OR '_' OR '$'); SET white_space ( ' ' OR S'ht' ); SET id_part ( alpha OR digit OR '_' OR '$' OR '.' OR '*' ); SET file_start ( alpha OR '[' OR '$' ); SET file_end ( alpha OR digit OR '.' OR ']' OR '[' OR ';' OR ':' OR '-' OR '$'); ! ! Token Definitions ! TOKEN stop_scan CASELESS {'Symbols By Name'}; ! Used as END-OF-SCAN marker so as to not ! waste time in the lower 80% of the map TOKEN undefined_symbol {'%LINK-W-USEUNDEF, undefined symbol '}; ! Used to match undefined symbols TOKEN module_token {'module '}; ! Used to match undefined symbols TOKEN file_token {'file '}; ! Used to match undefined symbols TOKEN paren ALIAS '(' { '(' }; TOKEN dot ALIAS '.' { '.' }; TOKEN blanks { white_space [white_space...] }; TOKEN id CASELESS { {'. BLANK .'} | {alpha [id_part...]} }; TOKEN file_id CASELESS { file_start [file_end...] }; TOKEN hex { hex_digit hex_digit hex_digit hex_digit ! A HEX number in a link map has 8 hex digits hex_digit hex_digit hex_digit hex_digit }; TOKEN integer { digit [digit...] }; TOKEN date_start CASELESS { digit [digit] '-' alpha alpha alpha '-' }; ! For matching module lines TOKEN ovr_or_con CASELESS { 'OVR,' | 'CON,' }; ! For PSECT attributes OVERLAY and CONCATENATE ! ! Type definitions ! TYPE PSECT_DATA: ! For buffering PSECT data for potential ! printing if there is an error in the PSECT RECORD name : STRING(20), ! Psect Module Name base : STRING(8), ! Base address length : STRING(10), ! Psect length error_flag : INTEGER, ! Error in this module? END RECORD; TYPE MSG_VECTOR: ! For SYS$PUTMSG calls RECORD arg_count : INTEGER, ! Length of message vector message_code : INTEGER, ! Error message code fao_param_count : INTEGER, ! How many FAO parameters (0 - 1) fao_p1 : POINTER TO STRING, ! First FAO parameter (optional) END RECORD; ! ! Global Variables ! DECLARE msgvec : MSG_VECTOR; ! SYS$PUTMSG mesasge vector DECLARE undefined_symbols : TREE(STRING,STRING) of STRING; ! Array of undefined symbol strings DECLARE number_undefined_symbols : INTEGER; ! How many in above array? DECLARE there_are_undefined_symbols : BOOLEAN; ! Are there any? DECLARE psect_list : TREE(INTEGER) of PSECT_DATA; ! Array of PSECT information ! PSECT data is always stored in psect_list(0) DECLARE psect_module_count : INTEGER; ! How many in above array? DECLARE module_list : GLOBAL TREE(STRING) of STRING; ! Array of module file names DECLARE psect_errors : BOOLEAN; ! Any errors in current PSECT? DECLARE skipping_this_psect : BOOLEAN; ! Skip PSECT when CON, attribute DECLARE first_data_dump : BOOLEAN; ! First error flag so you know ! when to open the output file DECLARE old_psect_name : STRING (20); ! Used for storing previous PSECT name ! since psect is terminated by a new psect ! and name is needed for report if any errors DECLARE input_map_name : STRING; ! Name of the input map file DECLARE output_file_name : STRING; ! Name of the output report file DECLARE exclude_tree : EXTERNAL TREE(STRING) of BOOLEAN; ! List of excluded PSECT names and UNDEFINED symbols ! ! Constant Declaration ! CONSTANT CHKMAP_OKAY EXTERNAL INTEGER; ! When no errors in map CONSTANT CHKMAP_BADMAP EXTERNAL INTEGER; ! When errors found in map CONSTANT CHKMAP_PSECT EXTERNAL INTEGER; ! When errors found in psect(s) CONSTANT CHKMAP_UNDEFSYM EXTERNAL INTEGER; ! When undefines found CONSTANT HEX_F0000 = 983040; ! SYS$PUTMSG print flags CONSTANT NO_ERRORS = 0; ! No Psect errors for module CONSTANT BASE_ERROR = 1; ! BASE Address Psect errors for module CONSTANT LENGTH_ERROR = 2; ! LENGTH Psect errors for module CONSTANT BOTH_ERRORS = 3; ! Both BASE and LENGTH Psect errors for module ! ! FORWARD Procedure Declarations ! FORWARD PROCEDURE dump_psect_data; FORWARD PROCEDURE dump_undefined_data; FORWARD PROCEDURE add_to_psect_list ( INTEGER, STRING, STRING, STRING ); ! ! EXTERNAL Procedure Declaration ! EXTERNAL PROCEDURE SYS$PUTMSG ( MSG_VECTOR, FILL(4), FILL(4), FILL(4) ); EXTERNAL PROCEDURE print_psect_data (DESCRIPTOR STRING(20), DESCRIPTOR STRING(8), DESCRIPTOR STRING(10) ); EXTERNAL PROCEDURE print_psect_module_data (DESCRIPTOR STRING(20), DESCRIPTOR STRING(8), DESCRIPTOR STRING(10), DESCRIPTOR STRING, VALUE INTEGER); EXTERNAL PROCEDURE open_output_file (DESCRIPTOR STRING, DESCRIPTOR STRING); EXTERNAL PROCEDURE print_undefined_symbols (VALUE INTEGER, DESCRIPTOR STRING, DESCRIPTOR STRING, DESCRIPTOR STRING); EXTERNAL PROCEDURE close_output_file; !+ ! MACRO Definitions follow for MACROS: ! ! find_psect ! find_psect_module ! find_module ! stop_scanning ! find_undefined_symbol !- ! ! This MACRO matches PSECT lines in the MAP file ! MACRO find_psect TRIGGER { psect_name: id blanks base_address: hex blanks hex blanks hex blanks '(' blanks psect_length: { integer | hex } '.' COLUMN(92) attribute: ovr_or_con FIND(s'eol') }; ! New PSECT line hit - maybe ... IF psect_name <> old_psect_name THEN IF psect_errors ! Dump previous PSECT data if there was THEN ! an error in the previous PSECT CALL dump_psect_data; psect_errors = FALSE; END IF; IF attribute = 'CON,' OR psect_name = '$BLANK' ! If PSECT has CON atrribute then skip OR EXISTS(exclude_tree(psect_name)) ! up to next PSECT THEN skipping_this_psect = TRUE; ELSE skipping_this_psect = FALSE; old_psect_name = psect_name; ! Remember this for report psect_module_count = 0; ! Set module count to 0 CALL add_to_psect_list (psect_module_count, ! Fill in psect_list tree ' ', base_address, psect_length ); END IF; END IF; END MACRO; ! ! This MACRO matches the module lines that follow a PSECT line in the MAP file ! MACRO find_psect_module TRIGGER { blanks module_name: id blanks base_address: hex blanks hex blanks hex blanks '(' blanks psect_length: { integer | hex } '.' FIND(s'eol') }; IF NOT skipping_this_psect ! Only process these in OVR, attribute! THEN CALL add_to_psect_list (psect_module_count, ! Store data in psect_list tree module_name, base_address, psect_length ); IF ( (psect_list(0).base <> base_address) OR ! Check for errors by comparing against PSECT (psect_list(0).length <> psect_length) ) THEN psect_errors = TRUE; IF ( (psect_list(0).base <> base_address) AND (psect_list(0).length <> psect_length) ) THEN psect_list(psect_module_count-1).error_flag = BOTH_ERRORS; ELSE IF psect_list(0).length <> psect_length THEN psect_list(psect_module_count-1).error_flag = LENGTH_ERROR; ELSE psect_list(psect_module_count-1).error_flag = BASE_ERROR; END IF; END IF; END IF; END IF; END MACRO; ! ! This MACRO finds module file names from the MAP file ! MACRO find_module TRIGGER { module_name: id COLUMN(43) in_file: file_id blanks date_start FIND(s'eol') }; module_list(module_name) = in_file; ! Add module name and in_file to module_list tree END MACRO; ! ! This MACRO is used to find the pseudo-END-OF-FILE marker ! MACRO stop_scanning TRIGGER { stop_scan FIND (s'eol') }; ! Before we stop scanning do we have any: IF psect_errors ! Psect data to dump? THEN CALL dump_psect_data; END IF; IF there_are_undefined_symbols ! Undefined symbol data to dump? THEN CALL dump_undefined_data; END IF; STOP SCAN; ! Let's stop this nonsense END MACRO; ! ! This MACRO finds undefined LINK symbols in the MAP ! MACRO find_undefined_symbol TRIGGER { undefined_symbol symbol_name: id FIND('module',TRUE) module_token module_name: id blanks file_token file_name: file_id }; IF NOT EXISTS(exclude_tree(symbol_name)) ! Make sure we are not skipping these ... THEN undefined_symbols(symbol_name,module_name) = file_name; there_are_undefined_symbols = TRUE; number_undefined_symbols = number_undefined_symbols + 1; IF number_undefined_symbols = 1 ! If first undefined symbol print THEN ! some warning mesages msgvec.arg_count = HEX_F0000 + 2; msgvec.message_code = CHKMAP_UNDEFSYM; msgvec.fao_param_count = 0; CALL SYS$PUTMSG(msgvec, *, *, * ); END IF; END IF; END MACRO; ! ! PROCEDURES Follow ! !+ ! NAME ! dump_psect_data -- this routine dumps psect data when there is an error ! ! DESCRIPTION ! This routine is called whenever there is at least one error ! found in a PSECT. ! ! The PSECT header is dumped, followed by the module information. ! ! RETURN VALUE ! ! HISTORY ! 4-12-88 Bauer Initial implementation. ! !- PROCEDURE dump_psect_data; DECLARE i : INTEGER; ! Counter DECLARE tree_index : STRING; ! Tree subscript IF first_data_dump ! If first time, then open output file THEN ! and throw a header onto it msgvec.arg_count = HEX_F0000 + 2; ! and print a warning message msgvec.message_code = CHKMAP_PSECT; msgvec.fao_param_count = 0; CALL SYS$PUTMSG( msgvec, *, *, * ); CALL open_output_file (output_file_name, input_map_name); first_data_dump = FALSE; END IF; CALL print_psect_data ( old_psect_name, ! Print the PSECT header and data psect_list(0).base, psect_list(0).length ); FOR i = 1 to psect_module_count-1; tree_index = psect_list(i).name[1..INDEX(psect_list(i).name, ' ')-1]; CALL print_psect_module_data ( psect_list(i).name, ! Print the module data psect_list(i).base, psect_list(i).length, module_list( tree_index ), psect_list(i).error_flag ); END FOR; END PROCEDURE; !+ ! NAME ! dump_undefined_data -- this routine dumps undefined symbol data at the end of the report ! ! DESCRIPTION ! This routine is called whenever there is at least one undefined ! symbol in a link map. ! ! RETURN VALUE ! ! HISTORY ! 4-12-88 Bauer Initial implementation. ! !- PROCEDURE dump_undefined_data; DECLARE i : INTEGER; ! Counter DECLARE undef_ptr : TREEPTR(STRING) TO TREE(STRING) OF STRING; ! Pointer to Symbol name subscript DECLARE modname_ptr : TREEPTR(STRING) TO STRING; ! Pointer to module name subscript DECLARE und_sym, mod_sym, fil_sym : STRING; ! String variables for printing IF first_data_dump ! If first error then open output file and print THEN ! header information CALL open_output_file (output_file_name, input_map_name); first_data_dump = FALSE; END IF; i = 1; ! Keep track of how many unique symbols are printed undef_ptr = FIRST (undefined_symbols); ! Get root of tree ... while undef_ptr <> NIL; ! Process until tree node is NIL und_sym = SUBSCRIPT(undef_ptr); modname_ptr = FIRST (TREEPTR(undefined_symbols(und_sym))); ! Get module name subtree while modname_ptr <> NIL; ! Process until tree node is NIL mod_sym = SUBSCRIPT(modname_ptr); fil_sym = VALUE(undefined_symbols(und_sym,mod_sym)); CALL print_undefined_symbols ( i, ! Print undefined symbol line und_sym, mod_sym, fil_sym ); modname_ptr = NEXT(modname_ptr); ! Get next module data END WHILE; undef_ptr = NEXT(undef_ptr); ! Get next symbol data i = i + 1; END WHILE; END PROCEDURE; !+ ! NAME ! add_to_psect_list -- adds data to psect list tree ! ! DESCRIPTION ! This routine is called whenever there more module or psect data ! to be added to the psect tree. ! ! RETURN VALUE ! ! HISTORY ! 4-12-88 Bauer Initial implementation. ! !- PROCEDURE add_to_psect_list ( index : INTEGER, module_name : STRING, starting_address : STRING, psect_length : STRING ); psect_list(index).name = module_name; psect_list(index).base = starting_address; psect_list(index).length = psect_length; psect_list(index).error_flag = NO_ERRORS; ! Assume no errors to start index = index + 1; ! Increment subscript counter END PROCEDURE; !+ ! NAME ! cmap_testor -- main routine for this SCAN module ! ! DESCRIPTION ! This routine is thedriver for this scan module that parses the map file. ! ! RETURN VALUE ! ! HISTORY ! 4-12-88 Bauer Initial implementation. ! !- PROCEDURE cmap_testor ( inp_file : STRING, out_file : STRING ) OF integer; number_undefined_symbols = 0; ! Assume no undefined symbols there_are_undefined_symbols = FALSE; psect_errors = FALSE; ! Assume no PSECT errors yet first_data_dump = TRUE; ! And assume nothing has been printed yet output_file_name = out_file; ! Report file name input_map_name = inp_file; ! Map name START SCAN INPUT FILE input_map_name OUTPUT FILE 'NL:'; IF first_data_dump AND (number_undefined_symbols = 0) ! Any errors found??? THEN RETURN CHKMAP_OKAY; ! No errors found ELSE CALL close_output_file; RETURN CHKMAP_BADMAP; ! Errors found - return a warning END IF; END PROCEDURE; END MODULE;