none
Why doesn't setting a watch in the debugger actually stop execution when debugging?

    Question

  • Something I've never understood about Visual Studio is why setting a watch is, at least for me, a useless activity. OK, I'm harkening back to my VB6 days. When I set a watch on a variable in a file in VB6, and then ran it in the debugger, the instant that variable changed the debugger stopped execution and I could see where I was in the code when the change occurred, and what the old value was and the new value is. I loved that feature and greatly miss it ever since going to Visual Studio.NET Beta, back in the day.

    When I set a watch on a variable in a C# class VS never, ever stops. I really hate that! And there appears to be no way to modify the behavior of the debugger, because believe me I've tried. I'd right mouse button clicked on the watch in hopes of getting some popup menu. Yeah, you can forget that, as it ain't happenin'. I'm trying to find where a variable's value changes, but since I can't find anyway at all of making the watch functionality of VS 2015 to work as I hope it would, I'm having to spend hours and sometimes DAYS trying to track down a problem that, if I could set a watch on a variable and know that the debugger in VS would stop execution so I could see what the old value was, what the new value is and where in the code its happened, I could get this problem solved in under 5 minutes. But VS isn't allowing for that kind of productivity. Instead for me the whole concept of a watch on a variable in VS 2015 seems to me to be an broken promise.

    So, two questions: First, can VS 2015's Watch in the debugger be made so that when one watches a variable for a change in value, and then when I'm debugging it will actually stop running the program and show me the new value and place where the change occurred? (I guess I can live with VS not showing me the old value.)

    If the answer to the first question is "Yes", then please tell me how to do it! Because believe me there is nothing at all obvious to me as to how you enable that functionality.


    Rod

    Friday, June 24, 2016 4:52 PM

Answers

  • The debugger needs to halt execution of your program to evaluate expressions and examine the contents of VARIABLES.

    The other other feature is that the CPU typically supports setting a few hardware breakpoints on memory access...provided you know exactly which byte in memory you want to watch.  Those are available via "Data breakpoints".

    To set one, you have to be in native debugging (so this does not apply to Visual Basic or C#) and you have to know the address of your variable (hence does not generally apply to managed code).  But once you have hit a breakpoint or have paused execution of your program with Debug > Break All, then you can choose Debug > New Breakpoint > New Data Breakpoint.  This will program your CPU to watch for writes to a particular memory address with a hardware breakpoint.  Typically only 4 addresses can be watched simultaneously.  That's a CPU architecture thing.

    -- This doesn't happen in managed code because every time the address of the variable changes, the hardware breakpoint would have to be updated... This simply doesn't happen in the current implementation.

    VB6 wasn't managed code, that's why it worked.  It was setting hardware data breakpoints for fixed address variables.

    Without this feature your debugger would have to single step the processor, re-evaluate the debug expression and repeat until the break condition was true.  Possible, but SERIOUSLY PAINFULLY slow.  Usually only practical if you are stepping over a few dozen statements.

    ---

    Now as for managed programming, this should be easier because you have much more knowledge about who has access to what variables.  In particular it should be easy to stub in an accessor function such as a property set and break when the setter is called.  Variables can only get new values in so many ways so it's usually pretty straightforward to intercept the setter using good patterns, interfaces and abstraction.



    • Edited by Wyck Friday, June 24, 2016 5:59 PM minor edit
    • Marked as answer by Rod at Work Friday, June 24, 2016 8:29 PM
    Friday, June 24, 2016 5:59 PM

All replies

  • The debugger needs to halt execution of your program to evaluate expressions and examine the contents of VARIABLES.

    The other other feature is that the CPU typically supports setting a few hardware breakpoints on memory access...provided you know exactly which byte in memory you want to watch.  Those are available via "Data breakpoints".

    To set one, you have to be in native debugging (so this does not apply to Visual Basic or C#) and you have to know the address of your variable (hence does not generally apply to managed code).  But once you have hit a breakpoint or have paused execution of your program with Debug > Break All, then you can choose Debug > New Breakpoint > New Data Breakpoint.  This will program your CPU to watch for writes to a particular memory address with a hardware breakpoint.  Typically only 4 addresses can be watched simultaneously.  That's a CPU architecture thing.

    -- This doesn't happen in managed code because every time the address of the variable changes, the hardware breakpoint would have to be updated... This simply doesn't happen in the current implementation.

    VB6 wasn't managed code, that's why it worked.  It was setting hardware data breakpoints for fixed address variables.

    Without this feature your debugger would have to single step the processor, re-evaluate the debug expression and repeat until the break condition was true.  Possible, but SERIOUSLY PAINFULLY slow.  Usually only practical if you are stepping over a few dozen statements.

    ---

    Now as for managed programming, this should be easier because you have much more knowledge about who has access to what variables.  In particular it should be easy to stub in an accessor function such as a property set and break when the setter is called.  Variables can only get new values in so many ways so it's usually pretty straightforward to intercept the setter using good patterns, interfaces and abstraction.



    • Edited by Wyck Friday, June 24, 2016 5:59 PM minor edit
    • Marked as answer by Rod at Work Friday, June 24, 2016 8:29 PM
    Friday, June 24, 2016 5:59 PM
  • Thank you, Wyck. Now I understand why Watch in Visual Studio.NET doesn't work the way I was used to from VB6. I don't understand what benefit it gives by being there, but oh well.

    Rod


    Friday, June 24, 2016 8:30 PM
  • Watch works great when you break execution, either manually or with a breakpoint, or from a debug exception.  That's the benefit it gives by being there.  It also works great when you single-step using F10.

    If the variable change is reproducible, then another common way to identify where it changed its value is via bisection.  Locate a point in execution before the variable has changed and a point after it has changed, and examine any point approximately half way between.  You'll eliminate half of the execution path .. repeat until you've narrowed it down to a single call.  Use conditional breakpoints if you must.


    Saturday, June 25, 2016 4:48 AM
  • My problem is that sometimes I have no clue at all where a variable is changing. It certainly is true in this case. I set a breakpoint at each and every place where the variable is assigned and then ran the program in the debugger. None of those breakpoints were ever hit. And yet I know through other means that the variable's value changes. This is driving me nuts.

    Thank you for your help, Wyck. I've just given up on trying to figure it out, because I have no way of doing so.


    Rod

    Sunday, June 26, 2016 1:43 PM
  • It sounds like you would definitely get great benefit from using a property instead of manipulating variables directly.  The benefit to you will be correctness (you will hopefully eliminate accidental modification) and debug-ability (you can set a breakpoint on a property-set call).

    See the article called Differences Between Properties and Variables in Visual Basic.

    Even if you don't use a formal property, you can adopt a property pattern, where all modifications to a value go through a SetFoo(...) call, which you could set breakpoints on.  Here the abstraction of the contract of modification of your variable gets firmed up into an interface or at least a method call, so that you can intercept it (with a breakpoint, if nothing else) and abstract it.

    Monday, June 27, 2016 5:21 PM