code: /**
   * Copyright (c) 2004-2005, Regents of the University of California
   * 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 University of California, Los Angeles 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.
   */
  
  package avrora.core;
  
  import cck.text.StringUtil;
  
  import java.util.*;
  
  /**
   * The <code>SourceMapping</code> class embodies the concept of mapping machine code level
   * addresses and constructions in the <code>Program</code> class back to a source code program,
   * either in assembly language (labels), or a high-level programming lagnguage like C. This
   * class is used by the simulator to report information about the program in a higher-level
   * way more readibly understandable, for example to report calls / returns between functions
   * by their names rather than their machine code addresses.
   *
   * @author Ben L. Titzer
   */
  public class SourceMapping {
  
      /**
       * The <code>program</code> field stores a reference to the program for this source mapping.
       */
      protected final Program program;
      protected final HashMap<String, Location> labels;
      protected final HashMap<Integer, String> reverseMap;
  
      /**
       * The <code>LOCATION_COMPARATOR</code> comparator is used in order to sort locations
       * in the program from lowest address to highest address.
       */
      public static Comparator<Location> LOCATION_COMPARATOR = new Comparator<Location>() {
          public int compare(Location l1, Location l2) {
              if (l1.lma_addr == l2.lma_addr) {
                  if (l1.name == null) return 1;
                  if (l2.name == null) return -1;
                  return l1.name.compareTo(l2.name);
              }
              return l1.lma_addr - l2.lma_addr;
          }
      };
  
      /**
       * The <code>Location</code> class represents a location in the program; either named by
       * a label, or an unnamed integer address. The location may refer to any of the code, data,
       * or eeprom segments.
       */
      public class Location {
  
          /**
           * The <code>section</code> field records the name of the segment that this label refers to,
           * such as ".text" or ".data".
           */
          public final String section;
  
          /**
           * The <code>name</code> field records the name of this label.
           */
          public final String name;
  
          /**
           * The <code>address</code> field records the address of this label as a byte address.
           */
          public final int vma_addr;
  
          /**
           * The <code>address</code> field records the address of this label as a byte address.
           */
          public final int lma_addr;
          
          /**
           * The <code>size</code> field records the size of a variable in bytes if it is a variable
           * and the information can be read from the ELF file. Size is minimum 1, which is ensured
           * by the constructor.
           */
          public final int size;
  
          /**
           * The constructor for the <code>Location</code> class creates a new location for the
           * specified lable and address. It is used internally to create labels.
           * @param s the name of the segment as a string
           * @param n the name of the label as a string
           * @param vma_addr the virtual memory address
           * @param lma_addr the linear memory address (physical)
           * @param size the size of the variable
           */
          Location(String s, String n, int vma_addr, int lma_addr, int size) {
              section = s;
              if ( n == null ) name = StringUtil.addrToString(lma_addr);
              else name = n;
              this.vma_addr = vma_addr;
              this.lma_addr = lma_addr;
              this.size = size < 1 ? 1 : size;
          }
  
          /**
           * The <code>hashCode()</code> method computes the hash code of this location so that
           * it can be used in any of the standard collection libraries.
           * @return an integer value that represents the hash code
           */
          public int hashCode() {
              if (name == null) return lma_addr;
              else return name.hashCode();
          }
  
          /**
           * The <code>equals()</code> method compares this location against another object. It will return
           * true if and only if the specified object is an instance of <code>Location</code>, the addresses
           * match, and the names match.
           * @param o the other object to test this location for equality
           * @return true if the other object is equal to this label; false otherwise
           */
          public boolean equals(Object o) {
              if (o == this) return true;
              if (!(o instanceof Location)) return false;
              Location l = (Location)o;
              return l.name.equals(this.name) && l.lma_addr == this.lma_addr;
          }
  
          public String toString() {
              return name;
          }
      }
  
      /**
       * The <code>getName()</code> method translates a code address into a name that is more useful to
       * the user, such as a label. In the implementation of the label mapping, this method will return
       * the label name for this address if there is one. If there is no label for the specified address,
       * this method will render the address as a hexadecimal string via the <code>StringUtil.addrToString()<.code>
       * method.
       * @param address the address of an instruction in the program
       * @return a string representation of the address as a label or a hexadecimal string
       */
      public String getName(int address) {
          String s = reverseMap.get(new Integer(address));
          return s == null ? StringUtil.addrToString(address) : s;
      }
  
      /**
       * The constructor for the <code>SourceMapping</code> base class creates a new instance of source mapping
       * information for the specified program. The mapping is tied to the program throughout its lifetime.
       * @param p the program to create the source mapping for
       */
      public SourceMapping(Program p) {
          program = p;
          labels = new HashMap<String, Location>();
          reverseMap = new HashMap<Integer, String>();
      }
  
      /**
       * The <code>getProgram()</code> class returns a reference to the program for which this class
       * provides source information.
       * @return the program associated with this source mapping
       */
      public Program getProgram() {
          return program;
      }
  
      /**
       * The <code>getLocation()</code> method retrieves an object that represents a location for the given name,
       * if the name exists in the program. If the name does not exist in the program, this method will return null.
       * For strings beginning with "0x", this method will evaluate them as hexadecimal literals and return a
       * location corresponding to an unnamed location at that address with size 1.
       * @param name the name of a program location as a label or a hexadecimal constant
       * @return a <code>Location</code> object representing that program location; <code>null</code> if the
       * specified label is not contained in the program
       */
      public Location getLocation(String name) {
          if ( StringUtil.isHex(name) ) {
              int val = StringUtil.evaluateIntegerLiteral(name);
              return new Location(null, null, val, val, 1);
          }
          return labels.get(name);
      }
  
      /**
       * The <code>newLocation()</code> method creates a new program location with the specified label name that
       * is stored internally.
       * @param section the name of the section which contains this label
       * @param name the name of the label
       * @param vma_addr the virtual address in the program
       * @param lma_addr the address in the program for which to create and store a new location
       * @param size the size of the symbol if it is a variable
       */
      public void newLocation(String section, String name, int vma_addr, int lma_addr, int size) {
          Location l = new Location(section, name, vma_addr, lma_addr, size);
          labels.put(name, l);
          reverseMap.put(new Integer(lma_addr), name);
      }
  
      /**
       * The <code>getIterator()</code> method creates an iterator over the labels
       * in this source mapping.
       * @return an iterator that will allow iterating over all of the labels in this source mapping
       */
      public Iterator<Location> getIterator() {
          return labels.values().iterator();
      }
  }
  