I am trying to instrument branches using dexlib2. However, since certain instructions only allow to use the local registers v0-v15 and my instrumentation requires one additional register, it is necessary to save the value of v0, use v0 for the actual instrumentation and after restore the original value of v0. This is done by two move instructions, e.g.
move vNew, v0
... // actual instrumentation code using v0
move v0, vNew
However, it is necessary to use the correct move instruction. In particular, we need to distinguish between move, move-wide and move-object depending on type of v0 (the content of it). Fortunately, dexlib2 provides some MethodAnalyzer, which performs this kind of analysis, but the MethodAnalyzer called as follows:
analyzer = new MethodAnalyzer(new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)),true, ClassPath.NOT_ART), method, null, true);
fails with certain classes like java/lang/StringBuilder. For instance, the following stack-trace is produced:
org.jf.dexlib2.analysis.UnresolvedClassException: Could not resolve class Ljava/lang/StringBuilder;
at org.jf.dexlib2.analysis.ClassPath.getClassDef(ClassPath.java:155)
at org.jf.dexlib2.analysis.ClassProto$1.get(ClassProto.java:93)
at org.jf.dexlib2.analysis.ClassProto$1.get(ClassProto.java:91)
at com.google.common.base.Suppliers$MemoizingSupplier.get(Suppliers.java:125)
at org.jf.dexlib2.analysis.ClassProto.getClassDef(ClassProto.java:87)
at org.jf.dexlib2.analysis.ClassProto.getSuperclass(ClassProto.java:326)
at org.jf.dexlib2.analysis.MethodAnalyzer.normalizeMethodReference(MethodAnalyzer.java:1987)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyzeInvokeVirtual(MethodAnalyzer.java:1756)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyzeInstruction(MethodAnalyzer.java:798)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyze(MethodAnalyzer.java:201)
at org.jf.dexlib2.analysis.MethodAnalyzer.<init>(MethodAnalyzer.java:131)
at BranchCoverage.main(BranchCoverage.java:578)
Update:
The MethodAnalyzer seems to work now. However, my instrumentation still ends up with some verify errors. In particular, the following stack trace is produced:
12-30 09:45:55.415 3486-3486/ws.xsoh.etar E/AndroidRuntime: FATAL EXCEPTION: main
Process: ws.xsoh.etar, PID: 3486
java.lang.VerifyError: Verifier rejected class com.android.calendar.AllInOneActivity: void com.android.calendar.AllInOneActivity.setMainPane(android.app.FragmentTransaction, int, int, long, boolean) failed to verify: void com.android.calendar.AllInOneActivity.setMainPane(android.app.FragmentTransaction, int, int, long, boolean): [0xA9] Rejecting invocation, long or double parameter at index 1 is not a pair: 15 + 0.
void com.android.calendar.AllInOneActivity.updateSecondaryTitleFields(long) failed to verify: void com.android.calendar.AllInOneActivity.updateSecondaryTitleFields(long): [0x1D3] Expected category1 register type not 'Long (Low Half)' (declaration of 'com.android.calendar.AllInOneActivity' appears in /data/app/ws.xsoh.etar-1/base.apk)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1078)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2557)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
It seems like I am still using the wrong move instruction. I am assigning
move to BOOLEAN,CHAR,INTEGER,FLOAT,SHORT
move-wide to DOUBLE,LONG
move-object to the remaining types.
Is this assignment correct? What move instruction is appropriate for UNINIT, CONFLICTED, UNINIT_THIS, etc?