Merge branch 'master' into type-inference-wip
This commit is contained in:
+1
-1
@@ -54,7 +54,7 @@ allprojects {
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.1"
|
||||
toolVersion = "0.8.2"
|
||||
}
|
||||
jacocoTestReport {
|
||||
reports {
|
||||
|
||||
@@ -116,14 +116,16 @@ class DeobfPresets {
|
||||
}
|
||||
}
|
||||
for (FieldInfo fld : deobfuscator.getFldMap().keySet()) {
|
||||
list.add(String.format("f %s = %s", fld.getFullId(), fld.getAlias()));
|
||||
list.add(String.format("f %s = %s", fld.getRawFullId(), fld.getAlias()));
|
||||
}
|
||||
for (MethodInfo mth : deobfuscator.getMthMap().keySet()) {
|
||||
list.add(String.format("m %s = %s", mth.getFullId(), mth.getAlias()));
|
||||
list.add(String.format("m %s = %s", mth.getRawFullId(), mth.getAlias()));
|
||||
}
|
||||
Collections.sort(list);
|
||||
FileUtils.writeLines(deobfMapFile, MAP_FILE_CHARSET, list);
|
||||
list.clear();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Deobfuscation map file saved as: {}", deobfMapFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dfsPackageName(List<String> list, String prefix, PackageNode node) {
|
||||
@@ -140,11 +142,11 @@ class DeobfPresets {
|
||||
}
|
||||
|
||||
public String getForFld(FieldInfo fld) {
|
||||
return fldPresetMap.get(fld.getFullId());
|
||||
return fldPresetMap.get(fld.getRawFullId());
|
||||
}
|
||||
|
||||
public String getForMth(MethodInfo mth) {
|
||||
return mthPresetMap.get(mth.getFullId());
|
||||
return mthPresetMap.get(mth.getRawFullId());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
||||
@@ -409,6 +409,9 @@ public class Deobfuscator {
|
||||
@Nullable
|
||||
private String getMethodAlias(MethodNode mth) {
|
||||
MethodInfo methodInfo = mth.getMethodInfo();
|
||||
if (methodInfo.isClassInit() || methodInfo.isConstructor()) {
|
||||
return null;
|
||||
}
|
||||
String alias = mthMap.get(methodInfo);
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
|
||||
@@ -57,6 +57,10 @@ public final class FieldInfo {
|
||||
return declClass.getFullName() + "." + name + ":" + TypeGen.signature(type);
|
||||
}
|
||||
|
||||
public String getRawFullId() {
|
||||
return declClass.makeRawFullName() + "." + name + ":" + TypeGen.signature(type);
|
||||
}
|
||||
|
||||
public boolean isRenamed() {
|
||||
return !name.equals(alias);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ public final class MethodInfo {
|
||||
return declClass.getFullName() + "." + shortId;
|
||||
}
|
||||
|
||||
public String getRawFullId() {
|
||||
return declClass.makeRawFullName() + "." + shortId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method name and signature
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,6 @@ public class SplitterBlockAttr implements IAttribute {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Splitter: " + block;
|
||||
return "Splitter:" + block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class BlockFinish extends AbstractVisitor {
|
||||
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
block.updateCleanSuccessors();
|
||||
fixSplitterBlock(block);
|
||||
fixSplitterBlock(mth, block);
|
||||
}
|
||||
|
||||
mth.finishBasicBlocks();
|
||||
@@ -36,7 +36,7 @@ public class BlockFinish extends AbstractVisitor {
|
||||
* For evey exception handler must be only one splitter block,
|
||||
* select correct one and remove others if necessary.
|
||||
*/
|
||||
private static void fixSplitterBlock(BlockNode block) {
|
||||
private static void fixSplitterBlock(MethodNode mth, BlockNode block) {
|
||||
ExcHandlerAttr excHandlerAttr = block.get(AType.EXC_HANDLER);
|
||||
if (excHandlerAttr == null) {
|
||||
return;
|
||||
@@ -58,7 +58,7 @@ public class BlockFinish extends AbstractVisitor {
|
||||
}
|
||||
BlockNode topSplitter = BlockUtils.getTopBlock(splitters.keySet());
|
||||
if (topSplitter == null) {
|
||||
LOG.warn("Unknown top splitter block from list: {}", splitters);
|
||||
mth.addWarn("Unknown top exception splitter block from list: " + splitters);
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<BlockNode, SplitterBlockAttr> entry : splitters.entrySet()) {
|
||||
|
||||
@@ -226,12 +226,13 @@ public class BlockSplitter extends AbstractVisitor {
|
||||
BlockNode thisBlock = getBlock(jump.getDest(), blocksMap);
|
||||
connect(srcBlock, thisBlock);
|
||||
}
|
||||
connectExceptionHandlers(block, insn);
|
||||
connectExceptionHandlers(block, insn, blocksMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void connectExceptionHandlers(BlockNode block, InsnNode insn) {
|
||||
private static void connectExceptionHandlers(BlockNode block, InsnNode insn,
|
||||
Map<Integer, BlockNode> blocksMap) {
|
||||
CatchAttr catches = insn.get(AType.CATCH_BLOCK);
|
||||
SplitterBlockAttr spl = block.get(AType.SPLITTER_BLOCK);
|
||||
if (catches == null || spl == null) {
|
||||
@@ -240,7 +241,7 @@ public class BlockSplitter extends AbstractVisitor {
|
||||
BlockNode splitterBlock = spl.getBlock();
|
||||
boolean tryEnd = insn.contains(AFlag.TRY_LEAVE);
|
||||
for (ExceptionHandler h : catches.getTryBlock().getHandlers()) {
|
||||
BlockNode handlerBlock = h.getHandlerBlock();
|
||||
BlockNode handlerBlock = initHandlerBlock(h, blocksMap);
|
||||
// skip self loop in handler
|
||||
if (splitterBlock != handlerBlock) {
|
||||
if (!handlerBlock.contains(AType.SPLITTER_BLOCK)) {
|
||||
@@ -254,6 +255,16 @@ public class BlockSplitter extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockNode initHandlerBlock(ExceptionHandler excHandler, Map<Integer, BlockNode> blocksMap) {
|
||||
BlockNode handlerBlock = excHandler.getHandlerBlock();
|
||||
if (handlerBlock != null) {
|
||||
return handlerBlock;
|
||||
}
|
||||
BlockNode blockByOffset = getBlock(excHandler.getHandleOffset(), blocksMap);
|
||||
excHandler.setHandlerBlock(blockByOffset);
|
||||
return blockByOffset;
|
||||
}
|
||||
|
||||
private static boolean isSplitByJump(InsnNode prevInsn, InsnNode currentInsn) {
|
||||
List<JumpInfo> pJumps = prevInsn.getAll(AType.JUMP);
|
||||
for (JumpInfo jump : pJumps) {
|
||||
|
||||
@@ -60,7 +60,7 @@ public class CheckRegions extends AbstractVisitor {
|
||||
&& !block.getInstructions().isEmpty()
|
||||
&& !block.contains(AFlag.SKIP)) {
|
||||
String blockCode = getBlockInsnStr(mth, block);
|
||||
mth.addWarn("Missing block: " + block + ", code:" + CodeWriter.NL + blockCode);
|
||||
mth.addWarn("Missing block: " + block + ", code skipped:" + CodeWriter.NL + blockCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-25
@@ -27,7 +27,6 @@ import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
/**
|
||||
* Extract blocks to separate try/catch region
|
||||
@@ -67,34 +66,39 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
|
||||
// for each try block search nearest dominator block
|
||||
for (TryCatchBlock tb : tryBlocks) {
|
||||
if (tb.getHandlersCount() == 0) {
|
||||
LOG.warn("No exception handlers in catch block, method: {}", mth);
|
||||
mth.addWarn("No exception handlers in catch block: " + tb);
|
||||
continue;
|
||||
}
|
||||
BitSet bs = new BitSet(mth.getBasicBlocks().size());
|
||||
for (ExceptionHandler excHandler : tb.getHandlers()) {
|
||||
BlockNode handlerBlock = excHandler.getHandlerBlock();
|
||||
if (handlerBlock != null) {
|
||||
SplitterBlockAttr splitter = handlerBlock.get(AType.SPLITTER_BLOCK);
|
||||
if (splitter != null) {
|
||||
BlockNode block = splitter.getBlock();
|
||||
bs.set(block.getId());
|
||||
}
|
||||
processTryCatchBlock(mth, tb, tryBlocksMap);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processTryCatchBlock(MethodNode mth, TryCatchBlock tb, Map<BlockNode, TryCatchBlock> tryBlocksMap) {
|
||||
BitSet bs = new BitSet(mth.getBasicBlocks().size());
|
||||
for (ExceptionHandler excHandler : tb.getHandlers()) {
|
||||
BlockNode handlerBlock = excHandler.getHandlerBlock();
|
||||
if (handlerBlock != null) {
|
||||
SplitterBlockAttr splitter = handlerBlock.get(AType.SPLITTER_BLOCK);
|
||||
if (splitter != null) {
|
||||
BlockNode block = splitter.getBlock();
|
||||
bs.set(block.getId());
|
||||
}
|
||||
}
|
||||
List<BlockNode> domBlocks = BlockUtils.bitSetToBlocks(mth, bs);
|
||||
BlockNode domBlock;
|
||||
if (domBlocks.size() != 1) {
|
||||
domBlock = BlockUtils.getTopBlock(domBlocks);
|
||||
if (domBlock == null) {
|
||||
throw new JadxRuntimeException("Exception block dominator not found, method:" + mth + ", dom blocks: " + domBlocks);
|
||||
}
|
||||
} else {
|
||||
domBlock = domBlocks.get(0);
|
||||
}
|
||||
TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb);
|
||||
if (prevTB != null) {
|
||||
ErrorsCounter.methodWarn(mth, "Failed to process nested try/catch");
|
||||
}
|
||||
List<BlockNode> domBlocks = BlockUtils.bitSetToBlocks(mth, bs);
|
||||
BlockNode domBlock;
|
||||
if (domBlocks.size() != 1) {
|
||||
domBlock = BlockUtils.getTopBlock(domBlocks);
|
||||
if (domBlock == null) {
|
||||
mth.addWarn("Exception block dominator not found, dom blocks: " + domBlocks);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
domBlock = domBlocks.get(0);
|
||||
}
|
||||
TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb);
|
||||
if (prevTB != null) {
|
||||
mth.addWarn("Failed to process nested try/catch");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +109,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
|
||||
if (region.getSubBlocks().contains(dominator)) {
|
||||
TryCatchBlock tb = tryBlocksMap.get(dominator);
|
||||
if (!wrapBlocks(region, tb, dominator)) {
|
||||
ErrorsCounter.methodWarn(mth, "Can't wrap try/catch for " + region);
|
||||
ErrorsCounter.methodWarn(mth, "Can't wrap try/catch for region: " + region);
|
||||
}
|
||||
tryBlocksMap.remove(dominator);
|
||||
return true;
|
||||
|
||||
@@ -932,7 +932,7 @@ public class RegionMaker {
|
||||
}
|
||||
}
|
||||
for (ExceptionHandler handler : tc.getHandlers()) {
|
||||
processExcHandler(handler, exits);
|
||||
processExcHandler(mth, handler, exits);
|
||||
}
|
||||
}
|
||||
return processHandlersOutBlocks(mth, tcs);
|
||||
@@ -971,12 +971,12 @@ public class RegionMaker {
|
||||
return excOutRegion;
|
||||
}
|
||||
|
||||
private void processExcHandler(ExceptionHandler handler, Set<BlockNode> exits) {
|
||||
private void processExcHandler(MethodNode mth, ExceptionHandler handler, Set<BlockNode> exits) {
|
||||
BlockNode start = handler.getHandlerBlock();
|
||||
if (start == null) {
|
||||
return;
|
||||
}
|
||||
RegionStack stack = new RegionStack(mth);
|
||||
RegionStack stack = new RegionStack(this.mth);
|
||||
BlockNode dom;
|
||||
if (handler.isFinally()) {
|
||||
SplitterBlockAttr splitterAttr = start.get(AType.SPLITTER_BLOCK);
|
||||
@@ -989,11 +989,11 @@ public class RegionMaker {
|
||||
stack.addExits(exits);
|
||||
}
|
||||
BitSet domFrontier = dom.getDomFrontier();
|
||||
List<BlockNode> handlerExits = BlockUtils.bitSetToBlocks(mth, domFrontier);
|
||||
boolean inLoop = mth.getLoopForBlock(start) != null;
|
||||
List<BlockNode> handlerExits = BlockUtils.bitSetToBlocks(this.mth, domFrontier);
|
||||
boolean inLoop = this.mth.getLoopForBlock(start) != null;
|
||||
for (BlockNode exit : handlerExits) {
|
||||
if ((!inLoop || BlockUtils.isPathExists(start, exit))
|
||||
&& RegionUtils.isRegionContainsBlock(mth.getRegion(), exit)) {
|
||||
&& RegionUtils.isRegionContainsBlock(this.mth.getRegion(), exit)) {
|
||||
stack.addExit(exit);
|
||||
}
|
||||
}
|
||||
@@ -1001,7 +1001,7 @@ public class RegionMaker {
|
||||
|
||||
ExcHandlerAttr excHandlerAttr = start.get(AType.EXC_HANDLER);
|
||||
if (excHandlerAttr == null) {
|
||||
LOG.warn("Missing exception handler attribute for start block");
|
||||
mth.addWarn("Missing exception handler attribute for start block: " + start);
|
||||
} else {
|
||||
handler.getHandlerRegion().addAttr(excHandlerAttr);
|
||||
}
|
||||
|
||||
@@ -135,23 +135,36 @@ public abstract class BaseExternalTest extends IntegrationTest {
|
||||
String[] lines = code.split(CodeWriter.NL);
|
||||
for (MethodNode mth : classNode.getMethods()) {
|
||||
if (isMthMatch(mth, mthPattern)) {
|
||||
int decompiledLine = mth.getDecompiledLine();
|
||||
int decompiledLine = mth.getDecompiledLine() - 1;
|
||||
StringBuilder mthCode = new StringBuilder();
|
||||
int startLine = getCommentLinesCount(lines, decompiledLine);
|
||||
int brackets = 0;
|
||||
for (int i = decompiledLine - 1; i > 0 && i < lines.length; i++) {
|
||||
for (int i = startLine; i > 0 && i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
mthCode.append(line).append(CodeWriter.NL);
|
||||
brackets += StringUtils.countMatches(line, '{');
|
||||
brackets -= StringUtils.countMatches(line, '}');
|
||||
if (brackets <= 0) {
|
||||
break;
|
||||
if (i >= decompiledLine) {
|
||||
brackets += StringUtils.countMatches(line, '{');
|
||||
brackets -= StringUtils.countMatches(line, '}');
|
||||
if (brackets <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.info("{}\n{}", mth.getMethodInfo().getShortId(), mthCode);
|
||||
LOG.info("Print method: {}\n{}", mth.getMethodInfo().getShortId(), mthCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int getCommentLinesCount(String[] lines, int line) {
|
||||
for (int i = line - 1; i > 0 && i < lines.length; i--) {
|
||||
String str = lines[i];
|
||||
if (str.isEmpty() || str.equals(CodeWriter.NL)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void printErrorReport(JadxDecompiler jadx) {
|
||||
jadx.printErrorsReport();
|
||||
assertThat(jadx.getErrorsCount(), is(0));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id 'edu.sc.seis.launch4j' version '2.4.4'
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.4'
|
||||
id 'com.github.johnrengelman.shadow' version '4.0.3'
|
||||
}
|
||||
|
||||
apply plugin: 'application'
|
||||
|
||||
Reference in New Issue
Block a user