?? RIGHT := 110 ??
*copyc OSD$DEFAULT_PRAGMATS
?? TITLE := 'NOS/VE : Loader : Cross reference information management' ??
?? NEWTITLE := '  Global declarations', EJECT ??
MODULE lom$cross_reference_management;

{  PURPOSE:
{    This module contains procedures responsible for storing and retrieving information used in generation
{    of the entry point cross reference portion of the load map.

{  NOTE:
{    Conditions raised: LOE$ABORT_LOAD, LOE$INSUFFICIENT_MEMORY, LOE$LOADER_MALFUNCTION.
?? PUSH (LISTEXT := ON) ??
*copyc LOT$LOADER_TYPE_DEFINITIONS
*copyc LOE$ABORT_LOAD
?? POP ??
*copyc MMP$CREATE_SEGMENT
*copyc MMP$DELETE_SEGMENT
*copyc LOP$PROCESS_ALL_ENTRY_DEFINITNS
*copyc PMP$CAUSE_CONDITION
*copyc PMP$EXIT
*copyc LOP$REPORT_ERROR
*copyc LOP$GENERATE_LOAD_MAP_TEXT
*copyc LOV$SECONDARY_STATUS

  VAR
    cross_reference_container: [STATIC] ^SEQ ( * ) := NIL;

?? TITLE := '  [XDCL] lop$record_cross_reference', EJECT ??

  PROCEDURE [XDCL] lop$record_cross_reference (referencing_module: pmt$program_name;
    VAR entry_definition {input_output} : lot$entry_definition);

{  PURPOSE:
{    This procedure records detected references to an entry point by adding an element to the list
{    of cross references threaded off the entry definition.

    VAR
      segment_pointer: mmt$segment_pointer,
      cross_reference: ^lot$cross_reference,
      abort_status: ^ost$status;

    IF cross_reference_container = NIL THEN
      mmp$create_segment (NIL, mmc$sequence_pointer, loc$loader_ring, segment_pointer, lov$secondary_status);
      IF NOT lov$secondary_status.normal THEN
        lop$report_error (lle$unable_to_create_table, 'CROSS REFERENCES', '', 0);
        PUSH abort_status;
        pmp$cause_condition (loe$abort_load, NIL, abort_status^);
        pmp$exit (abort_status^);
      IFEND;
      cross_reference_container := segment_pointer.seq_pointer;
    IFEND;
    NEXT cross_reference IN cross_reference_container;
    IF cross_reference <> NIL THEN
      cross_reference^.nnext := entry_definition.xref_list;
      entry_definition.xref_list := cross_reference;
      entry_definition.xref_listed := FALSE;
      entry_definition.xref_list^.mmodule := referencing_module;
    ELSE
      lop$report_error (lle$loader_table_overflow, 'CROSS REFERENCES', '', 0);
      PUSH abort_status;
      pmp$cause_condition (loe$insufficient_memory, NIL, abort_status^);
      pmp$exit (abort_status^);
    IFEND;
  PROCEND lop$record_cross_reference;
?? TITLE := '  [XDCL] lop$generate_cross_refernce_map', EJECT ??

  PROCEDURE [XDCL] lop$generate_cross_refernce_map;

{  PURPOSE:
{    This procedure directs generation of the cross reference portion of the load map.  For each
{    entry point defined during a program load, all modules which reference the entry point are
{    itemized.

    VAR
      segment_pointer: mmt$segment_pointer,
      load_map_data1: lot$load_map_data,
      abort_status: ^ost$status;

    ?? NEWTITLE := '    itemize_references', EJECT ??

    PROCEDURE itemize_references (entry_point_name: pmt$program_name;
          definitions_list_head: ^^lot$entry_definition);

{  PURPOSE:
{    This procedure directs generation of load map text which itemizes all modules which made reference
{    to a unique entry point name.
{  NOTE:
{    There may be multiple definitions for a single entry point name (if the definitions
{    correspond to different protection environments).  This procedure causes generation of
{    a seperate itemization for each definition.

      VAR
        definition: ^lot$entry_definition,
        load_map_data: lot$load_map_data,
        cross_reference: ^lot$cross_reference;

      definition := definitions_list_head^;
      WHILE definition <> NIL DO
        IF NOT definition^.xref_listed THEN
          load_map_data.code := loc$lm_xref_detail;
          load_map_data.entry_name := entry_point_name;
          load_map_data.loaded_ring_for_xref := definition^.attributes.loaded_ring;
          load_map_data.entry_address := definition^.attributes.address;
          IF definition^.attributes.gated THEN
            load_map_data.entry_attribute := 'GATED';
          ELSE
            load_map_data.entry_attribute := '';
          IFEND;
          load_map_data.defining_module := definition^.defining_module;
          lop$generate_load_map_text (load_map_data);
          load_map_data.code := loc$lm_accumulate_names;
          cross_reference := definition^.xref_list;
          WHILE cross_reference <> NIL DO
            load_map_data.name := cross_reference^.mmodule;
            lop$generate_load_map_text (load_map_data);
            cross_reference := cross_reference^.nnext;
          WHILEND;
          load_map_data.code := loc$lm_flush_accumulated_names;
          lop$generate_load_map_text (load_map_data);
          definition^.xref_list := NIL;
          definition^.xref_listed := TRUE;
        IFEND;
        definition := definition^.nnext;
      WHILEND;
    PROCEND itemize_references;
?? OLDTITLE, EJECT ??
    IF cross_reference_container <> NIL THEN
      load_map_data1.code := loc$lm_xref_header_init;
      lop$generate_load_map_text (load_map_data1);
      lop$process_all_entry_definitns (^itemize_references);
      segment_pointer.kind := mmc$sequence_pointer;
      segment_pointer.seq_pointer := cross_reference_container;
      cross_reference_container := NIL;
      mmp$delete_segment (segment_pointer, loc$loader_ring, lov$secondary_status);
      IF NOT lov$secondary_status.normal THEN
        PUSH abort_status;
        pmp$cause_condition (loe$loader_malfunction, ^lov$secondary_status, abort_status^);
        pmp$exit (abort_status^);
      IFEND;
    ELSE
      lop$report_error (lle$no_xrefs_to_report, '', '', 0);
    IFEND;

  PROCEND lop$generate_cross_refernce_map;
MODEND lom$cross_reference_management;
