Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
J
jadx
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open-source
jadx
Commits
ed67f8e1
Commit
ed67f8e1
authored
Dec 06, 2013
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: make strict shrink code implementation
parent
45312560
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
721 additions
and
300 deletions
+721
-300
Jadx.java
jadx-core/src/main/java/jadx/core/Jadx.java
+5
-2
InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+5
-3
RegionGen.java
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
+14
-0
NameMapper.java
jadx-core/src/main/java/jadx/core/deobf/NameMapper.java
+1
-1
ArgType.java
...rc/main/java/jadx/core/dex/instructions/args/ArgType.java
+7
-6
InsnArg.java
...rc/main/java/jadx/core/dex/instructions/args/InsnArg.java
+0
-4
RegisterArg.java
...ain/java/jadx/core/dex/instructions/args/RegisterArg.java
+0
-5
ConstructorInsn.java
...java/jadx/core/dex/instructions/mods/ConstructorInsn.java
+12
-8
InsnNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java
+24
-0
RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+2
-0
LoopRegion.java
...-core/src/main/java/jadx/core/dex/regions/LoopRegion.java
+8
-9
CodeShrinker.java
...re/src/main/java/jadx/core/dex/visitors/CodeShrinker.java
+189
-221
SimplifyVisitor.java
...src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
+211
-0
RegionMaker.java
...main/java/jadx/core/dex/visitors/regions/RegionMaker.java
+12
-17
BlockUtils.java
jadx-core/src/main/java/jadx/core/utils/BlockUtils.java
+16
-12
InsnList.java
jadx-core/src/main/java/jadx/core/utils/InsnList.java
+65
-0
InternalJadxTest.java
jadx-core/src/test/java/jadx/api/InternalJadxTest.java
+9
-4
TestLoopCondition.java
.../src/test/java/jadx/tests/internal/TestLoopCondition.java
+1
-1
TestRedundantThis.java
.../src/test/java/jadx/tests/internal/TestRedundantThis.java
+1
-3
TestStringBuilderElimination.java
...ava/jadx/tests/internal/TestStringBuilderElimination.java
+6
-4
TestInline.java
.../src/test/java/jadx/tests/internal/inline/TestInline.java
+30
-0
TestInline2.java
...src/test/java/jadx/tests/internal/inline/TestInline2.java
+34
-0
TestInline3.java
...src/test/java/jadx/tests/internal/inline/TestInline3.java
+40
-0
TestCF3.java
jadx-samples/src/main/java/jadx/samples/TestCF3.java
+29
-0
No files found.
jadx-core/src/main/java/jadx/core/Jadx.java
View file @
ed67f8e1
...
...
@@ -12,6 +12,7 @@ import jadx.core.dex.visitors.FallbackModeVisitor;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.dex.visitors.MethodInlinerVisitor
;
import
jadx.core.dex.visitors.ModVisitor
;
import
jadx.core.dex.visitors.SimplifyVisitor
;
import
jadx.core.dex.visitors.regions.CheckRegions
;
import
jadx.core.dex.visitors.regions.CleanRegions
;
import
jadx.core.dex.visitors.regions.PostRegionVisitor
;
...
...
@@ -50,12 +51,13 @@ public class Jadx {
passes
.
add
(
new
BlockMakerVisitor
());
passes
.
add
(
new
TypeResolver
());
passes
.
add
(
new
ConstInlinerVisitor
());
passes
.
add
(
new
FinishTypeResolver
());
if
(
args
.
isRawCFGOutput
())
passes
.
add
(
new
DotGraphVisitor
(
outDir
,
false
,
true
));
passes
.
add
(
new
ConstInlinerVisitor
());
passes
.
add
(
new
FinishTypeResolver
());
passes
.
add
(
new
ModVisitor
());
passes
.
add
(
new
EnumVisitor
());
...
...
@@ -66,6 +68,7 @@ public class Jadx {
passes
.
add
(
new
PostRegionVisitor
());
passes
.
add
(
new
CodeShrinker
());
passes
.
add
(
new
SimplifyVisitor
());
passes
.
add
(
new
ProcessVariables
());
passes
.
add
(
new
CheckRegions
());
if
(
args
.
isCFGOutput
())
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
View file @
ed67f8e1
...
...
@@ -128,7 +128,9 @@ public class InsnGen {
private
String
ifield
(
FieldInfo
field
,
InsnArg
arg
)
throws
CodegenException
{
String
name
=
field
.
getName
();
if
(
arg
.
isThis
())
{
// TODO: add jadx argument ""
// FIXME: check variable names in scope
if
(
false
&&
arg
.
isThis
())
{
boolean
useShort
=
true
;
List
<
RegisterArg
>
args
=
mth
.
getArguments
(
false
);
for
(
RegisterArg
param
:
args
)
{
...
...
@@ -138,7 +140,7 @@ public class InsnGen {
}
}
if
(
useShort
)
{
return
name
;
// FIXME: check variable names in scope
return
name
;
}
}
return
arg
(
arg
)
+
"."
+
name
;
...
...
@@ -672,7 +674,7 @@ public class InsnGen {
// "++" or "--"
if
(
insn
.
getArg
(
1
).
isLiteral
()
&&
(
op
==
ArithOp
.
ADD
||
op
==
ArithOp
.
SUB
))
{
LiteralArg
lit
=
(
LiteralArg
)
insn
.
getArg
(
1
);
if
(
Math
.
abs
(
lit
.
getLiteral
())
==
1
&&
lit
.
isInteger
()
)
{
if
(
lit
.
isInteger
()
&&
lit
.
getLiteral
()
==
1
)
{
code
.
add
(
assignVar
(
insn
)).
add
(
op
.
getSymbol
()).
add
(
op
.
getSymbol
());
return
;
}
...
...
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
View file @
ed67f8e1
...
...
@@ -16,6 +16,7 @@ import jadx.core.dex.instructions.args.InsnArg;
import
jadx.core.dex.instructions.args.InsnWrapArg
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.IBlock
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.IRegion
;
...
...
@@ -134,6 +135,19 @@ public class RegionGen extends InsnGen {
}
private
CodeWriter
makeLoop
(
LoopRegion
region
,
CodeWriter
code
)
throws
CodegenException
{
BlockNode
header
=
region
.
getHeader
();
if
(
header
!=
null
)
{
List
<
InsnNode
>
headerInsns
=
header
.
getInstructions
();
if
(
headerInsns
.
size
()
>
1
)
{
// write not inlined instructions from header
mth
.
getAttributes
().
add
(
AttributeFlag
.
INCONSISTENT_CODE
);
for
(
int
i
=
0
;
i
<
headerInsns
.
size
()
-
1
;
i
++)
{
InsnNode
insn
=
headerInsns
.
get
(
i
);
makeInsn
(
insn
,
code
);
}
}
}
IfCondition
condition
=
region
.
getCondition
();
if
(
condition
==
null
)
{
// infinite loop
...
...
jadx-core/src/main/java/jadx/core/deobf/NameMapper.java
View file @
ed67f8e1
...
...
@@ -21,7 +21,7 @@ public class NameMapper {
"continue"
,
"default"
,
"do"
,
"double
"
,
"double"
,
"else"
,
"enum"
,
"extends"
,
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java
View file @
ed67f8e1
...
...
@@ -339,15 +339,16 @@ public abstract class ArgType {
}
public
static
ArgType
merge
(
ArgType
a
,
ArgType
b
)
{
if
(
a
.
equals
(
b
))
return
a
;
if
(
b
==
null
||
a
==
null
)
if
(
b
==
null
||
a
==
null
)
{
return
null
;
}
if
(
a
.
equals
(
b
))
{
return
a
;
}
ArgType
res
=
mergeInternal
(
a
,
b
);
if
(
res
==
null
)
if
(
res
==
null
)
{
res
=
mergeInternal
(
b
,
a
);
// swap
}
return
res
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java
View file @
ed67f8e1
...
...
@@ -87,10 +87,6 @@ public abstract class InsnArg extends Typed {
case
MOVE:
case
CONST:
arg
=
insn
.
getArg
(
0
);
String
name
=
insn
.
getResult
().
getTypedVar
().
getName
();
if
(
name
!=
null
)
{
arg
.
getTypedVar
().
setName
(
name
);
}
break
;
case
CONST_STR:
arg
=
wrap
(
insn
);
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java
View file @
ed67f8e1
...
...
@@ -10,7 +10,6 @@ import jadx.core.dex.nodes.DexNode;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.parser.FieldValueAttr
;
import
jadx.core.dex.visitors.InstructionRemover
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -96,10 +95,6 @@ public class RegisterArg extends InsnArg {
if
(
ai
!=
null
&&
ai
.
getType
()
==
InsnType
.
MOVE
)
{
InsnArg
arg
=
ai
.
getArg
(
0
);
if
(
arg
!=
this
&&
arg
.
isThis
())
{
// actually we need to remove this instruction but we can't
// because of iterating on instructions list
// so unbind insn and rely on code shrinker
InstructionRemover
.
unbindInsn
(
ai
);
return
true
;
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/mods/ConstructorInsn.java
View file @
ed67f8e1
...
...
@@ -11,6 +11,8 @@ import jadx.core.dex.nodes.MethodNode;
public
class
ConstructorInsn
extends
InsnNode
{
private
final
MethodInfo
callMth
;
private
final
CallType
callType
;
private
final
RegisterArg
instanceArg
;
private
static
enum
CallType
{
CONSTRUCTOR
,
// just new instance
...
...
@@ -19,30 +21,28 @@ public class ConstructorInsn extends InsnNode {
SELF
// call itself
}
private
CallType
callType
;
public
ConstructorInsn
(
MethodNode
mth
,
InvokeNode
invoke
)
{
super
(
InsnType
.
CONSTRUCTOR
,
invoke
.
getArgsCount
()
-
1
);
this
.
callMth
=
invoke
.
getCallMth
();
ClassInfo
classType
=
callMth
.
getDeclClass
();
instanceArg
=
(
RegisterArg
)
invoke
.
getArg
(
0
);
instanceArg
.
setParentInsn
(
this
);
if
(
in
voke
.
getArg
(
0
)
.
isThis
())
{
if
(
in
stanceArg
.
isThis
())
{
if
(
classType
.
equals
(
mth
.
getParentClass
().
getClassInfo
()))
{
if
(
callMth
.
getShortId
().
equals
(
mth
.
getMethodInfo
().
getShortId
()))
{
// self constructor
callType
=
CallType
.
SELF
;
}
else
if
(
mth
.
getMethodInfo
().
isConstructor
())
{
}
else
{
callType
=
CallType
.
THIS
;
}
}
else
{
callType
=
CallType
.
SUPER
;
}
}
if
(
callType
==
null
)
{
}
else
{
callType
=
CallType
.
CONSTRUCTOR
;
setResult
(
(
RegisterArg
)
invoke
.
getArg
(
0
)
);
setResult
(
instanceArg
);
}
for
(
int
i
=
1
;
i
<
invoke
.
getArgsCount
();
i
++)
{
addArg
(
invoke
.
getArg
(
i
));
}
...
...
@@ -53,6 +53,10 @@ public class ConstructorInsn extends InsnNode {
return
callMth
;
}
public
RegisterArg
getInstanceArg
()
{
return
instanceArg
;
}
public
ClassInfo
getClassType
()
{
return
callMth
.
getDeclClass
();
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java
View file @
ed67f8e1
...
...
@@ -133,6 +133,30 @@ public class InsnNode extends LineAttrNode {
}
}
public
boolean
canReorder
()
{
switch
(
getType
())
{
case
CONST:
case
CONST_STR:
case
CONST_CLASS:
case
CAST:
case
MOVE:
case
ARITH:
case
NEG:
case
CMP_L:
case
CMP_G:
case
CHECK_CAST:
case
INSTANCE_OF:
case
FILL_ARRAY:
case
FILLED_NEW_ARRAY:
case
NEW_ARRAY:
case
NEW_MULTIDIM_ARRAY:
case
STR_CONCAT:
case
MOVE_EXCEPTION:
return
true
;
}
return
false
;
}
@Override
public
String
toString
()
{
return
InsnUtils
.
formatOffset
(
offset
)
+
": "
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
View file @
ed67f8e1
...
...
@@ -66,7 +66,9 @@ public class RootNode {
for
(
ClassNode
cls
:
inner
)
{
ClassNode
parent
=
resolveClass
(
cls
.
getClassInfo
().
getParentClass
());
if
(
parent
==
null
)
{
names
.
remove
(
cls
.
getFullName
());
cls
.
getClassInfo
().
notInner
();
names
.
put
(
cls
.
getFullName
(),
cls
);
}
else
{
parent
.
addInnerClass
(
cls
);
}
...
...
jadx-core/src/main/java/jadx/core/dex/regions/LoopRegion.java
View file @
ed67f8e1
...
...
@@ -40,10 +40,6 @@ public final class LoopRegion extends AbstractRegion {
return
conditionBlock
;
}
public
void
setHeader
(
BlockNode
conditionBlock
)
{
this
.
conditionBlock
=
conditionBlock
;
}
public
IContainer
getBody
()
{
return
body
;
}
...
...
@@ -64,7 +60,7 @@ public final class LoopRegion extends AbstractRegion {
}
private
IfNode
getIfInsn
()
{
return
(
IfNode
)
conditionBlock
.
getInstructions
().
get
(
conditionBlock
.
getInstructions
().
size
()
-
1
);
return
(
IfNode
)
conditionBlock
.
getInstructions
().
get
(
0
);
}
/**
...
...
@@ -108,10 +104,13 @@ public final class LoopRegion extends AbstractRegion {
*/
public
void
mergePreCondition
()
{
if
(
preCondition
!=
null
&&
conditionBlock
!=
null
)
{
preCondition
.
getInstructions
().
addAll
(
conditionBlock
.
getInstructions
());
conditionBlock
.
getInstructions
().
clear
();
conditionBlock
.
getInstructions
().
addAll
(
preCondition
.
getInstructions
());
preCondition
.
getInstructions
().
clear
();
List
<
InsnNode
>
condInsns
=
conditionBlock
.
getInstructions
();
List
<
InsnNode
>
preCondInsns
=
preCondition
.
getInstructions
();
preCondInsns
.
addAll
(
condInsns
);
condInsns
.
clear
();
condInsns
.
addAll
(
preCondInsns
);
preCondInsns
.
clear
();
preCondition
=
null
;
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java
View file @
ed67f8e1
This diff is collapsed.
Click to expand it.
jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
0 → 100644
View file @
ed67f8e1
package
jadx
.
core
.
dex
.
visitors
;
import
jadx.core.Consts
;
import
jadx.core.dex.info.FieldInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.ArithNode
;
import
jadx.core.dex.instructions.ArithOp
;
import
jadx.core.dex.instructions.IfNode
;
import
jadx.core.dex.instructions.IndexInsnNode
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.InvokeNode
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.FieldArg
;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.InsnWrapArg
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.mods.ConstructorInsn
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
SimplifyVisitor
extends
AbstractVisitor
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
SimplifyVisitor
.
class
);
@Override
public
void
visit
(
MethodNode
mth
)
{
if
(
mth
.
isNoCode
())
{
return
;
}
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
List
<
InsnNode
>
list
=
block
.
getInstructions
();
for
(
int
i
=
0
;
i
<
list
.
size
();
i
++)
{
InsnNode
modInsn
=
simplifyInsn
(
mth
,
list
.
get
(
i
));
if
(
modInsn
!=
null
)
{
list
.
set
(
i
,
modInsn
);
}
}
}
}
private
static
InsnNode
simplifyInsn
(
MethodNode
mth
,
InsnNode
insn
)
{
for
(
InsnArg
arg
:
insn
.
getArguments
())
{
if
(
arg
.
isInsnWrap
())
{
InsnNode
ni
=
simplifyInsn
(
mth
,
((
InsnWrapArg
)
arg
).
getWrapInsn
());
if
(
ni
!=
null
)
{
arg
.
wrapInstruction
(
ni
);
}
}
}
switch
(
insn
.
getType
())
{
case
ARITH:
ArithNode
arith
=
(
ArithNode
)
insn
;
if
(
arith
.
getArgsCount
()
==
2
)
{
InsnArg
litArg
=
null
;
if
(
arith
.
getArg
(
1
).
isInsnWrap
())
{
InsnNode
wr
=
((
InsnWrapArg
)
arith
.
getArg
(
1
)).
getWrapInsn
();
if
(
wr
.
getType
()
==
InsnType
.
CONST
)
{
litArg
=
wr
.
getArg
(
0
);
}
}
else
if
(
arith
.
getArg
(
1
).
isLiteral
())
{
litArg
=
arith
.
getArg
(
1
);
}
if
(
litArg
!=
null
)
{
long
lit
=
((
LiteralArg
)
litArg
).
getLiteral
();
boolean
invert
=
false
;
if
(
arith
.
getOp
()
==
ArithOp
.
ADD
&&
lit
<
0
)
{
invert
=
true
;
}
// fix 'c + (-1)' => 'c - (1)'
if
(
invert
)
{
return
new
ArithNode
(
ArithOp
.
SUB
,
arith
.
getResult
(),
insn
.
getArg
(
0
),
InsnArg
.
lit
(-
lit
,
litArg
.
getType
()));
}
}
}
break
;
case
IF:
// simplify 'cmp' instruction in if condition
IfNode
ifb
=
(
IfNode
)
insn
;
InsnArg
f
=
ifb
.
getArg
(
0
);
if
(
f
.
isInsnWrap
())
{
InsnNode
wi
=
((
InsnWrapArg
)
f
).
getWrapInsn
();
if
(
wi
.
getType
()
==
InsnType
.
CMP_L
||
wi
.
getType
()
==
InsnType
.
CMP_G
)
{
if
(
ifb
.
isZeroCmp
()
||
((
LiteralArg
)
ifb
.
getArg
(
1
)).
getLiteral
()
==
0
)
{
ifb
.
changeCondition
(
wi
.
getArg
(
0
),
wi
.
getArg
(
1
),
ifb
.
getOp
());
}
else
{
LOG
.
warn
(
"TODO: cmp"
+
ifb
);
}
}
}
break
;
case
INVOKE:
MethodInfo
callMth
=
((
InvokeNode
)
insn
).
getCallMth
();
if
(
callMth
.
getDeclClass
().
getFullName
().
equals
(
Consts
.
CLASS_STRING_BUILDER
)
&&
callMth
.
getShortId
().
equals
(
"toString()"
)
&&
insn
.
getArg
(
0
).
isInsnWrap
())
{
try
{
List
<
InsnNode
>
chain
=
flattenInsnChain
(
insn
);
if
(
chain
.
size
()
>
1
&&
chain
.
get
(
0
).
getType
()
==
InsnType
.
CONSTRUCTOR
)
{
ConstructorInsn
constr
=
(
ConstructorInsn
)
chain
.
get
(
0
);
if
(
constr
.
getClassType
().
getFullName
().
equals
(
Consts
.
CLASS_STRING_BUILDER
)
&&
constr
.
getArgsCount
()
==
0
)
{
int
len
=
chain
.
size
();
InsnNode
concatInsn
=
new
InsnNode
(
InsnType
.
STR_CONCAT
,
len
-
1
);
for
(
int
i
=
1
;
i
<
len
;
i
++)
{
concatInsn
.
addArg
(
chain
.
get
(
i
).
getArg
(
1
));
}
concatInsn
.
setResult
(
insn
.
getResult
());
return
concatInsn
;
}
}
}
catch
(
Throwable
e
)
{
LOG
.
debug
(
"Can't convert string concatenation: {} insn: {}"
,
mth
,
insn
,
e
);
}
}
break
;
case
IPUT:
case
SPUT:
// convert field arith operation to arith instruction
// (IPUT = ARITH (IGET, lit) -> ARITH (fieldArg <op>= lit))
InsnArg
arg
=
insn
.
getArg
(
0
);
if
(
arg
.
isInsnWrap
())
{
InsnNode
wrap
=
((
InsnWrapArg
)
arg
).
getWrapInsn
();
InsnType
wrapType
=
wrap
.
getType
();
if
((
wrapType
==
InsnType
.
ARITH
||
wrapType
==
InsnType
.
STR_CONCAT
)
&&
wrap
.
getArg
(
0
).
isInsnWrap
())
{
InsnNode
get
=
((
InsnWrapArg
)
wrap
.
getArg
(
0
)).
getWrapInsn
();
InsnType
getType
=
get
.
getType
();
if
(
getType
==
InsnType
.
IGET
||
getType
==
InsnType
.
SGET
)
{
FieldInfo
field
=
(
FieldInfo
)
((
IndexInsnNode
)
insn
).
getIndex
();
FieldInfo
innerField
=
(
FieldInfo
)
((
IndexInsnNode
)
get
).
getIndex
();
if
(
field
.
equals
(
innerField
))
{
try
{
RegisterArg
reg
=
null
;
if
(
getType
==
InsnType
.
IGET
)
{
reg
=
((
RegisterArg
)
get
.
getArg
(
0
));
}
RegisterArg
fArg
=
new
FieldArg
(
field
,
reg
!=
null
?
reg
.
getRegNum
()
:
-
1
);
if
(
reg
!=
null
)
{
fArg
.
replaceTypedVar
(
get
.
getArg
(
0
));
}
if
(
wrapType
==
InsnType
.
ARITH
)
{
ArithNode
ar
=
(
ArithNode
)
wrap
;
return
new
ArithNode
(
ar
.
getOp
(),
fArg
,
fArg
,
ar
.
getArg
(
1
));
}
else
{
int
argsCount
=
wrap
.
getArgsCount
();
InsnNode
concat
=
new
InsnNode
(
InsnType
.
STR_CONCAT
,
argsCount
-
1
);
for
(
int
i
=
1
;
i
<
argsCount
;
i
++)
{
concat
.
addArg
(
wrap
.
getArg
(
i
));
}
return
new
ArithNode
(
ArithOp
.
ADD
,
fArg
,
fArg
,
InsnArg
.
wrap
(
concat
));
}
}
catch
(
Throwable
e
)
{
LOG
.
debug
(
"Can't convert field arith insn: {}, mth: {}"
,
insn
,
mth
,
e
);
}
}
}
}
}
break
;
case
CHECK_CAST:
InsnArg
castArg
=
insn
.
getArg
(
0
);
ArgType
castType
=
(
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
();
if
(!
ArgType
.
isCastNeeded
(
castArg
.
getType
(),
castType
))
{
InsnNode
insnNode
=
new
InsnNode
(
InsnType
.
MOVE
,
1
);
insnNode
.
setResult
(
insn
.
getResult
());
insnNode
.
addArg
(
castArg
);
return
insnNode
;
}
break
;
default
:
break
;
}
return
null
;
}
private
static
List
<
InsnNode
>
flattenInsnChain
(
InsnNode
insn
)
{
List
<
InsnNode
>
chain
=
new
ArrayList
<
InsnNode
>();
InsnArg
i
=
insn
.
getArg
(
0
);
while
(
i
.
isInsnWrap
())
{
InsnNode
wrapInsn
=
((
InsnWrapArg
)
i
).
getWrapInsn
();
chain
.
add
(
wrapInsn
);
if
(
wrapInsn
.
getArgsCount
()
==
0
)
{
break
;
}
i
=
wrapInsn
.
getArg
(
0
);
}
Collections
.
reverse
(
chain
);
return
chain
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java
View file @
ed67f8e1
...
...
@@ -186,7 +186,7 @@ public class RegionMaker {
if
(
loopRegion
.
isConditionAtEnd
())
{
// TODO: add some checks
}
else
{
if
(
condBlock
!=
loop
.
getStart
()
)
{
if
(
condBlock
!=
loop
Start
)
{
if
(
condBlock
.
getPredecessors
().
contains
(
loopStart
))
{
loopRegion
.
setPreCondition
(
loopStart
);
// if we can't merge pre-condition this is not correct header
...
...
@@ -492,10 +492,8 @@ public class RegionMaker {
IfCondition
nestedCondition
=
IfCondition
.
fromIfNode
(
nestedIfInsn
);
if
(
isPathExists
(
bElse
,
nestedIfBlock
))
{
// else branch
if
(
bThen
!=
nbThen
&&
!
isEqualReturns
(
bThen
,
nbThen
))
{
if
(
bThen
!=
nbElse
&&
!
isEqualReturns
(
bThen
,
nbElse
))
{
if
(!
isEqualReturns
(
bThen
,
nbThen
))
{
if
(!
isEqualReturns
(
bThen
,
nbElse
))
{
// not connected conditions
break
;
}
...
...
@@ -505,10 +503,8 @@ public class RegionMaker {
condition
=
IfCondition
.
merge
(
Mode
.
OR
,
condition
,
nestedCondition
);
}
else
{
// then branch
if
(
bElse
!=
nbElse
&&
!
isEqualReturns
(
bElse
,
nbElse
))
{
if
(
bElse
!=
nbThen
&&
!
isEqualReturns
(
bElse
,
nbThen
))
{
if
(!
isEqualReturns
(
bElse
,
nbElse
))
{
if
(!
isEqualReturns
(
bElse
,
nbThen
))
{
// not connected conditions
break
;
}
...
...
@@ -693,21 +689,20 @@ public class RegionMaker {
if
(
b1
==
b2
)
{
return
true
;
}
if
(
b1
==
null
||
b2
==
null
)
{
if
(
b1
==
null
||
b2
==
null
)
{
return
false
;
}
if
(
b1
.
getInstructions
().
size
()
+
b2
.
getInstructions
().
size
()
!=
2
)
{
List
<
InsnNode
>
b1Insns
=
b1
.
getInstructions
();
List
<
InsnNode
>
b2Insns
=
b2
.
getInstructions
();
if
(
b1Insns
.
size
()
!=
1
||
b2Insns
.
size
()
!=
1
)
{
return
false
;
}
if
(!
b1
.
getAttributes
().
contains
(
AttributeFlag
.
RETURN
)
||
!
b2
.
getAttributes
().
contains
(
AttributeFlag
.
RETURN
))
{
||
!
b2
.
getAttributes
().
contains
(
AttributeFlag
.
RETURN
))
{
return
false
;
}
if
(
b1
.
getInstructions
().
get
(
0
).
getArgsCount
()
>
0
)
{
if
(
b1
.
getInstructions
().
get
(
0
).
getArg
(
0
)
!=
b2
.
getInstructions
().
get
(
0
).
getArg
(
0
))
{
if
(
b1Insns
.
get
(
0
).
getArgsCount
()
>
0
)
{
if
(
b1Insns
.
get
(
0
).
getArg
(
0
)
!=
b2Insns
.
get
(
0
).
getArg
(
0
))
{
return
false
;
}
}
...
...
jadx-core/src/main/java/jadx/core/utils/BlockUtils.java
View file @
ed67f8e1
...
...
@@ -87,18 +87,6 @@ public class BlockUtils {
return
false
;
}
/**
* Return instruction position in block (use == for comparison, not equals)
*/
public
static
int
insnIndex
(
BlockNode
block
,
InsnNode
insn
)
{
int
size
=
block
.
getInstructions
().
size
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(
block
.
getInstructions
().
get
(
i
)
==
insn
)
return
i
;
}
return
-
1
;
}
public
static
boolean
lastInsnType
(
BlockNode
block
,
InsnType
type
)
{
List
<
InsnNode
>
insns
=
block
.
getInstructions
();
if
(
insns
.
isEmpty
())
...
...
@@ -190,6 +178,22 @@ public class BlockUtils {
return
traverseSuccessorsUntil
(
start
,
end
,
new
HashSet
<
BlockNode
>());
}
public
static
boolean
isOnlyOnePathExists
(
BlockNode
start
,
BlockNode
end
)
{
if
(
start
==
end
)
{
return
true
;
}
if
(!
end
.
isDominator
(
start
))
{
return
false
;
}
while
(
start
.
getCleanSuccessors
().
size
()
==
1
)
{
start
=
start
.
getCleanSuccessors
().
get
(
0
);
if
(
start
==
end
)
{
return
true
;
}
}
return
false
;
}
/**
* Search for first node which not dominated by block, starting from child
*/
...
...
jadx-core/src/main/java/jadx/core/utils/InsnList.java
0 → 100644
View file @
ed67f8e1
package
jadx
.
core
.
utils
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
java.util.Iterator
;
import
java.util.List
;
public
final
class
InsnList
implements
Iterable
<
InsnNode
>
{
public
static
void
remove
(
List
<
InsnNode
>
list
,
InsnNode
insn
)
{
for
(
Iterator
<
InsnNode
>
iterator
=
list
.
iterator
();
iterator
.
hasNext
();
)
{
InsnNode
next
=
iterator
.
next
();
if
(
next
==
insn
)
{
iterator
.
remove
();
return
;
}
}
}
public
static
void
remove
(
BlockNode
block
,
InsnNode
insn
)
{
remove
(
block
.
getInstructions
(),
insn
);
}
public
static
int
getIndex
(
List
<
InsnNode
>
list
,
InsnNode
insn
)
{
int
i
=
0
;
for
(
InsnNode
curObj
:
list
)
{
if
(
curObj
==
insn
)
{
return
i
;
}
i
++;
}
return
-
1
;
}
private
final
List
<
InsnNode
>
list
;
public
InsnList
(
List
<
InsnNode
>
list
)
{
this
.
list
=
list
;
}
public
int
getIndex
(
InsnNode
insn
)
{
return
getIndex
(
list
,
insn
);
}
public
boolean
contains
(
InsnNode
insn
)
{
return
getIndex
(
insn
)
!=
-
1
;
}
public
void
remove
(
InsnNode
insn
)
{
remove
(
list
,
insn
);
}
public
Iterator
<
InsnNode
>
iterator
()
{
return
list
.
iterator
();
}
public
InsnNode
get
(
int
index
)
{
return
list
.
get
(
index
);
}
public
int
size
()
{
return
list
.
size
();
}
}
jadx-core/src/test/java/jadx/api/InternalJadxTest.java
View file @
ed67f8e1
...
...
@@ -19,6 +19,7 @@ import java.util.jar.JarEntry;
import
java.util.jar.JarOutputStream
;
import
static
junit
.
framework
.
Assert
.
assertEquals
;
import
static
junit
.
framework
.
Assert
.
assertNotNull
;
import
static
junit
.
framework
.
Assert
.
fail
;
public
abstract
class
InternalJadxTest
{
...
...
@@ -32,14 +33,18 @@ public abstract class InternalJadxTest {
Decompiler
d
=
new
Decompiler
();
try
{
d
.
loadFile
(
temp
);
assertEquals
(
d
.
getClasses
().
size
(),
1
);
}
catch
(
Exception
e
)
{
fail
(
e
.
getMessage
());
}
finally
{
temp
.
delete
();
}
List
<
ClassNode
>
classes
=
d
.
getRoot
().
getClasses
(
false
);
ClassNode
cls
=
classes
.
get
(
0
);
String
clsName
=
clazz
.
getName
();
ClassNode
cls
=
null
;
for
(
ClassNode
aClass
:
classes
)
{
if
(
aClass
.
getFullName
().
equals
(
clsName
))
{
cls
=
aClass
;
}
}
assertNotNull
(
"Class not found: "
+
clsName
,
cls
);
assertEquals
(
cls
.
getFullName
(),
clazz
.
getName
());
...
...
jadx-core/src/test/java/jadx/tests/internal/TestLoopCondition.java
View file @
ed67f8e1
...
...
@@ -58,7 +58,7 @@ public class TestLoopCondition extends InternalJadxTest {
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"i < f.length()"
));
assertThat
(
code
,
containsString
(
"i <
this.
f.length()"
));
assertThat
(
code
,
containsString
(
"while (a && i < 10) {"
));
assertThat
(
code
,
containsString
(
"list.set(i, \"ABC\")"
));
assertThat
(
code
,
containsString
(
"list.set(i, \"DEF\")"
));
...
...
jadx-core/src/test/java/jadx/tests/internal/TestRedundantThis.java
View file @
ed67f8e1
...
...
@@ -3,8 +3,6 @@ package jadx.tests.internal;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
...
...
@@ -29,7 +27,7 @@ public class TestRedundantThis extends InternalJadxTest {
}
}
@Test
//
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
...
...
jadx-core/src/test/java/jadx/tests/internal/TestStringBuilderElimination.java
View file @
ed67f8e1
...
...
@@ -3,8 +3,6 @@ package jadx.tests.internal;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
...
...
@@ -15,7 +13,7 @@ public class TestStringBuilderElimination extends InternalJadxTest {
private
static
final
long
serialVersionUID
=
4245254480662372757L
;
public
MyException
(
String
str
,
Exception
e
)
{
//
super("msg:" + str, e);
super
(
"msg:"
+
str
,
e
);
}
public
void
method
(
int
k
)
{
...
...
@@ -23,10 +21,14 @@ public class TestStringBuilderElimination extends InternalJadxTest {
}
}
@Test
//
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
MyException
.
class
);
String
code
=
cls
.
getCode
().
toString
();
System
.
out
.
println
(
code
);
assertThat
(
code
,
containsString
(
"MyException(String str, Exception e) {"
));
assertThat
(
code
,
containsString
(
"super(\"msg:\" + str, e);"
));
assertThat
(
code
,
not
(
containsString
(
"new StringBuilder"
)));
assertThat
(
code
,
containsString
(
"System.out.println(\"k=\" + k);"
));
...
...
jadx-core/src/test/java/jadx/tests/internal/inline/TestInline.java
0 → 100644
View file @
ed67f8e1
package
jadx
.
tests
.
internal
.
inline
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestInline
extends
InternalJadxTest
{
public
static
class
TestCls
extends
Exception
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
System
.
out
.
println
(
"Test: "
+
new
TestCls
().
testRun
());
}
private
boolean
testRun
()
{
return
false
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"System.out.println(\"Test: \" + new TestInline$TestCls().testRun());"
));
}
}
jadx-core/src/test/java/jadx/tests/internal/inline/TestInline2.java
0 → 100644
View file @
ed67f8e1
package
jadx
.
tests
.
internal
.
inline
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestInline2
extends
InternalJadxTest
{
public
static
class
TestCls
extends
Exception
{
public
int
simple_loops
()
throws
InterruptedException
{
int
[]
a
=
new
int
[]{
1
,
2
,
4
,
6
,
8
};
int
b
=
0
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++)
{
b
+=
a
[
i
];
}
for
(
long
i
=
b
;
i
>
0
;
i
--)
{
b
+=
i
;
}
return
b
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"i < a.length"
));
}
}
jadx-core/src/test/java/jadx/tests/internal/inline/TestInline3.java
0 → 100644
View file @
ed67f8e1
package
jadx
.
tests
.
internal
.
inline
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestInline3
extends
InternalJadxTest
{
public
static
class
TestCls
{
public
TestCls
(
int
b1
,
int
b2
)
{
this
(
b1
,
b2
,
0
,
0
,
0
);
}
public
TestCls
(
int
a1
,
int
a2
,
int
a3
,
int
a4
,
int
a5
)
{
}
public
class
A
extends
TestCls
{
public
A
(
int
a
)
{
super
(
a
,
a
);
}
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsString
(
"this(b1, b2, 0, 0, 0);"
));
assertThat
(
code
,
containsString
(
"super(a, a);"
));
assertThat
(
code
,
not
(
containsString
(
"super(a, a).this$0"
)));
assertThat
(
code
,
containsString
(
"public class A extends TestInline3$TestCls {"
));
}
}
jadx-samples/src/main/java/jadx/samples/TestCF3.java
View file @
ed67f8e1
...
...
@@ -164,6 +164,32 @@ public class TestCF3 extends AbstractTest {
return
i
;
}
private
void
f
()
{
try
{
Thread
.
sleep
(
50
);
}
catch
(
InterruptedException
e
)
{
// ignore
}
}
public
long
testInline
()
{
long
l
=
System
.
nanoTime
();
f
();
return
System
.
nanoTime
()
-
l
;
}
private
int
f2
=
1
;
public
void
func
()
{
this
.
f2
++;
}
public
boolean
testInline2
()
{
int
a
=
this
.
f2
;
func
();
return
a
!=
this
.
f2
;
}
@Override
public
boolean
testRun
()
throws
Exception
{
setEnabled
(
false
);
...
...
@@ -200,6 +226,9 @@ public class TestCF3 extends AbstractTest {
assertEquals
(
testComplexIfInLoop3
(
2
),
2
);
assertEquals
(
testComplexIfInLoop3
(
6
),
6
);
assertEquals
(
testComplexIfInLoop3
(
8
),
24
);
assertTrue
(
testInline
()
>
20
);
assertTrue
(
testInline2
());
return
true
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment