Show native stacks in the debugger stack trace when breaking on JS
Categories
(DevTools :: Debugger, enhancement, P3)
Tracking
(Not tracked)
People
(Reporter: mconley, Unassigned)
References
(Blocks 2 open bugs)
Details
Attachments
(1 file)
(deleted),
image/png
|
Details |
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.
Updated•3 years ago
|
Comment 1•3 years ago
|
||
Thanks for reporting Mike!
This will fit into the browser toolbox improvement work planned.
Comment 2•3 years ago
|
||
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.
Updated•3 years ago
|
Comment 3•3 years ago
|
||
Julien, do you know how the Profiler is getting the C/C++ stacks? Any pointers?
Comment 4•3 years ago
|
||
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.
Comment 5•3 years ago
|
||
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.
Reporter | ||
Comment 6•3 years ago
|
||
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.
Comment 7•3 years ago
|
||
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.
Description
•