-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Debugger: Conditional breakpoints #9334
Conversation
It would likely be a bigger task but inputs already uses an expression parser. It'd be nice in general if we could split that out and leverage it in other places (such as this). I know several times I've thought about a feature that required some complex expression parsing and shied away from it. EDIT: we don't have to use the inputs one, I just think it'd be nice to standardize on a single expression parser. |
I'm guessing that this pr makes https://github.com/dolphin-emu/dolphin/pull/6728/files completely obsolete, doesn't it? |
I did notice there was a parser for input mappings, but it seemed fairly purpose-built. Trying to generalize it appeared to be more effort (and would risk breaking the input code) than introducing a general purpose (but small) expression parser. I am open to feedback on this point, though I would prefer not to write a parser from scratch or make sweeping changes to an existing one. 😀 |
That PR actually looks like it would still be very useful. It would be nice to be able to disable breakpoints without deleting them. I may dust that one off if the original author has moved on. |
I believe I've addressed everything in the first round of feedback. I removed my strawman global variable implementation for now; I may add them back later. In the meantime I'll be starting down the TODO list. |
- Support hex prefix 0x or OX - Support scientific notation Also, reconcile the bitwise complement operator with C (use ~ instead of ^).
To prevent the INI parser from interpreting breakpoints as key/value pairs when the condition contains an equals sign, they are now prefixed with '$' (understood by the parser to be a raw line designator). Load support is retained for breakpoints without this prefix so old INIs will still work.
Encapsulate expressions in new Expression class that stores the compiled expression and associated variable list.
This is necessary to retain precision above 32 bits, but more importantly to prevent an expression like (0x80000000 | 1) from flipping the sign of the result.
This allows for easy reinterpretation of GPRs in an expression.
…oints - Add access to FPRs - Add access PC, LR, CTR - Support modifications to all of the above + GPRs
The initial purpose of this PR is unrelated to what my PR is doing. The goal is to expose debugging features (in that case BPs) though the debugger interface. That interface could be used later for scripting languages such as python/lua. Feel free take over my PR or create your own as this one is really low on my TODO list. |
There was a map here. It's gone now.
For reference, the last force push was to sneak "pc" back in as a built-in variable. |
This doesn't seem to work correctly with "write to log"; if I create a conditional breakpoint in Super Mario Sunshine at 802f3630 (
The code that does this logging is this, and the first value in parentheses is r3, but it's getting logged even though it's clearly not equal to 5: dolphin/Source/Core/Core/PowerPC/PowerPC.cpp Lines 609 to 616 in c21581a
It doesn't actually break in those cases, but this does make conditional breakpoints unusable for e.g. checking how many times a specific condition is hit per frame (which is something I wanted to do). Checking the condition in |
Will any more work be done on this? I was thinking BPs with a specific call stack conditional would be really helpful for me. I don't think doing it as an individual PR would be right, but I imagine it could be added onto this after it gets merged. |
I would love to see this completed and merged. One of my biggest time wasters when debugging with breakpoints is pressing play 100+ times until I stumble across the correct instance of the breakpoint for what I need. This would completely eliminate that and also make debugging with Dolphin more enticing. |
Conditional breakpoints! Like breakpoints, but they only work some of the time! Er...
Note: I am seeking feedback on the design and implementation of this feature. Don't be shy!
Who is this for
What does it do
Allow a C-style expression to be attached to breakpoints. The breakpoint will only trigger a break in execution if the expression evaluates to true.
Why is this useful
There is often code that executes many times but is only interesting under specific conditions. This gives users a way to find the signal in the noise. It's a pretty common feature in debuggers.
How does it work
When creating a breakpoint, there is now a text box for an optional condition expression. As an example, in Final Fantasy Crystal Chronicles (GCCE01), setting a breakpoint at address
80017B18
with the following condition will trigger a break right before the game performs a texture copy that will overrun the destination buffer:r26 <= r0 && ((r5+3)&-4) * ((r6+3)&-4) * 4 > r0
(see #9329 for details).Design considerations
Currently using expr with a slight modification (replacing float with double, which can hold 32-bit integers at full precision), which is < 1k LOC in a single header and implements most of the standard C operators and supports variable assignment. Also considered TinyExpr, but it doesn't support bitwise, logical, comparison, or assignment operators. There's also cparse, which seems to handle a superset of what expr does but is ~3x larger.
Allowing expressions to modify guest state, such as registers or memory, would be only marginal additional work. Expressions with side effects require extra care from the user, but they seem useful nonetheless.
Expression local variables e.g. ("x = r3+r4, x > 42") would permit some expressions to be simplified considerably. The bigger questions are whether variables should persist across evaluations of a given expression, and whether they should be shared between expressions. There is a lot of power in a persistent global scope for variables, but they could become frustrating to use without an additional means for inspection. We may want to persist them to save states as well.
An obvious next step would be to add an immediate window, or REPL, where the user can enter any expression they like for immediate evaluation. This could be extended to support debugger commands, as well. There are other PRs that go further and wire the emulator to a full scripting language (see Lua scripting #9205, [WIP] Add Python Scripting support #7064). What I am suggesting is something a bit simpler: exposing the existing debugger functionality - currently accessible only to the GUI - through a text interface.
TODO
Cut/postponed