I’d like to use lldb’s backtrace as a library as opposed to using lldb program, so that I can generate good stack traces inside a C/C++/D program without having to spawn a separate process that would call ‘lldb -p pid’.
How should I proceed? Or, what is the relevant function call?
Actually I just realized I’ve posted a related question before: “process calling lldb to symbolicate its own backtrace”.
However it didn’t seem so easy to do judging from the thread. Has anything changed since then? There should be a simple way to do this important task.
This should get you started:
You will link against LLDB.framework on MacOSX, or liblldb.so on unix, or liblldb.dll on windows.
The you would do:
#if defined(__APPLE__)
#include <LLDB/LLDB.h>
#else
#include "lldb/SBDefines.h"
#include "lldb/SBAddress.h"
#include "lldb/SBBlock.h"
#include "lldb/SBBreakpoint.h"
#include "lldb/SBBreakpointLocation.h"
#include "lldb/SBBroadcaster.h"
#include "lldb/SBCommandInterpreter.h"
#include "lldb/SBCommandReturnObject.h"
#include "lldb/SBCommunication.h"
#include "lldb/SBCompileUnit.h"
#include "lldb/SBData.h"
#include "lldb/SBDebugger.h"
#include "lldb/SBDeclaration.h"
#include "lldb/SBError.h"
#include "lldb/SBEvent.h"
#include "lldb/SBFileSpec.h"
#include "lldb/SBFrame.h"
#include "lldb/SBFunction.h"
#include "lldb/SBHostOS.h"
#include "lldb/SBInstruction.h"
#include "lldb/SBInstructionList.h"
#include "lldb/SBLineEntry.h"
#include "lldb/SBListener.h"
#include "lldb/SBModule.h"
#include "lldb/SBProcess.h"
#include "lldb/SBQueue.h"
#include "lldb/SBQueueItem.h"
#include "lldb/SBSourceManager.h"
#include "lldb/SBStream.h"
#include "lldb/SBStringList.h"
#include "lldb/SBSymbol.h"
#include "lldb/SBSymbolContext.h"
#include "lldb/SBTarget.h"
#include "lldb/SBThread.h"
#include "lldb/SBType.h"
#include "lldb/SBValue.h"
#include "lldb/SBValueList.h"
#endif
using namespace lldb;
int main(int argc, const char * argv[])
{
if (argc != 2)
{
printf ("usage: backtrace <pid>\n");
exit(0);
}
SBDebugger::Initialize();
const bool source_init_files = true;
SBDebugger debugger = SBDebugger::Create(source_init_files);
debugger.SetAsync (false); // Set debugger to synchronous mode
const char *filename = NULL; // Fill this in if you know the filename, else leave NULL
const char *target_triple = "x86_64";
const char *platform_name = NULL; // Leave NULL
bool add_dependent_modules = true; //
lldb::SBError error;
lldb::pid_t pid = (int)strtol(argv[1], (char **)NULL, 10);
SBAttachInfo attach_info (pid);
SBTarget target = debugger.CreateTarget (filename, target_triple, platform_name, add_dependent_modules, error);
SBStream stream;
stream.RedirectToFileHandle(stdout, false);
if (target.IsValid())
{
SBProcess process = target.Attach (attach_info, error);
if (process.IsValid())
{
process.GetDescription(stream);
stream.Printf("\n");
uint32_t num_threads = process.GetNumThreads();
for (uint32_t thread_idx=0; thread_idx<num_threads; ++thread_idx)
{
SBThread thread = process.GetThreadAtIndex(thread_idx);
if (thread.IsValid())
{
thread.GetDescription(stream);
stream.Printf("\n");
uint32_t num_frames = thread.GetNumFrames();
for (uint32_t frame_idx=0; frame_idx<num_frames; ++frame_idx)
{
SBFrame frame = thread.GetFrameAtIndex(frame_idx);
frame.GetDescription(stream);
}
}
}
process.Detach();
}
else
{
fprintf(stderr, "error: failed to attach to process: %s\n", error.GetCString());
}
}
else
{
fprintf(stderr, "error: failed to create target: %s\n", error.GetCString());
}
SBDebugger::Terminate();
return 0;
}
No, nothing has changed. lldb only operates in "control other process" mode, not in "observe other process" mode, and controlling yourself is a neat trick you might be able to manage, but would add a lot of complexity for no clear benefit for most of the usages of lldb.
On OSX, you can use CoreSymbolication to take a backtrace of yourself. There are likely similar facilities on other systems.
Jim
backtrace/backtrace_symbols /atos(osx)/addr2line(linux) is not a viable
alternative, as it doesn't give proper/accurate line numbers in many cases,
unlike what lldb provides.