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
917cf20d
Commit
917cf20d
authored
Dec 28, 2013
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: fix decompiled lines info
parent
dabaeed8
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
156 additions
and
35 deletions
+156
-35
CodeWriter.java
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
+21
-1
InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+32
-26
RegionGen.java
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
+6
-5
ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+4
-1
InternalJadxTest.java
jadx-core/src/test/java/jadx/api/InternalJadxTest.java
+14
-2
TestLineNumbers.java
...re/src/test/java/jadx/tests/internal/TestLineNumbers.java
+79
-0
No files found.
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
View file @
917cf20d
...
...
@@ -17,7 +17,7 @@ public class CodeWriter {
private
static
final
int
MAX_FILENAME_LENGTH
=
128
;
public
static
final
String
NL
=
System
.
getProperty
(
"line.separator"
);
p
rivate
static
final
String
INDENT
=
"\t"
;
p
ublic
static
final
String
INDENT
=
"\t"
;
private
final
StringBuilder
buf
=
new
StringBuilder
();
private
String
indentStr
;
...
...
@@ -183,6 +183,10 @@ public class CodeWriter {
}
}
public
boolean
isEmpty
()
{
return
buf
.
length
()
==
0
;
}
public
boolean
notEmpty
()
{
return
buf
.
length
()
!=
0
;
}
...
...
@@ -227,4 +231,20 @@ public class CodeWriter {
}
}
@Override
public
int
hashCode
()
{
return
buf
.
toString
().
hashCode
();
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(!(
o
instanceof
CodeWriter
))
{
return
false
;
}
CodeWriter
that
=
(
CodeWriter
)
o
;
return
buf
.
toString
().
equals
(
that
.
buf
.
toString
());
}
}
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
View file @
917cf20d
...
...
@@ -77,38 +77,38 @@ public class InsnGen {
return
fallback
;
}
public
String
arg
(
InsnNode
insn
,
int
arg
)
throws
CodegenException
{
public
CodeWriter
arg
(
InsnNode
insn
,
int
arg
)
throws
CodegenException
{
return
arg
(
insn
.
getArg
(
arg
));
}
public
String
arg
(
InsnArg
arg
)
throws
CodegenException
{
public
CodeWriter
arg
(
InsnArg
arg
)
throws
CodegenException
{
return
arg
(
arg
,
true
);
}
public
String
arg
(
InsnArg
arg
,
boolean
wrap
)
throws
CodegenException
{
public
CodeWriter
arg
(
InsnArg
arg
,
boolean
wrap
)
throws
CodegenException
{
CodeWriter
code
=
new
CodeWriter
();
if
(
arg
.
isRegister
())
{
return
mgen
.
makeArgName
((
RegisterArg
)
arg
);
code
.
add
(
mgen
.
makeArgName
((
RegisterArg
)
arg
)
);
}
else
if
(
arg
.
isLiteral
())
{
return
lit
((
LiteralArg
)
arg
);
code
.
add
(
lit
((
LiteralArg
)
arg
)
);
}
else
if
(
arg
.
isInsnWrap
())
{
CodeWriter
code
=
new
CodeWriter
();
IGState
flag
=
wrap
?
IGState
.
BODY_ONLY
:
IGState
.
BODY_ONLY_NOWRAP
;
makeInsn
(((
InsnWrapArg
)
arg
).
getWrapInsn
(),
code
,
flag
);
return
code
.
toString
();
}
else
if
(
arg
.
isNamed
())
{
return
((
NamedArg
)
arg
).
getName
(
);
code
.
add
(((
NamedArg
)
arg
).
getName
()
);
}
else
if
(
arg
.
isField
())
{
FieldArg
f
=
(
FieldArg
)
arg
;
if
(
f
.
isStatic
())
{
return
sfield
(
f
.
getField
(
));
code
.
add
(
sfield
(
f
.
getField
()
));
}
else
{
RegisterArg
regArg
=
new
RegisterArg
(
f
.
getRegNum
());
regArg
.
replaceTypedVar
(
f
);
return
ifield
(
f
.
getField
(),
regArg
);
code
.
add
(
ifield
(
f
.
getField
(),
regArg
)
);
}
}
else
{
throw
new
CodegenException
(
"Unknown arg type "
+
arg
);
}
return
code
;
}
public
String
assignVar
(
InsnNode
insn
)
throws
CodegenException
{
...
...
@@ -116,7 +116,7 @@ public class InsnGen {
if
(
insn
.
getAttributes
().
contains
(
AttributeType
.
DECLARE_VARIABLE
))
{
return
declareVar
(
arg
);
}
else
{
return
arg
(
arg
);
return
arg
(
arg
)
.
toString
()
;
}
}
...
...
@@ -130,7 +130,7 @@ public class InsnGen {
private
String
ifield
(
FieldInfo
field
,
InsnArg
arg
)
throws
CodegenException
{
FieldNode
fieldNode
=
mth
.
getParentClass
().
searchField
(
field
);
if
(
fieldNode
!=
null
&&
fieldNode
.
getAttributes
().
contains
(
AttributeFlag
.
DONT_GENERATE
))
{
if
(
fieldNode
!=
null
&&
fieldNode
.
getAttributes
().
contains
(
AttributeFlag
.
DONT_GENERATE
))
{
return
""
;
}
String
name
=
field
.
getName
();
...
...
@@ -149,7 +149,7 @@ public class InsnGen {
return
name
;
}
}
String
argStr
=
arg
(
arg
);
CodeWriter
argStr
=
arg
(
arg
);
return
argStr
.
isEmpty
()
?
name
:
argStr
+
"."
+
name
;
}
...
...
@@ -162,7 +162,7 @@ public class InsnGen {
// Android specific resources class handler
ClassInfo
parentClass
=
declClass
.
getParentClass
();
if
(
parentClass
!=
null
&&
parentClass
.
getShortName
().
equals
(
"R"
))
{
return
useClass
(
parentClass
)
+
"."
+
declClass
.
getShortName
()
+
"."
+
field
.
getName
();
return
useClass
(
parentClass
)
+
"."
+
declClass
.
getShortName
()
+
"."
+
field
.
getName
();
}
return
useClass
(
declClass
)
+
'.'
+
field
.
getName
();
}
...
...
@@ -173,8 +173,9 @@ public class InsnGen {
if
(
field
.
getDeclClass
().
getFullName
().
equals
(
thisClass
))
{
// if we generate this field - don't init if its final and used
FieldNode
fn
=
mth
.
getParentClass
().
searchField
(
field
);
if
(
fn
!=
null
&&
fn
.
getAccessFlags
().
isFinal
())
if
(
fn
!=
null
&&
fn
.
getAccessFlags
().
isFinal
())
{
fn
.
getAttributes
().
remove
(
AttributeType
.
FIELD_VALUE
);
}
}
}
...
...
@@ -246,14 +247,16 @@ public class InsnGen {
case
CHECK_CAST:
case
CAST:
{
boolean
wrap
=
state
.
contains
(
IGState
.
BODY_ONLY
);
if
(
wrap
)
if
(
wrap
)
{
code
.
add
(
"("
);
}
code
.
add
(
"("
);
code
.
add
(
useType
(((
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
())));
code
.
add
(
") "
);
code
.
add
(
arg
(
insn
.
getArg
(
0
)));
if
(
wrap
)
if
(
wrap
)
{
code
.
add
(
")"
);
}
break
;
}
case
ARITH:
...
...
@@ -270,10 +273,11 @@ public class InsnGen {
break
;
case
RETURN:
if
(
insn
.
getArgsCount
()
!=
0
)
if
(
insn
.
getArgsCount
()
!=
0
)
{
code
.
add
(
"return "
).
add
(
arg
(
insn
.
getArg
(
0
),
false
));
else
}
else
{
code
.
add
(
"return"
);
}
break
;
case
BREAK:
...
...
@@ -318,8 +322,9 @@ public class InsnGen {
ArgType
arrayType
=
insn
.
getResult
().
getType
();
int
dim
=
arrayType
.
getArrayDimension
();
code
.
add
(
"new "
).
add
(
useType
(
arrayType
.
getArrayRootElement
())).
add
(
'['
).
add
(
arg
(
insn
,
0
)).
add
(
']'
);
for
(
int
i
=
0
;
i
<
dim
-
1
;
i
++)
for
(
int
i
=
0
;
i
<
dim
-
1
;
i
++)
{
code
.
add
(
"[]"
);
}
break
;
}
...
...
@@ -460,8 +465,9 @@ public class InsnGen {
code
.
add
(
'{'
);
for
(
int
i
=
0
;
i
<
c
;
i
++)
{
code
.
add
(
arg
(
insn
,
i
));
if
(
i
+
1
<
c
)
if
(
i
+
1
<
c
)
{
code
.
add
(
", "
);
}
}
code
.
add
(
'}'
);
}
...
...
@@ -581,8 +587,8 @@ public class InsnGen {
InsnArg
arg
=
insn
.
getArg
(
0
);
// FIXME: add 'this' for equals methods in scope
if
(!
arg
.
isThis
())
{
String
argStr
=
arg
(
arg
);
if
(!
argStr
.
isEmpty
())
{
CodeWriter
argStr
=
arg
(
arg
);
if
(!
argStr
.
isEmpty
())
{
code
.
add
(
argStr
).
add
(
'.'
);
}
}
...
...
@@ -685,15 +691,15 @@ public class InsnGen {
private
void
makeArith
(
ArithNode
insn
,
CodeWriter
code
,
EnumSet
<
IGState
>
state
)
throws
CodegenException
{
ArithOp
op
=
insn
.
getOp
();
String
v1
=
arg
(
insn
.
getArg
(
0
));
String
v2
=
arg
(
insn
.
getArg
(
1
));
CodeWriter
v1
=
arg
(
insn
.
getArg
(
0
));
CodeWriter
v2
=
arg
(
insn
.
getArg
(
1
));
if
(
state
.
contains
(
IGState
.
BODY_ONLY
))
{
// wrap insn in brackets for save correct operation order
code
.
add
(
'('
).
add
(
v1
).
add
(
' '
).
add
(
op
.
getSymbol
()).
add
(
' '
).
add
(
v2
).
add
(
')'
);
}
else
if
(
state
.
contains
(
IGState
.
BODY_ONLY_NOWRAP
))
{
code
.
add
(
v1
).
add
(
' '
).
add
(
op
.
getSymbol
()).
add
(
' '
).
add
(
v2
);
}
else
{
String
res
=
arg
(
insn
.
getResult
());
CodeWriter
res
=
arg
(
insn
.
getResult
());
if
(
res
.
equals
(
v1
)
&&
insn
.
getResult
().
equals
(
insn
.
getArg
(
0
)))
{
state
.
add
(
IGState
.
NO_RESULT
);
// "++" or "--"
...
...
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
View file @
917cf20d
...
...
@@ -60,8 +60,9 @@ public class RegionGen extends InsnGen {
if
(
tc
!=
null
)
{
makeTryCatch
(
cont
,
tc
.
getTryBlock
(),
code
);
}
else
{
for
(
IContainer
c
:
r
.
getSubBlocks
())
for
(
IContainer
c
:
r
.
getSubBlocks
())
{
makeRegion
(
code
,
c
);
}
}
}
else
if
(
cont
instanceof
IfRegion
)
{
code
.
startLine
();
...
...
@@ -214,7 +215,7 @@ public class RegionGen extends InsnGen {
op
=
op
.
invert
();
}
if
(
op
==
IfOp
.
EQ
)
{
return
arg
(
firstArg
,
false
);
// == true
return
arg
(
firstArg
,
false
)
.
toString
()
;
// == true
}
else
if
(
op
==
IfOp
.
NE
)
{
return
"!"
+
arg
(
firstArg
);
// != true
}
...
...
@@ -257,8 +258,7 @@ public class RegionGen extends InsnGen {
code
.
startLine
(
"case "
);
if
(
k
instanceof
IndexInsnNode
)
{
code
.
add
(
sfield
((
FieldInfo
)
((
IndexInsnNode
)
k
).
getIndex
()));
}
else
{
}
else
{
code
.
add
(
TypeGen
.
literalToString
((
Integer
)
k
,
arg
.
getType
()));
}
code
.
add
(
':'
);
...
...
@@ -295,8 +295,9 @@ public class RegionGen extends InsnGen {
if
(!
handler
.
isCatchAll
())
{
makeCatchBlock
(
code
,
handler
);
}
else
{
if
(
allHandler
!=
null
)
if
(
allHandler
!=
null
)
{
LOG
.
warn
(
"Several 'all' handlers in try/catch block in "
+
mth
);
}
allHandler
=
handler
;
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
View file @
917cf20d
...
...
@@ -295,7 +295,10 @@ public class ClassNode extends LineAttrNode implements ILoadable {
}
public
FieldNode
searchField
(
FieldInfo
field
)
{
String
name
=
field
.
getName
();
return
searchFieldByName
(
field
.
getName
());
}
public
FieldNode
searchFieldByName
(
String
name
)
{
for
(
FieldNode
f
:
fields
)
{
if
(
f
.
getName
().
equals
(
name
))
return
f
;
...
...
jadx-core/src/test/java/jadx/api/InternalJadxTest.java
View file @
917cf20d
...
...
@@ -25,6 +25,8 @@ import static junit.framework.Assert.fail;
public
abstract
class
InternalJadxTest
{
protected
boolean
outputCFG
=
false
;
protected
boolean
deleteTmpJar
=
true
;
protected
String
outDir
=
"test-out-tmp"
;
public
ClassNode
getClassNode
(
Class
<?>
clazz
)
{
...
...
@@ -40,7 +42,7 @@ public abstract class InternalJadxTest {
String
clsName
=
clazz
.
getName
();
ClassNode
cls
=
null
;
for
(
ClassNode
aClass
:
classes
)
{
if
(
aClass
.
getFullName
().
equals
(
clsName
))
{
if
(
aClass
.
getFullName
().
equals
(
clsName
))
{
cls
=
aClass
;
}
}
...
...
@@ -90,7 +92,11 @@ public abstract class InternalJadxTest {
add
(
file
,
path
+
"/"
+
file
.
getName
(),
jo
);
}
jo
.
close
();
temp
.
deleteOnExit
();
if
(
deleteTmpJar
)
{
temp
.
deleteOnExit
();
}
else
{
System
.
out
.
println
(
"Temporary jar file path: "
+
temp
.
getAbsolutePath
());
}
return
temp
;
}
...
...
@@ -145,4 +151,10 @@ public abstract class InternalJadxTest {
protected
void
setOutputCFG
()
{
this
.
outputCFG
=
true
;
}
// Use only for debug purpose
@Deprecated
protected
void
notDeleteTmpJar
()
{
this
.
deleteTmpJar
=
false
;
}
}
jadx-core/src/test/java/jadx/tests/internal/TestLineNumbers.java
0 → 100644
View file @
917cf20d
package
jadx
.
tests
.
internal
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.attributes.LineAttrNode
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestLineNumbers
extends
InternalJadxTest
{
public
static
class
TestCls
extends
Exception
{
int
field
;
public
void
func
()
{
}
public
static
class
Inner
{
int
innerField
;
public
void
innerFunc
()
{
}
public
void
innerFunc2
()
{
new
Runnable
()
{
@Override
public
void
run
()
{
}
}.
run
();
}
public
void
innerFunc3
()
{
}
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
FieldNode
field
=
cls
.
searchFieldByName
(
"field"
);
MethodNode
func
=
cls
.
searchMethodByName
(
"func()V"
);
ClassNode
inner
=
cls
.
getInnerClasses
().
get
(
0
);
MethodNode
innerFunc
=
inner
.
searchMethodByName
(
"innerFunc()V"
);
MethodNode
innerFunc2
=
inner
.
searchMethodByName
(
"innerFunc2()V"
);
MethodNode
innerFunc3
=
inner
.
searchMethodByName
(
"innerFunc3()V"
);
FieldNode
innerField
=
inner
.
searchFieldByName
(
"innerField"
);
// check source lines (available only for instructions and methods)
int
testClassLine
=
18
;
assertEquals
(
testClassLine
+
3
,
func
.
getSourceLine
());
assertEquals
(
testClassLine
+
9
,
innerFunc
.
getSourceLine
());
assertEquals
(
testClassLine
+
12
,
innerFunc2
.
getSourceLine
());
assertEquals
(
testClassLine
+
20
,
innerFunc3
.
getSourceLine
());
// check decompiled lines
String
[]
lines
=
code
.
split
(
CodeWriter
.
NL
);
checkLine
(
lines
,
field
,
"int field;"
);
checkLine
(
lines
,
func
,
"public void func() {"
);
checkLine
(
lines
,
inner
,
"public static class Inner {"
);
checkLine
(
lines
,
innerField
,
"int innerField;"
);
checkLine
(
lines
,
innerFunc
,
"public void innerFunc() {"
);
checkLine
(
lines
,
innerFunc2
,
"public void innerFunc2() {"
);
checkLine
(
lines
,
innerFunc3
,
"public void innerFunc3() {"
);
}
private
static
void
checkLine
(
String
[]
lines
,
LineAttrNode
node
,
String
str
)
{
int
lineNumber
=
node
.
getDecompiledLine
();
String
line
=
lines
[
lineNumber
-
1
];
assertThat
(
line
,
containsString
(
str
));
}
}
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