RetransformAgent.java revision 11884:b45c81ca8671
133965Sjdp/*
2218822Sdim * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
3218822Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
460484Sobrien *
533965Sjdp * This code is free software; you can redistribute it and/or modify it
633965Sjdp * under the terms of the GNU General Public License version 2 only, as
733965Sjdp * published by the Free Software Foundation.
833965Sjdp *
933965Sjdp * This code is distributed in the hope that it will be useful, but WITHOUT
1033965Sjdp * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1133965Sjdp * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1233965Sjdp * version 2 for more details (a copy is included in the LICENSE file that
1333965Sjdp * accompanied this code).
1433965Sjdp *
1533965Sjdp * You should have received a copy of the GNU General Public License version
1633965Sjdp * 2 along with this work; if not, write to the Free Software Foundation,
1733965Sjdp * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1833965Sjdp *
1933965Sjdp * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20218822Sdim * or visit www.oracle.com if you need additional information or have any
21218822Sdim * questions.
2233965Sjdp */
2333965Sjdp
2433965Sjdp/**
2533965Sjdp * @test
2660484Sobrien * @bug 6274264 6274241 5070281
27218822Sdim * @summary test retransformClasses
28218822Sdim * @author Robert Field, Sun Microsystems
29218822Sdim *
30218822Sdim * @modules java.base/jdk.internal.org.objectweb.asm
31218822Sdim * @run shell/timeout=240 MakeJAR2.sh RetransformAgent RetransformApp 'Can-Retransform-Classes: true'
32218822Sdim * @run main/othervm -javaagent:RetransformAgent.jar RetransformApp
33218822Sdim */
34218822Sdim
35218822Sdimimport java.lang.instrument.*;
36218822Sdimimport java.security.ProtectionDomain;
37218822Sdimimport java.io.*;
38218822Sdimimport asmlib.*;
39218822Sdim
40218822Sdimclass RetransformAgent {
41218822Sdim
42218822Sdim    static ClassFileTransformer t1, t2, t3, t4;
43218822Sdim    static Instrumentation inst;
44218822Sdim    static boolean succeeded = true;
45218822Sdim    static int markCount = 0;
46218822Sdim    static int[] markGolden = {30, 40, 20, 30, 40, 20, 30, 40, 20, 30, 40, 20,
47218822Sdim                               11, 40, 20, 11, 40, 20, 11, 40, 20, 11, 40, 20};
48218822Sdim
49218822Sdim    static class Tr implements ClassFileTransformer {
50218822Sdim        final String trname;
51218822Sdim        final boolean onLoad;
52218822Sdim        final int loadIndex;
53218822Sdim        final boolean onRedef;
54218822Sdim        final int redefIndex;
55218822Sdim        final String cname;
56218822Sdim        final String nname;
57218822Sdim
58218822Sdim        Tr(String trname, boolean onLoad, int loadIndex, boolean onRedef, int redefIndex,
59218822Sdim           String cname, String nname) {
60218822Sdim            this.trname = trname;
61218822Sdim            this.onLoad = onLoad;
62218822Sdim            this.loadIndex = loadIndex;
6360484Sobrien            this.onRedef = onRedef;
6460484Sobrien            this.redefIndex = redefIndex;
6560484Sobrien            this.cname = cname;
6660484Sobrien            this.nname = nname;
6760484Sobrien        }
6860484Sobrien
6960484Sobrien        public byte[] transform(ClassLoader loader,
7060484Sobrien                                String className,
7160484Sobrien                                Class<?> classBeingRedefined,
7260484Sobrien                                ProtectionDomain    protectionDomain,
7360484Sobrien                                byte[] classfileBuffer) {
7460484Sobrien            boolean redef = classBeingRedefined != null;
7577298Sobrien            // System.err.println("hook " + trname + ": " + className +
7677298Sobrien            //                    (redef? " REDEF" : " LOAD"));
7777298Sobrien            if ((redef? onRedef : onLoad) && className != null && className.equals(cname)) {
7877298Sobrien                int fixedIndex = redef ? redefIndex : loadIndex;
7977298Sobrien                try {
8060484Sobrien                    byte[] newcf = Instrumentor.instrFor(classfileBuffer)
8160484Sobrien                                   .addMethodEntryInjection(
8260484Sobrien                                        nname,
8360484Sobrien                                        (h)->{
8433965Sjdp                                           h.push(fixedIndex);
8533965Sjdp                                           h.invokeStatic("RetransformAgent", "callTracker", "(I)V", false);
8633965Sjdp                                        })
8733965Sjdp                                   .apply();
8833965Sjdp                    /*** debugging ...
8933965Sjdp                         if (newcf != null) {
9033965Sjdp                            String fname = trname + (redef?"_redef" : "") + "/" + className;
9133965Sjdp                            System.err.println("dumping to: " + fname);
9233965Sjdp                            write_buffer(fname + "_before.class", classfileBuffer);
9333965Sjdp                            write_buffer(fname + "_instr.class", newcf);
9433965Sjdp                         }
9560484Sobrien                    ***/
9677298Sobrien                    System.err.println(trname + ": " + className + " index: " + fixedIndex +
9777298Sobrien                                       (redef? " REDEF" : " LOAD") +
9877298Sobrien                                       " len before: " + classfileBuffer.length +
9977298Sobrien                                       " after: " + newcf.length);
10077298Sobrien                    return newcf;
10160484Sobrien                } catch (Throwable ex) {
102218822Sdim                    System.err.println("Injection failure: " + ex);
10360484Sobrien                    ex.printStackTrace();
104218822Sdim                }
105218822Sdim            }
106218822Sdim            return null;
107218822Sdim        }
108218822Sdim    }
109218822Sdim
11077298Sobrien    static void write_buffer(String fname, byte[]buffer) {
11160484Sobrien        try {
11260484Sobrien            File f = new File(fname);
113218822Sdim            if (!f.getParentFile().exists()) {
11460484Sobrien                f.getParentFile().mkdirs();
11560484Sobrien            }
11689857Sobrien            try (FileOutputStream outStream = new FileOutputStream(f)) {
11789857Sobrien                outStream.write(buffer, 0, buffer.length);
11889857Sobrien            }
11989857Sobrien        } catch (IOException ex) {
12089857Sobrien            System.err.println("EXCEPTION in write_buffer: " + ex);
121218822Sdim        }
122218822Sdim    }
123218822Sdim
124218822Sdim    public static void premain (String agentArgs, Instrumentation instArg) {
12533965Sjdp        inst = instArg;
126218822Sdim        System.err.println("Premain");
127218822Sdim
128218822Sdim        t1 = new Tr("TR1", false, 10, true, 11, "RetransformApp", "foo");
129218822Sdim        inst.addTransformer(t1, true);
130218822Sdim        t2 = new Tr("TN2", true,  20, true, 21, "RetransformApp", "foo");
131218822Sdim        inst.addTransformer(t2, false);
132218822Sdim        t3 = new Tr("TR3", true,  30, true, 31, "RetransformApp", "foo");
133218822Sdim        inst.addTransformer(t3, true);
134218822Sdim        t4 = new Tr("TN4", true,  40, true, 41, "RetransformApp", "foo");
13533965Sjdp        inst.addTransformer(t4, false);
13633965Sjdp    }
13733965Sjdp
13833965Sjdp    public static void undo() {
13933965Sjdp        inst.removeTransformer(t3);
14033965Sjdp        try {
14133965Sjdp            System.err.println("RETRANSFORM");
14277298Sobrien            inst.retransformClasses(new RetransformApp().getClass());
14333965Sjdp        } catch (Exception ex) {
144130561Sobrien            System.err.println("EXCEPTION on undo: " + ex);
14589857Sobrien        }
146104834Sobrien    }
147130561Sobrien
148130561Sobrien    public static boolean succeeded() {
14933965Sjdp        return succeeded && markCount == markGolden.length;
150130561Sobrien    }
15133965Sjdp
152130561Sobrien    public static void callTracker(int mark) {
15333965Sjdp        System.err.println("got mark " + mark);
154130561Sobrien        if (markCount >= markGolden.length || mark != markGolden[markCount++]) {
155130561Sobrien            succeeded = false;
15633965Sjdp        }
157130561Sobrien    }
158130561Sobrien}
15933965Sjdp