git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@360 379699f6-c40d-0410-875b-85095c16579estable
parent
77f2fbe9d7
commit
633f044a20
@ -0,0 +1,11 @@ |
||||
\input texinfo @c -*- texinfo -*- |
||||
|
||||
@setfilename jode.info |
||||
@settitle Jode, a Java Decompiler |
||||
@direntry |
||||
* Jode: (jode). A Java Decompiler |
||||
@end direntry |
||||
|
||||
|
||||
@include technical.texi |
||||
@bye |
@ -0,0 +1,200 @@ |
||||
@node Technical Info, Top, Top, Top |
||||
@chapter Technical Information |
||||
|
||||
This chapter contains information, how the decompiler works. |
||||
|
||||
@menu |
||||
* Types:: |
||||
* Expression analysis:: |
||||
* Flow analysis:: |
||||
* Solving unknown stack-ops:: |
||||
* Highlevel analysis:: |
||||
@end menu |
||||
|
||||
@node Types, Expression analysis, Technical Info, Technical Info |
||||
@section Type checking and guessing |
||||
@cindex Types, Conversions |
||||
|
||||
The type class has the following operators: |
||||
|
||||
getSubType |
||||
getSuperType |
||||
intersection |
||||
(getCastHelper?) |
||||
(getImplicitCast?) |
||||
|
||||
reference types (classes, interfaces, arrays and null type) often appear |
||||
in ranges. They have the methods: |
||||
|
||||
createRangeType |
||||
getSpecializedType |
||||
getGeneralizedType |
||||
|
||||
The meaning is |
||||
ref1.intersection(ref2) = |
||||
ref1.getSpecializedType(ref2).createRangeType(ref1.getGeneralizedType(ref2)) |
||||
|
||||
<Object - NULL> |
||||
<Object[] - NULL> |
||||
<Object[] - Serialized[]> |
||||
<tUnknown[]> |
||||
<Object - tUnknown[]> |
||||
{IBCS}[] intersect {CSZ}[] = {CS}[] |
||||
<Object - {ICSB}[]> intersect <Serializable - {CSZ}[]> |
||||
--> <Serializable - { |
||||
|
||||
The byte code distinguishes five different types: |
||||
|
||||
@enumerate |
||||
@item 16 bit integral types (boolean, byte, short, char and int) |
||||
@item long |
||||
@item float |
||||
@item double |
||||
@item reference types (objects, interfaces, arrays, null type) |
||||
@end enumerate |
||||
|
||||
It sometimes makes a difference between byte, short, char and int, but |
||||
not always. |
||||
|
||||
|
||||
16bit integral types: |
||||
|
||||
We differ seven different 16 bit integral types: |
||||
@table @asis |
||||
@item I |
||||
@code{int} type |
||||
@item C |
||||
@code{char} type |
||||
@item S |
||||
@code{short} type |
||||
@item B |
||||
@code{byte} type |
||||
@item Z |
||||
@code{boolean} type |
||||
@item cS |
||||
An @code{int} constant whose value is in @code{short} range. |
||||
@item cB |
||||
An @code{int} constant whose value is in @code{byte} range. |
||||
@end table |
||||
|
||||
Each of this types has a super range and a sub range: |
||||
@multitable {type} {(I,C,S,B,Z,cS,cB)} {(I,C,S,B,Z,cS,cB)} |
||||
@item type @tab sub types @tab super types |
||||
@item I @tab (I,C,S,B,cS,cB) @tab (I) |
||||
@item C @tab (C) @tab (I,C) |
||||
@item S @tab (S,B,cS,cB) @tab (I,S) |
||||
@item B @tab (B,cB) @tab (I,S,B) |
||||
@item Z @tab (Z) @tab (Z) |
||||
@item cS @tab (cS,cB) @tab (I,S,cS) |
||||
@item cB @tab (cB) @tab (I,S,B,cS,cB) |
||||
@end multitable |
||||
|
||||
getTop() getBottom() give the type directly. |
||||
|
||||
createRangeType(Type bottom) does the following: |
||||
If top == tUnknown , union all supertypes |
||||
If top is 16bit type, |
||||
intersect (union of subtypes of top) (union of supertypes) |
||||
Return tError otherwise. |
||||
|
||||
Type.createRangeType(Type top) does the following: |
||||
if Type == tUnknown |
||||
if top is IntegerType |
||||
new IntegerType(union of subtypes of top) |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hints. We distinguish strong and weak Hints: |
||||
|
||||
strong Hints: |
||||
assignment: |
||||
lhs.strongHint = mergeHint(lhs.strongHint, rhs.strongHint) |
||||
lhs.weakHint = mergeHint(lhs.weakHint, rhs.weakHint) |
||||
rhs.strongHint = lhs.strongHint |
||||
|
||||
|
||||
binary op: |
||||
left.weakHint = mergeHints(left.weakHint, right.strongHint?strongHint: weakHint) |
||||
|
||||
binary op |
||||
types that may occur directly in bytecode: |
||||
(I,Z) |
||||
(I) |
||||
(Z) |
||||
(I,C,S,B,Z) |
||||
(I,cS,cB) |
||||
(I,cS) |
||||
(I,C,cS,cB) |
||||
(I,C,cS) |
||||
(I,C) |
||||
(C) |
||||
(S) |
||||
(B) |
||||
(B,Z) |
||||
|
||||
now the sub (>) and super (<) operators |
||||
|
||||
>(I,Z) = (I,C,S,B,Z,cS,cB) New! |
||||
>(I) = (I,C,S,B,cS,cB) New! |
||||
>(Z) = (Z) |
||||
>(I,C,S,B,Z) = (I,C,S,B,Z,cS,cB) |
||||
>(I,cS,cB) = (I,C,S,B,cS,cB) |
||||
>(I,cS) = (I,C,S,B,cS,cB) |
||||
>(I,C,cS,cB) = (I,C,S,B,cS,cB) |
||||
>(I,C,cS) = (I,C,S,B,cS,cB) |
||||
>(I,C) = (I,C,S,B,cS,cB) |
||||
>(C) = (C) |
||||
>(S) = (S,B,cS,cB) New! |
||||
>(B) = (B,cB) New! |
||||
>(B,Z) = (B,Z,cB) New! |
||||
|
||||
<(I,Z) = (I,Z) |
||||
<(I) = (I) |
||||
<(Z) = (Z) |
||||
<(I,C,S,B,Z) = (I,C,S,B,Z) |
||||
<(I,cS,cB) = (I,S,B,cS,cB) New! |
||||
<(I,cS) = (I,S,cS) New! |
||||
<(I,C,cS,cB) = (I,C,S,B,cS,cB) |
||||
<(I,C,cS) = (I,C,S,cS) New! |
||||
<(I,C) = (I,C) |
||||
<(C) = (I,C) |
||||
<(S) = (I,S) New! |
||||
<(B) = (I,S,B) New! |
||||
<(B,Z) = (I,S,B,Z) New! |
||||
|
||||
>(I,C,S,B,Z,cS,cB) = (I,C,S,B,Z,cS,cB) |
||||
>(I,C,S,B,cS,cB) = (I,C,S,B,cS,cB) |
||||
>(B,Z,cB) = (B,Z,cB) |
||||
>(I,C,S,cS) = (I,C,S,B,cS,cB) |
||||
>(I,S,B,Z) = (I,C,S,B,Z,cS,cB) |
||||
>(I,S,B,cS,cB) = (I,C,S,B,cS,cB) |
||||
|
||||
<(I,C,S,B,Z,cS,cB) = (I,C,S,B,Z,cS,cB) |
||||
<(I,C,S,B,cS,cB) = (I,C,S,B,cS,cB) |
||||
<(B,Z,cB) = (I,S,B,Z,cS,cB) |
||||
<(I,C,S,cS) = (I,C,S,cS) |
||||
<(I,S,B,Z) = (I,S,B,Z) |
||||
<(I,S,B,cS,cB) = (I,S,B,cS,cB) |
||||
|
||||
|
||||
Zu betrachtende 32bit Typen: |
||||
|
||||
(I,Z) = (I,Z) |
||||
(I) = (I) |
||||
(Z) = (Z) |
||||
(I,C,S,B,Z) |
||||
(I,cS,cB) |
||||
(I,cS) |
||||
(I,C,cS,cB) |
||||
(I,C,cS) |
||||
(I,C) |
||||
(B,Z) |
||||
(I,C,S,B,Z,cS,cB) |
||||
(I,C,S,B,cS,cB) |
||||
(B,Z,cB) |
||||
(I,C,S,cS) |
||||
(I,S,B,Z) |
||||
(I,S,B,cS,cB) |
||||
|
@ -0,0 +1,288 @@ |
||||
/* |
||||
* IntegerType (c) 1998 Jochen Hoenicke |
||||
* |
||||
* You may distribute under the terms of the GNU General Public License. |
||||
* |
||||
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, |
||||
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF |
||||
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE |
||||
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
||||
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" |
||||
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, |
||||
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||||
* |
||||
* $Id$ |
||||
*/ |
||||
|
||||
package jode; |
||||
|
||||
/** |
||||
* This is a type class for 16 bit integral types. There are seven |
||||
* different types, namely <code>int, char, short, byte, boolean, |
||||
* const short, const byte</code> abbreviated <code>I, C, S, B, Z, cS, |
||||
* cB</code>. <code>cB</code> and <code>cS</code> specify constant |
||||
* ints whose value is in byte resp. short range. They may be |
||||
* converted to B resp. S, but sometimes need an explicit cast. |
||||
* |
||||
* @author Jochen Hoenicke */ |
||||
public class IntegerType extends Type { |
||||
|
||||
public static final int IT_I = 0x01; |
||||
public static final int IT_C = 0x02; |
||||
public static final int IT_S = 0x04; |
||||
public static final int IT_B = 0x08; |
||||
public static final int IT_Z = 0x10; |
||||
public static final int IT_cS = 0x20; |
||||
public static final int IT_cB = 0x40; |
||||
private static final int NUM_TYPES = 7; |
||||
|
||||
private static final int[] subTypes = { |
||||
/*I*/ IT_I|IT_C|IT_S|IT_B/*|IT_cS|IT_cB*/, /*C*/ IT_C, |
||||
/*S*/ IT_S|IT_B/*|IT_cS|IT_cB*/, /*B*/ IT_B/*|IT_cB*/, |
||||
/*Z*/ IT_Z, |
||||
/*cS*/IT_cS|IT_cB, /*cB*/IT_cB |
||||
}; |
||||
private static final int[] superTypes = { |
||||
/*I*/ IT_I, /*C*/ IT_I|IT_C, |
||||
/*S*/ IT_I|IT_S, /*B*/ IT_I|IT_S|IT_B, |
||||
/*Z*/ IT_Z, |
||||
/*cS*/IT_I|IT_C|IT_S|IT_cS, /*cB*/IT_I|IT_C|IT_S|IT_B|IT_cS|IT_cB |
||||
}; |
||||
private static final Type[] simpleTypes = { |
||||
new IntegerType(IT_I), new IntegerType(IT_C), |
||||
new IntegerType(IT_S), new IntegerType(IT_B), |
||||
new IntegerType(IT_Z), |
||||
new IntegerType(IT_cS), new IntegerType(IT_cB) |
||||
}; |
||||
private static final String[] typeNames = { |
||||
"I","C","S","B","Z","cS","cB" |
||||
}; |
||||
|
||||
|
||||
int possTypes; |
||||
int strongHint = 0; |
||||
int weakHint = 0; |
||||
|
||||
/** |
||||
* Create a new type with the given type. |
||||
*/ |
||||
public IntegerType(int types) { |
||||
super(TC_INTEGER); |
||||
possTypes = types; |
||||
} |
||||
|
||||
public Type getHint() { |
||||
int hint = ((possTypes & IT_Z) != 0 ? IT_Z |
||||
: strongHint != 0 ? strongHint |
||||
: weakHint != 0 ? weakHint |
||||
: possTypes); |
||||
int i = 0; |
||||
for (int it = 0x1; (it & hint) == 0; it <<= 1) |
||||
i++; |
||||
return simpleTypes[i]; |
||||
} |
||||
|
||||
private int getSubTypes() { |
||||
int result = 0; |
||||
for (int i=0; i < NUM_TYPES; i++) { |
||||
if (((1<<i) & possTypes) != 0) |
||||
result |= subTypes[i]; |
||||
} |
||||
return result; |
||||
} |
||||
private int getSuperTypes() { |
||||
int result = 0; |
||||
for (int i=0; i < NUM_TYPES; i++) { |
||||
if (((1<<i) & possTypes) != 0) |
||||
result |= superTypes[i]; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public Type getSubType() { |
||||
return new IntegerType(getSubTypes()); |
||||
} |
||||
|
||||
public Type getSuperType() { |
||||
return new IntegerType(getSuperTypes()); |
||||
} |
||||
|
||||
// /**
|
||||
// * Returns the common sub type of this and type.
|
||||
// * @param type the other type.
|
||||
// * @return the common sub type.
|
||||
// */
|
||||
// public Type getSpecializedType(Type type) {
|
||||
// /* tError , x -> tError
|
||||
// * x , tUnknown -> x
|
||||
// * Integer , Integer -> possTypes1 & possTypes2 == 0 ? tError
|
||||
// */
|
||||
// if (type == tUnknown)
|
||||
// return this;
|
||||
// if (type.typecode != TC_INTEGER)
|
||||
// return tError;
|
||||
// IntegerType other = (IntegerType) type;
|
||||
// int mergeTypes = possTypes & other.possTypes;
|
||||
// /* HINTING XXX */
|
||||
// if (mergeTypes == possTypes)
|
||||
// return this;
|
||||
// if (mergeTypes == other.possTypes)
|
||||
// return other;
|
||||
// if (mergeTypes == 0)
|
||||
// return tError;
|
||||
// return new IntegerType(mergeTypes);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Returns the common super type of this and type.
|
||||
// * @param type the other type.
|
||||
// * @return the common super type.
|
||||
// */
|
||||
// public Type getGeneralizedType(Type type) {
|
||||
// return getSpecializedType(type);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Create the type corresponding to the range from bottomType to this.
|
||||
// * @param bottomType the start point of the range
|
||||
// * @return the range type, or tError if not possible.
|
||||
// */
|
||||
// public Type intersection(Type bottomType) {
|
||||
// /* Note that this can't be tBoolByte or tBoolInt */
|
||||
// /* x , tError -> tError
|
||||
// * object , tUnknown -> <object, tUnknown>
|
||||
// * boolean , tUnknown -> boolean
|
||||
// * int , tUnknown -> <int, byte>
|
||||
// * boolint , tUnknown -> boolint
|
||||
// * tUnknown, x -> getSuperTypes(x)
|
||||
// * tUnknown, short -> <int, short>
|
||||
// * short , byte -> <short, byte>
|
||||
// * byte , short -> tError
|
||||
// * tUnknown, float -> float
|
||||
// */
|
||||
// if (bottomType == tUnknown)
|
||||
// return this;
|
||||
// else if (bottomType.typecode != TC_INTEGER)
|
||||
// return tError;
|
||||
// /*XXX HINTING*/
|
||||
|
||||
// int result = ((IntegerType)bottomType).possTypes & possTypes;
|
||||
// return new IntegerType(result);
|
||||
// }
|
||||
|
||||
/** |
||||
* Checks if this type represents a valid type instead of a list |
||||
* of minimum types. |
||||
*/ |
||||
public boolean isValidType() { |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Check if this and <unknown -- type&rt; are not disjunct. |
||||
* @param type a simple type; this mustn't be a range type. |
||||
* @return true if this is the case. |
||||
*/ |
||||
public boolean isOfType(Type type) { |
||||
return (type.typecode == TC_INTEGER |
||||
&& (((IntegerType)type).possTypes & possTypes) != 0); |
||||
} |
||||
|
||||
public String getDefaultName() { |
||||
switch (((IntegerType)getHint()).possTypes) { |
||||
case IT_Z: |
||||
return "bool"; |
||||
case IT_C: |
||||
return "c"; |
||||
case IT_B: |
||||
case IT_S: |
||||
case IT_I: |
||||
return "i"; |
||||
default: |
||||
throw new jode.AssertError("Local can't be of constant type!"); |
||||
} |
||||
} |
||||
|
||||
public String getTypeSignature() { |
||||
switch (((IntegerType)getHint()).possTypes) { |
||||
case IT_Z: |
||||
return "Z"; |
||||
case IT_C: |
||||
return "C"; |
||||
case IT_B: |
||||
return "B"; |
||||
case IT_S: |
||||
return "S"; |
||||
case IT_I: |
||||
default: |
||||
return "I"; |
||||
} |
||||
} |
||||
|
||||
public String toString() { |
||||
switch (possTypes) { |
||||
case IT_Z: |
||||
return "boolean"; |
||||
case IT_C: |
||||
return "char"; |
||||
case IT_B: |
||||
return "byte"; |
||||
case IT_S: |
||||
return "short"; |
||||
case IT_I: |
||||
return "int"; |
||||
default: |
||||
StringBuffer sb = new StringBuffer("{"); |
||||
String comma = ""; |
||||
for (int i=0; i< NUM_TYPES; i++) |
||||
if (((1<<i) & possTypes) != 0) { |
||||
sb.append(comma).append(typeNames[i]); |
||||
comma = ","; |
||||
} |
||||
sb.append("}"); |
||||
return sb.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Intersect this type with another type and return the new type. |
||||
* @param type the other type. |
||||
* @return the intersection, or tError, if a type conflict happens. |
||||
*/ |
||||
public Type intersection(Type type) { |
||||
if (type == tError) |
||||
return type; |
||||
if (type == tUnknown) |
||||
return this; |
||||
|
||||
int mergeTypes; |
||||
if (type.typecode != TC_INTEGER) |
||||
mergeTypes = 0; |
||||
else { |
||||
IntegerType other = (IntegerType) type; |
||||
mergeTypes = possTypes & other.possTypes; |
||||
/* HINTING XXX */ |
||||
if (mergeTypes == possTypes) |
||||
return this; |
||||
if (mergeTypes == other.possTypes) |
||||
return other; |
||||
} |
||||
Type result = mergeTypes == 0 ? tError : new IntegerType(mergeTypes); |
||||
if (Decompiler.isTypeDebugging || result == tError) { |
||||
Decompiler.err.println("intersecting "+ this +" and "+ type + |
||||
" to " + result); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (o == this) |
||||
return true; |
||||
if (o instanceof IntegerType) |
||||
return ((IntegerType)o).possTypes == possTypes; |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
package jode; |
||||
public class NullType extends ClassInterfacesType { |
||||
public NullType() { |
||||
super(null, null); |
||||
typecode = TC_NULL; |
||||
} |
||||
|
||||
public Type createRangeType(ClassInterfacesType bottomType) { |
||||
return tRange(bottomType, this); |
||||
} |
||||
|
||||
/** |
||||
* Returns the generalized type of this and type. We have two |
||||
* classes and multiple interfaces. The result should be the |
||||
* object that is the the super class of both objects and all |
||||
* interfaces, that one class or interface of each type |
||||
* implements. */ |
||||
public Type getGeneralizedType(Type type) { |
||||
if (type.typecode == TC_RANGE) |
||||
type = ((RangeType) type).getTop(); |
||||
return type; |
||||
} |
||||
/** |
||||
* Returns the specialized type of this and type. |
||||
* We have two classes and multiple interfaces. The result |
||||
* should be the object that extends both objects |
||||
* and the union of all interfaces. |
||||
*/ |
||||
public Type getSpecializedType(Type type) { |
||||
if (type.typecode == TC_RANGE) |
||||
type = ((RangeType) type).getBottom(); |
||||
return type; |
||||
} |
||||
|
||||
/** |
||||
* Marks this type as used, so that the class is imported. |
||||
*/ |
||||
public void useType() { |
||||
} |
||||
|
||||
public String toString() { |
||||
return "/*NULL*/" + env.classString("java.lang.Object"); |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
return o == this; |
||||
} |
||||
|
||||
/** |
||||
* Intersect this type with another type and return the new type. |
||||
* @param type the other type. |
||||
* @return the intersection, or tError, if a type conflict happens. |
||||
*/ |
||||
public Type intersection(Type type) { |
||||
throw new AssertError("NULL.intersection"); |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue