예제 #1
0
  /**
   * Performs debug info encoding.
   *
   * @param file null-ok; file to refer to during encoding
   * @param prefix null-ok; prefix to attach to each line of output
   * @param debugPrint null-ok; if specified, an alternate output for annotations
   * @param out null-ok; if specified, where annotations should go
   * @param consume whether to claim to have consumed output for <code>out</code>
   * @return non-null; the encoded array
   */
  private byte[] encode(
      DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out, boolean consume) {
    byte[] result = encode0(file, prefix, debugPrint, out, consume);

    if (ENABLE_ENCODER_SELF_CHECK && (file != null)) {
      try {
        DebugInfoDecoder.validateEncode(result, file, ref, code, isStatic);
      } catch (RuntimeException ex) {
        // Reconvert, annotating to System.err.
        encode0(file, "", new PrintWriter(System.err, true), null, false);
        throw ex;
      }
    }

    return result;
  }
  private static void validateEncode0(
      byte[] info,
      int codeSize,
      int countRegisters,
      boolean isStatic,
      CstMethodRef ref,
      DexFile file,
      PositionList pl,
      LocalList ll) {
    DebugInfoDecoder decoder =
        new DebugInfoDecoder(info, codeSize, countRegisters, isStatic, ref, file);

    decoder.decode();

    /*
     * Go through the decoded position entries, matching up
     * with original entries.
     */

    List<PositionEntry> decodedEntries = decoder.getPositionList();

    if (decodedEntries.size() != pl.size()) {
      throw new RuntimeException(
          "Decoded positions table not same size was "
              + decodedEntries.size()
              + " expected "
              + pl.size());
    }

    for (PositionEntry entry : decodedEntries) {
      boolean found = false;
      for (int i = pl.size() - 1; i >= 0; i--) {
        PositionList.Entry ple = pl.get(i);

        if (entry.line == ple.getPosition().getLine() && entry.address == ple.getAddress()) {
          found = true;
          break;
        }
      }

      if (!found) {
        throw new RuntimeException(
            "Could not match position entry: " + entry.address + ", " + entry.line);
      }
    }

    /*
     * Go through the original local list, in order, matching up
     * with decoded entries.
     */

    List<LocalEntry> decodedLocals = decoder.getLocals();
    int thisStringIdx = decoder.thisStringIdx;
    int decodedSz = decodedLocals.size();
    int paramBase = decoder.getParamBase();

    /*
     * Preflight to fill in any parameters that were skipped in
     * the prologue (including an implied "this") but then
     * identified by full signature.
     */
    for (int i = 0; i < decodedSz; i++) {
      LocalEntry entry = decodedLocals.get(i);
      int idx = entry.nameIndex;

      if ((idx < 0) || (idx == thisStringIdx)) {
        for (int j = i + 1; j < decodedSz; j++) {
          LocalEntry e2 = decodedLocals.get(j);
          if (e2.address != 0) {
            break;
          }
          if ((entry.reg == e2.reg) && e2.isStart) {
            decodedLocals.set(i, e2);
            decodedLocals.remove(j);
            decodedSz--;
            break;
          }
        }
      }
    }

    int origSz = ll.size();
    int decodeAt = 0;
    boolean problem = false;

    for (int i = 0; i < origSz; i++) {
      LocalList.Entry origEntry = ll.get(i);

      if (origEntry.getDisposition() == LocalList.Disposition.END_REPLACED) {
        /*
         * The encoded list doesn't represent replacements, so
         * ignore them for the sake of comparison.
         */
        continue;
      }

      LocalEntry decodedEntry;

      do {
        decodedEntry = decodedLocals.get(decodeAt);
        if (decodedEntry.nameIndex >= 0) {
          break;
        }
        /*
         * A negative name index means this is an anonymous
         * parameter, and we shouldn't expect to see it in the
         * original list. So, skip it.
         */
        decodeAt++;
      } while (decodeAt < decodedSz);

      int decodedAddress = decodedEntry.address;

      if (decodedEntry.reg != origEntry.getRegister()) {
        System.err.println("local register mismatch at orig " + i + " / decoded " + decodeAt);
        problem = true;
        break;
      }

      if (decodedEntry.isStart != origEntry.isStart()) {
        System.err.println("local start/end mismatch at orig " + i + " / decoded " + decodeAt);
        problem = true;
        break;
      }

      /*
       * The secondary check here accounts for the fact that a
       * parameter might not be marked as starting at 0 in the
       * original list.
       */
      if ((decodedAddress != origEntry.getAddress())
          && !((decodedAddress == 0) && (decodedEntry.reg >= paramBase))) {
        System.err.println("local address mismatch at orig " + i + " / decoded " + decodeAt);
        problem = true;
        break;
      }

      decodeAt++;
    }

    if (problem) {
      System.err.println("decoded locals:");
      for (LocalEntry e : decodedLocals) {
        System.err.println("  " + e);
      }
      throw new RuntimeException("local table problem");
    }
  }