> On Jul 27, 2015, at 10:10 PM, Schlottke-Lakemper, Michael > <m.schlottke-lakem...@aia.rwth-aachen.de> wrote: > > Hi folks, > > We are looking for a way to use lldb.so to print out a stack trace > programmatically. In our scientific simulation tool (written in C++) , we > use a custom terminate function where we are already able to print stack > traces in case of an abnormal abort, which uses some gcc-specific magic. > > My idea is to link our tool to lldb.so when compiling for debugging and to > use the library to print a stack trace programmatically, including demangled > names and correct line numbers. However, I don't really know how to start > thus I am wondering > > - has someone here done or seen something like this before?
Not sure who has done anything like this. > - is there a tutorial for linking to lldb.so and making use of it through > C++? At the end of the email is an example of something that will attach to its parent process and iterate through all of the threads/frames. > - would this also work when compiling with other compilers than clang? If the debug info is DWARF, then yes. > > Any help or pointers to relevant projects/documentation etc is greatly > appreciated! Let me know if this helps. Code sample: #include <stdint.h> #include <stdlib.h> #if defined(__APPLE__) #include <LLDB/LLDB.h> #else #include "LLDB/SBBlock.h" #include "LLDB/SBCompileUnit.h" #include "LLDB/SBDebugger.h" #include "LLDB/SBFrame.h" #include "LLDB/SBFunction.h" #include "LLDB/SBModule.h" #include "LLDB/SBStream.h" #include "LLDB/SBSymbol.h" #include "LLDB/SBTarget.h" #include "LLDB/SBThread.h" #include "LLDB/SBProcess.h" #endif #include <string> using namespace lldb; int main (int argc, char const *argv[]) { // Use a sentry object to properly initialize/terminate LLDB. SBDebugger::Initialize(); SBDebugger debugger (SBDebugger::Create()); // Create a debugger instance so we can create a target if (!debugger.IsValid()) { fprintf (stderr, "error: failed to create a debugger object\n"); exit(1); } SBError error; pid_t pid = getppid(); // Assuming parent process is what we want to backtrace SBAttachInfo attach_info(pid); const char *filename = nullptr; const char *target_triple = nullptr; const char *platform_name = nullptr; bool add_dependent_modules = false; SBTarget target = debugger.CreateTarget (filename, target_triple, platform_name, add_dependent_modules, error); SBStream strm; const bool append = false; strm.RedirectToFile ("/tmp/stack.txt", append); if (target.IsValid()) { SBProcess process = target.Attach (attach_info, error); if (process.IsValid()) { // Get the description of the process process.GetDescription(strm); const uint32_t num_threads = process.GetNumThreads(); for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { lldb::SBThread thread = process.GetThreadAtIndex (thread_idx); if (thread.IsValid()) { // Do one of the following: // 1 - Get a description of the thread thread.GetDescription(strm); // 1 - END // 2 - Do things yourself by using the public API to look a the stop reason lldb::StopReason thread_stop_reason = thread.GetStopReason(); switch (thread_stop_reason) { case eStopReasonInvalid: case eStopReasonNone: // Thread is stopped because other threads were stopped case eStopReasonTrace: // Thread completed a single instruction step break; case eStopReasonBreakpoint: { uint32_t idx = 0; uint64_t bp_id, bp_loc_id; do { bp_id = thread.GetStopReasonDataAtIndex(idx++); bp_loc_id = thread.GetStopReasonDataAtIndex(idx++); SBBreakpoint bp = target.FindBreakpointByID(bp_id); SBBreakpointLocation bp_loc = bp.FindLocationByID (bp_loc_id); // Do something with "bp" if desired } while (bp_id != 0); } break; case eStopReasonWatchpoint: { const uint64_t wp_id = thread.GetStopReasonDataAtIndex(0); SBWatchpoint wp = target.FindWatchpointByID(wp_id); // Do something with "wp" if desired } break; case eStopReasonSignal: { const uint64_t signo = thread.GetStopReasonDataAtIndex(0); // Do something with "signo" if desired } break; case eStopReasonException: case eStopReasonExec: case eStopReasonPlanComplete: case eStopReasonThreadExiting: case eStopReasonInstrumentation: break; } char decription[1024]; if (thread.GetStopDescription(description, sizeof(decription))) { // Do something with the stop description } // 2 - END // Now iterate through all of the frames in the thread const uint32_t num_frames = thread.GetNumFrames(); for (uint32_t frame_idx = 0; frame_idx < num_frames; ++frame_idx) { SBFrame frame = thread.GetFrameAtIndex (frame_idx); if (frame.IsValid()) { // Do one of the following: // 1 - Let the frame describe itself frame.GetDescription (strm); // 1 - END // 2 - Do things manually using the SB API lldb::SBModule module = frame.GetModule(); lldb::SBCompileUnit compile_unit = frame.GetCompileUnit(); lldb::SBFunction function = frame.GetFunction(); lldb::SBBlock block = frame.GetBlock(); lldb::SBLineEntry line_entry = frame.GetLineEntry(); lldb::SBSymbol symbol = frame.GetSymbol(); // Now use the above objects // 2 - END } } } } process.Detach(); } } SBDebugger::Terminate(); return 0; } _______________________________________________ lldb-dev mailing list lldb-dev@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev