Skip to content
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

Investigate Debugging story #68

Closed
glennblock opened this issue Mar 7, 2013 · 29 comments
Closed

Investigate Debugging story #68

glennblock opened this issue Mar 7, 2013 · 29 comments

Comments

@glennblock
Copy link
Contributor

One of the things people are asking is how they can debug Rosyln sripts. Today Roslyn doesn't support debugging, though it does support compiling to a dll.

So, the question is can one figure out how using that you could attach to a process using VS to debug.

I am not sure it's doable, as Roslyn may not include PDBs. Anyway, if someone wants to run with this to see if it's possible, we'd love it!

We're not asking for a PR (yet) we're asking for a proof of concept.

@dschenkelman
Copy link
Contributor

I can give this a shot, as long as there is no need to have it ASAP as I don't know how much time I'll have to work on this.

@glennblock
Copy link
Contributor Author

@dschenkelman no rush.

@dschenkelman
Copy link
Contributor

I have created a small spike that takes a .csx file (with a main method as entry point) and creates a console app .exe and a related .pdb.

I have uploaded it to my repo fork, and created a readme that explains the most important things. Check it out here.

The spike shows that a .pdb file can be correclty created (assuming tweaks are performed to scriptcs code gen) and debugged (tried it using mdbg).

If you think the spike is useful, we can have a discussion about where to go next.

@glennblock
Copy link
Contributor Author

Wow, this is awesome dude! I can't wait to check it out.

On Thu, Mar 7, 2013 at 8:23 PM, dschenkelman notifications@github.comwrote:

I have created a small spike that takes a .csx file (with a main method as
entry point) and creates a console app .exe and a related .pdb.

I have uploaded it to my repo fork, and created a readme that explains the
most important things. Check it out herehttps://github.com/dschenkelman/scriptcs/tree/dev/spikes/DebugSymbols
.

The spike shows that a .pdb file can be correclty created (assuming tweaks
are performed to scriptcs code gen) and debugged (tried it using mdbg).

If you think the spike is useful, we can have a discussion about where to
go next.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14602113
.

@glennblock
Copy link
Contributor Author

Took a quick peak, I see you are compiling the syntax tree. One question is
what happens to the host object in this model. The host object is going to
surface capabilities to the script or ability to interact with runtime
hosts living in the script pack. I need to see if there's some things we
can do to allow that to still work.

On Thu, Mar 7, 2013 at 9:38 PM, Glenn Block glenn.block@gmail.com wrote:

Wow, this is awesome dude! I can't wait to check it out.

On Thu, Mar 7, 2013 at 8:23 PM, dschenkelman notifications@github.comwrote:

I have created a small spike that takes a .csx file (with a main method
as entry point) and creates a console app .exe and a related .pdb.

I have uploaded it to my repo fork, and created a readme that explains
the most important things. Check it out herehttps://github.com/dschenkelman/scriptcs/tree/dev/spikes/DebugSymbols
.

The spike shows that a .pdb file can be correclty created (assuming
tweaks are performed to scriptcs code gen) and debugged (tried it using
mdbg).

If you think the spike is useful, we can have a discussion about where to
go next.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14602113
.

@glennblock
Copy link
Contributor Author

Or at least allow the same code to still compile i.e. the host object
surfaces some other way.

On Thu, Mar 7, 2013 at 9:41 PM, Glenn Block glenn.block@gmail.com wrote:

Took a quick peak, I see you are compiling the syntax tree. One question
is what happens to the host object in this model. The host object is going
to surface capabilities to the script or ability to interact with runtime
hosts living in the script pack. I need to see if there's some things we
can do to allow that to still work.

On Thu, Mar 7, 2013 at 9:38 PM, Glenn Block glenn.block@gmail.com wrote:

Wow, this is awesome dude! I can't wait to check it out.

On Thu, Mar 7, 2013 at 8:23 PM, dschenkelman notifications@github.comwrote:

I have created a small spike that takes a .csx file (with a main method
as entry point) and creates a console app .exe and a related .pdb.

I have uploaded it to my repo fork, and created a readme that explains
the most important things. Check it out herehttps://github.com/dschenkelman/scriptcs/tree/dev/spikes/DebugSymbols
.

The spike shows that a .pdb file can be correclty created (assuming
tweaks are performed to scriptcs code gen) and debugged (tried it using
mdbg).

If you think the spike is useful, we can have a discussion about where
to go next.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14602113
.

@dschenkelman
Copy link
Contributor

I'll spend a bit of time checking out possible approaches to get this done although I don't know if it will be possible. Perhaps I'm getting ahead, but what I believe is the bad part of this approach is generating code that can be compiled using the SyntaxTree approach from the *.csx files.

@dschenkelman
Copy link
Contributor

After a bit of time looking for an approach to get the compilation from the .csx without using the SyntaxTree, using the .csx script directly, I found a possible way.

var scriptEngine = new ScriptEngine();
scriptEngine.AddReference("System");
scriptEngine.AddReference("System.Core");
var session = scriptEngine.CreateSession();

Submission<object> s = session.CompileSubmission<object>(code);

var temp = (Compilation)s.Compilation;
// using ConsoleApplication is just a spike, the default is .dll
var compilation = temp.WithOptions(temp.Options.WithOutputKind(OutputKind.ConsoleApplication));

CommonEmitResult result;

using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
{
    result = compilation.Emit(outputStream, outputName, pdbPath, pdbStream);
}

The .exe and .pdb are generated:
generatedCode

But when the .exe is run, the following error is thrown:

Unhandled Exception: System.MethodAccessException: Main method for type 'Submiss
ion#0' has invalid signature.

Perhaps the correct approach would be to compile to a .dll an then invoke the method, but it seems that this would allow us to keep host objects by providing the session to the generated .dll.

@glennblock
Copy link
Contributor Author

You ae making great progress. Can you do a test as a dll?

On Friday, March 8, 2013, dschenkelman wrote:

After a bit of time looking for an approach to get the compilation from
the .csx without using the SyntaxTree, using the .csx script directly, I
found a possible way.

var scriptEngine = new ScriptEngine();
scriptEngine.AddReference("System");
scriptEngine.AddReference("System.Core");
var session = scriptEngine.CreateSession();

Submission s = session.CompileSubmission(code, isInteractive: true);

var temp = (Compilation)s.Compilation;
// using ConsoleApplication is just a spike, the default is .dll
var compilation = temp.WithOptions(temp.Options.WithOutputKind(OutputKind.ConsoleApplication));

CommonEmitResult result;

using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
{
result = compilation.Emit(outputStream, outputName, pdbPath, pdbStream);
}

The .exe and .pdb are generated:
[image: generatedCode]https://f.cloud.github.com/assets/3376731/236750/633ee340-87fb-11e2-844b-00a2bcde9b60.png

But when the .exe is run, the following error is thrown:

Unhandled Exception: System.MethodAccessException: Main method for type 'Submiss
ion#0' has invalid signature.

Perhaps the correct approach would be to compile to a .dll an then invoke
the method, but it seems that this would allow us to keep host objects by
providing the session to the generated .dll.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14622591
.

@dschenkelman
Copy link
Contributor

Just performed one to see if the script runs using this code:

var scriptEngine = new ScriptEngine();
scriptEngine.AddReference("System");
scriptEngine.AddReference("System.Core");
var session = scriptEngine.CreateSession();

Submission<string> s = session.CompileSubmission<string>(code);

var compilation = (Compilation)s.Compilation;

// need to add assemblies
CommonEmitResult result;

using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
{
    result = compilation.Emit(outputStream, outputName, pdbPath, pdbStream);
}

if (result.Success)
{
    Console.WriteLine("Compilation successful");
    Console.WriteLine(string.Format("Output .exe at {0}", outputPath));
    Console.WriteLine(string.Format("Output .pdb at {0}", pdbPath));

    var assembly = Assembly.LoadFrom(outputName);
    var type = assembly.GetType("Submission#0");
    var method = type.GetMethod("<Factory>", BindingFlags.Static | BindingFlags.Public);
    method.Invoke(null, new[]{ session });
}

This produced the expected output:

IMPORTANT
================================================
In this spike the .csx file must only make use of classes in mscorlib, System an
d System.Core assemblies.
================================================

Compilation successful
Output .exe at C:\Users\Damian\Documents\GitHub\scriptcs\spikes\DebugSymbols\Deb
ugSymbols\bin\Debug\test.dll
Output .pdb at C:\Users\Damian\Documents\GitHub\scriptcs\spikes\DebugSymbols\Deb
ugSymbols\bin\Debug\test.pdb
Attach and the press ENTER to start

3

My next step will be to either attach to the running instance with mdbg (if possible), or create an .exe that just invokes the script through reflection assuming that the .dll is in the same dir.

@filipw
Copy link
Member

filipw commented Mar 8, 2013

Nice!

@dschenkelman
Copy link
Contributor

Been working on attaching to a running console app (which simulates scriptcs.exe) from either VS or mdbg.

  • [success] Able to attach from mdbg (more on that below)
  • [failed] Could not attach from VS.

VS issue

As there is no 1 to 1 mapping between source and compiled code, so the .pdb does not have a related file and VS cannot attached to a particular file to be debugged (any ideas to work around this?). For example, this source:

using System;
using System.Diagnostics;

Debugger.Break();

Console.WriteLine("Testing");

public class Writer
{
    public void Write(string s)
    {
        Console.WriteLine(s);
    }
}

int a = 1;
int b = 2;

int c = a + b;
new Writer().Write(c.ToString());
Console.ReadLine

Is compiled into:

using Microsoft.CSharp.RuntimeHelpers;
using Roslyn.Scripting;
using System;
using System.Diagnostics;
public sealed class Submission#0
{
    public class Writer
    {
        public void Write(string s)
        {
            Console.WriteLine(s);
        }
    }
    public int a;
    public int b;
    public int c;
    public Submission#0(Session session, ref object submissionResult)
    {
        SessionHelpers.SetSubmission(session, 0, this);
        Debugger.Break();
        Console.WriteLine("Testing");
        this.a = 1;
        this.b = 2;
        this.c = checked(this.a + this.b);
        new Submission#0.Writer().Write(this.c.ToString());
        submissionResult = Console.ReadLine();
    }
    public static object <Factory>(Session session)
    {
        object result;
        new Submission#0(session, ref result);
        return result;
    }
}

Using mdbg

I have been able to run a console app that compiles the .csx into a .dll with its related .pdb and attach to it using mdbg.exe that is located at C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools (the location is important because there are might be others at C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin that are installed with the Windows SDK that did not work).
The steps to attach are:

  1. Run the application (simulating scripcs.exe) which prompts the user to attach the debugger before continuing.
  2. Attach to the console application using mdbg by running attach {pid}.
  3. Press ENTER in the console app.
  4. Run go in mdbg, which is like VS F5. The first breakpoint will be hit.

The following figures show a simple debugging session (using the source code provided above). The line numbers are the same as the ones in the original source code file, but there is no out-of-the-box way to check the source code from mdbg because .pdb does not point to the source file:
debugSession
Debug session

execution
Execution

Possible improvements

The aforementioned approach does work but is definitely a "poor man's debugger". Some of the things I have considered to improve this are (in no particular order):

  1. Tooling to map source code to the debugger's current line, which will allow users to directly see where they are without having both things side by side.
  2. Support for some sort of #break directive in .csx files so users don't have to include System.Diagnostics and which is only taken into account when scriptcs is configured to debug (something like scriptcs -d?).
  3. Immediate window debugging support, so you could step through the code using mdbg but have the ability to watch variables in a simpler way (would having access to the Session and using its execute method work?).

Nevertheless, there are some related items that you might probably would like to see addressed before 1 and 3, such as:

Proposal

For the time being (unless you would like to me help in any of the above), I could:

  1. Create a new ScriptExecutor that is similar to the current one, but produces .dll and .pdb files when the -d flag is provided to scriptcs.
  2. Create a readme that explains how to work with mdbg and scriptcs.

Let me know if you would like to have a discussion about any of this.

@glennblock
Copy link
Contributor Author

We'd love for you to do this!

I didn't digest it all, but does it need a new executor? Should we have a
-debug swtich to activate it?

On Sat, Mar 9, 2013 at 1:10 PM, dschenkelman notifications@github.comwrote:

Been working on attaching to a running console app (which simulates
scriptcs.exe) from either VS or mdbg. I was able to do it from mdbg (more
on that below), but can't get it done with VS.
VS issue

As there is no 1 to 1 mapping between source and compiled code, so the
.pdb does not have a related file and VS cannot attached to a particular
file to be debugged (any ideas to work around this?). For example, this
source:

using System;using System.Diagnostics;
Debugger.Break();
Console.WriteLine("Testing");
public class Writer{
public void Write(string s)
{
Console.WriteLine(s);
}}
int a = 1;int b = 2;
int c = a + b;new Writer().Write(c.ToString());Console.ReadLine

Is compiled into:

using Microsoft.CSharp.RuntimeHelpers;using Roslyn.Scripting;using System;using System.Diagnostics;public sealed class Submission#0{
public class Writer
{
public void Write(string s)
{
Console.WriteLine(s);
}
}
public int a;
public int b;
public int c;
public Submission#0(Session session, ref object submissionResult)
{
SessionHelpers.SetSubmission(session, 0, this);
Debugger.Break();
Console.WriteLine("Testing");
this.a = 1;
this.b = 2;
this.c = checked(this.a + this.b);
new Submission#0.Writer().Write(this.c.ToString());
submissionResult = Console.ReadLine();
}
public static object (Session session)
{
object result;
new Submission#0(session, ref result);
return result;
}}

Using mdbg

I have been able to run a console app that compiles the .csx into a .dll
with its related .pdb and attach to it using mdbg.exe that is located at C:\Program
Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools
(the location is
important because there are might be others at C:\Program
Files\Microsoft SDKs\Windows\v7.1\Bin
that are installed with the
Windows SDK that did not work).
The steps to attach are:

  1. Run the application (simulating scripcs.exe) which prompts the user to
    attach the debugger before continuing.
  2. Attach to the console application using mdbg by running attach {pid}.
  3. Press ENTER in the console app.
  4. Run go in mdbg, which is like VS F5. The first breakpoint will be hit.

The following figures show a simple debugging session (using the source
code provided above). The line numbers are the same as the ones in the
original source code file, but there is no out-of-the-box way to check the
source code from mdbg because .pdb does not point to the source file:
[image: debugSession]https://f.cloud.github.com/assets/3376731/240184/df89b368-88f9-11e2-9a05-c350aa472997.png
Debug session

[image: execution]https://f.cloud.github.com/assets/3376731/240187/f0a2fb96-88f9-11e2-9da4-d4f100e66227.png
Execution
Possible improvements

The aforementioned approach does work but is definitely a "poor man's
debugger". Some of the things I have considered to improve this are (in no
particular order):

  1. Tooling to map source code to the debugger's current line, which will
    allow users to directly see where they are without having both things side
    by side.
  2. Support for some sort of #break directive in .csx files so users don't
    have to include System.Diagnostics and which is only taken into account
    when scriptcs is configured to debug (something like scriptcs -d?).
  3. Immediate window debugging support, so you could step through the code
    using mdbg but have the ability to watch variables in a simpler way (would
    having access to the Session and using its execute method work?).

Nevertheless, there are some related items that you might probably would
like to see addressed before 1 and 3, such as:

Proposal

For the time being (unless you would like to me help in any of the above),
I could:

  1. Create a new ScriptExecutor that is similar to the current one, but
    produces .dll and .pdb files when the -d flag is provided to scriptcs.
  2. Create a readme that explains how to work with mdbg and scriptcs.

Let me know if you would like to have a discussion about any of this.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14670730
.

@glennblock
Copy link
Contributor Author

Instead of #break, we could just add the diagnostics namespace / ref by
default no?

or are you thinking we make #break because it is less verbose?

On Sat, Mar 9, 2013 at 1:41 PM, Glenn Block glenn.block@gmail.com wrote:

We'd love for you to do this!

I didn't digest it all, but does it need a new executor? Should we have a
-debug swtich to activate it?

On Sat, Mar 9, 2013 at 1:10 PM, dschenkelman notifications@github.comwrote:

Been working on attaching to a running console app (which simulates
scriptcs.exe) from either VS or mdbg. I was able to do it from mdbg (more
on that below), but can't get it done with VS.
VS issue

As there is no 1 to 1 mapping between source and compiled code, so the
.pdb does not have a related file and VS cannot attached to a particular
file to be debugged (any ideas to work around this?). For example, this
source:

using System;using System.Diagnostics;
Debugger.Break();
Console.WriteLine("Testing");
public class Writer{
public void Write(string s)
{
Console.WriteLine(s);
}}
int a = 1;int b = 2;
int c = a + b;new Writer().Write(c.ToString());Console.ReadLine

Is compiled into:

using Microsoft.CSharp.RuntimeHelpers;using Roslyn.Scripting;using System;using System.Diagnostics;public sealed class Submission#0{
public class Writer
{
public void Write(string s)
{
Console.WriteLine(s);
}
}
public int a;
public int b;
public int c;
public Submission#0(Session session, ref object submissionResult)
{
SessionHelpers.SetSubmission(session, 0, this);
Debugger.Break();
Console.WriteLine("Testing");
this.a = 1;
this.b = 2;
this.c = checked(this.a + this.b);
new Submission#0.Writer().Write(this.c.ToString());
submissionResult = Console.ReadLine();
}
public static object (Session session)
{
object result;
new Submission#0(session, ref result);
return result;
}}

Using mdbg

I have been able to run a console app that compiles the .csx into a .dll
with its related .pdb and attach to it using mdbg.exe that is located at
C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools (the
location is important because there are might be others at C:\Program
Files\Microsoft SDKs\Windows\v7.1\Bin
that are installed with the
Windows SDK that did not work).
The steps to attach are:

  1. Run the application (simulating scripcs.exe) which prompts the user to
    attach the debugger before continuing.
  2. Attach to the console application using mdbg by running attach {pid}.
  3. Press ENTER in the console app.
  4. Run go in mdbg, which is like VS F5. The first breakpoint will be hit.

The following figures show a simple debugging session (using the source
code provided above). The line numbers are the same as the ones in the
original source code file, but there is no out-of-the-box way to check the
source code from mdbg because .pdb does not point to the source file:
[image: debugSession]https://f.cloud.github.com/assets/3376731/240184/df89b368-88f9-11e2-9a05-c350aa472997.png
Debug session

[image: execution]https://f.cloud.github.com/assets/3376731/240187/f0a2fb96-88f9-11e2-9da4-d4f100e66227.png
Execution
Possible improvements

The aforementioned approach does work but is definitely a "poor man's
debugger". Some of the things I have considered to improve this are (in no
particular order):

  1. Tooling to map source code to the debugger's current line, which will
    allow users to directly see where they are without having both things side
    by side.
  2. Support for some sort of #break directive in .csx files so users
    don't have to include System.Diagnostics and which is only taken into
    account when scriptcs is configured to debug (something like scriptcs -d
    ?).
  3. Immediate window debugging support, so you could step through the code
    using mdbg but have the ability to watch variables in a simpler way (would
    having access to the Session and using its execute method work?).

Nevertheless, there are some related items that you might probably would
like to see addressed before 1 and 3, such as:

Proposal

For the time being (unless you would like to me help in any of the
above), I could:

  1. Create a new ScriptExecutor that is similar to the current one, but
    produces .dll and .pdb files when the -d flag is provided to scriptcs.
  2. Create a readme that explains how to work with mdbg and scriptcs.

Let me know if you would like to have a discussion about any of this.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14670730
.

@dschenkelman
Copy link
Contributor

The idea of having a new executor is that the normal (current one) won't generate the .dll and the .pdb. The -debug activated one will. They will probably end up inheriting from a base class and overriding just one or two methods.

I like #break better because it is less verbose. We should automatically add System.Diagnostics if -debug is provided.

@dschenkelman
Copy link
Contributor

I've created #76 and will start to work on it.

@glennblock
Copy link
Contributor Author

The downside to #break is it will "break" scenarios of upgrading to a full
vs project. Though I guess that is a choice.

I like the simplicity, but interested to hear what others think.

On Sat, Mar 9, 2013 at 2:36 PM, dschenkelman notifications@github.comwrote:

I've created #76 #76 and
will start to work on it.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14672169
.

@dschenkelman
Copy link
Contributor

Yes, I agree with that. There's no rush for this and it would be good to
hear more voices before deciding on one.

On Sat, Mar 9, 2013 at 8:27 PM, Glenn Block notifications@github.comwrote:

The downside to #break is it will "break" scenarios of upgrading to a full
vs project. Though I guess that is a choice.

I like the simplicity, but interested to hear what others think.

On Sat, Mar 9, 2013 at 2:36 PM, dschenkelman notifications@github.comwrote:

I've created #76 #76 and
will start to work on it.


Reply to this email directly or view it on GitHub<
https://github.com/scriptcs/scriptcs/issues/68#issuecomment-14672169>
.


Reply to this email directly or view it on GitHubhttps://github.com//issues/68#issuecomment-14672945
.

@dschenkelman
Copy link
Contributor

This one should probaly be closed. At least for the time being there probably won't be any major updates in debugging per se.

@jrusbatch
Copy link
Member

Closing in favor of #76.

@glennblock
Copy link
Contributor Author

@dschenkelman I got a pointer from the Roslyn team that might be worth investigating aroun the #line directive: http://blogs.msdn.com/b/abhinaba/archive/2005/10/10/479016.aspx

This "might" allow doing the source mapping if the CTP supports it.

@glennblock glennblock reopened this Mar 12, 2013
@dschenkelman
Copy link
Contributor

@glennblock Wow! That absolutely did the trick. We definitely need to address #71 before adding support for this, but it seems to be definitely working!
debuggingInVs

@dschenkelman
Copy link
Contributor

Been going over the opened pull requests. We would need to:

  1. Merge Refactored roslyn out of core to fix #90 in preperation for #80 #92 and Refactored and fixed bug in FilePreProcessor. Fixes #98 #102.
  2. Implement track line number correctly if script is composed of multiple scripts through #load` #71 (I have it assigned, but is waiting for Refactored and fixed bug in FilePreProcessor. Fixes #98 #102).

After that I will work automatically generating #line directives correctly #104.

@glennblock
Copy link
Contributor Author

@dschenkelman awesome!!!!!

@BrendanThompson
Copy link

@dschenkelman this is amazingly awesome!!

@jrusbatch
Copy link
Member

@glennblock @dschenkelman Agreed, 100%. Best screen shot I've seen all day.

@dschenkelman
Copy link
Contributor

Thanks guys, I'm really having a good time as I can do something fun while also adding value.

@glennblock
Copy link
Contributor Author

@dschenkelman and we're having a good time with you!

@dschenkelman
Copy link
Contributor

@glennblock @filipw @jrusbatch
Should be closed. #86 is open to track the pending work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants