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 avrora.arch.*;
  import avrora.arch.legacy.LegacyInstr;
  import cck.text.StringUtil;
  import cck.util.Util;
  import java.util.*;
  
  /**
   * The <code>Program</code> class represents a complete program of AVR instructions. It stores the actual
   * instructions and initialized data of the program.
   *
   * @author Ben L. Titzer
   * @see LegacyInstr
   * @see ControlFlowGraph
   * @see ProcedureMap
   */
  public class Program {
  
      private final AbstractArchitecture arch;
  
      private final HashMap<Integer, List<Integer>> indirectEdges;
  
      private SourceMapping sourceMapping;
  
      private ControlFlowGraph cfg;
  
      /**
       * The <code>program_start</code> field records the lowest address in the program segment that contains
       * valid code or data.
       */
      public final int program_start;
  
      /**
       * The <code>program_end</code> field records the address following the highest address in the program
       * segment that contains valid code or data.
       */
      public final int program_end;
  
      /**
       * The <code>program_length</code> field records the size of the program (the difference between
       * <code>program_start</code> and <code>program_end</code>.
       */
      public final int program_length;
  
      /**
       * The <code>flash_data</code> field stores a reference to the array that contains the raw data (bytes) of the
       * program segment. NO EFFORT IS MADE IN THIS CLASS TO KEEP THIS CONSISTENT WITH THE INSTRUCTION
       * REPRESENTATIONS.
       */
      protected final byte[] flash_data;
  
      /**
       * The <code>flash_instrs</code> field stores a reference to the array that contains the instruction
       * representations of the program segment. NO EFFORT IS MADE IN THIS CLASS TO KEEP THIS CONSISTENT WITH
       * THE RAW DATA OF THE PROGRAM SEGMENT.
       */
      protected final AbstractInstr[] flash_instrs;
  
      /**
       * The constructor of the <code>Program</code> class builds an internal representation of the program that
       * is initially empty, but has the given parameters in terms of how big segments are and where they
       * start.
       *
       * @param a a reference to the <code>AbstractArchitecture</code> class that represents the
       * instruction set architecture for this program
       * @param pstart the start of the program segment
       * @param pend   the end of the program segment
       */
      public Program(AbstractArchitecture a, int pstart, int pend) {
          arch = a;
          program_start = pstart;
          program_end = pend;
          program_length = pend - pstart;
  
          int size = program_end - program_start;
          flash_data = new byte[size];
          flash_instrs = arch.newInstrArray(size);
          Arrays.fill(flash_data, (byte)0xff);
  
          indirectEdges = new HashMap<>();
      }
  
      /**
       * The <code>writeInstr()</code> method is used to write an instruction to the internal representation of
       * the program at the given address. No attempt to assemble the instruction machine code is made; thus the
       * raw data (if any) at that location in the program will not be modified.
       *
       * @param i       the instruction to write
       * @param address the byte address to write the instruction to that must be aligned on a 2-byte boundary.
       * @throws Util.InternalError if the address is not within the limits put on the program instance when
       *                              it was created.
       */
      public void writeInstr(AbstractInstr i, int address) {
          int size = i.getSize();
          checkAddress(address);
          checkAddress(address + size - 1);
  
          flash_instrs[address - program_start] = i;
          for (int cntr = 1; cntr < size; cntr++) {
              flash_instrs[address - program_start + cntr] = null;
          }
      }
  
      /**
       * The <code>readInstr()</code> method reads an instruction from the specified address in the program. No
       * attempt to disassemble raw data into usable instructions is made, and unaligned accesses will return
       * null.
       *
       * @param address the byte address in the program
       * @return the <code>LegacyInstr</code> instance at that address if that address is valid code from creation of
       *         the <code>Program</code> instance; null if the instruction is misaligned or only raw data is
       *         present at that location.
       * @throws Util.InternalError if the address is not within the limits put on the program instance when
       *                              it was created.
       */
      public AbstractInstr readInstr(int address) {
          if ( address < program_start || address >= program_end ) return null;
          return flash_instrs[address - program_start];
      }
  
      public AbstractInstr disassembleInstr(int address) {
          if ( address < program_start || address >= program_end ) return null;
          AbstractDisassembler d = arch.getDisassembler();
          int offset = address - program_start;
          AbstractInstr instr = d.disassemble(program_start, offset, flash_data);
          if ( instr != null ) flash_instrs[offset] = instr; 
          return instr;
      }
  
      /**
       * The <code>readProgramByte()</code> method reads a byte into the program segment at the specified byte
       * address. If the address overlaps with an instruction, no effort is made to get the correct encoded byte
       * of the instruction.
       *
       * @param address the program address from which to read the byte
       * @return the byte value of the program segment at that location
       */
      public byte readProgramByte(int address) {
          checkAddress(address);
          return flash_data[address - program_start];
      }
  
      /**
       * The <code>writeProgramByte()</code> method writes a byte into the program segment at the specified byte
       * address. If the address overlaps with an instruction, no effort is made to keep the instruction
       * representation up to date.
       *
       * @param val         the value to write
       * @param byteAddress the byte address in the program segment to write the byte value to
       */
      public void writeProgramByte(byte val, int byteAddress) {
          checkAddress(byteAddress);
          int offset = byteAddress - program_start;
          writeByteInto(val, offset);
      }
  
      private void writeByteInto(byte val, int offset) {
          flash_data[offset] = val;
      }
  
      /**
       * The <code>writeProgramBytes()</code> method writes an array of bytes into the program segment at the
       * specified byte address. If the range of addresses modified overlaps with any instructions, no effort is
       * made to keep the instruction representations up to date.
       *
       * @param val         the byte values to write
       * @param byteAddress the byte address to begin writing the values to
       */
      public void writeProgramBytes(byte[] val, int byteAddress) {
          checkAddress(byteAddress);
          checkAddress(byteAddress + val.length - 1);
          int offset = byteAddress - program_start;
          for (int cntr = 0; cntr < val.length; cntr++)
              writeByteInto(val[cntr], offset + cntr);
      }
  
      /**
       * The <code>checkAddress()</code> method simply checks an address against the bounds of the program and
       * throws an error if the address is not within the bounds.
       *
       * @param addr the byte address to check
       * @throws Util.InternalError if the address is not within the limits of the program segment
       */
      protected void checkAddress(int addr) {
          // TODO: throw correct error type
          if (addr < program_start || addr >= program_end)
              throw Util.failure("address out of range: " + StringUtil.addrToString(addr));
      }
  
      /**
       * The <code>getNextPC()</code> method computes the program counter value of the next instruction
       * following the instruction referenced by the given program counter value. Thus, it simply adds the size
       * of the instruction at the specified pc to the pc. It is useful as a commonly-used utility method.
       *
       * @param pc the program counter location of the current instruction
       * @return the program counter value of the instruction following the specified instruction in program
       *         order
       */
      public int getNextPC(int pc) {
          // TODO: better error checking
          if (pc > program_end)
              throw Util.failure("no next PC after: " + StringUtil.addrToString(pc));
          AbstractInstr i = readInstr(pc);
          if (i == null) return pc + 2;
          return pc + i.getSize();
      }
  
      /**
       * The <code>getIndirectEdges</code> returns a list of integers representing the possible target program
       * locations for a given callsite. This is auxilliary information that is supplied at the command line
       * which is used for a variety of analysis questions.
       *
       * @param callsite the program counter location of an indirect branch or call
       * @return a list of <code>java.lang.Integer</code> objects that represent the possible targets of the
       *         call or branch instruction
       */
      public List<Integer> getIndirectEdges(int callsite) {
          return indirectEdges.get(new Integer(callsite));
      }
  
      /**
       * The <code>addIndirectEdge</code> adds an indirect edge between a callsite and possible target. This is
       * auxilliary information that is supplied at the command line which is used for a variety of analysis
       * questions.
       *
       * @param callsite the program counter location of the call or branch instruction
       * @param target   the possible target of the call or branch instruction
       */
      public void addIndirectEdge(int callsite, int target) {
          Integer c = new Integer(callsite);
          Integer t = new Integer(target);
  
          List<Integer> l = indirectEdges.get(c);
  
          if (l == null) {
              l = new LinkedList<Integer>();
              l.add(t);
              indirectEdges.put(c, l);
          } else {
              l.add(t);
          }
  
      }
  
      /**
       * The <code>getArchitecture()</code> method returns a reference to the <code>AbstractArchitecture</code>
       * object that represents the instruction set architecture for this program.
       * @return a reference to the abstract architecture for this program
       */
      public AbstractArchitecture getArchitecture() {
          return arch;
      }
  
      /**
       * The <code>getSourceMapping()</code> method returns a reference to the <code>SourceMapping</code>
       * class that contains information about mapping the machine code program back to the source code,
       * either a high-level language such as C, or a source-assembly program.
       * @return a reference to the source mapping for this program
       */
      public SourceMapping getSourceMapping() {
          return sourceMapping;
      }
  
      /**
       * The <code>setSourceMapping()</code> method updates the reference to the <code>SourceMapping</code>
       * for this program.
       * @param s the new source mapping for this program
       */
      public void setSourceMapping(SourceMapping s) {
          sourceMapping = s;
      }
  
      /**
       * The <code>getCFG()</code> method returns a reference to the control flow graph of the program. This is
       * an instance of <code>ControlFlowGraph</code> that is constructed lazily--i.e. the first time this
       * method is called. No effort is made to keep the control flow graph up to date with a changing program
       * representation; adding instructions or writing bytes into the program segment of the program will not
       * alter the CFG once it has been constructed.
       *
       * @return a reference to the <code>ControlFlowGraph</code> instance that represents the control flow
       *         graph for this program
       */
      public synchronized ControlFlowGraph getCFG() {
          if (cfg == null) {
              cfg = new CFGBuilder(this).buildCFG();
          }
          return cfg;
      }
  
  }
  