Skip to content

Breakpoints in SDK code don't work for framework code (found from Go-to-Definition) #27189

Closed

Description

@DanTup

Breakpoints only work if I use the debugger to step into dart: libraries and add breakpoints, but not if I set them by navigating into the code using Go-to-Definition (via the analyzer).

For example, take this code:

void main() {
  print('test');
  runApp(const GalleryApp());
}

If I go-to-definition on print I will be taken to the implementation of print that lives inside my SDK folder (this path comes back from the analyzer):

/Users/dantup/Dev/Google/flutter/bin/cache/pkg/sky_engine/lib/core/print.dart

If I add a breakpoint in the definition of print then when I run the application, it's never hit. Here's what the addBreakpointWithScriptUri call looks like:

{
	"id": "7",
	"method": "addBreakpointWithScriptUri",
	"params": {
		"isolateId": "isolates/585724240",
		"scriptUri": "package:sky_engine/core/print.dart",
		"line": 9
	}
}
{
	"jsonrpc": "2.0",
	"result": {
		"type": "Breakpoint",
		"fixedId": true,
		"id": "breakpoints\/1",
		"breakpointNumber": 1,
		"resolved": false,
		"location": {
			"type": "UnresolvedSourceLocation",
			"scriptUri": "package:sky_engine\/core\/print.dart",
			"line": 9
		}
	},
	"id": "7"
}

I was under the impression this was expected, but @a-siva suggests maybe not. I think the issue is that the breakpoint I'm setting is in package:sky_engine/core/print.dart but if I step into print with the debugger the URI is dart:code/print.dart.

Activity

  1. added
    toolAffects the "flutter" command-line tool. See also t: labels.
    a: debuggingDebugging, breakpoints, expression evaluation
    on Jan 28, 2019
  2. added this to the milestone on Jan 28, 2019
  3. DanTup commented on Mar 20, 2019

    @DanTup
    ContributorAuthor

    This may not be specific to Flutter - while reviewing my skipped tests I noticed that this also doesn't work outside of Flutter (Dart CLI apps). I F12'd into Uri.parse() and added a breakpoint, but it doesn't get hit either.

    I'm adding it with a file:/// URI, since in VS Code I don't have a mapping of fs->URIs for the SDK:

    {
    	"id": "12",
    	"method": "addBreakpointWithScriptUri",
    	"params": {
    		"isolateId": "isolates/141746691",
    		"scriptUri": "file:///Users/dantup/Dev/dart-sdk/v2.2.1-dev.1.1/lib/core/uri.dart",
    		"line": 789
    	}
    }

    (fyi @bkonyi :-))

  4. bkonyi commented on Mar 26, 2019

    @bkonyi
    Contributor

    For setting breakpoints within dart:* libraries, you'll want to pass a URI with the org-dartlang-sdk:// scheme. For example, to set a breakpoint for print in dart:core you would use the following for the scriptUri: org-dartlang-sdk:///sdk/lib/core/print.dart. Can you give that a shot and let me know if that works?

    Also, as an aside, is there any way to get the output from the VM when running through VSCode? I'll admit I haven't tried very hard to find it, so I could be missing something obvious :)

  5. DanTup commented on Mar 26, 2019

    @DanTup
    ContributorAuthor

    For setting breakpoints within dart:* libraries

    The complicated bit here is that we don't really know what's a dart: library. In the editor the user just invokes "Go to definition" and the analysis server gives us a filepath back. It may be in the SDK, it might not. Is there any possibility of supporting the file paths in the debugger?

    It's possible I could just look for file paths the start with the SDK folder we're running from, but it feels a little fragile.

    Also, as an aside, is there any way to get the output from the VM when running through VSCode?

    Do you mean the VM service JSON? There are two ways:

    1. Set the dart.observatoryLogFile setting - this will log the JSON on every debug session (overwriting the file each time). I leave this enabled all the time, so if I spot a bug I can grab it and not have to worry about reproducing it again.

    2. Run the Dart: Capture Logs command and tick Observatory. This will start logging to a temp file, which will be opened when you click the Stop Logging button (which may collapse into the bell icon after a while).

    In both cases, you might want to also increase the dart.maxLogLineLength setting to reduce truncation of long messages (default is 2k characters).

  6. bkonyi commented on Mar 26, 2019

    @bkonyi
    Contributor

    For setting breakpoints within dart:* libraries

    The complicated bit here is that we don't really know what's a dart: library. In the editor the user just invokes "Go to definition" and the analysis server gives us a filepath back. It may be in the SDK, it might not. Is there any possibility of supporting the file paths in the debugger?

    It's possible I could just look for file paths the start with the SDK folder we're running from, but it feels a little fragile.

    Oh that's unfortunate. We don't have the dart:* sources mapped to file URIs as they're part of the platform kernel which is linked into the VM. Basically, since the files for these sources aren't actually on the filesystem in a typical sense, the platform kernel uses URIs with the org-dartlang-sdk:// scheme. Unfortunately, you'll probably have to hack at the path a bit to get to the desired URI but I can't think of any way to get around it.

    Also, as an aside, is there any way to get the output from the VM when running through VSCode?

    Do you mean the VM service JSON? There are two ways:

    1. Set the dart.observatoryLogFile setting - this will log the JSON on every debug session (overwriting the file each time). I leave this enabled all the time, so if I spot a bug I can grab it and not have to worry about reproducing it again.
    2. Run the Dart: Capture Logs command and tick Observatory. This will start logging to a temp file, which will be opened when you click the Stop Logging button (which may collapse into the bell icon after a while).

    In both cases, you might want to also increase the dart.maxLogLineLength setting to reduce truncation of long messages (default is 2k characters).

    Perfect, thanks! :)

  7. DanTup commented on Mar 28, 2019

    @DanTup
    ContributorAuthor

    Just to clarify, are the path segments for dart:, org-dartlang-sdk: and the path in the local SDK folder all the same?

                  dart:xxx/yyy/zzz.dart
    org-dartlang-sdk://xxx/yyy/zzz.dart
        {sdk path}/lib/xxx/yyy/zzz.dart
    

    For example:

                  dart:core/uri.dart
    org-dartlang-sdk://core/uri.dart
        {sdk path}/lib/core/uri.dart
    

    There are two places where the user can add breakpoints for SDK sources:

    1. At editor time - no debugger is running. They invoke Go-to-Definition on a built-in method/class and it takes them to the source code - this works by the analysis server returning us the path on disk to the SDK's lib folder (the last item in the lists above).
    2. At debug time - the user is debugging, they Step into an SDK source and the URI and source code is provided via the VM service, but we are not provided the real path on disk.

    Right now these appear in VS Code as two completely different files (even though to the user they are logically the same). It seems like I need to be able to map them to the same thing in order for this to work as the user would expect.

    As a potential complication, is it guaranteed that the source downloaded from the VM service matches what's in the SDK lib folder on disk for the VM that's executing the code? (assuming the user hasn't explicitly modified it or something daft). For ex., if we stopped downloading source code from the VM and always used the one on disk, could anything bad happen?

  8. DanTup commented on Apr 8, 2019

    @DanTup
    ContributorAuthor

    @bkonyi any thoughts on the above? Thanks!

  9. bkonyi commented on Apr 8, 2019

    @bkonyi
    Contributor

    Ah, sorry for the delay! Must have slipped through my emails... anyway, the path segments aren't the same exactly. For example, org-dartlang-sdk:///sdk/lib/async/stream_impl.dart is the same as dart:async/stream_impl.dart, org-darglang-sdk:///runtime/lib/async_patch.dart is the same as dart:async-patch/async_patch.dart (note the dart:async-patch, which is rather strange), etc.

    As for whether the files on disk match those provided by the VM service, they should match overall except for patch files. I'm not sure how we apply them or pull them in for the actual SDK release since they're not packaged with the SDK like the rest of the core library files, but I assume they're just linked into the VM itself.

  10. DanTup commented on Apr 10, 2019

    @DanTup
    ContributorAuthor

    anyway, the path segments aren't the same exactly

    The example you gave still looks computable by me (eg. if there's no subfolder, then foo.dart becomes foo/foo.dart). What concerns me more is org-dartlang-sdk:///sdk/ versus org-dartlang-sdk:///runtime/, since I'm not sure why that's different.

    If we can reliably convert a file system path to a VM URI with some basic code (eg. not requiring special knowledge from the VM) then I think we can make this work. I'm not worried about patch files, since I don't think the user could Go-to-Definition to them in the first place.

    If the mapping from FS -> sdk URIs is not consistent (eg. it requires a big mapping) then that seems like a blocker since we'd need some mapping table. If that's the case, I wonder if we should build it into the SDK and let the analysis server provide it (to avoid duplicating it in each IDE)? (@bwilkerson I presume the server doesn't already have this, but I don't know for sure that that's true).

  11. DanTup commented on Apr 30, 2019

    @DanTup
    ContributorAuthor

    @bkonyi not urgent, but I saw you resolve a comment about this in a doc. I'm still not sure whether the mapping from FS to URI is something we can compute in the editor (with some rules), or if they're arbitrary and would require us to include a big mapping (which is probably not feasible) - see last comment above.

  12. bkonyi commented on May 22, 2019

    @bkonyi
    Contributor

    anyway, the path segments aren't the same exactly

    The example you gave still looks computable by me (eg. if there's no subfolder, then foo.dart becomes foo/foo.dart). What concerns me more is org-dartlang-sdk:///sdk/ versus org-dartlang-sdk:///runtime/, since I'm not sure why that's different.

    If we can reliably convert a file system path to a VM URI with some basic code (eg. not requiring special knowledge from the VM) then I think we can make this work. I'm not worried about patch files, since I don't think the user could Go-to-Definition to them in the first place.

    If the mapping from FS -> sdk URIs is not consistent (eg. it requires a big mapping) then that seems like a blocker since we'd need some mapping table. If that's the case, I wonder if we should build it into the SDK and let the analysis server provide it (to avoid duplicating it in each IDE)? (@bwilkerson I presume the server doesn't already have this, but I don't know for sure that that's true).

    The reason why we have both org-dartlang-sdk:///sdk/ versus org-dartlang-sdk:///runtime/ is that the *_patch.dart files are located in the VM's runtime directory as they often contain native method invocations. AFAIK, the vast majority of the Dart files in the runtime directory are patch files, with only a few which aren't.

  13. DanTup commented on May 23, 2019

    @DanTup
    ContributorAuthor

    Ok, but if the pattern is consistent (anything ending _patch.dart goes into runtime, everything else into sdk) that still seems computable.

    I'm trying to understand if I can write a function that given an SDK file path can compute the correct URI to put a breakpoint there (or vice versa).

    Is there a way I can get a list of all the org-dartlang-sdk scripts loaded? Maybe the easier thing is for me to take a list and see if I can write such a function, and confirm all the files I map to exist on disk?

  14. 2 remaining items

  15. DanTup commented on Jun 5, 2019

    @DanTup
    ContributorAuthor

    Wait a minute :( Going back to the sample right at the top here, it has:

    package:sky_engine\/core\/print.dart

    What is the relationship between package:sky_engine and the SDK? (And if it's special, is it the only special one?)

  16. knopp commented on Jun 11, 2019

    @knopp
    Member

    Any progress on this? Not being able to place breakpoint in dart SDK has caught me very much by surprise. This is a fundamental thing that's broken.

  17. knopp commented on Jun 12, 2019

    @knopp
    Member

    Also, iirc sky_engine is package that contains subset of dart sdk relevant for flutter (specified in _embedder.yaml). I don't think it should be present at all if you run CLI app against regular dart SDK.

  18. knopp commented on Jun 12, 2019

    @knopp
    Member

    So I tried a rather trivial approach of checking whether file is within dart SDK, and if it is replacing SDK path with org-dartlang-sdk:///sdk/, and also replacing dart: prefix with actual location stackTraceRequest and I was able to debug code within the SDK. Even something as simple as this would be significant improvement.

  19. DanTup commented on Jun 12, 2019

    @DanTup
    ContributorAuthor

    It wouldn't, but I'd like to just fix it once and it work everywhere. sky_engine is the current complication, since that's where I end up when I hit F12 on print in a Flutter project, but the debugger still maps it to the base Dart SDK.

    I'd like to know how sky_engine is treated differently, and whether it's the only package that is (in which case, I should be able to map that similarly).

    @bkonyi is this something you know, or is there someone else I could ping? Thanks!

  20. knopp commented on Jun 12, 2019

    @knopp
    Member

    I assume, that's because of _embedder.yaml present it in sky_engine/lib. It might be necessary to parse _embedder.yaml for all packages where it is present. However another complication seems to be, that embedder for example only maps "dart:async" to "async/async.dart, which in turns includes all files from async folder.

    I.e. this is what analyzer does

    This is getting rather hairy. It does seem like the proper place for mapping between org-dartlang-sdk and filesystem is in the analyzer, as it already knows about packages that embed sdk.

  21. DanTup commented on Jun 12, 2019

    @DanTup
    ContributorAuthor

    Aha, that's how it works.

    Yeah, it doesn't feel like this logic should exist in the editor, it seems like a pretty specific implementation detail and not some public API.

    @bwilkerson @devoncarew FYI..

    To save you reading the whole thread, the analyzer and the debugger have different ideas about URIs for SDK libraries (eg. analyzer gives file system paths, which for the SDK in flutter we end up mapping to package:sky_engine based on the .packages file, and for the SDK we just don't map). The debugger wants URIs for the SDK in specific formats (org-dartlang-sdk:///sdk/...).

    It doesn't seem like there's a great way for the editors to match these up. For example if you press Go-to-Definition on print when not debugging, and then also "step into" it during debugging, these two files are considered different by the editor. Each have their own set of breakpoints, one of which is never hit. This makes it really awkward to put breakpoints inside SDK files since you can only do it if you step into them first, not via Go-to-Definition.

    It would be great to support this, but I don't know where it should be fixed. My preference (biased entirely by the work I have to do in VS Code!) would be for the VM to handle file system paths for everything (including the SDK) since it already feels awkward for the editor to be doing its own parsing of .packages and mapping things to URIs, however it sounds like it doesn't have the information to do this.

    (I presume we must have this limitation in IntelliJ/Android Studio too?)

  22. knopp commented on Jun 12, 2019

    @knopp
    Member

    For reference, patch I'm using right now to get breakpoints working. Obviously this only works with dart SDK and doesn't handle embedded SDKs in any way.

  23. DanTup commented on Jun 12, 2019

    @DanTup
    ContributorAuthor

    @knopp thanks! Depending on what a potential future solution might be, I might run with something like this as a workaround in the meantime (probably special-casing sky_engine too, if that's the only one).

  24. added
    P2Important issues not at the top of the work list
    on May 29, 2020
  25. removed this from the milestone on Aug 17, 2020
  26. bkonyi commented on Nov 1, 2021

    @bkonyi
    Contributor

    This should be resolved by using the new RPCs landed in this CL. Closing, but feel free to reopen if you want to track that work here.

  27. github-actions commented on Nov 16, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  28. locked as resolved and limited conversation to collaborators on Nov 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: debuggingDebugging, breakpoints, expression evaluationtoolAffects the "flutter" command-line tool. See also t: labels.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions