From 7e8435ccebc6c9003f509667eb3cf0a1c05681a9 Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 6 Dec 2018 14:03:09 +0300 Subject: [PATCH 1/8] fix(gui): fill background before draw line numbers (#404) --- .../jadx/gui/ui/codearea/LineNumbers.java | 64 ++++++++++++------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java index c39ada2bb..04e2b86ba 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java @@ -20,8 +20,13 @@ import java.util.Map; import org.fife.ui.rsyntaxtextarea.SyntaxScheme; import org.fife.ui.rsyntaxtextarea.Token; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LineNumbers extends JPanel implements CaretListener { + private static final Logger LOG = LoggerFactory.getLogger(LineNumbers.class); + private static final long serialVersionUID = -4978268673635308190L; private static final int NUM_HEIGHT = Integer.MAX_VALUE - 1000000; @@ -92,30 +97,42 @@ public class LineNumbers extends JPanel implements CaretListener { @Override public void paintComponent(Graphics g) { super.paintComponent(g); - g.setFont(codeArea.getFont()); applyRenderHints(g); - FontMetrics fontMetrics = codeArea.getFontMetrics(codeArea.getFont()); + Font font = codeArea.getFont(); + font = font.deriveFont(font.getSize2D() - 1.0f); + g.setFont(font); + + Dimension size = getSize(); + g.setColor(codeArea.getBackground()); + g.fillRect(0, 0, size.width, size.height); + + FontMetrics fontMetrics = codeArea.getFontMetrics(font); Insets insets = getInsets(); - int availableWidth = getSize().width - insets.left - insets.right; + int availableWidth = size.width - insets.left - insets.right; Rectangle clip = g.getClipBounds(); int rowStartOffset = codeArea.viewToModel(new Point(0, clip.y)); int endOffset = codeArea.viewToModel(new Point(0, clip.y + clip.height)); while (rowStartOffset <= endOffset) { try { - if (isCurrentLine(rowStartOffset)) { - g.setColor(currentColor); - } else { - g.setColor(numberColor); - } String lineNumber = getTextLineNumber(rowStartOffset); - int stringWidth = fontMetrics.stringWidth(lineNumber); - int x = availableWidth - stringWidth + insets.left; - int y = getOffsetY(rowStartOffset, fontMetrics); - g.drawString(lineNumber, x, y); + if (lineNumber != null) { + if (isCurrentLine(rowStartOffset)) { + g.setColor(currentColor); + } else { + g.setColor(numberColor); + } + int stringWidth = fontMetrics.stringWidth(lineNumber); + int x = availableWidth - stringWidth + insets.left; + int y = getOffsetY(rowStartOffset, fontMetrics); + g.drawString(lineNumber, x, y); + } rowStartOffset = Utilities.getRowEnd(codeArea, rowStartOffset) + 1; } catch (Exception e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Line numbers draw error", e); + } break; } } @@ -140,22 +157,23 @@ public class LineNumbers extends JPanel implements CaretListener { return root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition); } + @Nullable protected String getTextLineNumber(int rowStartOffset) { Element root = codeArea.getDocument().getDefaultRootElement(); int index = root.getElementIndex(rowStartOffset); Element line = root.getElement(index); - if (line.getStartOffset() == rowStartOffset) { - int lineNumber = index + 1; - if (useSourceLines) { - Integer sourceLine = codeArea.getSourceLine(lineNumber); - if (sourceLine != null) { - return String.valueOf(sourceLine); - } - } else { - return String.valueOf(lineNumber); - } + if (line.getStartOffset() != rowStartOffset) { + return null; } - return ""; + int lineNumber = index + 1; + if (useSourceLines) { + Integer sourceLine = codeArea.getSourceLine(lineNumber); + if (sourceLine == null) { + return null; + } + return String.valueOf(sourceLine); + } + return String.valueOf(lineNumber); } private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException { From e0624ce986cc9a3ff55264709fed6aab6416afd9 Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 21 Dec 2018 19:41:10 +0300 Subject: [PATCH 2/8] fix: use '$' as separator for inner classes in .jobf file (#415) --- jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java | 4 ++-- jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java b/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java index c478baf23..ab27165fb 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java +++ b/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java @@ -112,7 +112,7 @@ class DeobfPresets { for (DeobfClsInfo deobfClsInfo : deobfuscator.getClsMap().values()) { if (deobfClsInfo.getAlias() != null) { list.add(String.format("c %s = %s", - deobfClsInfo.getCls().getClassInfo().getFullName(), deobfClsInfo.getAlias())); + deobfClsInfo.getCls().getClassInfo().makeRawFullName(), deobfClsInfo.getAlias())); } } for (FieldInfo fld : deobfuscator.getFldMap().keySet()) { @@ -136,7 +136,7 @@ class DeobfPresets { } public String getForCls(ClassInfo cls) { - return clsPresetMap.get(cls.getFullName()); + return clsPresetMap.get(cls.makeRawFullName()); } public String getForFld(FieldInfo fld) { diff --git a/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java index 7c65721d6..dcade6689 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java @@ -111,6 +111,10 @@ public final class ClassInfo { return pkg.isEmpty() ? shortName : pkg + "." + shortName; } + public String makeRawFullName() { + return makeFullClsName(this.name, true); + } + public String getFullPath() { ClassInfo usedAlias = getAlias(); return usedAlias.getPackage().replace('.', File.separatorChar) From a841d0ebe7dfff6639e3eabdd8ae7e79d6a35321 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 22 Dec 2018 13:02:27 +0300 Subject: [PATCH 3/8] fix: use '$' for inner classes also in methods and fields (#415) --- .../src/main/java/jadx/core/deobf/DeobfPresets.java | 12 +++++++----- .../src/main/java/jadx/core/dex/info/FieldInfo.java | 4 ++++ .../src/main/java/jadx/core/dex/info/MethodInfo.java | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java b/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java index ab27165fb..4c6741d8d 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java +++ b/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java @@ -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 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() { diff --git a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java index 6d4844f70..fd35db1de 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java @@ -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); } diff --git a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java index 1f49480f7..8aab5fca1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java @@ -68,6 +68,10 @@ public final class MethodInfo { return declClass.getFullName() + "." + shortId; } + public String getRawFullId() { + return declClass.makeRawFullName() + "." + shortId; + } + /** * Method name and signature */ From 0f27eba1b1c7a4de391df7cd50d75b6cae6b9a06 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 22 Dec 2018 13:03:06 +0300 Subject: [PATCH 4/8] fix: don't rename constructors and class init methods in deobfuscator (#415) --- jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java index ed0d45f91..7e18b1930 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java +++ b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java @@ -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; From 63c528dba9abfda10e1be3618043dcfd9c3b9a80 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 22 Dec 2018 14:57:06 +0300 Subject: [PATCH 5/8] build: update shadowJar for build with gradle 5.0 --- jadx-gui/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jadx-gui/build.gradle b/jadx-gui/build.gradle index aa38bae99..956922536 100644 --- a/jadx-gui/build.gradle +++ b/jadx-gui/build.gradle @@ -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' From fbf750f58878a9a48c28142777bc92a845b12300 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 22 Dec 2018 15:06:00 +0300 Subject: [PATCH 6/8] build: update jacoco for build with java 11 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 292e44867..48299476c 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,7 @@ allprojects { } jacoco { - toolVersion = "0.8.1" + toolVersion = "0.8.2" } jacocoTestReport { reports { From e9591efd7e9d504ec40661b904c653851307e6f2 Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 25 Dec 2018 17:27:42 +0300 Subject: [PATCH 7/8] fix: search exception handler splitter block by offset if jump source unknown (#406) --- .../dex/visitors/blocksmaker/BlockSplitter.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java index d800a0f47..5e4d3d680 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java @@ -223,12 +223,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 blocksMap) { CatchAttr catches = insn.get(AType.CATCH_BLOCK); SplitterBlockAttr spl = block.get(AType.SPLITTER_BLOCK); if (catches == null || spl == null) { @@ -237,7 +238,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)) { @@ -251,6 +252,16 @@ public class BlockSplitter extends AbstractVisitor { } } + private static BlockNode initHandlerBlock(ExceptionHandler excHandler, Map 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 pJumps = prevInsn.getAll(AType.JUMP); for (JumpInfo jump : pJumps) { From eadf046b2c08f8188adebee4915fd2108d5043e9 Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 25 Dec 2018 17:29:36 +0300 Subject: [PATCH 8/8] chore: show try/catch processing problems in code comments --- .../core/dex/trycatch/SplitterBlockAttr.java | 2 +- .../dex/visitors/blocksmaker/BlockFinish.java | 6 +-- .../dex/visitors/regions/CheckRegions.java | 2 +- .../regions/ProcessTryCatchRegions.java | 54 ++++++++++--------- .../dex/visitors/regions/RegionMaker.java | 14 ++--- .../jadx/tests/external/BaseExternalTest.java | 27 +++++++--- 6 files changed, 61 insertions(+), 44 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java index f7b952e04..561091c64 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java @@ -23,6 +23,6 @@ public class SplitterBlockAttr implements IAttribute { @Override public String toString() { - return "Splitter: " + block; + return "Splitter:" + block; } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java index 96db02e95..dd7d47bf6 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java @@ -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 entry : splitters.entrySet()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java index 106eeee7a..49389ea7b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java @@ -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); } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java index 33d544cc3..bb2d543e8 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java @@ -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 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 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 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; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java index 80860bf5a..c5aa7498a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java @@ -929,7 +929,7 @@ public class RegionMaker { } } for (ExceptionHandler handler : tc.getHandlers()) { - processExcHandler(handler, exits); + processExcHandler(mth, handler, exits); } } return processHandlersOutBlocks(mth, tcs); @@ -968,12 +968,12 @@ public class RegionMaker { return excOutRegion; } - private void processExcHandler(ExceptionHandler handler, Set exits) { + private void processExcHandler(MethodNode mth, ExceptionHandler handler, Set 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); @@ -986,11 +986,11 @@ public class RegionMaker { stack.addExits(exits); } BitSet domFrontier = dom.getDomFrontier(); - List handlerExits = BlockUtils.bitSetToBlocks(mth, domFrontier); - boolean inLoop = mth.getLoopForBlock(start) != null; + List 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); } } @@ -998,7 +998,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); } diff --git a/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java b/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java index 90ac8de9e..58b29cc5d 100644 --- a/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java +++ b/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java @@ -127,23 +127,36 @@ public abstract class BaseExternalTest extends IntegrationTest { String[] lines = code.split(CodeWriter.NL); for (MethodNode mth : classNode.getMethods()) { if (mthPattern.matcher(mth.getName()).matches()) { - 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{}", 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));