diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -3962,8 +3962,12 @@
"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 @@
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 @@
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 @@
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 @@
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 @@
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
--- /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")