提交 0c041120 编写于 作者: S Skylot

core: show all decompilation errors in code comments (#313)

上级 ecbb53aa
......@@ -10,31 +10,36 @@ public class JadxCLI {
private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class);
public static void main(String[] args) {
int result = 0;
try {
JadxCLIArgs jadxArgs = new JadxCLIArgs();
if (jadxArgs.processArgs(args)) {
processAndSave(jadxArgs);
result = processAndSave(jadxArgs);
}
} catch (Exception e) {
LOG.error("jadx error: {}", e.getMessage(), e);
System.exit(1);
result = 1;
} finally {
System.exit(result);
}
}
static void processAndSave(JadxCLIArgs inputArgs) {
static int processAndSave(JadxCLIArgs inputArgs) {
JadxDecompiler jadx = new JadxDecompiler(inputArgs.toJadxArgs());
try {
jadx.load();
} catch (JadxArgsValidateException e) {
LOG.error("Incorrect arguments: {}", e.getMessage());
System.exit(1);
return 1;
}
jadx.save();
if (jadx.getErrorsCount() != 0) {
int errorsCount = jadx.getErrorsCount();
if (errorsCount != 0) {
jadx.printErrorsReport();
LOG.error("finished with errors");
} else {
LOG.info("done");
}
return errorsCount;
}
}
......@@ -264,6 +264,13 @@ public final class JadxDecompiler {
return root.getErrorsCounter().getErrorCount();
}
public int getWarnsCount() {
if (root == null) {
return 0;
}
return root.getErrorsCounter().getWarnsCount();
}
public void printErrorsReport() {
if (root == null) {
return;
......
......@@ -18,6 +18,8 @@ import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.AttrNode;
import jadx.core.dex.attributes.nodes.EnumClassAttr;
import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JadxWarn;
import jadx.core.dex.attributes.nodes.LineAttrNode;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.info.AccessInfo;
......@@ -253,6 +255,7 @@ public class ClassGen {
if (code.getLine() != clsDeclLine) {
code.newLine();
}
int savedIndent = code.getIndent();
try {
addMethod(code, mth);
} catch (Exception e) {
......@@ -260,6 +263,7 @@ public class ClassGen {
code.newLine().add(ErrorsCounter.methodError(mth, "Method generation error", e));
code.newLine().add(Utils.getStackTrace(e));
code.newLine().add("*/");
code.setIndent(savedIndent);
}
}
}
......@@ -292,12 +296,11 @@ public class ClassGen {
}
code.add(';');
} else {
insertDecompilationProblems(code, mth);
boolean badCode = mth.contains(AFlag.INCONSISTENT_CODE);
if (badCode) {
code.startLine("/* JADX WARNING: inconsistent code. */");
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */");
ErrorsCounter.methodError(mth, "Inconsistent code");
if (showInconsistentCode) {
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */");
mth.remove(AFlag.INCONSISTENT_CODE);
badCode = false;
}
......@@ -324,6 +327,26 @@ public class ClassGen {
}
}
private void insertDecompilationProblems(CodeWriter code, MethodNode mth) {
List<JadxError> errors = mth.getAll(AType.JADX_ERROR);
List<JadxWarn> warns = mth.getAll(AType.JADX_WARN);
if (!errors.isEmpty()) {
errors.forEach(err -> {
code.startLine("/* JADX ERROR: ").add(err.getError());
Throwable cause = err.getCause();
if (cause != null) {
code.incIndent();
Utils.appendStackTrace(code, cause);
code.decIndent();
}
code.add("*/");
});
}
if (!warns.isEmpty()) {
warns.forEach(warn -> code.startLine("/* JADX WARNING: ").add(warn.getWarn()).add(" */"));
}
}
private void addFields(CodeWriter code) throws CodegenException {
addEnumFields(code);
for (FieldNode f : cls.getFields()) {
......
......@@ -191,6 +191,11 @@ public class CodeWriter {
return indent;
}
public void setIndent(int indent) {
this.indent = indent;
updateIndent();
}
public int getLine() {
return line;
}
......
......@@ -122,7 +122,7 @@ public class ConditionGen extends InsnGen {
wrap(code, firstArg);
return;
}
ErrorsCounter.methodError(mth, "Unsupported boolean condition " + op.getSymbol());
ErrorsCounter.methodWarn(mth, "Unsupported boolean condition " + op.getSymbol());
}
addArg(code, firstArg, isArgWrapNeeded(firstArg));
......
......@@ -580,7 +580,7 @@ public class InsnGen {
// anonymous class construction
if (cls.contains(AFlag.DONT_GENERATE)) {
code.add("/* anonymous class already generated */");
ErrorsCounter.methodError(mth, "Anonymous class already generated: " + cls);
ErrorsCounter.methodWarn(mth, "Anonymous class already generated: " + cls);
return;
}
ArgType parent;
......
......@@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.annotations.MethodParameters;
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.ArgType;
......@@ -23,7 +22,6 @@ import jadx.core.dex.visitors.DepthTraversal;
import jadx.core.dex.visitors.FallbackModeVisitor;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.InsnUtils;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.DecodeException;
......@@ -108,7 +106,7 @@ public class MethodGen {
} else if (args.size() > 2) {
args = args.subList(2, args.size());
} else {
LOG.warn(ErrorsCounter.formatErrorMsg(mth,
LOG.warn(ErrorsCounter.formatMsg(mth,
"Incorrect number of args for enum constructor: " + args.size()
+ " (expected >= 2)"
));
......@@ -143,7 +141,7 @@ public class MethodGen {
classGen.useType(argsCode, elType);
argsCode.add("...");
} else {
LOG.warn(ErrorsCounter.formatErrorMsg(mth, "Last argument in varargs method not array"));
LOG.warn(ErrorsCounter.formatMsg(mth, "Last argument in varargs method not array"));
classGen.useType(argsCode, arg.getType());
}
} else {
......@@ -163,17 +161,6 @@ public class MethodGen {
if (mth.contains(AType.JADX_ERROR)
|| mth.contains(AFlag.INCONSISTENT_CODE)
|| mth.getRegion() == null) {
JadxErrorAttr err = mth.get(AType.JADX_ERROR);
if (err != null) {
code.startLine("/* JADX: method processing error */");
Throwable cause = err.getCause();
if (cause != null) {
code.newLine();
code.add("/*");
code.newLine().add("Error: ").addMultiLine(Utils.getStackTrace(cause));
code.add("*/");
}
}
code.startLine("/*");
addFallbackMethodCode(code);
code.startLine("*/");
......@@ -189,19 +176,14 @@ public class MethodGen {
public void addFallbackMethodCode(CodeWriter code) {
if (mth.getInstructions() == null) {
JadxErrorAttr errorAttr = mth.get(AType.JADX_ERROR);
if (errorAttr == null
|| errorAttr.getCause() == null
|| !errorAttr.getCause().getClass().equals(DecodeException.class)) {
// load original instructions
try {
mth.load();
DepthTraversal.visit(new FallbackModeVisitor(), mth);
} catch (DecodeException e) {
LOG.error("Error reload instructions in fallback mode:", e);
code.startLine("// Can't load method instructions: " + e.getMessage());
return;
}
// load original instructions
try {
mth.load();
DepthTraversal.visit(new FallbackModeVisitor(), mth);
} catch (DecodeException e) {
LOG.error("Error reload instructions in fallback mode:", e);
code.startLine("// Can't load method instructions: " + e.getMessage());
return;
}
}
InsnNode[] insnArr = mth.getInstructions();
......@@ -251,5 +233,4 @@ public class MethodGen {
public static String getLabelName(int offset) {
return "L_" + InsnUtils.formatOffset(offset);
}
}
......@@ -7,6 +7,7 @@ import java.util.Set;
import jadx.core.Consts;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.MethodInfo;
......@@ -136,11 +137,11 @@ public class NameGen {
private String makeNameForType(ArgType type) {
if (type.isPrimitive()) {
return makeNameForPrimitive(type);
} else if (type.isArray()) {
}
if (type.isArray()) {
return makeNameForType(type.getArrayRootElement()) + "Arr";
} else {
return makeNameForObject(type);
}
return makeNameForObject(type);
}
private static String makeNameForPrimitive(ArgType type) {
......
......@@ -153,7 +153,7 @@ public class RegionGen extends InsnGen {
if (header != null) {
List<InsnNode> headerInsns = header.getInstructions();
if (headerInsns.size() > 1) {
ErrorsCounter.methodError(mth, "Found not inlined instructions from loop header");
ErrorsCounter.methodWarn(mth, "Found not inlined instructions from loop header");
int last = headerInsns.size() - 1;
for (int i = 0; i < last; i++) {
InsnNode insn = headerInsns.get(i);
......
......@@ -9,7 +9,8 @@ import jadx.core.dex.attributes.nodes.EnumMapAttr;
import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.ForceReturnAttr;
import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr;
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JadxWarn;
import jadx.core.dex.attributes.nodes.JumpInfo;
import jadx.core.dex.attributes.nodes.LoopInfo;
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
......@@ -33,13 +34,15 @@ public class AType<T extends IAttribute> {
public static final AType<AttrList<LoopInfo>> LOOP = new AType<>();
public static final AType<AttrList<EdgeInsnAttr>> EDGE_INSN = new AType<>();
public static final AType<AttrList<JadxError>> JADX_ERROR = new AType<>();
public static final AType<AttrList<JadxWarn>> JADX_WARN = new AType<>();
public static final AType<ExcHandlerAttr> EXC_HANDLER = new AType<>();
public static final AType<CatchAttr> CATCH_BLOCK = new AType<>();
public static final AType<SplitterBlockAttr> SPLITTER_BLOCK = new AType<>();
public static final AType<ForceReturnAttr> FORCE_RETURN = new AType<>();
public static final AType<FieldInitAttr> FIELD_INIT = new AType<>();
public static final AType<FieldReplaceAttr> FIELD_REPLACE = new AType<>();
public static final AType<JadxErrorAttr> JADX_ERROR = new AType<>();
public static final AType<MethodInlineAttr> METHOD_INLINE = new AType<>();
public static final AType<EnumClassAttr> ENUM_CLASS = new AType<>();
public static final AType<EnumMapAttr> ENUM_MAP = new AType<>();
......
package jadx.core.dex.attributes;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import jadx.core.utils.Utils;
......@@ -8,7 +8,7 @@ import jadx.core.utils.Utils;
public class AttrList<T> implements IAttribute {
private final AType<AttrList<T>> type;
private final List<T> list = new LinkedList<>();
private final List<T> list = new ArrayList<>();
public AttrList(AType<AttrList<T>> type) {
this.type = type;
......
package jadx.core.dex.attributes.nodes;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttribute;
import jadx.core.utils.Utils;
public class JadxErrorAttr implements IAttribute {
public class JadxError {
private final String error;
private final Throwable cause;
public JadxErrorAttr(Throwable cause) {
public JadxError(Throwable cause) {
this(null, cause);
}
public JadxError(String error, Throwable cause) {
this.error = error;
this.cause = cause;
}
public Throwable getCause() {
return cause;
public String getError() {
return error;
}
@Override
public AType<JadxErrorAttr> getType() {
return AType.JADX_ERROR;
public Throwable getCause() {
return cause;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("JadxError: ");
if (cause == null) {
str.append("null");
} else {
if (error != null) {
str.append(error);
str.append(' ');
}
if (cause != null) {
str.append(cause.getClass());
str.append(":");
str.append(cause.getMessage());
......@@ -36,5 +41,4 @@ public class JadxErrorAttr implements IAttribute {
}
return str.toString();
}
}
package jadx.core.dex.attributes.nodes;
import java.util.Objects;
public class JadxWarn {
private final String warn;
public JadxWarn(String warn) {
this.warn = Objects.requireNonNull(warn);
}
public String getWarn() {
return warn;
}
@Override
public String toString() {
return "JadxWarn: " + warn;
}
}
......@@ -55,7 +55,7 @@ public class RegisterArg extends InsnArg implements Named {
}
public void setName(String name) {
if (sVar != null) {
if (sVar != null && name != null) {
sVar.setName(name);
}
}
......
......@@ -2,8 +2,6 @@ package jadx.core.dex.nodes;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import jadx.core.dex.attributes.AFlag;
......@@ -35,7 +33,7 @@ public class BlockNode extends AttrNode implements IBlock {
// immediate dominator
private BlockNode idom;
// blocks on which dominates this block
private List<BlockNode> dominatesOn = Collections.emptyList();
private List<BlockNode> dominatesOn = new ArrayList<>(3);
public BlockNode(int id, int offset) {
this.id = id;
......@@ -84,7 +82,7 @@ public class BlockNode extends AttrNode implements IBlock {
if (sucList.isEmpty()) {
return sucList;
}
List<BlockNode> toRemove = new LinkedList<>();
List<BlockNode> toRemove = new ArrayList<>(sucList.size());
for (BlockNode b : sucList) {
if (BlockUtils.isBlockMustBeCleared(b)) {
toRemove.add(b);
......@@ -159,9 +157,6 @@ public class BlockNode extends AttrNode implements IBlock {
}
public void addDominatesOn(BlockNode block) {
if (dominatesOn.isEmpty()) {
dominatesOn = new LinkedList<>();
}
dominatesOn.add(block);
}
......
......@@ -22,7 +22,6 @@ import org.slf4j.LoggerFactory;
import jadx.core.Consts;
import jadx.core.codegen.CodeWriter;
import jadx.core.dex.attributes.annotations.Annotation;
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
import jadx.core.dex.attributes.nodes.LineAttrNode;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.info.AccessInfo;
......@@ -248,8 +247,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
try {
mth.load();
} catch (Exception e) {
LOG.error("Method load error: {}", mth, e);
mth.addAttr(new JadxErrorAttr(e));
mth.addError("Method load error", e);
}
}
for (ClassNode innerCls : getInnerClasses()) {
......@@ -418,6 +416,11 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
return dex.root();
}
@Override
public String typeName() {
return "class";
}
public String getRawName() {
return clsInfo.getRawName();
}
......
......@@ -235,6 +235,11 @@ public class DexNode implements IDexNode {
return this;
}
@Override
public String typeName() {
return "dex";
}
public int getDexId() {
return dexId;
}
......@@ -243,5 +248,4 @@ public class DexNode implements IDexNode {
public String toString() {
return "DEX: " + file;
}
}
......@@ -2,6 +2,8 @@ package jadx.core.dex.nodes;
public interface IDexNode {
String typeName();
DexNode dex();
RootNode root();
......
......@@ -39,6 +39,7 @@ import jadx.core.dex.regions.Region;
import jadx.core.dex.trycatch.ExcHandlerAttr;
import jadx.core.dex.trycatch.ExceptionHandler;
import jadx.core.dex.trycatch.TryCatchBlock;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxRuntimeException;
......@@ -605,6 +606,19 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
return dex().root();
}
@Override
public String typeName() {
return "method";
}
public void addWarn(String errStr) {
ErrorsCounter.methodWarn(this, errStr);
}
public void addError(String errStr, Exception e) {
ErrorsCounter.methodError(this, errStr, e);
}
public MethodInfo getMethodInfo() {
return mthInfo;
}
......
......@@ -26,7 +26,7 @@ public class DebugInfoVisitor extends AbstractVisitor {
processDebugInfo(mth, debugOffset);
}
} catch (Exception e) {
LOG.error("Error in debug info parser: {}", ErrorsCounter.formatErrorMsg(mth, e.getMessage()), e);
LOG.error("Error in debug info parser: {}", ErrorsCounter.formatMsg(mth, e.getMessage()), e);
} finally {
mth.unloadInsnArr();
}
......
......@@ -259,8 +259,7 @@ public class DotGraphVisitor extends AbstractVisitor {
} else {
CodeWriter code = new CodeWriter();
List<InsnNode> instructions = block.getInstructions();
MethodGen.addFallbackInsns(code, mth,
instructions.toArray(new InsnNode[instructions.size()]), false);
MethodGen.addFallbackInsns(code, mth, instructions.toArray(new InsnNode[0]), false);
String str = escape(code.newLine().toString());
if (str.startsWith(NL)) {
str = str.substring(NL.length());
......
......@@ -366,7 +366,7 @@ public class ModVisitor extends AbstractVisitor {
elType = insnElementType;
}
if (!elType.equals(insnElementType) && !insnArrayType.equals(ArgType.OBJECT)) {
ErrorsCounter.methodError(mth,
ErrorsCounter.methodWarn(mth,
"Incorrect type for fill-array insn " + InsnUtils.formatOffset(insn.getOffset())
+ ", element type: " + elType + ", insn element type: " + insnElementType
);
......
......@@ -529,7 +529,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
return false;
}
if (removeInfo.getOuts().isEmpty()) {
ErrorsCounter.methodError(mth, "Failed to extract finally block: empty outs");
ErrorsCounter.methodWarn(mth, "Failed to extract finally block: empty outs");
return false;
}
// safe checks finished, altering blocks tree
......
......@@ -6,15 +6,19 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.codegen.CodeWriter;
import jadx.core.codegen.InsnGen;
import jadx.core.codegen.MethodGen;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.IBlock;
import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.loops.LoopRegion;
import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.JadxException;
public class CheckRegions extends AbstractVisitor {
......@@ -23,6 +27,7 @@ public class CheckRegions extends AbstractVisitor {
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()
|| mth.getRegion() == null
|| mth.getBasicBlocks().isEmpty()
|| mth.contains(AType.JADX_ERROR)) {
return;
......@@ -44,9 +49,10 @@ public class CheckRegions extends AbstractVisitor {
&& !block.contains(AFlag.SKIP)
&& !block.contains(AFlag.SYNTHETIC)
&& !block.getInstructions().isEmpty()) {
// TODO
// mth.add(AFlag.INCONSISTENT_CODE);
LOG.debug(" Duplicated block: {} in {}", block, mth);
if (LOG.isDebugEnabled()) {
LOG.debug("Duplicated block: {} - {}", mth, block);
}
//mth.addWarn("Duplicated block: " + block);
}
}
});
......@@ -55,8 +61,8 @@ public class CheckRegions extends AbstractVisitor {
if (!blocksInRegions.contains(block)
&& !block.getInstructions().isEmpty()
&& !block.contains(AFlag.SKIP)) {
mth.add(AFlag.INCONSISTENT_CODE);
LOG.debug(" Missing block: {} in {}", block, mth);
String blockCode = getBlockInsnStr(mth, block);
mth.addWarn("Missing block: " + block + ", code:" + CodeWriter.NL + blockCode);
}
}
}
......@@ -68,11 +74,27 @@ public class CheckRegions extends AbstractVisitor {
if (region instanceof LoopRegion) {
BlockNode loopHeader = ((LoopRegion) region).getHeader();
if (loopHeader != null && loopHeader.getInstructions().size() != 1) {
ErrorsCounter.methodError(mth, "Incorrect condition in loop: " + loopHeader);
mth.addWarn("Incorrect condition in loop: " + loopHeader);
}
}
return true;
}
});
}
private static String getBlockInsnStr(MethodNode mth, BlockNode block) {
CodeWriter code = new CodeWriter();
code.setIndent(3);
MethodGen mg = MethodGen.getFallbackMethodGen(mth);
InsnGen ig = new InsnGen(mg, true);
for (InsnNode insn : block.getInstructions()) {
try {
ig.makeInsn(insn, code);
} catch (CodegenException ignored) {
}
}
code.newLine().addIndent();
code.finish();
return code.toString();
}
}
......@@ -93,7 +93,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
}
TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb);
if (prevTB != null) {
ErrorsCounter.methodError(mth, "Failed to process nested try/catch");
ErrorsCounter.methodWarn(mth, "Failed to process nested try/catch");
}
}
}
......@@ -105,7 +105,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
if (region.getSubBlocks().contains(dominator)) {
TryCatchBlock tb = tryBlocksMap.get(dominator);
if (!wrapBlocks(region, tb, dominator)) {
ErrorsCounter.methodError(mth, "Can't wrap try/catch for " + region);
ErrorsCounter.methodWarn(mth, "Can't wrap try/catch for " + region);
}
tryBlocksMap.remove(dominator);
return true;
......
......@@ -532,7 +532,7 @@ public class RegionMaker {
BlockNode body = getNextBlock(block);
if (body == null) {
ErrorsCounter.methodError(mth, "Unexpected end of synchronized block");
ErrorsCounter.methodWarn(mth, "Unexpected end of synchronized block");
return null;
}
BlockNode exit = null;
......@@ -904,7 +904,7 @@ public class RegionMaker {
blocks.add(handlerBlock);
splitters.addAll(handlerBlock.getPredecessors());
} else {
LOG.debug(ErrorsCounter.formatErrorMsg(mth, "No exception handler block: " + handler));
LOG.debug(ErrorsCounter.formatMsg(mth, "No exception handler block: " + handler));
}
}
Set<BlockNode> exits = new HashSet<>();
......@@ -912,7 +912,7 @@ public class RegionMaker {
for (BlockNode handler : blocks) {
List<BlockNode> s = splitter.getSuccessors();
if (s.isEmpty()) {
LOG.debug(ErrorsCounter.formatErrorMsg(mth, "No successors for splitter: " + splitter));
LOG.debug(ErrorsCounter.formatMsg(mth, "No successors for splitter: " + splitter));
continue;
}
BlockNode ss = s.get(0);
......
......@@ -23,6 +23,6 @@ public class CheckTypeVisitor {
}
private static void error(String msg, MethodNode mth, InsnNode insn) {
ErrorsCounter.methodError(mth, msg + ": " + insn);
ErrorsCounter.methodWarn(mth, msg + ": " + insn);
}
}
......@@ -11,9 +11,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JadxWarn;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.IDexNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.exceptions.JadxOverflowException;
......@@ -22,34 +25,53 @@ public class ErrorsCounter {
private final Set<IAttributeNode> errorNodes = new HashSet<>();
private int errorsCount;
private final Set<IAttributeNode> warnNodes = new HashSet<>();
private int warnsCount;
public int getErrorCount() {
return errorsCount;
}
private synchronized void addError(IAttributeNode node, String msg, @Nullable Throwable e) {
public int getWarnsCount() {
return warnsCount;
}
private synchronized <N extends IDexNode & IAttributeNode> String addError(N node, String error, @Nullable Throwable e) {
errorNodes.add(node);
errorsCount++;
if (e != null) {
if (e instanceof JadxOverflowException) {
// don't print full stack trace
e = new JadxOverflowException(e.getMessage());
LOG.error("{}, message: {}", msg, e.getMessage());
} else {
LOG.error(msg, e);
}
node.addAttr(new JadxErrorAttr(e));
String msg = formatMsg(node, error);
if (e == null) {
LOG.error(msg);
} else if (e instanceof JadxOverflowException) {
// don't print full stack trace
e = new JadxOverflowException(e.getMessage());
LOG.error("{}, details: {}", msg, e.getMessage());
} else {
LOG.error(msg, e);
}
node.addAttr(AType.JADX_ERROR, new JadxError(error, e));
node.remove(AFlag.INCONSISTENT_CODE);
return msg;
}
private synchronized <N extends IDexNode & IAttributeNode> String addWarning(N node, String warn) {
warnNodes.add(node);
warnsCount++;
node.addAttr(AType.JADX_WARN, new JadxWarn(warn));
if (!node.contains(AType.JADX_ERROR)) {
node.add(AFlag.INCONSISTENT_CODE);
LOG.error(msg);
}
String msg = formatMsg(node, warn);
LOG.warn(msg);
return msg;
}
public static String classError(ClassNode cls, String errorMsg, Throwable e) {
String msg = formatErrorMsg(cls, errorMsg);
cls.dex().root().getErrorsCounter().addError(cls, msg, e);
return msg;
return cls.dex().root().getErrorsCounter().addError(cls, errorMsg, e);
}
public static String classError(ClassNode cls, String errorMsg) {
......@@ -57,13 +79,15 @@ public class ErrorsCounter {
}
public static String methodError(MethodNode mth, String errorMsg, Throwable e) {
String msg = formatErrorMsg(mth, errorMsg);
mth.dex().root().getErrorsCounter().addError(mth, msg, e);
return msg;
return mth.root().getErrorsCounter().addError(mth, errorMsg, e);
}
public static String methodWarn(MethodNode mth, String warnMsg) {
return mth.root().getErrorsCounter().addWarning(mth, warnMsg);
}
public static String methodError(MethodNode mth, String errorMsg) {
return methodError(mth, errorMsg, null);
public static String formatMsg(IDexNode node, String msg) {
return msg + " in " + node.typeName() + ": " + node + ", dex: " + node.dex().getDexFile().getName();
}
public void printReport() {
......@@ -79,13 +103,8 @@ public class ErrorsCounter {
LOG.error(" {}", err);
}
}
}
public static String formatErrorMsg(ClassNode cls, String msg) {
return msg + " in class: " + cls + ", dex: " + cls.dex().getDexFile().getName();
}
public static String formatErrorMsg(MethodNode mth, String msg) {
return msg + " in method: " + mth + ", dex: " + mth.dex().getDexFile().getName();
if (getWarnsCount() > 0) {
LOG.warn("{} warnings in {} nodes", getWarnsCount(), warnNodes.size());
}
}
}
package jadx.core.utils;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
......@@ -9,6 +10,7 @@ import java.util.List;
import java.util.function.Function;
import jadx.api.JadxDecompiler;
import jadx.core.codegen.CodeWriter;
public class Utils {
......@@ -80,6 +82,30 @@ public class Utils {
return sw.getBuffer().toString();
}
public static void appendStackTrace(CodeWriter code, Throwable throwable) {
if (throwable == null) {
return;
}
code.startLine();
OutputStream w = new OutputStream() {
@Override
public void write(int b) {
char c = (char) b;
if (c == '\r') {
// ignore
} else if (c == '\n') {
code.startLine();
} else {
code.add(c);
}
}
};
PrintWriter pw = new PrintWriter(w, true);
filterRecursive(throwable);
throwable.printStackTrace(pw);
pw.flush();
}
private static void filterRecursive(Throwable th) {
try {
filter(th);
......
......@@ -17,11 +17,11 @@ public class JadxException extends Exception {
}
public JadxException(ClassNode cls, String msg, Throwable th) {
super(ErrorsCounter.formatErrorMsg(cls, msg), th);
super(ErrorsCounter.formatMsg(cls, msg), th);
}
public JadxException(MethodNode mth, String msg, Throwable th) {
super(ErrorsCounter.formatErrorMsg(mth, msg), th);
super(ErrorsCounter.formatMsg(mth, msg), th);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册