In api 28, the vdex files in, e.g. the framework/arm directory are actually
just sym links to a shared vdex file in the framework directory. However,
the sym links use an absolute path, and so they don't resolve correctly in
the loop mounted system image.
As a simple workaround, we'll just search upward one directory in the path
if the vdex file can't be resolved.
Oat version 138 introduced the concept of an "uncompressed" dex file, where
the dex file is listed in the oat file, but it's not actually present in
the oat or vdex files, instead, it's in the apk as per usual.
This change makes dexlib2 ignore these files, treating them as if they are
not a part of the oat file.
Newer versions of art seem to use ! instead of : to separate the
inner dex filename from the name of the container containing it.
e.g.
/system/framework/framework.jar!classes2.dex
instead of
/system/framework/framework.jar:classes2.dex
Loading cdex files is mostly supported, except for the new debug info
structures.
Dumping is somewhat supported, but only when there's a single cdex file
in the vdex.
For cdex files, offsets into the data section are specified relative to
the start of the data section, instead of relative to the start of the dex
file.
This adds a separate data buffer that can be used to resolve these
references.
isOdexFile was no longer being used, and hasOdexOpcodes had a slightly
misleading name, since it could potentially return true for an odex or
oat embedded dex file that didn't actually have any odex opcodes.
The current implementation only supported 6 of the possible kind values for a MethodHandle object.
However, as the link below shows there are in fact 9. All 9 can be seen in the MethodHandleType
class which is used by dexdump to translate the kind value of a MethodHandle object to a string
representation.
https://android.googlesource.com/platform/art/+/android-8.1.0_r41/runtime/dex_file.h
Moreover, this in fact lines up with the 9 different kinds for a MethodHandle object in standard
java bytecode (though the values are swapped around for some reason).
https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandleInfo.html
These changes add in the additional 3 kind values and make sure all nesscary hooks using the
kind values of MethodHandle reference them.
For testing purposes, I found the easiest way to get correctly formatted invoke-custom and
invoke-polymorphic instructions was to use the already generated dex files used to test
dexdump. They can be found at the link below (invoke-custom.dex and invoke-polymorphic.dex).
https://android.googlesource.com/platform/art/+/android-8.1.0_r41/test/dexdump/
Previously the offset of the method prototype was 3 bytes from the
instruction start for both instructions. This would put it somewhere in
the middle of the register values and method reference. Changed it to
the correct offset which is 6 bytes in both cases.
45cc Instruction Format
op(8 bits)
number_of_regs(4 bits)
reg_g(4 bits)
method_reference(16 bits)
reg_d(4 bits)
reg_c(4 bits)
reg_f(4 bits)
ref_e(4 bits)
method_prototype(16 bits)
Example of invoke-polymorphic using 45cc
Instruction: fa302f0021030800
DexDump: invoke-polymorphic {v1, v2, v3}, Ljava/lang/invoke/MethodHandle;
.invoke:([Ljava/lang/Object;)Ljava/lang/Object;,
(II)Ljava/lang/Object; // method@002f, proto@0008
4rcc Instruction Format
op(8 bits)
number_of_regs(8 bits)
method_reference(16 bits)
start_register(16 bits)
method_prototype(16 bits)
Example of invoke-polymorphic using 4rcc
Instruction: fb092f0000000800
DexDump: invoke-polymorphic/range {v0, v1, v2, v3, v4, v5, v6, v7, v8},
Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)
Ljava/lang/Object;, (IIIIIIILjava/lang/String;)Ljava/lang/Object;
// method@002f, proto@0008