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
577176dd
Commit
577176dd
authored
Nov 23, 2014
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: implement 'finally' block extraction
parent
a135eb44
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1462 additions
and
460 deletions
+1462
-460
Jadx.java
jadx-core/src/main/java/jadx/core/Jadx.java
+13
-2
InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+2
-0
RegionGen.java
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
+9
-8
AFlag.java
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
+2
-0
AType.java
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
+2
-0
IgnoreEdgeAttr.java
...n/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java
+32
-0
BlockNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java
+5
-0
DebugInfoParser.java
...main/java/jadx/core/dex/nodes/parser/DebugInfoParser.java
+25
-24
TryCatchRegion.java
...e/src/main/java/jadx/core/dex/regions/TryCatchRegion.java
+35
-12
IfRegion.java
.../main/java/jadx/core/dex/regions/conditions/IfRegion.java
+1
-1
ExcHandlerAttr.java
.../src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java
+3
-3
ExceptionHandler.java
...rc/main/java/jadx/core/dex/trycatch/ExceptionHandler.java
+9
-0
TryCatchBlock.java
...e/src/main/java/jadx/core/dex/trycatch/TryCatchBlock.java
+19
-55
CodeShrinker.java
...re/src/main/java/jadx/core/dex/visitors/CodeShrinker.java
+1
-1
DebugInfoVisitor.java
...rc/main/java/jadx/core/dex/visitors/DebugInfoVisitor.java
+12
-8
ModVisitor.java
...core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
+27
-65
BlockExceptionHandler.java
.../core/dex/visitors/blocksmaker/BlockExceptionHandler.java
+38
-30
BlockFinallyExtract.java
...dx/core/dex/visitors/blocksmaker/BlockFinallyExtract.java
+527
-0
BlockFinish.java
.../java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java
+40
-0
BlockProcessor.java
...va/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java
+40
-192
BlockSplitter.java
...ava/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java
+226
-0
BlocksPair.java
...adx/core/dex/visitors/blocksmaker/helpers/BlocksPair.java
+43
-0
BlocksRemoveInfo.java
...re/dex/visitors/blocksmaker/helpers/BlocksRemoveInfo.java
+77
-0
CheckRegions.java
...ain/java/jadx/core/dex/visitors/regions/CheckRegions.java
+18
-5
RegionMaker.java
...main/java/jadx/core/dex/visitors/regions/RegionMaker.java
+35
-11
SSATransform.java
...rc/main/java/jadx/core/dex/visitors/ssa/SSATransform.java
+30
-26
BlockUtils.java
jadx-core/src/main/java/jadx/core/utils/BlockUtils.java
+16
-5
RegionUtils.java
jadx-core/src/main/java/jadx/core/utils/RegionUtils.java
+0
-4
TestDoWhileBreak.java
...t/java/jadx/tests/integration/loops/TestDoWhileBreak.java
+36
-0
TestSynchronized.java
.../jadx/tests/integration/synchronize/TestSynchronized.java
+3
-0
TestFinallyExtract.java
...a/jadx/tests/integration/trycatch/TestFinallyExtract.java
+43
-0
TestTryCatch3.java
...t/java/jadx/tests/integration/trycatch/TestTryCatch3.java
+39
-8
TestTryCatchFinally.java
.../jadx/tests/integration/trycatch/TestTryCatchFinally.java
+54
-0
No files found.
jadx-core/src/main/java/jadx/core/Jadx.java
View file @
577176dd
...
...
@@ -2,7 +2,6 @@ package jadx.core;
import
jadx.api.IJadxArgs
;
import
jadx.core.codegen.CodeGen
;
import
jadx.core.dex.visitors.BlockMakerVisitor
;
import
jadx.core.dex.visitors.ClassModifier
;
import
jadx.core.dex.visitors.CodeShrinker
;
import
jadx.core.dex.visitors.ConstInlinerVisitor
;
...
...
@@ -16,6 +15,11 @@ import jadx.core.dex.visitors.ModVisitor;
import
jadx.core.dex.visitors.PrepareForCodeGen
;
import
jadx.core.dex.visitors.ReSugarCode
;
import
jadx.core.dex.visitors.SimplifyVisitor
;
import
jadx.core.dex.visitors.blocksmaker.BlockExceptionHandler
;
import
jadx.core.dex.visitors.blocksmaker.BlockFinallyExtract
;
import
jadx.core.dex.visitors.blocksmaker.BlockFinish
;
import
jadx.core.dex.visitors.blocksmaker.BlockProcessor
;
import
jadx.core.dex.visitors.blocksmaker.BlockSplitter
;
import
jadx.core.dex.visitors.regions.CheckRegions
;
import
jadx.core.dex.visitors.regions.IfRegionVisitor
;
import
jadx.core.dex.visitors.regions.LoopRegionVisitor
;
...
...
@@ -55,10 +59,16 @@ public class Jadx {
if
(
args
.
isFallbackMode
())
{
passes
.
add
(
new
FallbackModeVisitor
());
}
else
{
passes
.
add
(
new
BlockMakerVisitor
());
passes
.
add
(
new
BlockSplitter
());
passes
.
add
(
new
BlockProcessor
());
passes
.
add
(
new
BlockExceptionHandler
());
passes
.
add
(
new
BlockFinallyExtract
());
passes
.
add
(
new
BlockFinish
());
passes
.
add
(
new
SSATransform
());
passes
.
add
(
new
DebugInfoVisitor
());
passes
.
add
(
new
TypeInference
());
if
(
args
.
isRawCFGOutput
())
{
passes
.
add
(
DotGraphVisitor
.
dumpRaw
(
outDir
));
}
...
...
@@ -72,6 +82,7 @@ public class Jadx {
passes
.
add
(
new
CodeShrinker
());
passes
.
add
(
new
ReSugarCode
());
if
(
args
.
isCFGOutput
())
{
passes
.
add
(
DotGraphVisitor
.
dump
(
outDir
));
}
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
View file @
577176dd
...
...
@@ -446,6 +446,8 @@ public class InsnGen {
break
;
case
PHI:
assert
isFallback
();
code
.
add
(
"PHI("
).
add
(
String
.
valueOf
(
insn
.
getArgsCount
())).
add
(
")"
);
break
;
/* fallback mode instructions */
...
...
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
View file @
577176dd
...
...
@@ -28,13 +28,13 @@ import jadx.core.dex.regions.loops.ForLoop;
import
jadx.core.dex.regions.loops.LoopRegion
;
import
jadx.core.dex.regions.loops.LoopType
;
import
jadx.core.dex.trycatch.ExceptionHandler
;
import
jadx.core.dex.trycatch.TryCatchBlock
;
import
jadx.core.utils.ErrorsCounter
;
import
jadx.core.utils.RegionUtils
;
import
jadx.core.utils.exceptions.CodegenException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.util.List
;
import
java.util.Map
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -282,27 +282,28 @@ public class RegionGen extends InsnGen {
}
private
void
makeTryCatch
(
TryCatchRegion
region
,
CodeWriter
code
)
throws
CodegenException
{
TryCatchBlock
tryCatchBlock
=
region
.
geTryCatchBlock
();
code
.
startLine
(
"try {"
);
makeRegionIndent
(
code
,
region
.
getTryRegion
());
// TODO: move search of 'allHandler' to 'TryCatchRegion'
ExceptionHandler
allHandler
=
null
;
for
(
ExceptionHandler
handler
:
tryCatchBlock
.
getHandlers
())
{
if
(!
handler
.
isCatchAll
())
{
makeCatchBlock
(
code
,
handler
);
}
else
{
for
(
Map
.
Entry
<
ExceptionHandler
,
IContainer
>
entry
:
region
.
getCatchRegions
().
entrySet
())
{
ExceptionHandler
handler
=
entry
.
getKey
();
if
(
handler
.
isCatchAll
())
{
if
(
allHandler
!=
null
)
{
LOG
.
warn
(
"Several 'all' handlers in try/catch block in {}"
,
mth
);
}
allHandler
=
handler
;
}
else
{
makeCatchBlock
(
code
,
handler
);
}
}
if
(
allHandler
!=
null
)
{
makeCatchBlock
(
code
,
allHandler
);
}
if
(
tryCatchBlock
.
getFinalRegion
()
!=
null
)
{
IContainer
finallyRegion
=
region
.
getFinallyRegion
();
if
(
finallyRegion
!=
null
)
{
code
.
startLine
(
"} finally {"
);
makeRegionIndent
(
code
,
tryCatchBlock
.
getFinalRegion
()
);
makeRegionIndent
(
code
,
finallyRegion
);
}
code
.
startLine
(
'}'
);
}
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
View file @
577176dd
...
...
@@ -10,6 +10,7 @@ public enum AFlag {
SYNTHETIC
,
RETURN
,
// block contains only return instruction
ORIG_RETURN
,
DECLARE_VAR
,
DONT_WRAP
,
...
...
@@ -18,6 +19,7 @@ public enum AFlag {
DONT_INLINE
,
DONT_GENERATE
,
SKIP
,
REMOVE
,
SKIP_FIRST_ARG
,
ANONYMOUS_CONSTRUCTOR
,
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
View file @
577176dd
...
...
@@ -7,6 +7,7 @@ import jadx.core.dex.attributes.nodes.EnumClassAttr;
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.JumpInfo
;
import
jadx.core.dex.attributes.nodes.LoopInfo
;
...
...
@@ -51,4 +52,5 @@ public class AType<T extends IAttribute> {
public
static
final
AType
<
SourceFileAttr
>
SOURCE_FILE
=
new
AType
<
SourceFileAttr
>();
public
static
final
AType
<
DeclareVariablesAttr
>
DECLARE_VARIABLES
=
new
AType
<
DeclareVariablesAttr
>();
public
static
final
AType
<
LoopLabelAttr
>
LOOP_LABEL
=
new
AType
<
LoopLabelAttr
>();
public
static
final
AType
<
IgnoreEdgeAttr
>
IGNORE_EDGE
=
new
AType
<
IgnoreEdgeAttr
>();
}
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java
0 → 100644
View file @
577176dd
package
jadx
.
core
.
dex
.
attributes
.
nodes
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.IAttribute
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.utils.Utils
;
import
java.util.HashSet
;
import
java.util.Set
;
public
class
IgnoreEdgeAttr
implements
IAttribute
{
private
final
Set
<
BlockNode
>
blocks
=
new
HashSet
<
BlockNode
>();
public
Set
<
BlockNode
>
getBlocks
()
{
return
blocks
;
}
public
boolean
contains
(
BlockNode
block
)
{
return
blocks
.
contains
(
block
);
}
@Override
public
AType
<
IgnoreEdgeAttr
>
getType
()
{
return
AType
.
IGNORE_EDGE
;
}
@Override
public
String
toString
()
{
return
"IGNORE_EDGES: "
+
Utils
.
listToString
(
blocks
);
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java
View file @
577176dd
...
...
@@ -3,6 +3,7 @@ package jadx.core.dex.nodes;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.AttrNode
;
import
jadx.core.dex.attributes.nodes.IgnoreEdgeAttr
;
import
jadx.core.dex.attributes.nodes.LoopInfo
;
import
jadx.core.utils.InsnUtils
;
...
...
@@ -99,6 +100,10 @@ public class BlockNode extends AttrNode implements IBlock {
toRemove
.
add
(
loop
.
getStart
());
}
}
IgnoreEdgeAttr
ignoreEdgeAttr
=
block
.
get
(
AType
.
IGNORE_EDGE
);
if
(
ignoreEdgeAttr
!=
null
)
{
toRemove
.
addAll
(
ignoreEdgeAttr
.
getBlocks
());
}
if
(
toRemove
.
isEmpty
())
{
return
sucList
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/parser/DebugInfoParser.java
View file @
577176dd
...
...
@@ -237,31 +237,32 @@ public class DebugInfoParser {
}
private
static
void
merge
(
InsnArg
arg
,
LocalVar
var
)
{
if
(
arg
!=
null
&&
arg
.
isRegister
())
{
RegisterArg
reg
=
(
RegisterArg
)
arg
;
if
(
var
.
getRegNum
()
==
reg
.
getRegNum
())
{
SSAVar
ssaVar
=
reg
.
getSVar
();
boolean
mergeRequired
=
false
;
if
(
ssaVar
!=
null
)
{
int
ssaEnd
=
ssaVar
.
getEndAddr
();
int
ssaStart
=
ssaVar
.
getStartAddr
();
int
localStart
=
var
.
getStartAddr
();
int
localEnd
=
var
.
getEndAddr
();
boolean
isIntersected
=
!((
localEnd
<
ssaStart
)
||
(
ssaEnd
<
localStart
));
if
(
isIntersected
&&
(
ssaEnd
<=
localEnd
))
{
mergeRequired
=
true
;
}
}
else
{
mergeRequired
=
true
;
}
if
(
mergeRequired
)
{
reg
.
mergeDebugInfo
(
var
.
getType
(),
var
.
getName
());
}
if
(
arg
==
null
||
!
arg
.
isRegister
())
{
return
;
}
RegisterArg
reg
=
(
RegisterArg
)
arg
;
if
(
var
.
getRegNum
()
!=
reg
.
getRegNum
())
{
return
;
}
boolean
mergeRequired
=
false
;
SSAVar
ssaVar
=
reg
.
getSVar
();
if
(
ssaVar
!=
null
)
{
int
ssaEnd
=
ssaVar
.
getEndAddr
();
int
ssaStart
=
ssaVar
.
getStartAddr
();
int
localStart
=
var
.
getStartAddr
();
int
localEnd
=
var
.
getEndAddr
();
boolean
isIntersected
=
!((
localEnd
<
ssaStart
)
||
(
ssaEnd
<
localStart
));
if
(
isIntersected
&&
(
ssaEnd
<=
localEnd
))
{
mergeRequired
=
true
;
}
}
else
{
mergeRequired
=
true
;
}
if
(
mergeRequired
)
{
reg
.
mergeDebugInfo
(
var
.
getType
(),
var
.
getName
());
}
}
}
jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java
View file @
577176dd
...
...
@@ -8,12 +8,15 @@ import jadx.core.utils.Utils;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
public
final
class
TryCatchRegion
extends
AbstractRegion
{
private
final
IContainer
tryRegion
;
private
List
<
IContainer
>
catchRegions
=
Collections
.
emptyList
();
private
Map
<
ExceptionHandler
,
IContainer
>
catchRegions
=
Collections
.
emptyMap
();
private
IContainer
finallyRegion
;
private
TryCatchBlock
tryCatchBlock
;
public
TryCatchRegion
(
IRegion
parent
,
IContainer
tryRegion
)
{
...
...
@@ -21,31 +24,50 @@ public final class TryCatchRegion extends AbstractRegion {
this
.
tryRegion
=
tryRegion
;
}
public
void
setTryCatchBlock
(
TryCatchBlock
tryCatchBlock
)
{
this
.
tryCatchBlock
=
tryCatchBlock
;
int
count
=
tryCatchBlock
.
getHandlersCount
();
this
.
catchRegions
=
new
LinkedHashMap
<
ExceptionHandler
,
IContainer
>(
count
);
for
(
ExceptionHandler
handler
:
tryCatchBlock
.
getHandlers
())
{
IContainer
handlerRegion
=
handler
.
getHandlerRegion
();
if
(
handlerRegion
!=
null
)
{
if
(
handler
.
isFinally
())
{
finallyRegion
=
handlerRegion
;
}
else
{
catchRegions
.
put
(
handler
,
handlerRegion
);
}
}
}
}
public
IContainer
getTryRegion
()
{
return
tryRegion
;
}
public
List
<
IContainer
>
getCatchRegions
()
{
public
Map
<
ExceptionHandler
,
IContainer
>
getCatchRegions
()
{
return
catchRegions
;
}
public
TryCatchBlock
geTryCatchBlock
()
{
public
TryCatchBlock
ge
t
TryCatchBlock
()
{
return
tryCatchBlock
;
}
public
void
setTryCatchBlock
(
TryCatchBlock
tryCatchBlock
)
{
this
.
tryCatchBlock
=
tryCatchBlock
;
this
.
catchRegions
=
new
ArrayList
<
IContainer
>(
tryCatchBlock
.
getHandlersCount
());
for
(
ExceptionHandler
handler
:
tryCatchBlock
.
getHandlers
())
{
catchRegions
.
add
(
handler
.
getHandlerRegion
());
}
public
IContainer
getFinallyRegion
(
)
{
return
finallyRegion
;
}
public
void
setFinallyRegion
(
IContainer
finallyRegion
)
{
this
.
finallyRegion
=
finallyRegion
;
}
@Override
public
List
<
IContainer
>
getSubBlocks
()
{
List
<
IContainer
>
all
=
new
ArrayList
<
IContainer
>(
1
+
catchRegions
.
size
());
List
<
IContainer
>
all
=
new
ArrayList
<
IContainer
>(
2
+
catchRegions
.
size
());
all
.
add
(
tryRegion
);
all
.
addAll
(
catchRegions
);
all
.
addAll
(
catchRegions
.
values
());
if
(
finallyRegion
!=
null
)
{
all
.
add
(
finallyRegion
);
}
return
Collections
.
unmodifiableList
(
all
);
}
...
...
@@ -57,6 +79,7 @@ public final class TryCatchRegion extends AbstractRegion {
@Override
public
String
toString
()
{
return
"Try: "
+
tryRegion
+
" catches: "
+
Utils
.
listToString
(
catchRegions
);
+
" catches: "
+
Utils
.
listToString
(
catchRegions
.
values
())
+
(
finallyRegion
==
null
?
""
:
" finally: "
+
finallyRegion
);
}
}
jadx-core/src/main/java/jadx/core/dex/regions/conditions/IfRegion.java
View file @
577176dd
...
...
@@ -116,6 +116,6 @@ public final class IfRegion extends AbstractRegion {
@Override
public
String
toString
()
{
return
"IF
("
+
condition
+
")
then "
+
thenRegion
+
" else "
+
elseRegion
;
return
"IF
"
+
header
+
"
then "
+
thenRegion
+
" else "
+
elseRegion
;
}
}
jadx-core/src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java
View file @
577176dd
...
...
@@ -28,8 +28,8 @@ public class ExcHandlerAttr implements IAttribute {
@Override
public
String
toString
()
{
return
"ExcHandler: "
+
(
handler
.
isCatchAll
()
?
"all"
:
handler
.
getCatchType
())
+
" "
+
handler
.
getArg
(
);
return
"ExcHandler: "
+
(
handler
.
isFinally
()
?
" FINALLY"
:
(
handler
.
isCatchAll
()
?
"all"
:
handler
.
getCatchType
())
+
" "
+
handler
.
getArg
()
);
}
}
jadx-core/src/main/java/jadx/core/dex/trycatch/ExceptionHandler.java
View file @
577176dd
...
...
@@ -21,6 +21,7 @@ public class ExceptionHandler {
private
InsnArg
arg
;
private
TryCatchBlock
tryBlock
;
private
boolean
isFinally
;
public
ExceptionHandler
(
int
addr
,
ClassInfo
type
)
{
this
.
handleOffset
=
addr
;
...
...
@@ -79,6 +80,14 @@ public class ExceptionHandler {
return
tryBlock
;
}
public
boolean
isFinally
()
{
return
isFinally
;
}
public
void
setFinally
(
boolean
isFinally
)
{
this
.
isFinally
=
isFinally
;
}
@Override
public
int
hashCode
()
{
return
(
catchType
==
null
?
0
:
31
*
catchType
.
hashCode
())
+
handleOffset
;
...
...
jadx-core/src/main/java/jadx/core/dex/trycatch/TryCatchBlock.java
View file @
577176dd
package
jadx
.
core
.
dex
.
trycatch
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.IBlock
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.InsnContainer
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.utils.InstructionRemover
;
import
jadx.core.utils.Utils
;
import
java.util.ArrayList
;
...
...
@@ -19,7 +16,6 @@ import java.util.List;
public
class
TryCatchBlock
{
private
final
List
<
ExceptionHandler
>
handlers
;
private
IContainer
finalRegion
;
// references for fast remove/modify
private
final
List
<
InsnNode
>
insns
;
...
...
@@ -55,6 +51,7 @@ public class TryCatchBlock {
for
(
Iterator
<
ExceptionHandler
>
it
=
handlers
.
iterator
();
it
.
hasNext
();
)
{
ExceptionHandler
h
=
it
.
next
();
if
(
h
==
handler
)
{
unbindHandler
(
h
);
it
.
remove
();
break
;
}
...
...
@@ -64,29 +61,20 @@ public class TryCatchBlock {
}
}
private
void
unbindHandler
(
ExceptionHandler
handler
)
{
for
(
BlockNode
block
:
handler
.
getBlocks
())
{
block
.
add
(
AFlag
.
SKIP
);
}
}
private
void
removeWholeBlock
(
MethodNode
mth
)
{
if
(
finalRegion
!=
null
)
{
// search catch attr
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
CatchAttr
cb
=
block
.
get
(
AType
.
CATCH_BLOCK
);
if
(
cb
==
attr
)
{
for
(
ExceptionHandler
eh
:
mth
.
getExceptionHandlers
())
{
if
(
eh
.
getBlocks
().
contains
(
block
))
{
TryCatchBlock
tb
=
eh
.
getTryBlock
();
tb
.
setFinalRegionFromInsns
(
mth
,
((
IBlock
)
finalRegion
).
getInstructions
());
}
}
}
}
}
else
{
// self destruction
for
(
InsnNode
insn
:
insns
)
{
insn
.
removeAttr
(
attr
);
}
insns
.
clear
();
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
block
.
removeAttr
(
attr
);
}
// self destruction
for
(
InsnNode
insn
:
insns
)
{
insn
.
removeAttr
(
attr
);
}
insns
.
clear
();
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
block
.
removeAttr
(
attr
);
}
}
...
...
@@ -108,36 +96,11 @@ public class TryCatchBlock {
return
attr
;
}
public
IContainer
getFinalRegion
()
{
return
finalRegion
;
}
public
void
setFinalRegion
(
IContainer
finalRegion
)
{
this
.
finalRegion
=
finalRegion
;
}
public
void
setFinalRegionFromInsns
(
MethodNode
mth
,
List
<
InsnNode
>
insns
)
{
List
<
InsnNode
>
finalBlockInsns
=
new
ArrayList
<
InsnNode
>(
insns
);
setFinalRegion
(
new
InsnContainer
(
finalBlockInsns
));
InstructionRemover
.
unbindInsnList
(
mth
,
finalBlockInsns
);
// remove these instructions from other handlers
for
(
ExceptionHandler
h
:
getHandlers
())
{
for
(
BlockNode
ehb
:
h
.
getBlocks
())
{
ehb
.
getInstructions
().
removeAll
(
finalBlockInsns
);
}
}
// remove from blocks with this catch
for
(
BlockNode
b
:
mth
.
getBasicBlocks
())
{
CatchAttr
ca
=
b
.
get
(
AType
.
CATCH_BLOCK
);
if
(
attr
==
ca
)
{
b
.
getInstructions
().
removeAll
(
finalBlockInsns
);
}
public
boolean
merge
(
MethodNode
mth
,
TryCatchBlock
tryBlock
)
{
if
(
tryBlock
==
this
)
{
return
false
;
}
}
public
void
merge
(
MethodNode
mth
,
TryCatchBlock
tryBlock
)
{
for
(
InsnNode
insn
:
tryBlock
.
getInsns
())
{
this
.
addInsn
(
insn
);
}
...
...
@@ -148,6 +111,7 @@ public class TryCatchBlock {
// clear
tryBlock
.
handlers
.
clear
();
tryBlock
.
removeWholeBlock
(
mth
);
return
true
;
}
@Override
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java
View file @
577176dd
...
...
@@ -208,7 +208,7 @@ public class CodeShrinker extends AbstractVisitor {
// }
SSAVar
sVar
=
arg
.
getSVar
();
// allow inline only one use arg or 'this'
if
(
sVar
.
getVariableUseCount
()
!=
1
&&
!
arg
.
isThis
(
))
{
if
(
sVar
==
null
||
(
sVar
.
getVariableUseCount
()
!=
1
&&
!
arg
.
isThis
()
))
{
continue
;
}
InsnNode
assignInsn
=
sVar
.
getAssign
().
getParentInsn
();
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/DebugInfoVisitor.java
View file @
577176dd
...
...
@@ -6,6 +6,7 @@ import jadx.core.dex.nodes.BlockNode;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.parser.DebugInfoParser
;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.exceptions.JadxException
;
public
class
DebugInfoVisitor
extends
AbstractVisitor
{
...
...
@@ -23,18 +24,21 @@ public class DebugInfoVisitor extends AbstractVisitor {
mth
.
setSourceLine
(
line
-
1
);
}
}
if
(!
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
)
&&
mth
.
getExitBlocks
().
size
()
>
1
)
{
if
(!
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
))
{
// fix debug for splitter 'return' instructions
for
(
BlockNode
exit
:
mth
.
getExitBlocks
())
{
InsnNode
ret
=
exit
.
getInstructions
().
get
(
0
);
InsnNode
ret
=
BlockUtils
.
getLastInsn
(
exit
);
if
(
ret
==
null
)
{
continue
;
}
InsnNode
oldRet
=
insnArr
[
ret
.
getOffset
()];
if
(
oldRet
!=
ret
)
{
RegisterArg
oldArg
=
(
RegisterArg
)
oldRet
.
getArg
(
0
);
RegisterArg
newArg
=
(
RegisterArg
)
ret
.
getArg
(
0
);
newArg
.
mergeDebugInfo
(
oldArg
.
getType
(),
oldArg
.
getName
());
ret
.
setSourceLine
(
oldRet
.
getSourceLine
());
if
(
oldRet
==
ret
)
{
continue
;
}
RegisterArg
oldArg
=
(
RegisterArg
)
oldRet
.
getArg
(
0
);
RegisterArg
newArg
=
(
RegisterArg
)
ret
.
getArg
(
0
);
newArg
.
mergeDebugInfo
(
oldArg
.
getType
(),
oldArg
.
getName
());
ret
.
setSourceLine
(
oldRet
.
getSourceLine
());
}
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
View file @
577176dd
...
...
@@ -28,7 +28,6 @@ import jadx.core.dex.trycatch.ExceptionHandler;
import
jadx.core.utils.InstructionRemover
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -51,10 +50,6 @@ public class ModVisitor extends AbstractVisitor {
removeStep
(
mth
,
remover
);
checkArgsNames
(
mth
);
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
processExceptionHandler
(
mth
,
block
);
}
}
private
static
void
replaceStep
(
MethodNode
mth
,
InstructionRemover
remover
)
{
...
...
@@ -110,6 +105,10 @@ public class ModVisitor extends AbstractVisitor {
}
break
;
case
MOVE_EXCEPTION:
processMoveException
(
mth
,
block
,
insn
,
remover
);
break
;
default
:
break
;
}
...
...
@@ -284,70 +283,33 @@ public class ModVisitor extends AbstractVisitor {
}
}
private
static
void
processExceptionHandler
(
MethodNode
mth
,
BlockNode
block
)
{
ExcHandlerAttr
handlerAttr
=
block
.
get
(
AType
.
EXC_HANDLER
);
if
(
handlerAttr
==
null
)
{
private
static
void
processMoveException
(
MethodNode
mth
,
BlockNode
block
,
InsnNode
insn
,
InstructionRemover
remover
)
{
ExcHandlerAttr
excHandlerAttr
=
block
.
get
(
AType
.
EXC_HANDLER
);
if
(
excHandlerAttr
==
null
)
{
return
;
}
ExceptionHandler
excHandler
=
handlerAttr
.
getHandler
();
boolean
noExitNode
=
true
;
// check if handler has exit edge to block not from this handler
boolean
reThrow
=
false
;
for
(
BlockNode
excBlock
:
excHandler
.
getBlocks
())
{
if
(
noExitNode
)
{
noExitNode
=
excHandler
.
getBlocks
().
containsAll
(
excBlock
.
getCleanSuccessors
());
}
ExceptionHandler
excHandler
=
excHandlerAttr
.
getHandler
();
List
<
InsnNode
>
insns
=
excBlock
.
getInstructions
();
int
size
=
insns
.
size
();
if
(
excHandler
.
isCatchAll
()
&&
size
>
0
&&
insns
.
get
(
size
-
1
).
getType
()
==
InsnType
.
THROW
)
{
reThrow
=
true
;
InstructionRemover
.
remove
(
mth
,
excBlock
,
size
-
1
);
// move not removed instructions to 'finally' block
if
(!
insns
.
isEmpty
())
{
// TODO: support instructions from several blocks
// tryBlock.setFinalBlockFromInsns(mth, insns);
// TODO: because of incomplete realization don't extract final block,
// just remove unnecessary instructions
insns
.
clear
();
}
}
}
List
<
InsnNode
>
blockInsns
=
block
.
getInstructions
();
if
(!
blockInsns
.
isEmpty
())
{
InsnNode
insn
=
blockInsns
.
get
(
0
);
if
(
insn
.
getType
()
==
InsnType
.
MOVE_EXCEPTION
)
{
// result arg used both in this insn and exception handler,
RegisterArg
resArg
=
insn
.
getResult
();
ArgType
type
=
excHandler
.
isCatchAll
()
?
ArgType
.
THROWABLE
:
excHandler
.
getCatchType
().
getType
();
String
name
=
excHandler
.
isCatchAll
()
?
"th"
:
"e"
;
if
(
resArg
.
getName
()
==
null
)
{
resArg
.
setName
(
name
);
}
SSAVar
sVar
=
insn
.
getResult
().
getSVar
();
if
(
sVar
.
getUseCount
()
==
0
)
{
excHandler
.
setArg
(
new
NamedArg
(
name
,
type
));
InstructionRemover
.
remove
(
mth
,
block
,
0
);
}
else
if
(
sVar
.
isUsedInPhi
())
{
// exception var moved to external variable => replace with 'move' insn
InsnNode
moveInsn
=
new
InsnNode
(
InsnType
.
MOVE
,
1
);
moveInsn
.
setResult
(
insn
.
getResult
());
NamedArg
namedArg
=
new
NamedArg
(
name
,
type
);
moveInsn
.
addArg
(
namedArg
);
excHandler
.
setArg
(
namedArg
);
replaceInsn
(
block
,
0
,
moveInsn
);
}
}
}
int
totalSize
=
0
;
for
(
BlockNode
excBlock
:
excHandler
.
getBlocks
())
{
totalSize
+=
excBlock
.
getInstructions
().
size
();
// result arg used both in this insn and exception handler,
RegisterArg
resArg
=
insn
.
getResult
();
ArgType
type
=
excHandler
.
isCatchAll
()
?
ArgType
.
THROWABLE
:
excHandler
.
getCatchType
().
getType
();
String
name
=
excHandler
.
isCatchAll
()
?
"th"
:
"e"
;
if
(
resArg
.
getName
()
==
null
)
{
resArg
.
setName
(
name
);
}
if
(
totalSize
==
0
&&
noExitNode
&&
reThrow
)
{
handlerAttr
.
getTryBlock
().
removeHandler
(
mth
,
excHandler
);
SSAVar
sVar
=
insn
.
getResult
().
getSVar
();
if
(
sVar
.
getUseCount
()
==
0
)
{
excHandler
.
setArg
(
new
NamedArg
(
name
,
type
));
remover
.
add
(
insn
);
}
else
if
(
sVar
.
isUsedInPhi
())
{
// exception var moved to external variable => replace with 'move' insn
InsnNode
moveInsn
=
new
InsnNode
(
InsnType
.
MOVE
,
1
);
moveInsn
.
setResult
(
insn
.
getResult
());
NamedArg
namedArg
=
new
NamedArg
(
name
,
type
);
moveInsn
.
addArg
(
namedArg
);
excHandler
.
setArg
(
namedArg
);
replaceInsn
(
block
,
0
,
moveInsn
);
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/
BlockProcessingHelp
er.java
→
jadx-core/src/main/java/jadx/core/dex/visitors/
blocksmaker/BlockExceptionHandl
er.java
View file @
577176dd
package
jadx
.
core
.
dex
.
visitors
;
package
jadx
.
core
.
dex
.
visitors
.
blocksmaker
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.instructions.IfNode
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.InsnArg
;
...
...
@@ -14,14 +13,16 @@ import jadx.core.dex.trycatch.CatchAttr;
import
jadx.core.dex.trycatch.ExcHandlerAttr
;
import
jadx.core.dex.trycatch.ExceptionHandler
;
import
jadx.core.dex.trycatch.TryCatchBlock
;
import
jadx.core.dex.visitors.AbstractVisitor
;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.InstructionRemover
;
import
java.util.
List
;
import
java.util.
Iterator
;
public
class
Block
ProcessingHelpe
r
{
public
class
Block
ExceptionHandler
extends
AbstractVisito
r
{
public
static
void
visit
(
MethodNode
mth
)
{
@Override
public
void
visit
(
MethodNode
mth
)
{
if
(
mth
.
isNoCode
())
{
return
;
}
...
...
@@ -30,7 +31,6 @@ public class BlockProcessingHelper {
}
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
block
.
updateCleanSuccessors
();
initBlocksInIfNodes
(
block
);
}
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
processExceptionHandlers
(
mth
,
block
);
...
...
@@ -38,6 +38,16 @@ public class BlockProcessingHelper {
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
processTryCatchBlocks
(
mth
,
block
);
}
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
Iterator
<
InsnNode
>
it
=
block
.
getInstructions
().
iterator
();
while
(
it
.
hasNext
())
{
InsnNode
insn
=
it
.
next
();
if
(
insn
.
getType
()
==
InsnType
.
NOP
)
{
it
.
remove
();
}
}
}
}
/**
...
...
@@ -88,24 +98,35 @@ public class BlockProcessingHelper {
// if 'throw' in exception handler block have 'catch' - merge these catch blocks
for
(
InsnNode
insn
:
excBlock
.
getInstructions
())
{
if
(
insn
.
getType
()
==
InsnType
.
THROW
)
{
CatchAttr
catchAttr
=
insn
.
get
(
AType
.
CATCH_BLOCK
);
if
(
catchAttr
!=
null
)
{
TryCatchBlock
handlerBlock
=
handlerAttr
.
getTryBlock
();
TryCatchBlock
catchBlock
=
catchAttr
.
getTryBlock
();
if
(
handlerBlock
!=
catchBlock
)
{
// TODO: why it can be?
handlerBlock
.
merge
(
mth
,
catchBlock
);
catchBlock
.
removeInsn
(
insn
);
}
}
CatchAttr
catchAttr
=
insn
.
get
(
AType
.
CATCH_BLOCK
);
if
(
catchAttr
==
null
)
{
continue
;
}
if
(
insn
.
getType
()
==
InsnType
.
THROW
||
onlyAllHandler
(
catchAttr
.
getTryBlock
()))
{
TryCatchBlock
handlerBlock
=
handlerAttr
.
getTryBlock
();
TryCatchBlock
catchBlock
=
catchAttr
.
getTryBlock
();
handlerBlock
.
merge
(
mth
,
catchBlock
);
}
}
}
}
}
private
static
boolean
onlyAllHandler
(
TryCatchBlock
tryBlock
)
{
if
(
tryBlock
.
getHandlersCount
()
==
1
)
{
ExceptionHandler
eh
=
tryBlock
.
getHandlers
().
iterator
().
next
();
if
(
eh
.
isCatchAll
()
||
eh
.
isFinally
())
{
return
true
;
}
}
return
false
;
}
/**
* If all instructions in block have same 'catch' attribute mark it as 'TryCatch' block.
*/
private
static
void
processTryCatchBlocks
(
MethodNode
mth
,
BlockNode
block
)
{
// if all instructions in block have same 'catch' attribute mark it as 'TryCatch' block
CatchAttr
commonCatchAttr
=
null
;
for
(
InsnNode
insn
:
block
.
getInstructions
())
{
CatchAttr
catchAttr
=
insn
.
get
(
AType
.
CATCH_BLOCK
);
...
...
@@ -138,17 +159,4 @@ public class BlockProcessingHelper {
}
}
}
/**
* Init 'then' and 'else' blocks for 'if' instruction.
*/
private
static
void
initBlocksInIfNodes
(
BlockNode
block
)
{
List
<
InsnNode
>
instructions
=
block
.
getInstructions
();
if
(
instructions
.
size
()
==
1
)
{
InsnNode
insn
=
instructions
.
get
(
0
);
if
(
insn
.
getType
()
==
InsnType
.
IF
)
{
((
IfNode
)
insn
).
initBlocks
(
block
);
}
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinallyExtract.java
0 → 100644
View file @
577176dd
This diff is collapsed.
Click to expand it.
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java
0 → 100644
View file @
577176dd
package
jadx
.
core
.
dex
.
visitors
.
blocksmaker
;
import
jadx.core.dex.instructions.IfNode
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.visitors.AbstractVisitor
;
import
java.util.List
;
public
class
BlockFinish
extends
AbstractVisitor
{
@Override
public
void
visit
(
MethodNode
mth
)
{
if
(
mth
.
isNoCode
())
{
return
;
}
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
block
.
updateCleanSuccessors
();
initBlocksInIfNodes
(
block
);
}
mth
.
finishBasicBlocks
();
}
/**
* Init 'then' and 'else' blocks for 'if' instruction.
*/
private
static
void
initBlocksInIfNodes
(
BlockNode
block
)
{
List
<
InsnNode
>
instructions
=
block
.
getInstructions
();
if
(
instructions
.
size
()
==
1
)
{
InsnNode
insn
=
instructions
.
get
(
0
);
if
(
insn
.
getType
()
==
InsnType
.
IF
)
{
((
IfNode
)
insn
).
initBlocks
(
block
);
}
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/
BlockMakerVisit
or.java
→
jadx-core/src/main/java/jadx/core/dex/visitors/
blocksmaker/BlockProcess
or.java
View file @
577176dd
This diff is collapsed.
Click to expand it.
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java
0 → 100644
View file @
577176dd
package
jadx
.
core
.
dex
.
visitors
.
blocksmaker
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.JumpInfo
;
import
jadx.core.dex.instructions.IfNode
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.trycatch.CatchAttr
;
import
jadx.core.dex.trycatch.ExceptionHandler
;
import
jadx.core.dex.trycatch.SplitterBlockAttr
;
import
jadx.core.dex.visitors.AbstractVisitor
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.util.EnumSet
;
import
java.util.HashMap
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
public
class
BlockSplitter
extends
AbstractVisitor
{
// leave these instructions alone in block node
private
static
final
Set
<
InsnType
>
SEPARATE_INSNS
=
EnumSet
.
of
(
InsnType
.
RETURN
,
InsnType
.
IF
,
InsnType
.
SWITCH
,
InsnType
.
MONITOR_ENTER
,
InsnType
.
MONITOR_EXIT
,
InsnType
.
THROW
);
@Override
public
void
visit
(
MethodNode
mth
)
{
if
(
mth
.
isNoCode
())
{
return
;
}
mth
.
checkInstructions
();
mth
.
initBasicBlocks
();
splitBasicBlocks
(
mth
);
removeInsns
(
mth
);
}
private
static
void
splitBasicBlocks
(
MethodNode
mth
)
{
InsnNode
prevInsn
=
null
;
Map
<
Integer
,
BlockNode
>
blocksMap
=
new
HashMap
<
Integer
,
BlockNode
>();
BlockNode
curBlock
=
startNewBlock
(
mth
,
0
);
mth
.
setEnterBlock
(
curBlock
);
// split into blocks
for
(
InsnNode
insn
:
mth
.
getInstructions
())
{
if
(
insn
==
null
)
{
continue
;
}
boolean
startNew
=
false
;
if
(
prevInsn
!=
null
)
{
InsnType
type
=
prevInsn
.
getType
();
if
(
type
==
InsnType
.
GOTO
||
type
==
InsnType
.
THROW
||
SEPARATE_INSNS
.
contains
(
type
))
{
if
(
type
==
InsnType
.
RETURN
||
type
==
InsnType
.
THROW
)
{
mth
.
addExitBlock
(
curBlock
);
}
BlockNode
block
=
startNewBlock
(
mth
,
insn
.
getOffset
());
if
(
type
==
InsnType
.
MONITOR_ENTER
||
type
==
InsnType
.
MONITOR_EXIT
)
{
connect
(
curBlock
,
block
);
}
curBlock
=
block
;
startNew
=
true
;
}
else
{
startNew
=
isSplitByJump
(
prevInsn
,
insn
)
||
SEPARATE_INSNS
.
contains
(
insn
.
getType
())
||
isDoWhile
(
blocksMap
,
curBlock
,
insn
)
||
prevInsn
.
contains
(
AFlag
.
TRY_LEAVE
)
||
prevInsn
.
getType
()
==
InsnType
.
MOVE_EXCEPTION
;
if
(
startNew
)
{
BlockNode
block
=
startNewBlock
(
mth
,
insn
.
getOffset
());
connect
(
curBlock
,
block
);
curBlock
=
block
;
}
}
}
// for try/catch make empty block for connect handlers
if
(
insn
.
contains
(
AFlag
.
TRY_ENTER
))
{
BlockNode
block
;
if
(
insn
.
getOffset
()
!=
0
&&
!
startNew
)
{
block
=
startNewBlock
(
mth
,
insn
.
getOffset
());
connect
(
curBlock
,
block
);
curBlock
=
block
;
}
blocksMap
.
put
(
insn
.
getOffset
(),
curBlock
);
// add this insn in new block
block
=
startNewBlock
(
mth
,
-
1
);
curBlock
.
add
(
AFlag
.
SYNTHETIC
);
SplitterBlockAttr
splitter
=
new
SplitterBlockAttr
(
curBlock
);
block
.
addAttr
(
splitter
);
curBlock
.
addAttr
(
splitter
);
connect
(
curBlock
,
block
);
curBlock
=
block
;
}
else
{
blocksMap
.
put
(
insn
.
getOffset
(),
curBlock
);
}
curBlock
.
getInstructions
().
add
(
insn
);
prevInsn
=
insn
;
}
// setup missing connections
setupConnections
(
mth
,
blocksMap
);
}
static
BlockNode
startNewBlock
(
MethodNode
mth
,
int
offset
)
{
BlockNode
block
=
new
BlockNode
(
mth
.
getBasicBlocks
().
size
(),
offset
);
mth
.
getBasicBlocks
().
add
(
block
);
return
block
;
}
static
void
connect
(
BlockNode
from
,
BlockNode
to
)
{
if
(!
from
.
getSuccessors
().
contains
(
to
))
{
from
.
getSuccessors
().
add
(
to
);
}
if
(!
to
.
getPredecessors
().
contains
(
from
))
{
to
.
getPredecessors
().
add
(
from
);
}
}
static
void
removeConnection
(
BlockNode
from
,
BlockNode
to
)
{
from
.
getSuccessors
().
remove
(
to
);
to
.
getPredecessors
().
remove
(
from
);
}
static
BlockNode
insertBlockBetween
(
MethodNode
mth
,
BlockNode
source
,
BlockNode
target
)
{
BlockNode
newBlock
=
startNewBlock
(
mth
,
target
.
getStartOffset
());
newBlock
.
add
(
AFlag
.
SYNTHETIC
);
removeConnection
(
source
,
target
);
connect
(
source
,
newBlock
);
connect
(
newBlock
,
target
);
return
newBlock
;
}
private
static
void
setupConnections
(
MethodNode
mth
,
Map
<
Integer
,
BlockNode
>
blocksMap
)
{
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
for
(
InsnNode
insn
:
block
.
getInstructions
())
{
List
<
JumpInfo
>
jumps
=
insn
.
getAll
(
AType
.
JUMP
);
for
(
JumpInfo
jump
:
jumps
)
{
BlockNode
srcBlock
=
getBlock
(
jump
.
getSrc
(),
blocksMap
);
BlockNode
thisBlock
=
getBlock
(
jump
.
getDest
(),
blocksMap
);
connect
(
srcBlock
,
thisBlock
);
}
// connect exception handlers
CatchAttr
catches
=
insn
.
get
(
AType
.
CATCH_BLOCK
);
// get synthetic block for handlers
SplitterBlockAttr
spl
=
block
.
get
(
AType
.
SPLITTER_BLOCK
);
if
(
catches
!=
null
&&
spl
!=
null
)
{
BlockNode
splitterBlock
=
spl
.
getBlock
();
boolean
tryEnd
=
insn
.
contains
(
AFlag
.
TRY_LEAVE
);
for
(
ExceptionHandler
h
:
catches
.
getTryBlock
().
getHandlers
())
{
BlockNode
handlerBlock
=
getBlock
(
h
.
getHandleOffset
(),
blocksMap
);
// skip self loop in handler
if
(
splitterBlock
!=
handlerBlock
)
{
handlerBlock
.
addAttr
(
spl
);
connect
(
splitterBlock
,
handlerBlock
);
}
if
(
tryEnd
)
{
connect
(
block
,
handlerBlock
);
}
}
}
}
}
}
private
static
boolean
isSplitByJump
(
InsnNode
prevInsn
,
InsnNode
currentInsn
)
{
List
<
JumpInfo
>
pJumps
=
prevInsn
.
getAll
(
AType
.
JUMP
);
for
(
JumpInfo
jump
:
pJumps
)
{
if
(
jump
.
getSrc
()
==
prevInsn
.
getOffset
())
{
return
true
;
}
}
List
<
JumpInfo
>
cJumps
=
currentInsn
.
getAll
(
AType
.
JUMP
);
for
(
JumpInfo
jump
:
cJumps
)
{
if
(
jump
.
getDest
()
==
currentInsn
.
getOffset
())
{
return
true
;
}
}
return
false
;
}
private
static
boolean
isDoWhile
(
Map
<
Integer
,
BlockNode
>
blocksMap
,
BlockNode
curBlock
,
InsnNode
insn
)
{
// split 'do-while' block (last instruction: 'if', target this block)
if
(
insn
.
getType
()
==
InsnType
.
IF
)
{
IfNode
ifs
=
(
IfNode
)
(
insn
);
BlockNode
targetBlock
=
blocksMap
.
get
(
ifs
.
getTarget
());
if
(
targetBlock
==
curBlock
)
{
return
true
;
}
}
return
false
;
}
private
static
BlockNode
getBlock
(
int
offset
,
Map
<
Integer
,
BlockNode
>
blocksMap
)
{
BlockNode
block
=
blocksMap
.
get
(
offset
);
if
(
block
==
null
)
{
throw
new
JadxRuntimeException
(
"Missing block: "
+
offset
);
}
return
block
;
}
private
static
void
removeInsns
(
MethodNode
mth
)
{
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
Iterator
<
InsnNode
>
it
=
block
.
getInstructions
().
iterator
();
while
(
it
.
hasNext
())
{
InsnType
insnType
=
it
.
next
().
getType
();
if
(
insnType
==
InsnType
.
GOTO
||
insnType
==
InsnType
.
NOP
)
{
it
.
remove
();
}
}
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/helpers/BlocksPair.java
0 → 100644
View file @
577176dd
package
jadx
.
core
.
dex
.
visitors
.
blocksmaker
.
helpers
;
import
jadx.core.dex.nodes.BlockNode
;
public
final
class
BlocksPair
{
private
final
BlockNode
first
;
private
final
BlockNode
second
;
public
BlocksPair
(
BlockNode
first
,
BlockNode
second
)
{
this
.
first
=
first
;
this
.
second
=
second
;
}
public
BlockNode
getFirst
()
{
return
first
;
}
public
BlockNode
getSecond
()
{
return
second
;
}
@Override
public
int
hashCode
()
{
return
31
*
first
.
hashCode
()
+
second
.
hashCode
();
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(!(
o
instanceof
BlocksPair
))
{
return
false
;
}
BlocksPair
other
=
(
BlocksPair
)
o
;
return
first
.
equals
(
other
.
first
)
&&
second
.
equals
(
other
.
second
);
}
@Override
public
String
toString
()
{
return
"("
+
first
+
", "
+
second
+
")"
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/helpers/BlocksRemoveInfo.java
0 → 100644
View file @
577176dd
package
jadx
.
core
.
dex
.
visitors
.
blocksmaker
.
helpers
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.BlockNode
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
org.jetbrains.annotations.Nullable
;
public
final
class
BlocksRemoveInfo
{
private
final
Set
<
BlocksPair
>
processed
=
new
HashSet
<
BlocksPair
>();
private
final
Set
<
BlocksPair
>
outs
=
new
HashSet
<
BlocksPair
>();
private
final
Map
<
RegisterArg
,
RegisterArg
>
regMap
=
new
HashMap
<
RegisterArg
,
RegisterArg
>();
private
final
BlocksPair
start
;
private
int
startSplitIndex
;
public
BlocksRemoveInfo
(
BlocksPair
start
)
{
this
.
start
=
start
;
}
public
Set
<
BlocksPair
>
getProcessed
()
{
return
processed
;
}
public
Set
<
BlocksPair
>
getOuts
()
{
return
outs
;
}
public
BlocksPair
getStart
()
{
return
start
;
}
public
int
getStartSplitIndex
()
{
return
startSplitIndex
;
}
public
void
setStartSplitIndex
(
int
startSplitIndex
)
{
this
.
startSplitIndex
=
startSplitIndex
;
}
public
Map
<
RegisterArg
,
RegisterArg
>
getRegMap
()
{
return
regMap
;
}
@Nullable
public
BlockNode
getByFirst
(
BlockNode
first
)
{
for
(
BlocksPair
blocksPair
:
processed
)
{
if
(
blocksPair
.
getFirst
()
==
first
)
{
return
blocksPair
.
getSecond
();
}
}
return
null
;
}
@Nullable
public
BlockNode
getBySecond
(
BlockNode
second
)
{
for
(
BlocksPair
blocksPair
:
processed
)
{
if
(
blocksPair
.
getSecond
()
==
second
)
{
return
blocksPair
.
getSecond
();
}
}
return
null
;
}
@Override
public
String
toString
()
{
return
"BRI start: "
+
start
+
", list: "
+
processed
+
", outs: "
+
outs
+
", regMap: "
+
regMap
+
", split: "
+
startSplitIndex
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java
View file @
577176dd
...
...
@@ -4,6 +4,7 @@ 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.IContainer
;
import
jadx.core.dex.nodes.IRegion
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.regions.loops.LoopRegion
;
...
...
@@ -11,9 +12,8 @@ import jadx.core.dex.visitors.AbstractVisitor;
import
jadx.core.utils.ErrorsCounter
;
import
jadx.core.utils.exceptions.JadxException
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
java.util.Li
s
t
;
import
java.util.Li
nkedHashSe
t
;
import
java.util.Set
;
import
org.slf4j.Logger
;
...
...
@@ -30,9 +30,11 @@ public class CheckRegions extends AbstractVisitor {
return
;
}
// printRegion(mth, mth.getRegion(), "|");
// check if all blocks included in regions
final
Set
<
BlockNode
>
blocksInRegions
=
new
HashSet
<
BlockNode
>();
DepthRegionTraversal
.
traverse
All
(
mth
,
new
AbstractRegionVisitor
()
{
DepthRegionTraversal
.
traverse
(
mth
,
new
AbstractRegionVisitor
()
{
@Override
public
void
processBlock
(
MethodNode
mth
,
IBlock
container
)
{
if
(!(
container
instanceof
BlockNode
))
{
...
...
@@ -49,7 +51,7 @@ public class CheckRegions extends AbstractVisitor {
// TODO
// mth.add(AFlag.INCONSISTENT_CODE);
LOG
.
debug
(
" Duplicated block: {} in {}"
,
block
,
mth
);
//
printRegionsWithBlock(mth, block);
printRegionsWithBlock
(
mth
,
block
);
}
}
});
...
...
@@ -79,7 +81,7 @@ public class CheckRegions extends AbstractVisitor {
}
private
static
void
printRegionsWithBlock
(
MethodNode
mth
,
final
BlockNode
block
)
{
final
List
<
IRegion
>
regions
=
new
ArrayLis
t
<
IRegion
>();
final
Set
<
IRegion
>
regions
=
new
LinkedHashSe
t
<
IRegion
>();
DepthRegionTraversal
.
traverseAll
(
mth
,
new
TracedRegionVisitor
()
{
@Override
public
void
processBlockTraced
(
MethodNode
mth
,
IBlock
container
,
IRegion
currentRegion
)
{
...
...
@@ -90,4 +92,15 @@ public class CheckRegions extends AbstractVisitor {
});
LOG
.
debug
(
" Found block: {} in regions: {}"
,
block
,
regions
);
}
private
void
printRegion
(
MethodNode
mth
,
IRegion
region
,
String
indent
)
{
LOG
.
debug
(
indent
+
region
);
for
(
IContainer
container
:
region
.
getSubBlocks
())
{
if
(
container
instanceof
IRegion
)
{
printRegion
(
mth
,
(
IRegion
)
container
,
indent
+
" "
);
}
else
{
LOG
.
debug
(
indent
+
" "
+
container
);
}
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java
View file @
577176dd
...
...
@@ -22,6 +22,7 @@ import jadx.core.dex.regions.conditions.IfRegion;
import
jadx.core.dex.regions.loops.LoopRegion
;
import
jadx.core.dex.trycatch.ExcHandlerAttr
;
import
jadx.core.dex.trycatch.ExceptionHandler
;
import
jadx.core.dex.trycatch.SplitterBlockAttr
;
import
jadx.core.dex.trycatch.TryCatchBlock
;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.ErrorsCounter
;
...
...
@@ -316,7 +317,8 @@ public class RegionMaker {
Region
body
=
makeRegion
(
loopStart
,
stack
);
BlockNode
loopEnd
=
loop
.
getEnd
();
if
(!
RegionUtils
.
isRegionContainsBlock
(
body
,
loopEnd
)
&&
!
loopEnd
.
contains
(
AType
.
EXC_HANDLER
))
{
&&
!
loopEnd
.
contains
(
AType
.
EXC_HANDLER
)
&&
!
inExceptionHandlerBlocks
(
loopEnd
))
{
body
.
getSubBlocks
().
add
(
loopEnd
);
}
loopRegion
.
setBody
(
body
);
...
...
@@ -330,6 +332,18 @@ public class RegionMaker {
return
loopExit
;
}
private
boolean
inExceptionHandlerBlocks
(
BlockNode
loopEnd
)
{
if
(
mth
.
getExceptionHandlersCount
()
==
0
)
{
return
false
;
}
for
(
ExceptionHandler
eh
:
mth
.
getExceptionHandlers
())
{
if
(
eh
.
getBlocks
().
contains
(
loopEnd
))
{
return
true
;
}
}
return
false
;
}
private
boolean
canInsertBreak
(
BlockNode
exit
)
{
if
(
exit
.
contains
(
AFlag
.
RETURN
)
||
BlockUtils
.
checkLastInsnType
(
exit
,
InsnType
.
BREAK
))
{
...
...
@@ -747,23 +761,33 @@ public class RegionMaker {
}
}
// TODO add blocks common for several handlers to some region
private
void
processExcHandler
(
ExceptionHandler
handler
,
Set
<
BlockNode
>
exits
)
{
BlockNode
start
=
handler
.
getHandlerBlock
();
if
(
start
==
null
)
{
return
;
}
// TODO extract finally part which exists in all handlers from same try block
// TODO add blocks common for several handlers to some region
RegionStack
stack
=
new
RegionStack
(
mth
);
stack
.
addExits
(
exits
);
BlockNode
exit
=
BlockUtils
.
traverseWhileDominates
(
start
,
start
);
if
(
exit
!=
null
&&
RegionUtils
.
isRegionContainsBlock
(
mth
.
getRegion
(),
exit
))
{
stack
.
addExit
(
exit
);
BlockNode
dom
;
if
(
handler
.
isFinally
())
{
SplitterBlockAttr
splitterAttr
=
start
.
get
(
AType
.
SPLITTER_BLOCK
);
if
(
splitterAttr
==
null
)
{
return
;
}
dom
=
splitterAttr
.
getBlock
();
}
else
{
dom
=
start
;
stack
.
addExits
(
exits
);
}
BitSet
domFrontier
=
dom
.
getDomFrontier
();
List
<
BlockNode
>
handlerExits
=
BlockUtils
.
bitSetToBlocks
(
mth
,
domFrontier
);
boolean
inLoop
=
mth
.
getLoopForBlock
(
start
)
!=
null
;
for
(
BlockNode
exit
:
handlerExits
)
{
if
((!
inLoop
||
BlockUtils
.
isPathExists
(
start
,
exit
))
&&
RegionUtils
.
isRegionContainsBlock
(
mth
.
getRegion
(),
exit
))
{
stack
.
addExit
(
exit
);
}
}
handler
.
setHandlerRegion
(
makeRegion
(
start
,
stack
));
ExcHandlerAttr
excHandlerAttr
=
start
.
get
(
AType
.
EXC_HANDLER
);
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ssa/SSATransform.java
View file @
577176dd
...
...
@@ -105,16 +105,17 @@ public class SSATransform extends AbstractVisitor {
for
(
InsnNode
insn
:
block
.
getInstructions
())
{
if
(
insn
.
getType
()
!=
InsnType
.
PHI
)
{
for
(
InsnArg
arg
:
insn
.
getArguments
())
{
if
(
arg
.
isRegister
())
{
RegisterArg
reg
=
(
RegisterArg
)
arg
;
int
regNum
=
reg
.
getRegNum
();
SSAVar
var
=
vars
[
regNum
]
;
if
(
var
==
null
)
{
var
=
mth
.
makeNewSVar
(
regNum
,
vers
,
null
)
;
vars
[
regNum
]
=
var
;
}
var
.
use
(
reg
);
if
(
!
arg
.
isRegister
())
{
continue
;
}
RegisterArg
reg
=
(
RegisterArg
)
arg
;
int
regNum
=
reg
.
getRegNum
();
SSAVar
var
=
vars
[
regNum
]
;
if
(
var
==
null
)
{
throw
new
JadxRuntimeException
(
"Not initialized variable reg: "
+
regNum
+
", insn: "
+
insn
+
", block:"
+
block
+
", method: "
+
mth
);
}
var
.
use
(
reg
);
}
}
RegisterArg
result
=
insn
.
getResult
();
...
...
@@ -125,24 +126,24 @@ public class SSATransform extends AbstractVisitor {
}
for
(
BlockNode
s
:
block
.
getSuccessors
())
{
PhiListAttr
phiList
=
s
.
get
(
AType
.
PHI_LIST
);
if
(
phiList
!=
null
)
{
int
j
=
s
.
getPredecessors
().
indexOf
(
block
);
if
(
j
==
-
1
)
{
throw
new
JadxRuntimeException
(
"Can't find predecessor for "
+
block
+
" "
+
s
);
if
(
phiList
==
null
)
{
continue
;
}
int
j
=
s
.
getPredecessors
().
indexOf
(
block
);
if
(
j
==
-
1
)
{
throw
new
JadxRuntimeException
(
"Can't find predecessor for "
+
block
+
" "
+
s
);
}
for
(
PhiInsn
phiInsn
:
phiList
.
getList
())
{
if
(
j
>=
phiInsn
.
getArgsCount
())
{
continue
;
}
for
(
PhiInsn
phiInsn
:
phiList
.
getList
())
{
if
(
j
>=
phiInsn
.
getArgsCount
())
{
continue
;
}
int
regNum
=
phiInsn
.
getResult
().
getRegNum
();
SSAVar
var
=
vars
[
regNum
];
if
(
var
==
null
)
{
var
=
mth
.
makeNewSVar
(
regNum
,
vers
,
null
);
vars
[
regNum
]
=
var
;
}
var
.
use
(
phiInsn
.
getArg
(
j
));
var
.
setUsedInPhi
(
phiInsn
);
int
regNum
=
phiInsn
.
getResult
().
getRegNum
();
SSAVar
var
=
vars
[
regNum
];
if
(
var
==
null
)
{
continue
;
}
var
.
use
(
phiInsn
.
getArg
(
j
));
var
.
setUsedInPhi
(
phiInsn
);
}
}
for
(
BlockNode
domOn
:
block
.
getDominatesOn
())
{
...
...
@@ -231,7 +232,10 @@ public class SSATransform extends AbstractVisitor {
for
(
PhiInsn
phiInsn
:
insnToRemove
)
{
if
(
list
.
remove
(
phiInsn
))
{
for
(
InsnArg
arg
:
phiInsn
.
getArguments
())
{
((
RegisterArg
)
arg
).
getSVar
().
setUsedInPhi
(
null
);
SSAVar
sVar
=
((
RegisterArg
)
arg
).
getSVar
();
if
(
sVar
!=
null
)
{
sVar
.
setUsedInPhi
(
null
);
}
}
InstructionRemover
.
remove
(
mth
,
block
,
phiInsn
);
}
...
...
jadx-core/src/main/java/jadx/core/utils/BlockUtils.java
View file @
577176dd
...
...
@@ -23,6 +23,8 @@ import java.util.LinkedList;
import
java.util.List
;
import
java.util.Set
;
import
org.jetbrains.annotations.Nullable
;
public
class
BlockUtils
{
private
BlockUtils
()
{
...
...
@@ -112,12 +114,17 @@ public class BlockUtils {
}
public
static
boolean
checkLastInsnType
(
BlockNode
block
,
InsnType
expectedType
)
{
InsnNode
insn
=
getLastInsn
(
block
);
return
insn
!=
null
&&
insn
.
getType
()
==
expectedType
;
}
@Nullable
public
static
InsnNode
getLastInsn
(
BlockNode
block
)
{
List
<
InsnNode
>
insns
=
block
.
getInstructions
();
if
(
insns
.
isEmpty
())
{
return
false
;
return
null
;
}
InsnNode
insn
=
insns
.
get
(
insns
.
size
()
-
1
);
return
insn
.
getType
()
==
expectedType
;
return
insns
.
get
(
insns
.
size
()
-
1
);
}
public
static
BlockNode
getBlockByInsn
(
MethodNode
mth
,
InsnNode
insn
)
{
...
...
@@ -135,7 +142,7 @@ public class BlockUtils {
return
null
;
}
p
rivate
static
BlockNode
searchBlockWithPhi
(
MethodNode
mth
,
PhiInsn
insn
)
{
p
ublic
static
BlockNode
searchBlockWithPhi
(
MethodNode
mth
,
PhiInsn
insn
)
{
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
PhiListAttr
phiListAttr
=
block
.
get
(
AType
.
PHI_LIST
);
if
(
phiListAttr
!=
null
)
{
...
...
@@ -225,7 +232,11 @@ public class BlockUtils {
}
public
static
List
<
BlockNode
>
bitSetToBlocks
(
MethodNode
mth
,
BitSet
bs
)
{
List
<
BlockNode
>
blocks
=
new
ArrayList
<
BlockNode
>(
bs
.
cardinality
());
int
size
=
bs
.
cardinality
();
if
(
size
==
0
)
{
return
Collections
.
emptyList
();
}
List
<
BlockNode
>
blocks
=
new
ArrayList
<
BlockNode
>(
size
);
for
(
int
i
=
bs
.
nextSetBit
(
0
);
i
>=
0
;
i
=
bs
.
nextSetBit
(
i
+
1
))
{
BlockNode
block
=
mth
.
getBasicBlocks
().
get
(
i
);
blocks
.
add
(
block
);
...
...
jadx-core/src/main/java/jadx/core/utils/RegionUtils.java
View file @
577176dd
...
...
@@ -183,10 +183,6 @@ public class RegionUtils {
return
true
;
}
}
if
(
tb
.
getFinalRegion
()
!=
null
&&
isRegionContainsRegion
(
tb
.
getFinalRegion
(),
region
))
{
return
true
;
}
}
if
(
isRegionContainsRegion
(
b
,
region
))
{
return
true
;
...
...
jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak.java
0 → 100644
View file @
577176dd
package
jadx
.
tests
.
integration
.
loops
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestDoWhileBreak
extends
IntegrationTest
{
public
static
class
TestCls
{
public
int
test
(
int
k
)
throws
InterruptedException
{
int
i
=
3
;
do
{
if
(
k
>
9
)
{
i
=
0
;
break
;
}
i
++;
}
while
(
i
<
5
);
return
i
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"while ("
));
}
}
jadx-core/src/test/java/jadx/tests/integration/synchronize/TestSynchronized.java
View file @
577176dd
...
...
@@ -38,5 +38,8 @@ public class TestSynchronized extends IntegrationTest {
assertThat
(
code
,
containsString
(
"synchronized (this.o) {"
));
assertThat
(
code
,
not
(
containsString
(
indent
(
3
)
+
";"
)));
assertThat
(
code
,
not
(
containsString
(
"try {"
)));
assertThat
(
code
,
not
(
containsString
(
"} catch (Throwable th) {"
)));
assertThat
(
code
,
not
(
containsString
(
"throw th;"
)));
}
}
jadx-core/src/test/java/jadx/tests/integration/trycatch/TestFinallyExtract.java
0 → 100644
View file @
577176dd
package
jadx
.
tests
.
integration
.
trycatch
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
java.io.IOException
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestFinallyExtract
extends
IntegrationTest
{
public
static
class
TestCls
{
public
String
test
()
throws
IOException
{
boolean
success
=
false
;
try
{
String
value
=
test
();
success
=
true
;
return
value
;
}
finally
{
if
(!
success
)
{
test
();
}
}
}
}
@Test
public
void
test
()
{
setOutputCFG
();
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"success = true;"
));
assertThat
(
code
,
containsOne
(
"return value;"
));
assertThat
(
code
,
containsOne
(
"try {"
));
assertThat
(
code
,
containsOne
(
"} finally {"
));
assertThat
(
code
,
containsOne
(
"if (!success) {"
));
}
}
jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch3.java
View file @
577176dd
...
...
@@ -6,27 +6,47 @@ import jadx.tests.api.IntegrationTest;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
public
class
TestTryCatch3
extends
IntegrationTest
{
public
static
class
TestCls
{
private
final
static
Object
obj
=
new
Object
();
private
boolean
mDiscovering
;
private
int
f
=
0
;
private
boolean
test
(
Object
obj
)
{
this
.
mDiscovering
=
false
;
boolean
res
;
try
{
exc
(
obj
);
res
=
exc
(
obj
);
}
catch
(
Exception
e
)
{
e
.
toString
()
;
res
=
false
;
}
finally
{
mDiscovering
=
true
;
f
++
;
}
return
mDiscovering
;
return
res
;
}
private
void
exc
(
Object
obj
)
throws
Exception
{
private
boolean
exc
(
Object
obj
)
throws
Exception
{
if
(
"r"
.
equals
(
obj
))
{
throw
new
AssertionError
();
}
return
true
;
}
public
void
check
()
{
f
=
0
;
assertTrue
(
test
(
null
));
assertEquals
(
1
,
f
);
f
=
0
;
try
{
test
(
"r"
);
}
catch
(
AssertionError
e
)
{
// pass
}
assertEquals
(
1
,
f
);
}
}
...
...
@@ -38,5 +58,16 @@ public class TestTryCatch3 extends IntegrationTest {
assertThat
(
code
,
containsString
(
"try {"
));
assertThat
(
code
,
containsString
(
"exc(obj);"
));
assertThat
(
code
,
containsString
(
"} catch (Exception e) {"
));
assertThat
(
code
,
not
(
containsString
(
"throw th;"
)));
}
@Test
public
void
test2
()
{
noDebugInfo
();
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
not
(
containsString
(
"throw th;"
)));
}
}
jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally.java
0 → 100644
View file @
577176dd
package
jadx
.
tests
.
integration
.
trycatch
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
public
class
TestTryCatchFinally
extends
IntegrationTest
{
public
static
class
TestCls
{
public
boolean
f
;
private
boolean
test
(
Object
obj
)
{
this
.
f
=
false
;
try
{
exc
(
obj
);
}
catch
(
Exception
e
)
{
e
.
getMessage
();
}
finally
{
f
=
true
;
}
return
f
;
}
private
static
boolean
exc
(
Object
obj
)
throws
Exception
{
if
(
obj
==
null
)
{
throw
new
Exception
(
"test"
);
}
return
(
obj
instanceof
String
);
}
public
void
check
()
{
assertTrue
(
test
(
"a"
));
assertTrue
(
test
(
null
));
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"exc(obj);"
));
assertThat
(
code
,
containsOne
(
"} catch (Exception e) {"
));
assertThat
(
code
,
containsOne
(
"e.getMessage();"
));
assertThat
(
code
,
containsOne
(
"} finally {"
));
assertThat
(
code
,
containsOne
(
"f = true;"
));
assertThat
(
code
,
containsOne
(
"return this.f;"
));
}
}
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