当变量被赋值时中断
我希望 jdb (我通过 Eclipse 调试器使用它)在为变量分配某个值时中断。 我对在某些特定行设置断点不感兴趣,而是更一般地设置断点。
例如,每次 x == null 时都会中断。
这样的事情可以实现吗?
I want jdb (which I'm using via the Eclipse debugger) to break when a variable is assigned some value.
I'm not interested in setting a breakpoint at some specific line but rather more generally.
For example, break every time x == null.
Is such a thing achievable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
因为这也用
jdb
标记,但没有答案讨论如何在后者中做到这一点...(顺便说一句,Eclipse 很可能不直接使用 jdb,但很可能使用 JDI API,它在另一个答案中进行了讨论。)JDK 1.8 中
jdb
的 html 文档,没有提及如何添加观察点。但是(查看源代码)事实证明这实际上是受支持的,甚至(部分!)记录在案,尽管仅在 jdb 的内置帮助中。内置帮助的内容(作为字符串):
让我们尝试一下:
因为它是基于 shell 的调试器,所以它(默认情况下)基本上会在(字段)分配上中断。使用 JDI 可以设置一个不中断线程的观察点 (
setSuspendPolicy(EventRequest.SUSPEND_NONE)
),因此人们可能想知道 jdb 是否可以做到这一点,事实证明这是可能的,使用未记录的(即使在内置帮助级别)watch go
命令!所以,是的,这就是其中之一,“你应该阅读来源,卢克”的答案! (人们将这些作为评论发布在我的问题下,同时也投了反对票,哈哈。)
现在,您可能已经注意到了一个稍微奇怪的问题。 jdb 实际上在这两种模式下报告了两个不同的字段初始值!
hmmmF
的实际来源是:带回家 问:两种报告模式中哪一种是正确的?答:也许
watch go
模式没有记录,因为就分配时报告的旧值而言,它似乎存在错误。也许这是由于没有为go
/SUSPEND_NONE
禁用 JVM 优化,我不确定。即使在“go”模式下,分配的新值也会被正确报告。 (在 Linux 上使用 JDK 1.8u412 进行测试。)请注意,不支持任意条件下的条件断点
jdb,也不是由 JDI 提供。 Eclipse 等可能完成这些的方式是
总是中断、检查调试器级别的条件、恢复或
可能使用一些我不知道的 OpenJ9 功能(如果使用该 VM
蚀)。第三种可能性是彻底重写(即
检测
[通常使用 ASM] 与 JDI 结合)来检查调试程序中的状况。虽然 ASM 有相当多的前端,但我不确定其中是否有任何一个也允许轻松插入断点。 (并且它必须由相同的工具支持,因为据我所知,您只能附加一个 Java 代理。旁白:这实际上是一种反调试技术,由一些人提出,即相互调试Java机器以排除真正的调试器,哈哈。)关于 Eclipse 的精确信息,请查看 Eclipse JDT Debug (他们当前的调试器“核心”,它似乎)是什么does 条件断点是我上面提到的选项 1:只是(总是)使用 JDI 中断并检查 Eclipse-JDT 上的条件-边。 (当然,与 jdb 不同,自动完成这一点很好,即使它不会通过这种调试器端条件检查打破任何速度记录。)
Since this is also tagged with
jdb
but no answer discusses how to do it in the latter... (BTW, Eclipse very likely doesn't use jdb directly, but most likely uses the JDI API, which was discussed in another answer.)The html doc for
jdb
in JDK 1.8, doesn't mention how to add watchpoints. But (grepping the source code) it turns out this is actually supported, and even (partially!) documented, albeit only in the built-in help of jdb.What the built-in help says (as a string):
Let's try it:
Since it's a shell-based debugger it will (by default) essentially break on the (field) assignment. Using the JDI it's possible to set a watchpoint that doesn't interrupt the thread (
setSuspendPolicy(EventRequest.SUSPEND_NONE)
) and so one may wonder if that's possible with jdb, and it turns out that it is possible, using the undocumented (even at built-in help level)watch go
command!So, yeah, this is one of those, "you should have read the source, Luke" answers! (People post those as comments under my Qs, while downvoting too, LOL.)
Now, there's one slightly odd issue that you might have noticed. jdb actually reported two different initial values for the filed in these two modes! What the actual source of
hmmmF
does is:Take home Q: which of the two reported modes is correct? A: Maybe the
watch go
mode isn't documented because it appears buggy, in terms of the old value reported at assignment time. Perhaps this is due to JVM optimizations that are not disabled for thego
/SUSPEND_NONE
, I'm not sure. The new value being assigned is correctly reported though, even in `go' mode. (Tested with JDK 1.8u412 on Linux.)Note that conditional breakpoint on arbitrary conditions aren't supported by
jdb, nor by the JDI. The way those are probalby done by Eclipse etc. are either
always breaking, checking the condition on the debugger level, the resuming, or
possibly using some OpenJ9 feature I don't know about (if using that VM with
Eclipse). A third possibility is downright rewriting (i.e.
Instrumentation
[typically with ASM] in combination with JDI) to check the condition in the debugee. While there are quite a few front-ends for ASM, I'm not sure if any of them also allow easy insertion of breakpoints. (And it would have to be supported by the same tool, because AFAIK you can only have one Java agent attached. Aside: this is in fact an anti-debugging technique that was proposed by some, i.e. mutually-debugging Java machines to keep a real debugger out, LOL.)As to be more precise about Eclipse, looking through Eclipse JDT Debug (their current debugger 'core', it seems) what that does on conditional breakpoints is option 1 that I mentioned above: just (always) breaks using JDI and checks the condition on the Eclipse-JDT-side. (Of course it's nice to have that done automagically, unlike unlike in jdb, even if it won't break any speed records with that kind of debugger-side condition checking.)
是的 - 您需要设置的是“条件断点” - 这使您能够在达到应用程序的特定状态时停止程序执行并单步执行调试器。
因此,假设您想在满足特定条件时跳转到执行中的特定点(如附图所示),您可以按如下方式执行此操作:
1.
打开调试器透视图并选择 'BreakPoints ' 选项卡
在代码文件中添加一个新的断点 - 在您想要观察程序执行的适当位置
然后返回到“断点”选项卡,右键单击新添加的条目,然后选择“断点属性”
设置断点应遵循的条件激活
(来源:ibm.com)
Yes - What you need to setup is a 'Conditional Breakpoint' - this gives you the ability to stop the program execution and step through the debugger when a certain state of the application is reached.
So, let's say you want to jump into a particular point in the execution when a certain condition is fulfilled (as per the image attached), you can do this as follows:
1.
Open your debugger perspective and select the 'BreakPoints' tab
Add a new BreakPoint in the code file - at the appropriate place where you would like to observe the program execution
Then go back to the 'Breakpoints' tab, right-click on the newly added entry, and select 'Breakpoint Properties'
Set the condition upon which it should be activated
(source: ibm.com)
您可以非常接近 字段修改观察点。它们仅限于放置在对象的字段上(不是局部变量、参数或表达式),并且每当写入字段时就会触发它们,但它是 Eclipse 最接近您想要的。
You can come pretty close with Field Modification Watchpoints. They are limited to being placed on fields of objects (not local variables, parameters, or expressions) and they are triggered whenever the field is written to, but it's the closest Eclipse has to what you want.
编辑:我在此答案中链接的票证 已标记为已验证/已修复。它已集成到最新的 Oxygen 版本中,详细信息请参阅发行说明。我将在下面留下我原来的答案,因为它有很多关于 JDI 和 JDT 如何在 Eclipse 中协同工作的有用信息。
我将从您问题的最终答案开始,这样您就不必阅读详细信息(如果您不想)。基本上,这是可能的,但有很多问题必须首先回答。如果您想跳过该步骤并直接查看票证,这里,但我建议您继续阅读。
Eclipse 使用 JDI (非常底层该页面的)以向 JVM 注册观察点。这是通过
EventRequestManager
创建观察点的方法(实现由 JVM 本身提供,而不是 Eclipse),即EventRequstManager.createModificationWatchpointRequest
。这些方法唯一接受的是Field
(请注意,这不是反射Field
类)。所以简而言之,Eclipse不能直接通过Java来做。不用担心,Java 也不处理条件断点。这些也是直接通过Eclipse实现的,而不是依赖Java。然而,有一些警告使得条件观察点比条件断点更难实现。让我们考虑一下简单的条件断点。为了让它们工作,您需要一个可以执行代码片段的上下文。如果没有代码的执行上下文,我们就无法评估代码片段中的表达式/语句,因为我们无法解析变量、值、类型等。这是使用 AST 解析器,将 Java 代码处理为实际指令。请记住,您可以在条件中键入多个语句,而不仅仅是单个表达式。然后,评估器使用上下文(具体来说,
IJavaStackFrame
) 在解析表达式后对其求值。现在考虑一个条件观察点,因为最后一点非常重要。什么是观察点的执行上下文?变量访问不仅可以发生在同一个类中,还可以发生在其他类中(想想受保护的成员和包成员),也可以发生在内部类中(通过 MyClass.this.myField >)。这意味着:
super
或类似的内容进行限定MyClass.this.myField
(用于内部类访问)。这种功能的可行性是有限的。您很难实际评估观察点的不变条件语句,因为执行上下文中绝对没有任何内容是一致的。这意味着如果不对代码片段应用特殊含义,则无法轻松解析和解释代码,例如:
这使事情变得相当复杂,尤其是在一个已经相对复杂的系统中。可以找到条件断点代码的示例 此处(使用 Ctrl+F 搜索
getEvaluationEngine
)。现在,根据一组有关我们所在位置和字段所在位置的规则,添加对表达式的预处理,并且执行操作可能会变得复杂。AFAIK,您不能执行类似“如果旧/新值是这样,则暂停”之类的操作,因为从堆栈帧(因此从调试器)中获取的信息根本无法获得该信息。分配给该值的表达式已在命中观察点时进行了求值,但其结果不可用于调试器,因此它不可用于观察点本身的求值器。必须首先执行一个步骤来执行分配,然后必须在该步骤之后计算表达式。这会非常混乱,而且老实说,这相当老套。
无论如何,如果您想表达对此功能的支持,可以使用 这张 Eclipse 票。然而,它从 2005 年就已经存在了(到目前为止已经有 8 年了),并且来自社区的支持有限。说实话,我认为它不会走得太远,尤其是在没有进一步澄清这种功能请求背后的期望并且没有首先考虑一些主要设计考虑的情况下。
Edit: The ticket I've linked in this answer has been marked verified/fixed. It has been integrated into the latest Oxygen release, as detailed in the release notes. I'll leave my original answer below since it has a lot of useful information regarding how JDI and JDT work together in Eclipse.
I'm going to start with the final answer to your question so you don't have to read the details if you don't want to. Basically, this is kind of possible but with a lot of questions that have to be answered first. If you want to skip that and go straight to the ticket, here you go, but I recommend you read on.
Eclipse uses JDI (very bottom of that page) to register watchpoints with the JVM. This is done through the
EventRequestManager
methods (the implementation is provided by the JVM itself, not Eclipse) that create watchpoints, i.e.EventRequstManager.createModificationWatchpointRequest
. The only thing that these methods accept is aField
(note that this isn't the reflectiveField
class). So in short, Eclipse can't do it directly through Java. Never fear, Java doesn't handle conditional breakpoints either. Those are also implemented through Eclipse directly instead of relying on Java. There are, however, some caveats that make conditional watchpoints much more difficult to implement than conditional breakpoints.Let's consider plain, conditional breakpoints. In order for them to work, you need a context in which you can execute the code snippet. Without an execution context for the code, we can't evaluate the expression/statements in the snippet since we have no way of resolving variables, values, types, etc. This is done using an AST parser that processes the Java code into actual instructions. Remember that you can type a number of statements into a condition, not just a single expression. The evaluator then uses a context (specifically, an
IJavaStackFrame
) to evaluate the expression itself after parsing it.Now think about a conditional watchpoint, because that last point is very important. What is a watchpoint's execution context? Variable access can happen not only within the same class, but also in other classes (think
protected
and package members), and in inner classes as well (viaMyClass.this.myField
). This means that:super
or with something likeMyClass.this.myField
(for inner class access).The feasibility of such a feature is kind of limited. You'd be hard-pressed to actually evaluate a non-changing conditional statement for a watchpoint since absolutely nothing in the execution context is going to be consistent. This means that the code cannot be easily parsed and interpreted without special meaning applied to pieces of the code, such as:
This complicates things quite a bit, especially in a system that is already relatively complex. An example of the conditional breakpoint code can be found here (search for
getEvaluationEngine
using Ctrl+F). Now take that and add in pre-processing on the expression based on a set of rules about where we are and where the field is, and doing things can get complicated.AFAIK, you can't do something like, "if the old/new value is this, suspend", because that information simply isn't available from the information you can get in the stack frame (and thus from the debugger). The expression being assigned to the value has been evaluated by time the watchpoint is hit, but its result isn't available to the debugger, therefore it isn't available to an evaluator on the watchpoint itself. A step would have to be performed first to perform the assignment, then the expression would have to be evaluated after the step. It'd be horribly messy, and honestly, rather hacky at that.
In any case, if you want to voice your support for this feature, you can use this Eclipse ticket. However, it's been around since 2005 (8 years as of now) and has limited support from the community. TBH, I don't see it going very far, especially without more clarification of the expectations behind this kind of a feature request and without some major design consideration put behind it first.
是的,这些称为观察点,并且观察点可以具有观察表达式。
根据版本等,您可以通过在大纲视图中选择一个变量并右键单击它,或者在变量视图中控制/单击它来完成此操作。
上下文菜单将包含“添加监视表达式”和“编辑监视表达式”的选项。
Yes, those are called watchpoints, and watchpoints can have watch expressions.
Depending on versions and such, you do this by selecting a variable in the Outline view and right-clicking on it, or in the Variables view, control/click on it.
A context menu will have choices for Add Watch Expression and Edit Watch Expression.
抱歉,在 Eclipse 中无法实现您想要的功能。您需要的是带有断点条件表达式的观察点。它在 Eclipse 中不存在。
您的问题也是特定的调试库。可能还有其他方法可以实现您的需求。在论坛中搜索,看看开发人员是如何做到这一点的。
Sorry, but there is no way to do what you want in Eclipse. What you need is a watchpoints with the conditional expression of a breakpoint. It does not exist in Eclipse.
Your problem is also specific debug a library. There are probably other ways to achieve what you need. Search over forum to see how developers do that.