Debugger StepInto auto-generated code and JMC issue - c#

I'm making a managed .NET debugger using MDBG sample.
Currently I'm struggling with StepInto behavior, while StepOut and StepOver seems to work.
To achieve Just-My-Code stepping I'm calling SetJMCStatus on modules load. That works fine and allow me to debug just my code.
But since I'm setting entire module as JMC, some auto-generated code comes into play and ruin stepping-into. An example of such code could be auto-property.
Since debugger is executing Il instructions, with step-into I'm getting inside auto-generated get_propertyName and set_propertyName method, which are marked as my code, because they are part of my module.
To distinguish such auto-generated code from my code I can use presence of debugging symbols, that are missing in case of auto-generated code. And then I could simply mark method as not my code to skip it during stepping.
The problem is I don't know which methods are auto-generated before I'm getting inside during stepping. When I stepped inside a method that has no debugging symbols I can mark it as not my code, but it's too late - debugger stopped where it supposed not to stop.
Theoretically I could iterate over my module methods using IMetadataImport and set their JMCStatus when debugger starts, but it seems quite expensive:
foreach (var methodToken in mdbgModule.Importer.EnumerateAllMethodTokens()) {
var func = mdbgModule.GetFunction(methodToken);
if (func.SymMethod == null)
func.CorFunction.JMCStatus = false;
}
If only I would know what function is going to be executed next, then I would be able to set it's status and prevent stepping inside auto-generated code for the first time.
I'm sticking with MDBG approach for stepping, not changing anything, just calling SetJMCStatus where it's needed, so I'm not sure if it makes sense to provide any code... If so, I'll edit the question, just add a comment!
Any suggestion on topic is greatly appreciated!
Regards,

Mike Stall hinted at one option, you could set JMC for the entire module and then when the debugger stepper breaks, check to see if the method is debuggable, if not then disable it's JMC status and rerun the stepper. (I'm not sure if this will result in a change in behaviour if the resuming stepper would need to step out before stepping in again.)
You could probably improve things by only setting JMC for modules that have a pdb available and by disabling JMC for classes/methods with [DebuggerNonUserCode] applied (and perhaps [DebuggerHidden] too). But rather than enumerating all the classes/methods and checking if they have the attribute, enumerate the custom attributes and work back (IMetaDataImport::EnumCustomAttributes with tkType set but not tk, then use IMetaDataImport::GetCustomAttributeProps to get the thing its applied to).
You might be able to do something similar with the [CompilerGenerated] attribute if its applied at the method level, but will get false positives when applied at the class level (the compiler applies it to state machines for iterators and async methods, but both will likely have non-generated code too).

Related

Can VS Debugger break on change of an Object ID? Similar to C++ [duplicate]

How can I track a variable's values as they change, at runtime, in C#? I'm interested in the same functionality that the debugger provides when I'm tracing a variable through execution steps, only that I need to call upon it from my code. Some sort of key-value observing, but for all kinds of variables(local, class, static, etc), not only properties. So, basically, receive a notification when a variable's value changes.
You are working from the assumption that the debugger can track variable changes. It can't.
It is possible with unmanaged code, the processor has dedicated debug registers that allow setting data breakpoints. Up to three are provided. It generates a hardware interrupt when it sees a particular memory location getting written. This otherwise very useful feature isn't available in managed code however. The garbage collector is completely incompatible with it, it moves objects around, giving them another address.
The managed debugger does support a "when hit" condition on a breakpoint, allowing you to dump info to the output window. That however requires a breakpoint, it cannot be triggered by a change in variable value. It also really slows down code execution since the debugger actually enters a break state before executing the condition.
The obvious place to put such a breakpoint is in a property setter. Which is what you'll need to implement this feature in code. You can do anything you want in that setter, using the Trace class for example.
To add to what Marc said, if you want to do this for lots of properties and methods you might want to check out aspect oriented programming techniques, and libraries such as PostSharp.
http://www.sharpcrafters.com/postsharp
The managed debugger uses the ICorDebug COM API for pretty much everything. The part that you're interested is ICorDebugValue and its descendants. Note that a LOT of the debugging API requires that the process be not running (ie, have encountered a breakpoint) in order for the various inspections to happen. A high level overview of ICorDebug is here. The documentation on it is kinda sparse, but some Googling may help. Good luck.
The only sensible way you could do that without the debugger would be: don't use a variable, but use a property, and (perhaps conditionally) add trace to the setter:
private int myValue;
public int MyValue {
get {return myValue;}
set {
SomeTraceMethod(myValue, value, ...);
myValue = value;
}
}
Obviously this cannot then be used for arbitrary fields/variables.
As others mentioned a mechanism like that makes only sense when using properties. In .NET you can then make use of the INotifyPropertyChanged interface.
For a sample how to implement it see
How to: Implement the INotifyPropertyChanged Interface
The referenced article talks explicitly about Windows Forms, but you are not bound to that (the interface is actually declared in the System.ComponentModel namespace in System.dll). In fact, this interface is widely used for data binding scenarios, e.g. in WPF.

How to get an attribute to act as [Conditional("DEBUG")]?

I have a C# program where some parts of code are generated using D-style mixins (i.e., the body of the method is compiled, executed, and results inserted into a class). The method is marked with [MixinAttribute] and, naturally, I don't want it to be compiled into the program. Is there some cheap way of preventing the method decorated with this attribute from being included in a build?
The only way is with compiler conditionals:
#if DEBUG
[MixinAttribute]
// method you don't want included
#endif
The problem with this approach is that you then create a member which will be unavailable in builds where DEBUG is not defined. You then have to mark all usages with the conditional, and I don't think this is what you want. It's not quite clear but I think what you are really asking is how you create dynamic call sites at build time, or, rather, at JIT time (which is what the ConditionalAttribute controls). If this is the case, you can't really do this easily in C# without using some kind of dynamic dispatch overriding (using some proxying library) or by using some post-processing tool like PostSharp to manipulate the compiler output.

Monitoring changes of a private field in an external assembly without source

I want to monitor (or place a breakpoint on) each change of a static field which is member of an internal class which resides in an external assembly for which I don't have code:
Assembly: PresentationCore.dll
Class : MS.Internal.MemoryPressure
Field : private static long _totalMemory
Ideally I should be able to see the stacktraces which trigger the changes.
Is this possible with VS and if yes then how do I have to setup VS in order to do this? Or will I need some external profiling tool?
You cannot set a breakpoint on a field. You are in luck, there's only one method that modifies the value, called AddToTotal. Debug + New Breakpoint + Break At Function. Type "MS.Internal.MemoryPressure.AddToTotal" and untick the "Use IntelliSense" option. The debugger will break as soon as the method is called, typically when the code creates a bitmap. You will only have machine code to look at.
As soon as it breaks, you can add a watch for MS.Internal.MemoryPressure._totalMemory. Adjust the breakpoint in the disassembly so it breaks past the field assignment.
Since PresentationCore is part of .Net you can debug the framework source
Take a look at this question
what about this:
http://ayende.com/blog/4106/nhibernate-inotifypropertychanged
Both RedGate Reflector as well as JetBrains Resharper can help you do it. They both decompile the assembly and generate the C# source code after which they allow you to work with it as if it were yours including placing breakpoints, watching the stack, etc.
I started with reflector, but now (starting from v.6) I switched to resharper it seems at this point to be more robust. Resharper has a 30 days trial, reflector used to be free I am not sure what it is now

Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible

Here is the error
Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible, possibly because the code is optimized.
I am writing a simple console app and the first line of code is this:
List<MyObjectModel> list = MyObjectModel.GetNonCompletedReturns();
and the code for the function is:
public static List<MyObjectModel> GetNonCompletedReturns()
{
MyObject service = new MyObject();
List<MyObject> entities =
(from recs in service.Retrieve() where select recs).ToList();
List<MyObjectModel> models = new List<MyObjectModel>();
foreach (MyObject entity in entities)
{
models.Add(BindModel(entity));
}
return models;
}
and if I try to step through the code, as soon as I get back to the main of my app and hover over the list, I get the error message that I showed.
Can anyone help?
If your project is compiled in release (with optimizations turned on), you may see this. Have you tried the DEBUG configuration?
This error fires only when you are trying to use Watch dialog during debug.
Try to use some other technique to output the variables, like Debug.WriteLine, Console.WriteLine and so on.
None of the answers solved my problem so I'm posting the solution that helped me.
"If there is to much data in the parameters then this error can occure,
a simple solution is to make an object, not a struct because that's a dataobject.
Put this object in your parameters instead of all the different variables,
normally the problem will no longer take place."
Here's a little trick just in case you want to examine some objects and you are not able to change the parameters:
I've created a call to a new temporary function, inside the function from where I was unable to watch my object. Then, inside that new function I was able to watch my object. After the job is done, just delete the function.
While it's true that the "Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible, possibly because the code is optimized" error appears when in release mode, most developers just ensure that their projects are configured to compile as a debug build. BUT to be sure that you have no release-DLL issues, you also must check the references to DLLs that are in your solution and make sure that you don't have a reference to a release-build DLL. If you find that this is the case, delete the DLL reference and then add a project reference rather than a DLL reference. The project reference will ensure that your solution references debug or release versions of the DLL as specified in your build configuration.
Note that the above advice applies, of course, to only those DLLs to which you have source code and which are built from a project in your solution.
I got this too, when I hit a NullReferenceException from a 3rd party control.
In this one case, I found that if I set a breakpoint before I hit the exception, I could then single step through the rest of the code without seeing the problem.
No idea why, but this worked for me - in this case at least.
For what it's worth, this error can also be caused by an infinite loop in a property getter (simplified version below). When the debugger attempts to evaluate the property (e.g. in the watch window) the UI will hang for a few seconds and the "Cannot evaluate expression..." error will appear for many of the other properties in the same class.
public int MyProperty
{
get
{
while (true) { }
return 0;
}
}
First make sure that you're running your code in DEBUG mode and with code optimization turned off. you can turn that off from the properties of your project.
If you made all of the above and the problem persists, then it's probably a problem with the stack having Debug.Break() on top of it. The solution for this is very easy, just press F10 to move to the next line and you should be able to evaluate the expression.
You can check this SO question for more information about this issue.
I was experiencing the same error message in the Visual Studio debugger when evaluating a linq expression.
Disabling the VS debugger config setting 'Enable Just My Code' resolved the issue for me:
To enable or disable Just My Code, choose the Tools > Options menu in
Visual Studio. In the Debugging > General node, choose or clear Enable
Just My Code.
https://learn.microsoft.com/en-us/visualstudio/debugger/just-my-code
I was having same issue in Visual Studio 2017. Going to Debug> Options> Debugging> General and checking "Suppress JIT optimization on module load(Managed only)" fixed my issue

Debug vs Trace in C#

As I understand statements like Debug.WriteLine() will not stay in the code in the Release build. On the other hand Trace.WriteLine() will stay in the code in the Release build.
What is controling this behaviour? Does the C# compiler ignores everything from the System.Diagnostics.Debug class when the DEBUG is defined?
I am just trying to understand the internals of C# and just curious.
These methods use the ConditionalAttribute to designate when they should be included.
When DEBUG is specified as a #define, via the command line or the system environment (set DEBUG = 1 in the shell), a method marked with [Conditional("DEBUG")] will be included by the compiler. When DEBUG is not included, those methods and any calls to them will be omitted. You can use this mechanism yourself to include methods under certain circumstances and it is also used to control the Trace calls like Trace.WriteLine (this uses the TRACE define).
This is due to ConditionalAttribute; the compiler ignores calls to methods marked as conditional unless that symbol is defined.
You can have your own:
[Conditional("BLUE")]
void Bar() {...}
which will only be called when BLUE is defined.
Note that there are some restrictions, to make "definite assignment" work:
no return value
no out parameters
(the same restrictions apply to partial methods for similar reasons)

Categories

Resources