有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java字节好友通知中断Eclipse调试器

我用过网。拜特巴迪。asm。建议在适当注释的方法之前和之后添加代码,以启动和停止计时器。修改后的类在可以引用它们的原始类之前被手动加载到目标类加载器中,从而取代它们。我正在使用OSGi(Equinox)

非常好,但是当我在目标方法的断点上停止Eclipse(Photon 4.8.0)调试器时,Variables视图仅显示:

com.sun.jdi.InternalException: Got error code in reply:35 occurred retrieving 'this' from stack frame.

这是不可避免的吗?如果这使得插入指令的代码不可调试,则会破坏我的用例:(

(我已禁用选项“在步骤操作后显示方法结果”(如果VM支持;可能会很慢)。)

范例

我相信我可能发现了生成字节码的一些问题

要检测的类:

 1 package com.tom.test;
 2
 3 import com.tom.instrument.Instrumented;
 4 import com.tom.instrument.Timed;
 5
 6 @Instrumented(serviceType = "blah")
 7 public class Test {
 8
 9 @Timed
10 public void writeName() {
11   final String myLocal = "Tom";
12      System.out.println(myLocal);  
13   }
14
15 }

“忠告”:

package com.tom.instrument;

import net.bytebuddy.asm.Advice.OnMethodEnter;

public class Instrumentation {

    @OnMethodEnter
    public static void onMethodEnter() {
        System.out.println("Enter");
    }

}

呼叫好友:

new ByteBuddy()
    .redefine(type, ClassFileLocator.ForClassLoader.of(this.classLoader))
    .visit(Advice.to(Instrumentation.class)
    .on(isAnnotatedWith(Timed.class)))
    .make().saveIn(new File("instrumented"));

javap中的结果:

Compiled from "Test.java"
...

  public void writeName();
    Code:
       0: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #40                 // String Enter
       5: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: goto          11
      11: ldc           #17                 // String Tom
      13: astore_1
      14: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
      17: ldc           #17                 // String Tom
      19: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return
    LineNumberTable:
      line 11: 0
      line 12: 14
      line 13: 22
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
         11      12     0  this   Lcom/tom/test/Test;
         14       9     1 myLocal   Ljava/lang/String;
}

如果我在测试的第11行设置一个断点。java然后Eclipse调试视图显示:<unknown receiving type>(Test).writeName() line: 11

变量视图显示:com.sun.jdi.InternalException: Got error code in reply:35 occurred retrieving 'this' from stack frame.

如果我破解字节码,将0x2A2处的00更改为0B,那么行号表如下所示:

LineNumberTable:
  line 11: 11
  line 12: 14
  line 13: 22

那么一切都好了!这对我来说似乎是正确的,但我在这里不是专家

如果我也使用@OnMethodExit,那么它就有点复杂了。将以下内容添加到Instrumentation.class

@OnMethodExit
public static void onMethodExit() {
    System.out.println("Exit");
}

javap提供:

Compiled from "Test.java"
...

  public void writeName();
    Code:
       0: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #40                 // String Enter
       5: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: goto          11
      11: aload_0
      12: astore_1
      13: ldc           #17                 // String Tom
      15: astore_2
      16: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
      19: ldc           #17                 // String Tom
      21: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      24: goto          27
      27: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
      30: ldc           #42                 // String Exit
      32: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      35: goto          38
      38: return
    LineNumberTable:
      line 11: 0
      line 12: 16
      line 13: 24
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
         13      14     1  this   Lcom/tom/test/Test;
         16      11     2 myLocal   Ljava/lang/String;
}

为了解决这个问题,我必须更新行号表和局部变量表。像这样:

LineNumberTable:
  line 11: 13
  line 12: 16
  line 13: 24
LocalVariableTable:
  Start  Length  Slot  Name   Signature
     13      14     0  this   Lcom/tom/test/Test;
     16      11     1 myLocal   Ljava/lang/String;

差异: enter image description here

可能是Eclipse调试器希望this始终位于插槽0中的错误?或许这就是它应该的样子。但错误代码35来自JVM

添加退出建议更改插槽的原因似乎是因为它导致使用ForInstrumentedMethod.Default.Copying而不是Simple。它们有不同的variable()实现


共 (1) 个答案

  1. # 1 楼答案

    Eclipse bug 531706

    并非所有类都已插入指令时,就会出现此问题,请参见comment #4 by Tobias Hirning

    ...

    Now I am also getting a clearer picture: The errors only appeared in method invocations where the methods are in jar files. And I think they were not instrumented.

    ...

    错误发生在VM中,而不是Eclipse中。当Eclipse通过调试接口请求变量时,返回错误代码^{,而不是值。由于上述错误报告所做的更改是忽略它,请参见comment #7 by Till Brychcy (who made the change)

    ...

    I've been able to reproduce the problem and simply ignoring the InternalException in this codepath improves the situation.

    You'll sometimes see a message about the error code 35 in the variables view, but in general it seems to work.

    为了避免这个问题,你必须对所有的类进行测试