Getting valid frames and odd plugin selection behaviour

I'm trying to print a backtrace after a process stopped.
unfortunately i cant seen to use the frames at all, despite they're valid:

for(int i=0;i<m_process->GetNumThreads();i++) {
    lldb::SBThread t = m_process->GetThreadAtIndex(i);
    lldb::SBFrame fr = t.GetFrameAtIndex(0);
    fr.IsValid() --> true
    fr.GetFunction().isValid() --> false
    fr.GetBlock().isValid() --> false
    fr.GetCompileUnit().isValid() --> false

while attempting to print the highest frame t.GetFrameAtIndex(t.GetNumFrames()-1)
i got a bunch of crashes. one trace of the crash revealed that its trying to read memory through
the gdb remote process plugin, despite the process was started by the macos process plugin

In source/Target/Process.cpp Process::FindPlugin :
the exact conditions there are unclear to me, all i know is that they are inconsistent across the
debuggers lifetime, meaning it randomly picks an available plugin.
Also, if CanDebug returns false, it looks like the plugin instance is leaked?

After forcing the plugin to "process.macosx", I still get the same unusable frames though.
Should i use a different method there? Unfortunately the API does not match the internal command usage,
so i can only guess how this is meant to be used.

I'm trying to print a backtrace after a process stopped.
unfortunately i cant seen to use the frames at all, despite they're valid:

for(int i=0;i<m_process->GetNumThreads();i++) {
   lldb::SBThread t = m_process->GetThreadAtIndex(i);
   lldb::SBFrame fr = t.GetFrameAtIndex(0);
   fr.IsValid() --> true
   fr.GetFunction().isValid() --> false
   fr.GetBlock().isValid() --> false
   fr.GetCompileUnit().isValid() --> false

If you are on MacOSX, try debugging this with the standard process.gdb-remote plug-in (the most tested interface on our end), and run to the same point and do a backtrace and see what you get.

If you don't have debug information for the frame in which you stop, your frame will be value, but your compile unit, function, block and line entry will all be invalid. Only the symbol will be valid. I just added a SBFrame::GetSymbol() for you. With the newly added GetSymbol you should get something valid:

  fr.GetSymbol().isValid() --> true???

If you are on linux, you will probably not resolve anything because the dynamic loader plug-in hasn't been created and therefore your debug session doesn't know where any shared libraries are loaded and can't resolve any addresses.

while attempting to print the highest frame t.GetFrameAtIndex(t.GetNumFrames()-1)
i got a bunch of crashes. one trace of the crash revealed that its trying to read memory through
the gdb remote process plugin, despite the process was started by the macos process plugin

This shouldn't be happening. If you get a crash backtrace, please send it to me along with the program and exact steps you were using.

The "process.macosx" plug-in has bit rotted as we exclusively use the gdb-remote plug-in on darwin so we can sandbox the process in another process and it also helps us be ready for remote debugging.

In source/Target/Process.cpp Process::FindPlugin :
the exact conditions there are unclear to me, all i know is that they are inconsistent across the
debuggers lifetime, meaning it randomly picks an available plugin.

The theory is that each debugger plug-in knows what kind of executables it can handle and they each get a chance to say if they can debug the current binary. If the debugger plug-in likes the architecture, the file format, and anything else about the target, it can return true to CanDebug and it will be selected.

So the first debugger plug-in to return true to CanDebug wins.

Also, if CanDebug returns false, it looks like the plugin instance is leaked?

No, we are using an auto_ptr to hold onto the instance, and if CanDebug() returns true, happy with the plug-in we found, then we call "release" on the auto_ptr to have it let go of the heap based object and release ownership to the caller. If CanDebug() returns false, then the auto_ptr happily holds onto the instance and will delete it when it goes out of scope.

After forcing the plugin to "process.macosx", I still get the same unusable frames though.

Again, the "process.macosx" has bit rotted. I wouldn't use it at the moment.

Should i use a different method there? Unfortunately the API does not match the internal command usage,
so i can only guess how this is meant to be used.

Remember:
- compile unit, function, block and line entry are when you have debug info for a frame
- you will only get things to resolve to debug info if you have a dynamic loader plug-in

Let me know if the above information helped explain why you weren't seeing what you thought you would?

Greg Clayton

I just added a SBFrame::GetSymbol() for you. With the newly added GetSymbol you should get something valid:

thanks! That is indeed valid.

This shouldn't be happening. If you get a crash backtrace, please send it to me along with the program and exact steps you were using.

will do! For now i hardcoded the macosx plugin, which appears to work.

The "process.macosx" plug-in has bit rotted as we exclusively use the gdb-remote plug-in on darwin
so we can sandbox the process in another process and it also helps us be ready for remote debugging.

Well, i don't see how to choose the plugin from the public API. Also per default, there is no gdb running.

So the first debugger plug-in to return true to CanDebug wins.

Can the gdb plugin read memory from the inferior, without starting it itself? Attach-on-demand?
Otherwise why would CanDebug return true?

No, we are using an auto_ptr to hold onto the instance,

aah, thanks.

Let me know if the above information helped explain why you weren't seeing what you thought you would?

Yes indeed, thanks alot. I understand now, that the unwinder is not at fault. Looks like it fails somewhere in
Module::ResolveSymbolContextForAddress. resolved_flags is 2.
Gdb can print locals fine for that same binary. Will dig deeper and report back when i found something.

I just added a SBFrame::GetSymbol() for you. With the newly added GetSymbol you should get something valid:

thanks! That is indeed valid.

This shouldn't be happening. If you get a crash backtrace, please send it to me along with the program and exact steps you were using.

will do! For now i hardcoded the macosx plugin, which appears to work.

The "process.macosx" plug-in has bit rotted as we exclusively use the gdb-remote plug-in on darwin
so we can sandbox the process in another process and it also helps us be ready for remote debugging.

Well, i don't see how to choose the plugin from the public API. Also per default, there is no gdb running.

There currently is no option when launching from the public API. If we were to add it, we would add a "const char *plugin_name = NULL" default parameter to the to process launch in SBTarget:

    lldb::SBProcess
    LaunchProcess (char const **argv,
                   char const **envp,
                   const char *tty,
                   uint32_t launch_flags, // See lldb::LaunchFlags
                   bool stop_at_entry);

So the first debugger plug-in to return true to CanDebug wins.

Can the gdb plugin read memory from the inferior, without starting it itself? Attach-on-demand?
Otherwise why would CanDebug return true?

We use the gdb remote protocol locally on the current machine by _spawning_ an instance of "debugserver" (our own, from the ground up, re-implementation of a gdbserver binary) and then communicating with it. So we do use it unconventionally by spawning it ourselves. So it should be ok to use this.

No, we are using an auto_ptr to hold onto the instance,

aah, thanks.

Let me know if the above information helped explain why you weren't seeing what you thought you would?

Yes indeed, thanks alot. I understand now, that the unwinder is not at fault. Looks like it fails somewhere in
Module::ResolveSymbolContextForAddress. resolved_flags is 2.
Gdb can print locals fine for that same binary. Will dig deeper and report back when i found something.

Again, any code examples of what is failing for you and steps to reproduce can help us figure our what is crashing.