我有一个简单的程序是这样的:

package tests;

import java.util.Scanner;

public class TestSum {

    public static void main(String[] args) {
        int sum = 0;
        System.out.print("Please enter starting i: ");
        int i = new Scanner(System.in).nextInt();
        while ( i < 11 ) {
            sum = sum + i;
            i = i + 1;
        }
        System.out.println("sum = " + sum);
        System.out.println("Ending i = " + i);
    }
}


我将其构建到一个jar文件中,并且我想使用WALA添加更多检测到的源代码以计算出于动态分析目的的循环执行次数。

这是我通过使用Wala所做的事情,大部分内容都来自此示例Wala Bench Example

import com.ibm.wala.shrikeBT.*;
import com.ibm.wala.shrikeBT.analysis.Verifier;
import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder;
import com.ibm.wala.shrikeBT.shrikeCT.ClassInstrumenter;
import com.ibm.wala.shrikeBT.shrikeCT.OfflineInstrumenter;
import com.ibm.wala.shrikeCT.ClassWriter;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintStream;
import java.io.Writer;

/**
 * Created by quocnghi on 2/2/17.
 */
public class InstrumentedTest {
    private final static boolean disasm = true;

    private final static boolean verify = true;

    private static OfflineInstrumenter instrumenter = new OfflineInstrumenter(true);

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 1; i++) {

            Writer w = new BufferedWriter(new FileWriter("report", false));

            args = instrumenter.parseStandardArgs(args);

            instrumenter.setPassUnmodifiedClasses(true);
            instrumenter.beginTraversal();
            ClassInstrumenter ci;
            while ((ci = instrumenter.nextClass()) != null) {
                doClass(ci, w);
            }
            instrumenter.close();
        }
    }

    static final String fieldName = "_Bench_enable_trace";

    // Keep these commonly used instructions around
    static final Instruction getSysOut = Util.makeGet(System.class, "out");

    static final Instruction callPrintln = Util.makeInvoke(PrintStream.class, "println", new Class[]{String.class});

    private static void doClass(final ClassInstrumenter ci, Writer w) throws Exception {
        final String className = ci.getReader().getName();
        System.out.println("Class name : " + className);
        w.write("Class: " + className + "\n");
        w.flush();

        for (int m = 0; m < ci.getReader().getMethodCount(); m++) {
            MethodData d = ci.visitMethod(m);
            System.out.println(d.getName());
            // d could be null, e.g., if the method is abstract or native
            if (d != null) {
                w.write("Instrumenting " + ci.getReader().getMethodName(m) + " " + ci.getReader().getMethodType(m) + ":\n");
                w.flush();

                if (disasm) {
                    w.write("Initial ShrikeBT code:\n");
                    (new Disassembler(d)).disassembleTo(w);
                    w.flush();
                }

                if (verify) {
                    Verifier v = new Verifier(d);
                    v.verify();
                }

                MethodEditor methodEditor = new MethodEditor(d);
                methodEditor.beginPass();

                final int noTraceLabel = methodEditor.allocateLabel();

                IInstruction[] instr = methodEditor.getInstructions();
                final String msg0 = "Loop called at " + Util.makeClass("L" + ci.getReader().getName() + ";") + "."
                        + ci.getReader().getMethodName(m);
                int i = 0;

                for (IInstruction in : instr) {
                    if (in instanceof ConditionalBranchInstruction) {

                        int b = i;
                        methodEditor.insertBefore(i, new MethodEditor.Patch() {
                            @Override
                            public void emitTo(MethodEditor.Output w) {
                                w.emit(getSysOut);
                                w.emit(ConstantInstruction.makeString(msg0));
                                w.emit(callPrintln);
                                w.emitLabel(noTraceLabel);
                            }
                        });
                    }

                    i++;
                    System.out.println(in.toString());
                }
                methodEditor.applyPatches();
                if (disasm) {
                    w.write("Final ShrikeBT code:\n");
                    (new Disassembler(d)).disassembleTo(w);
                    w.flush();
                }
            }
        }
        ClassWriter cw = ci.emitClass();
        instrumenter.outputModifiedClass(ci, cw);
    }
}


我希望在添加更多检测到的代码之后,该程序应该像这样,在循环中添加一行System.out.println:

包装测试;

import java.util.Scanner;

public class TestSum {

    public static void main(String[] args) {
        int sum = 0;
        System.out.print("Please enter starting i: ");
        int i = new Scanner(System.in).nextInt();
        while ( i < 11 ) {
            sum = sum + i;
            i = i + 1;
            System.out.println("One count for this loop");
        }
        System.out.println("sum = " + sum);
        System.out.println("Ending i = " + i);
    }
}


但是我得到了这个错误:

java.lang.ClassFormatError: StackMapTable format error: wrong attribute size

最佳答案

WALA does have StackMapTable support,但也许有些问题。我建议filing an issue

10-05 17:46