Package jadx.core.dex.nodes.parser

Source Code of jadx.core.dex.nodes.parser.DebugInfoParser

package jadx.core.dex.nodes.parser;

import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.exceptions.DecodeException;

import java.util.List;

import com.android.dex.Dex.Section;

public class DebugInfoParser {

  private static final int DBG_END_SEQUENCE = 0x00;
  private static final int DBG_ADVANCE_PC = 0x01;
  private static final int DBG_ADVANCE_LINE = 0x02;
  private static final int DBG_START_LOCAL = 0x03;
  private static final int DBG_START_LOCAL_EXTENDED = 0x04;
  private static final int DBG_END_LOCAL = 0x05;
  private static final int DBG_RESTART_LOCAL = 0x06;
  private static final int DBG_SET_PROLOGUE_END = 0x07;
  private static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
  private static final int DBG_SET_FILE = 0x09;

  // the smallest special opcode
  private static final int DBG_FIRST_SPECIAL = 0x0a;
  // the smallest line number increment
  private static final int DBG_LINE_BASE = -4;
  // the number of line increments represented
  private static final int DBG_LINE_RANGE = 15;

  private final MethodNode mth;
  private final Section section;
  private final DexNode dex;

  private final LocalVar[] locals;
  private final InsnArg[] activeRegisters;
  private final InsnNode[] insnByOffset;

  public DebugInfoParser(MethodNode mth, int debugOffset, InsnNode[] insnByOffset) {
    this.mth = mth;
    this.dex = mth.dex();
    this.section = dex.openSection(debugOffset);

    int regsCount = mth.getRegsCount();
    this.locals = new LocalVar[regsCount];
    this.activeRegisters = new InsnArg[regsCount];
    this.insnByOffset = insnByOffset;
  }

  public void process() throws DecodeException {
    int addr = 0;
    int line = section.readUleb128();

    int paramsCount = section.readUleb128();
    List<RegisterArg> mthArgs = mth.getArguments(false);
    assert paramsCount == mthArgs.size();

    for (int i = 0; i < paramsCount; i++) {
      int id = section.readUleb128() - 1;
      if (id != DexNode.NO_INDEX) {
        String name = dex.getString(id);
        mthArgs.get(i).setName(name);
      }
    }

    for (RegisterArg arg : mthArgs) {
      int rn = arg.getRegNum();
      locals[rn] = new LocalVar(arg);
      activeRegisters[rn] = arg;
    }

    // process '0' instruction
    addrChange(-1, 1, line);
    setLine(addr, line);

    int c = section.readByte() & 0xFF;
    while (c != DBG_END_SEQUENCE) {
      switch (c) {
        case DBG_ADVANCE_PC: {
          int addrInc = section.readUleb128();
          addr = addrChange(addr, addrInc, line);
          setLine(addr, line);
          break;
        }
        case DBG_ADVANCE_LINE: {
          line += section.readSleb128();
          break;
        }

        case DBG_START_LOCAL: {
          int regNum = section.readUleb128();
          int nameId = section.readUleb128() - 1;
          int type = section.readUleb128() - 1;
          LocalVar var = new LocalVar(dex, regNum, nameId, type, DexNode.NO_INDEX);
          startVar(var, addr, line);
          break;
        }
        case DBG_START_LOCAL_EXTENDED: {
          int regNum = section.readUleb128();
          int nameId = section.readUleb128() - 1;
          int type = section.readUleb128() - 1;
          int sign = section.readUleb128() - 1;
          LocalVar var = new LocalVar(dex, regNum, nameId, type, sign);
          startVar(var, addr, line);
          break;
        }
        case DBG_RESTART_LOCAL: {
          int regNum = section.readUleb128();
          LocalVar var = locals[regNum];
          if (var != null) {
            if (var.end(addr, line)) {
              setVar(var);
            }
            var.start(addr, line);
          }
          break;
        }
        case DBG_END_LOCAL: {
          int regNum = section.readUleb128();
          LocalVar var = locals[regNum];
          if (var != null) {
            var.end(addr, line);
            setVar(var);
          }
          break;
        }

        case DBG_SET_PROLOGUE_END:
        case DBG_SET_EPILOGUE_BEGIN:
          // do nothing
          break;

        case DBG_SET_FILE: {
          int idx = section.readUleb128() - 1;
          if (idx != DexNode.NO_INDEX) {
            String sourceFile = dex.getString(idx);
            mth.addAttr(new SourceFileAttr(sourceFile));
          }
          break;
        }

        default: {
          if (c >= DBG_FIRST_SPECIAL) {
            int adjustedOpcode = c - DBG_FIRST_SPECIAL;
            int addrInc = adjustedOpcode / DBG_LINE_RANGE;
            addr = addrChange(addr, addrInc, line);
            line += DBG_LINE_BASE + (adjustedOpcode % DBG_LINE_RANGE);
            setLine(addr, line);
          } else {
            throw new DecodeException("Unknown debug insn code: " + c);
          }
          break;
        }
      }
      c = section.readByte() & 0xFF;
    }

    for (LocalVar var : locals) {
      if (var != null && !var.isEnd()) {
        var.end(mth.getCodeSize() - 1, line);
        setVar(var);
      }
    }
    setSourceLines(addr, insnByOffset.length, line);
  }

  private int addrChange(int addr, int addrInc, int line) {
    int newAddr = addr + addrInc;
    int maxAddr = insnByOffset.length - 1;
    newAddr = Math.min(newAddr, maxAddr);
    for (int i = addr + 1; i <= newAddr; i++) {
      InsnNode insn = insnByOffset[i];
      if (insn == null) {
        continue;
      }
      for (InsnArg arg : insn.getArguments()) {
        if (arg.isRegister()) {
          activeRegisters[((RegisterArg) arg).getRegNum()] = arg;
        }
      }
      RegisterArg res = insn.getResult();
      if (res != null) {
        activeRegisters[res.getRegNum()] = res;
      }
    }
    setSourceLines(addr, newAddr, line);
    return newAddr;
  }

  private void setSourceLines(int start, int end, int line) {
    for (int offset = start + 1; offset < end; offset++) {
      setLine(offset, line);
    }
  }

  private void setLine(int offset, int line) {
    InsnNode insn = insnByOffset[offset];
    if (insn != null) {
      insn.setSourceLine(line);
    }
  }

  private void startVar(LocalVar var, int addr, int line) {
    int regNum = var.getRegNum();
    LocalVar prev = locals[regNum];
    if (prev != null && !prev.isEnd()) {
      prev.end(addr, line);
      setVar(prev);
    }
    var.start(addr, line);
    locals[regNum] = var;
  }

  private void setVar(LocalVar var) {
    int start = var.getStartAddr();
    int end = var.getEndAddr();

    for (int i = start; i <= end; i++) {
      InsnNode insn = insnByOffset[i];
      if (insn != null) {
        fillLocals(insn, var);
      }
    }
    merge(activeRegisters[var.getRegNum()], var);
  }

  private static void fillLocals(InsnNode insn, LocalVar var) {
    merge(insn.getResult(), var);
    for (InsnArg arg : insn.getArguments()) {
      merge(arg, var);
    }
  }

  private static void merge(InsnArg arg, LocalVar var) {
    if (arg != null && arg.isRegister()) {
      RegisterArg reg = (RegisterArg) arg;
      if (var.getRegNum() == reg.getRegNum()) {
        SSAVar ssaVar = reg.getSVar();

        boolean mergeRequired = false;

        if (ssaVar != null) {
          int ssaEnd = ssaVar.getEndAddr();
          int ssaStart = ssaVar.getStartAddr();
          int localStart = var.getStartAddr();
          int localEnd = var.getEndAddr();

          boolean isIntersected = !((localEnd < ssaStart) || (ssaEnd < localStart));
          if (isIntersected && (ssaEnd <= localEnd)) {
            mergeRequired = true;
          }
        } else {
          mergeRequired = true;
        }

        if (mergeRequired) {
          reg.mergeDebugInfo(var.getType(), var.getName());
        }
      }
    }
  }
}
TOP

Related Classes of jadx.core.dex.nodes.parser.DebugInfoParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.