Open Bug 1753514 Opened 3 years ago Updated 3 years ago

Show native stacks in the debugger stack trace when breaking on JS

Categories

(DevTools :: Debugger, enhancement, P3)

enhancement

Tracking

(Not tracked)

People

(Reporter: mconley, Unassigned)

References

(Blocks 2 open bugs)

Details

Attachments

(1 file)

Attached image image.png (deleted) —

The Firefox Desktop front-end team uses the Browser Toolbox all of the time, and it's a fantastic tool. One of the things we use most often is the Debugger - we're often setting breakpoints and examining stuff to help us figure out issues.

Periodically, we'll have some front-end JS that's getting called from native code such that when we look at the stack, there's only the JS frame for the function we're inside.

What'd be amazing is if we could somehow get the native stack too. We don't expect to be able to step into that code and do breakpoints or anything, but just showing the native stack trace interleaved with the JS frames would be super helpful sometimes. We know there's a way of doing this dynamically, since the profiler does it all of the time... obviously, there might be some complexity around things like symbols or mangled names, but if you're looking for quality-of-life improvements for the Browser Toolbox debugger, this would be great.

Blocks: dbg-browser
Severity: -- → S3
Priority: -- → P3

Thanks for reporting Mike!
This will fit into the browser toolbox improvement work planned.

For now we are using spidermonkey's Debugger.getNewestFrame() method:
https://searchfox.org/mozilla-central/rev/072f9e6b7f10a00e12d0a02ac713431d0a7ee368/js/src/doc/Debugger/Debugger.md#363-366
https://searchfox.org/mozilla-central/rev/072f9e6b7f10a00e12d0a02ac713431d0a7ee368/js/src/debugger/Debugger.cpp#4554-4574

And then walk through the frames via Frame.older attribute:
https://searchfox.org/mozilla-central/rev/072f9e6b7f10a00e12d0a02ac713431d0a7ee368/js/src/doc/Debugger/Debugger.Frame.md#206-213

We do that over there:
https://searchfox.org/mozilla-central/rev/072f9e6b7f10a00e12d0a02ac713431d0a7ee368/devtools/server/actors/thread.js#1388-1441

AFAIK, these Debugger APIs only expose JavaScript frames.
So we would either need to tweak them to also expose native ones, or use another API in parallel to this one to fetch the native frames.

We would probably need some help about this as we don't have much knowledge about native stacks fetching in the devtools team.

Julien, do you know how the Profiler is getting the C/C++ stacks? Any pointers?

Flags: needinfo?(felash)

Getting the full native stacks sounds difficult, but I would say that getting just the Label Frames (as opposed to the full C++ stacks) would be much easier and already very useful for the frontend team, as a first step. I don't know how to get them but I'm sure Markus will have pointers.

Flags: needinfo?(felash) → needinfo?(mstange.moz)

We have profiler-internal functions to get this kind of stack synchronously for the current thread, but nothing that's ready to be exposed to a JS caller without some extra work.

Mike, could you list some example stacks you'd like to see, and say which of the frames in those stacks would be the most valuable? Would a label frame stack be sufficient for your use cases?

If we expose label frame stacks, we'll need to process them to remove any JS interpreter frames, otherwise the debugger will show those JS frames twice. And if we want to show C++ stacks, the debugger will also need to make a web request to the symbolication API.

Flags: needinfo?(mstange.moz) → needinfo?(mconley)

Mike, could you list some example stacks you'd like to see, and say which of the frames in those stacks would be the most valuable? Would a label frame stack be sufficient for your use cases?

Yep! So in the case from the screenshot, all we knew was that a popuphiding event was firing from native code, but we didn't know why. Ideally, the kind of stack we'd get would be similar from what we'd get by calling bt from within lldb or gdb... I don't think the pseudostack would be sufficient - unless the number of labels in the tree has increased a bunch since the last time I looked.

Flags: needinfo?(mconley)

Okay, yeah, in this example you really want the C++ frames from nsXULPopupManager. This code is not covered by label frames. So you really do need the full native stack.

To get the list of frame addresses on the native stack, you can do the same as this DMD code: https://searchfox.org/mozilla-central/rev/8e1eb5cbd89a2455c34032d921f8de28261d016b/memory/replace/dmd/DMD.cpp#616-671

This gives you a list of integers. To get symbols for these addresses, you also need the process's list of shared libraries, which you can get from SharedLibraryInfo::GetInfoForSelf(). You now need to match each address to the shared library which contains it, and subtract the library's base address in order to get a library-relative address. Then, you'll want to expose each stack frame as { relativeAddress, libraryDebugName, libraryBreakpadId } to JavaScript. Then JS can use the symbolication API to translate these relative addresses to symbol name strings.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: