From 47f79c6057764e0c83016269ae2359f8c5c8d135 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 21 Sep 2021 22:08:48 -0700 Subject: [PATCH] [lldb] Add --stack option to `target symbols add` command Currently you can ask the target symbols add command to locate the debug symbols for the current frame. This patch add an options to do that for the whole call stack. Differential revision: https://reviews.llvm.org/D110011 --- lldb/source/Commands/CommandObjectTarget.cpp | 72 +++++++++++++++- .../API/macosx/add-dsym/TestAddDsymDownload.py | 98 ++++++++++++++++++++++ 2 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 lldb/test/API/macosx/add-dsym/TestAddDsymDownload.py diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 92aa8fc..439ac45 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -3962,8 +3962,12 @@ public: "name."), m_current_frame_option( LLDB_OPT_SET_2, false, "frame", 'F', - "Locate the debug symbols for the currently selected frame.", - false, true) + "Locate the debug symbols for the currently selected frame.", false, + true), + m_current_stack_option(LLDB_OPT_SET_2, false, "stack", 'S', + "Locate the debug symbols for every frame in " + "the current call stack.", + false, true) { m_option_group.Append(&m_uuid_option_group, LLDB_OPT_SET_ALL, @@ -3971,6 +3975,8 @@ public: m_option_group.Append(&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_current_frame_option, LLDB_OPT_SET_2, LLDB_OPT_SET_2); + m_option_group.Append(&m_current_stack_option, LLDB_OPT_SET_2, + LLDB_OPT_SET_2); m_option_group.Finalize(); } @@ -4247,6 +4253,63 @@ protected: return true; } + bool AddSymbolsForStack(CommandReturnObject &result, bool &flush) { + assert(m_current_stack_option.GetOptionValue().OptionWasSet()); + + Process *process = m_exe_ctx.GetProcessPtr(); + if (!process) { + result.AppendError( + "a process must exist in order to use the --stack option"); + return false; + } + + const StateType process_state = process->GetState(); + if (!StateIsStoppedState(process_state, true)) { + result.AppendErrorWithFormat("process is not stopped: %s", + StateAsCString(process_state)); + return false; + } + + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (!thread) { + result.AppendError("invalid current thread"); + return false; + } + + bool symbols_found = false; + uint32_t frame_count = thread->GetStackFrameCount(); + for (uint32_t i = 0; i < frame_count; ++i) { + lldb::StackFrameSP frame_sp = thread->GetStackFrameAtIndex(i); + + ModuleSP frame_module_sp( + frame_sp->GetSymbolContext(eSymbolContextModule).module_sp); + if (!frame_module_sp) + continue; + + ModuleSpec module_spec; + module_spec.GetUUID() = frame_module_sp->GetUUID(); + + if (FileSystem::Instance().Exists( + frame_module_sp->GetPlatformFileSpec())) { + module_spec.GetArchitecture() = frame_module_sp->GetArchitecture(); + module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec(); + } + + bool current_frame_flush = false; + if (DownloadObjectAndSymbolFile(module_spec, result, current_frame_flush)) + symbols_found = true; + flush |= current_frame_flush; + } + + if (!symbols_found) { + result.AppendError( + "unable to find debug symbols in the current call stack"); + return false; + } + + return true; + } + bool DoExecute(Args &args, CommandReturnObject &result) override { Target *target = m_exe_ctx.GetTargetPtr(); result.SetStatus(eReturnStatusFailed); @@ -4257,6 +4320,8 @@ protected: const bool file_option_set = m_file_option.GetOptionValue().OptionWasSet(); const bool frame_option_set = m_current_frame_option.GetOptionValue().OptionWasSet(); + const bool stack_option_set = + m_current_stack_option.GetOptionValue().OptionWasSet(); const size_t argc = args.GetArgumentCount(); if (argc == 0) { @@ -4266,6 +4331,8 @@ protected: AddSymbolsForFile(result, flush); else if (frame_option_set) AddSymbolsForFrame(result, flush); + else if (stack_option_set) + AddSymbolsForStack(result, flush); else result.AppendError("one or more symbol file paths must be specified, " "or options must be specified"); @@ -4335,6 +4402,7 @@ protected: OptionGroupUUID m_uuid_option_group; OptionGroupFile m_file_option; OptionGroupBoolean m_current_frame_option; + OptionGroupBoolean m_current_stack_option; }; #pragma mark CommandObjectTargetSymbols diff --git a/lldb/test/API/macosx/add-dsym/TestAddDsymDownload.py b/lldb/test/API/macosx/add-dsym/TestAddDsymDownload.py new file mode 100644 index 0000000..c83d923 --- /dev/null +++ b/lldb/test/API/macosx/add-dsym/TestAddDsymDownload.py @@ -0,0 +1,98 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +@skipUnlessDarwin +class AddDsymDownload(TestBase): + + mydir = TestBase.compute_mydir(__file__) + dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') + + def get_uuid(self): + dwarfdump_cmd_output = subprocess.check_output( + ('/usr/bin/dwarfdump --uuid "%s"' % self.exe), + shell=True).decode("utf-8") + for line in dwarfdump_cmd_output.splitlines(): + match = self.dwarfdump_uuid_regex.search(line) + if match: + return match.group(1) + return None + + def create_dsym_for_uuid(self): + shell_cmds = [ + '#! /bin/sh', '# the last argument is the uuid', + 'while [ $# -gt 1 ]', 'do', ' shift', 'done', 'ret=0', + 'echo ""', + 'echo ""', + 'echo ""', '', + 'if [ "$1" != "%s" ]' % (self.uuid), 'then', + ' echo "DBGErrornot found"', + ' echo ""', ' exit 1', 'fi', + ' uuid=%s' % self.uuid, + ' bin=%s' % self.exe, + ' dsym=%s' % self.dsym, 'echo "$uuid"', '', + 'echo "DBGDSYMPath$dsym"', + 'echo "DBGSymbolRichExecutable$bin"', + 'echo ""', 'exit $ret' + ] + + with open(self.dsym_for_uuid, "w") as writer: + for l in shell_cmds: + writer.write(l + '\n') + + os.chmod(self.dsym_for_uuid, 0o755) + + def setUp(self): + TestBase.setUp(self) + self.source = 'main.c' + self.exe = self.getBuildArtifact("a.out") + self.dsym = os.path.join( + self.getBuildDir(), + "hide.app/Contents/a.out.dSYM/Contents/Resources/DWARF/", + os.path.basename(self.exe)) + self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") + + self.buildDefault(dictionary={'MAKE_DSYM': 'YES'}) + self.assertTrue(os.path.exists(self.exe)) + self.assertTrue(os.path.exists(self.dsym)) + + self.uuid = self.get_uuid() + self.assertNotEqual(self.uuid, None, "Could not get uuid for a.out") + + self.create_dsym_for_uuid() + + os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = self.dsym_for_uuid + self.addTearDownHook( + lambda: os.environ.pop('LLDB_APPLE_DSYMFORUUID_EXECUTABLE', None)) + + def do_test(self, command): + self.target = self.dbg.CreateTarget(self.exe) + self.assertTrue(self.target, VALID_TARGET) + + main_bp = self.target.BreakpointCreateByName("main", "a.out") + self.assertTrue(main_bp, VALID_BREAKPOINT) + + self.process = self.target.LaunchSimple( + None, None, self.get_process_working_directory()) + self.assertTrue(self.process, PROCESS_IS_VALID) + + # The stop reason of the thread should be breakpoint. + self.assertEquals(self.process.GetState(), lldb.eStateStopped, + STOPPED_DUE_TO_BREAKPOINT) + + self.runCmd(command) + self.expect("frame select", substrs=['a.out`main at main.c']) + + @no_debug_info_test + def test_frame(self): + self.do_test("add-dsym --frame") + + @no_debug_info_test + def test_uuid(self): + self.do_test("add-dsym --uuid {}".format(self.uuid)) + + @no_debug_info_test + def test_stack(self): + self.do_test("add-dsym --stack") -- 2.7.4