aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-06-16 21:04:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-06-16 21:04:22 +0000
commit4befb1f96d641a958548654b2c3b674f0ce8404c (patch)
tree664480204c546e55b123766a30e6fcf022c5486e
parentf1d04915a666728c241bedb36bd99aafee3ea444 (diff)
downloadsrc-4befb1f96d641a958548654b2c3b674f0ce8404c.tar.gz
src-4befb1f96d641a958548654b2c3b674f0ce8404c.zip
Vendor import of lldb trunk r305575:vendor/lldb/lldb-trunk-r305575
Notes
Notes: svn path=/vendor/lldb/dist/; revision=320023 svn path=/vendor/lldb/lldb-trunk-r305575/; revision=320024; tag=vendor/lldb/lldb-trunk-r305575
-rw-r--r--include/lldb/Core/Debugger.h2
-rw-r--r--include/lldb/Target/StackFrame.h11
-rw-r--r--include/lldb/Target/StackFrameList.h1
-rw-r--r--include/lldb/Target/Thread.h4
-rw-r--r--include/lldb/Utility/Status.h3
-rw-r--r--packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py2
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/num_threads/TestNumThreads.py74
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/num_threads/main.cpp26
-rw-r--r--packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py1
-rw-r--r--packages/Python/lldbsuite/test/lang/c/register_variables/test.c2
-rw-r--r--packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py4
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/Makefile21
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/TestBundleWithDotInFilename.py71
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/bundle.c4
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/main.c28
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Info.plist44
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Makefile28
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/MyFramework.h1
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/TestDeepBundle.py75
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/main.c22
-rw-r--r--packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/myframework.c4
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py1
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py2
-rw-r--r--scripts/lldb.swig8
-rw-r--r--source/Commands/CommandObjectThread.cpp137
-rw-r--r--source/Core/Debugger.cpp73
-rw-r--r--source/Host/common/Symbols.cpp76
-rw-r--r--source/Target/StackFrame.cpp16
-rw-r--r--source/Target/StackFrameList.cpp3
-rw-r--r--source/Target/Thread.cpp53
-rw-r--r--source/Utility/Status.cpp15
-rw-r--r--unittests/Utility/StatusTest.cpp3
32 files changed, 691 insertions, 124 deletions
diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h
index cedf9ecdb120..34d35ffe7c80 100644
--- a/include/lldb/Core/Debugger.h
+++ b/include/lldb/Core/Debugger.h
@@ -249,6 +249,8 @@ public:
const FormatEntity::Entry *GetFrameFormat() const;
+ const FormatEntity::Entry *GetFrameFormatUnique() const;
+
const FormatEntity::Entry *GetThreadFormat() const;
const FormatEntity::Entry *GetThreadStopFormat() const;
diff --git a/include/lldb/Target/StackFrame.h b/include/lldb/Target/StackFrame.h
index cb503875a5c0..d97043578ce9 100644
--- a/include/lldb/Target/StackFrame.h
+++ b/include/lldb/Target/StackFrame.h
@@ -342,10 +342,13 @@ public:
/// @param [in] strm
/// The Stream to print the description to.
///
+ /// @param [in] show_unique
+ /// Whether to print the function arguments or not for backtrace unique.
+ ///
/// @param [in] frame_marker
/// Optional string that will be prepended to the frame output description.
//------------------------------------------------------------------
- void DumpUsingSettingsFormat(Stream *strm,
+ void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false,
const char *frame_marker = nullptr);
//------------------------------------------------------------------
@@ -375,6 +378,10 @@ public:
/// @param[in] show_source
/// If true, print source or disassembly as per the user's settings.
///
+ /// @param[in] show_unique
+ /// If true, print using backtrace unique style, without function
+ /// arguments as per the user's settings.
+ ///
/// @param[in] frame_marker
/// Passed to DumpUsingSettingsFormat() for the frame info printing.
///
@@ -382,7 +389,7 @@ public:
/// Returns true if successful.
//------------------------------------------------------------------
bool GetStatus(Stream &strm, bool show_frame_info, bool show_source,
- const char *frame_marker = nullptr);
+ bool show_unique = false, const char *frame_marker = nullptr);
//------------------------------------------------------------------
/// Query whether this frame is a concrete frame on the call stack,
diff --git a/include/lldb/Target/StackFrameList.h b/include/lldb/Target/StackFrameList.h
index a770346b58f0..cb9fb136fb4e 100644
--- a/include/lldb/Target/StackFrameList.h
+++ b/include/lldb/Target/StackFrameList.h
@@ -70,6 +70,7 @@ public:
size_t GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames,
bool show_frame_info, uint32_t num_frames_with_source,
+ bool show_unique = false,
const char *frame_marker = nullptr);
protected:
diff --git a/include/lldb/Target/Thread.h b/include/lldb/Target/Thread.h
index cfab13069278..954347b5814c 100644
--- a/include/lldb/Target/Thread.h
+++ b/include/lldb/Target/Thread.h
@@ -1163,8 +1163,8 @@ public:
GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr);
size_t GetStatus(Stream &strm, uint32_t start_frame, uint32_t num_frames,
- uint32_t num_frames_with_source,
- bool stop_format);
+ uint32_t num_frames_with_source, bool stop_format,
+ bool only_stacks = false);
size_t GetStackFrameStatus(Stream &strm, uint32_t first_frame,
uint32_t num_frames, bool show_frame_info,
diff --git a/include/lldb/Utility/Status.h b/include/lldb/Utility/Status.h
index d8fd41707f8c..d520ebd942ee 100644
--- a/include/lldb/Utility/Status.h
+++ b/include/lldb/Utility/Status.h
@@ -104,7 +104,8 @@ public:
~Status();
// llvm::Error support
- explicit Status(llvm::Error error);
+ explicit Status(llvm::Error error) { *this = std::move(error); }
+ const Status &operator=(llvm::Error error);
llvm::Error ToError() const;
//------------------------------------------------------------------
diff --git a/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py b/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py
index bef4be1eb5f8..0b9ad0ed6323 100644
--- a/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py
+++ b/packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py
@@ -14,6 +14,7 @@ from lldbsuite.test import lldbutil
class ExprCommandThatRestartsTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
+ NO_DEBUG_INFO_TESTCASE = True
def setUp(self):
# Call super's setUp().
@@ -25,6 +26,7 @@ class ExprCommandThatRestartsTestCase(TestBase):
@skipIfFreeBSD # llvm.org/pr19246: intermittent failure
@skipIfDarwin # llvm.org/pr19246: intermittent failure
@skipIfWindows # Test relies on signals, unsupported on Windows
+ @expectedFlakeyAndroid(bugnumber="llvm.org/pr19246")
def test(self):
"""Test calling function that hits a signal and restarts."""
self.build()
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/num_threads/TestNumThreads.py b/packages/Python/lldbsuite/test/functionalities/thread/num_threads/TestNumThreads.py
index 094c86705969..85fa5d380cff 100644
--- a/packages/Python/lldbsuite/test/functionalities/thread/num_threads/TestNumThreads.py
+++ b/packages/Python/lldbsuite/test/functionalities/thread/num_threads/TestNumThreads.py
@@ -19,10 +19,11 @@ class NumberOfThreadsTestCase(TestBase):
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
- # Find the line number to break inside main().
- self.line = line_number('main.cpp', '// Set break point at this line.')
+ # Find the line numbers for our break points.
+ self.thread3_notify_all_line = line_number('main.cpp', '// Set thread3 break point on notify_all at this line.')
+ self.thread3_before_lock_line = line_number('main.cpp', '// Set thread3 break point on lock at this line.')
- def test(self):
+ def test_number_of_threads(self):
"""Test number of threads."""
self.build()
exe = os.path.join(os.getcwd(), "a.out")
@@ -30,15 +31,15 @@ class NumberOfThreadsTestCase(TestBase):
# This should create a breakpoint with 1 location.
lldbutil.run_break_set_by_file_and_line(
- self, "main.cpp", self.line, num_expected_locations=1)
+ self, "main.cpp", self.thread3_notify_all_line, num_expected_locations=1)
- # The breakpoint list should show 3 locations.
+ # The breakpoint list should show 1 location.
self.expect(
"breakpoint list -f",
"Breakpoint location shown correctly",
substrs=[
"1: file = 'main.cpp', line = %d, exact_match = 0, locations = 1" %
- self.line])
+ self.thread3_notify_all_line])
# Run the program.
self.runCmd("run", RUN_SUCCEEDED)
@@ -57,5 +58,64 @@ class NumberOfThreadsTestCase(TestBase):
# Using std::thread may involve extra threads, so we assert that there are
# at least 4 rather than exactly 4.
self.assertTrue(
- num_threads >= 4,
+ num_threads >= 13,
'Number of expected threads and actual threads do not match.')
+
+ def test_unique_stacks(self):
+ """Test backtrace unique with multiple threads executing the same stack."""
+ self.build()
+ exe = os.path.join(os.getcwd(), "a.out")
+ self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+ # Set a break point on the thread3 notify all (should get hit on threads 4-13).
+ lldbutil.run_break_set_by_file_and_line(
+ self, "main.cpp", self.thread3_before_lock_line, num_expected_locations=1)
+
+ # Run the program.
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # Stopped once.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stop reason = breakpoint 1."])
+
+ process = self.process()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ # Using std::thread may involve extra threads, so we assert that there are
+ # at least 10 thread3's rather than exactly 10.
+ self.assertTrue(
+ num_threads >= 10,
+ 'Number of expected threads and actual threads do not match.')
+
+ # Attempt to walk each of the thread's executing the thread3 function to
+ # the same breakpoint.
+ def is_thread3(thread):
+ for frame in thread:
+ if "thread3" in frame.GetFunctionName(): return True
+ return False
+
+ expect_threads = ""
+ for i in range(num_threads):
+ thread = process.GetThreadAtIndex(i)
+ self.assertTrue(thread.IsValid())
+ if not is_thread3(thread):
+ continue
+
+ # If we aren't stopped out the thread breakpoint try to resume.
+ if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
+ self.runCmd("thread continue %d"%(i+1))
+ self.assertEqual(thread.GetStopReason(), lldb.eStopReasonBreakpoint)
+
+ expect_threads += " #%d"%(i+1)
+
+ # Construct our expected back trace string
+ expect_string = "10 thread(s)%s" % (expect_threads)
+
+ # Now that we are stopped, we should have 10 threads waiting in the
+ # thread3 function. All of these threads should show as one stack.
+ self.expect("thread backtrace unique",
+ "Backtrace with unique stack shown correctly",
+ substrs=[expect_string,
+ "main.cpp:%d"%self.thread3_before_lock_line])
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/num_threads/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/num_threads/main.cpp
index 6a0ea4e0d119..42a07f353030 100644
--- a/packages/Python/lldbsuite/test/functionalities/thread/num_threads/main.cpp
+++ b/packages/Python/lldbsuite/test/functionalities/thread/num_threads/main.cpp
@@ -1,15 +1,19 @@
+#include "pseudo_barrier.h"
#include <condition_variable>
#include <mutex>
#include <thread>
+#include <vector>
std::mutex mutex;
std::condition_variable cond;
+pseudo_barrier_t thread3_barrier;
void *
thread3(void *input)
{
- std::unique_lock<std::mutex> lock(mutex);
- cond.notify_all(); // Set break point at this line.
+ pseudo_barrier_wait(thread3_barrier);
+ std::unique_lock<std::mutex> lock(mutex); // Set thread3 break point on lock at this line.
+ cond.notify_all(); // Set thread3 break point on notify_all at this line.
return NULL;
}
@@ -17,7 +21,7 @@ void *
thread2(void *input)
{
std::unique_lock<std::mutex> lock(mutex);
- cond.notify_all();
+ cond.notify_all(); // release main thread
cond.wait(lock);
return NULL;
}
@@ -36,15 +40,23 @@ int main()
std::unique_lock<std::mutex> lock(mutex);
std::thread thread_1(thread1, nullptr);
- cond.wait(lock);
+ cond.wait(lock); // wait for thread2
- std::thread thread_3(thread3, nullptr);
- cond.wait(lock);
+ pseudo_barrier_init(thread3_barrier, 10);
+
+ std::vector<std::thread> thread_3s;
+ for (int i = 0; i < 10; i++) {
+ thread_3s.push_back(std::thread(thread3, nullptr));
+ }
+
+ cond.wait(lock); // wait for thread_3s
lock.unlock();
thread_1.join();
- thread_3.join();
+ for (auto &t : thread_3s){
+ t.join();
+ }
return 0;
}
diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
index d54e62887ce1..c41600462561 100644
--- a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
+++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py
@@ -19,6 +19,7 @@ class NoreturnUnwind(TestBase):
@skipIfWindows # clang-cl does not support gcc style attributes.
# clang does not preserve LR in noreturn functions, making unwinding impossible
@skipIf(compiler="clang", archs=['arm'], oslist=['linux'])
+ @expectedFailureAll(bugnumber="llvm.org/pr33452", triple='^mips')
def test(self):
"""Test that we can backtrace correctly with 'noreturn' functions on the stack"""
self.build()
diff --git a/packages/Python/lldbsuite/test/lang/c/register_variables/test.c b/packages/Python/lldbsuite/test/lang/c/register_variables/test.c
index b95253ef9eea..f7fb1af13220 100644
--- a/packages/Python/lldbsuite/test/lang/c/register_variables/test.c
+++ b/packages/Python/lldbsuite/test/lang/c/register_variables/test.c
@@ -1,6 +1,6 @@
#include <stdio.h>
-#if defined(__arm__) || defined(__aarch64__)
+#if defined(__arm__) || defined(__aarch64__) || defined (__mips__)
// Clang does not accept regparm attribute on these platforms.
// Fortunately, the default calling convention passes arguments in registers
// anyway.
diff --git a/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py b/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
index 96c5a33f14b0..57f373545380 100644
--- a/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
+++ b/packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
@@ -121,6 +121,8 @@ class ObjCNewSyntaxTestCase(TestBase):
'7.0.0'])
@skipIf(macos_version=["<", "10.12"])
@expectedFailureAll(archs=["i[3-6]86"])
+ @expectedFailureAll(
+ bugnumber="rdar://32777981")
def test_update_dictionary(self):
self.runToBreakpoint()
@@ -163,6 +165,8 @@ class ObjCNewSyntaxTestCase(TestBase):
'7.0.0'])
@skipIf(macos_version=["<", "10.12"])
@expectedFailureAll(archs=["i[3-6]86"])
+ @expectedFailureAll(
+ bugnumber="rdar://32777981")
def test_dictionary_literal(self):
self.runToBreakpoint()
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/Makefile b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/Makefile
new file mode 100644
index 000000000000..7b321e3deae0
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/Makefile
@@ -0,0 +1,21 @@
+CC ?= clang
+
+ifeq "$(ARCH)" ""
+ ARCH = x86_64
+endif
+
+CFLAGS ?= -g -O0 -arch $(ARCH)
+
+all: clean
+ $(CC) $(CFLAGS) -dynamiclib -o com.apple.sbd bundle.c
+ mkdir com.apple.sbd.xpc
+ mv com.apple.sbd com.apple.sbd.xpc/
+ mkdir -p com.apple.sbd.xpc.dSYM/Contents/Resources/DWARF
+ mv com.apple.sbd.dSYM/Contents/Resources/DWARF/com.apple.sbd com.apple.sbd.xpc.dSYM/Contents/Resources/DWARF/
+ rm -rf com.apple.sbd.dSYM
+ mkdir hide.app
+ tar cf - com.apple.sbd.xpc com.apple.sbd.xpc.dSYM | ( cd hide.app;tar xBpf -)
+ $(CC) $(CFLAGS) -o find-bundle-with-dots-in-fn main.c
+
+clean:
+ rm -rf a.out a.out.dSYM hide.app com.apple.sbd com.apple.sbd.dSYM com.apple.sbd.xpc com.apple.sbd.xpc.dSYM find-bundle-with-dots-in-fn find-bundle-with-dots-in-fn.dSYM
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/TestBundleWithDotInFilename.py b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/TestBundleWithDotInFilename.py
new file mode 100644
index 000000000000..104e88752ec2
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/TestBundleWithDotInFilename.py
@@ -0,0 +1,71 @@
+"""Test that a dSYM can be found when a binary is in a bundle hnd has dots in the filename."""
+
+from __future__ import print_function
+
+#import unittest2
+import os.path
+from time import sleep
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+exe_name = 'find-bundle-with-dots-in-fn' # must match Makefile
+
+class BundleWithDotInFilenameTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfRemote
+ @skipUnlessDarwin
+ # This test is explicitly a dSYM test, it doesn't need to run for any other config, but
+ # the following doesn't work, fixme.
+ # @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
+
+ def setUp(self):
+ TestBase.setUp(self)
+ self.source = 'main.c'
+
+ def tearDown(self):
+ # Destroy process before TestBase.tearDown()
+ self.dbg.GetSelectedTarget().GetProcess().Destroy()
+
+ # Call super's tearDown().
+ TestBase.tearDown(self)
+
+ def test_attach_and_check_dsyms(self):
+ """Test attach to binary, see if the bundle dSYM is found"""
+ exe = os.path.join(os.getcwd(), exe_name)
+ self.build()
+ popen = self.spawnSubprocess(exe)
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ # Give the inferior time to start up, dlopen a bundle, remove the bundle it linked in
+ sleep(5)
+
+ # Since the library that was dlopen()'ed is now removed, lldb will need to find the
+ # binary & dSYM via target.exec-search-paths
+ settings_str = "settings set target.exec-search-paths " + self.get_process_working_directory() + "/hide.app"
+ self.runCmd(settings_str)
+
+ self.runCmd("process attach -p " + str(popen.pid))
+
+ target = self.dbg.GetSelectedTarget()
+ self.assertTrue(target.IsValid(), 'Should have a valid Target after attaching to process')
+
+ setup_complete = target.FindFirstGlobalVariable("setup_is_complete")
+ self.assertTrue(setup_complete.GetValueAsUnsigned() == 1, 'Check that inferior process has completed setup')
+
+ # Find the bundle module, see if we found the dSYM too (they're both in "hide.app")
+ i = 0
+ while i < target.GetNumModules():
+ mod = target.GetModuleAtIndex(i)
+ if mod.GetFileSpec().GetFilename() == 'com.apple.sbd':
+ dsym_name = mod.GetSymbolFileSpec().GetFilename()
+ self.assertTrue (dsym_name == 'com.apple.sbd', "Check that we found the dSYM for the bundle that was loaded")
+ i=i+1
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/bundle.c b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/bundle.c
new file mode 100644
index 000000000000..c100f9a2c075
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/bundle.c
@@ -0,0 +1,4 @@
+int foo ()
+{
+ return 5;
+}
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/main.c b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/main.c
new file mode 100644
index 000000000000..30761eb1b409
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/main.c
@@ -0,0 +1,28 @@
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int setup_is_complete = 0;
+
+int main()
+{
+
+ void *handle = dlopen ("com.apple.sbd.xpc/com.apple.sbd", RTLD_NOW);
+ if (handle)
+ {
+ if (dlsym(handle, "foo"))
+ {
+ system ("/bin/rm -rf com.apple.sbd.xpc com.apple.sbd.xpc.dSYM");
+ setup_is_complete = 1;
+
+ // At this point we want lldb to attach to the process. If lldb attaches
+ // before we've removed the dlopen'ed bundle, lldb will find the bundle
+ // at its actual filepath and not have to do any tricky work, invalidating
+ // the test.
+
+ for (int loop_limiter = 0; loop_limiter < 100; loop_limiter++)
+ sleep (1);
+ }
+ }
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Info.plist b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Info.plist
new file mode 100644
index 000000000000..82e17116e35e
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Info.plist
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>BuildMachineOSBuild</key>
+ <string>16B2657</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>MyFramework</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.test.framework</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>MyFramework</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>113</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleSupportedPlatforms</key>
+ <array>
+ <string>MacOSX</string>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>113</string>
+ <key>DTCompiler</key>
+ <string>com.apple.compilers.llvm.clang.1_0</string>
+ <key>DTPlatformBuild</key>
+ <string>9L120i</string>
+ <key>DTPlatformVersion</key>
+ <string>GM</string>
+ <key>DTSDKBuild</key>
+ <string>17A261x</string>
+ <key>DTSDKName</key>
+ <string>macosx10.13</string>
+ <key>DTXcode</key>
+ <string>0900</string>
+ <key>DTXcodeBuild</key>
+ <string>9L120i</string>
+</dict>
+</plist>
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Makefile b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Makefile
new file mode 100644
index 000000000000..33b09502378c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Makefile
@@ -0,0 +1,28 @@
+CC ?= clang
+
+ifeq "$(ARCH)" ""
+ ARCH = x86_64
+endif
+
+CFLAGS ?= -g -O0 -arch $(ARCH)
+
+all: clean
+ $(CC) $(CFLAGS) -install_name $(PWD)/MyFramework.framework/Versions/A/MyFramework -dynamiclib -o MyFramework myframework.c
+ mkdir -p MyFramework.framework/Versions/A/Headers
+ mkdir -p MyFramework.framework/Versions/A/Resources
+ cp MyFramework MyFramework.framework/Versions/A
+ cp MyFramework.h MyFramework.framework/Versions/A/Headers
+ cp Info.plist MyFramework.framework/Versions/A/Resources
+ ( cd MyFramework.framework/Versions ; ln -s A Current )
+ ( cd MyFramework.framework/ ; ln -s Versions/Current/Headers . )
+ ( cd MyFramework.framework/ ; ln -s Versions/Current/MyFramework . )
+ ( cd MyFramework.framework/ ; ln -s Versions/Current/Resources . )
+ mv MyFramework.dSYM MyFramework.framework.dSYM
+ mkdir hide.app
+ rm -f MyFramework
+ tar cf - MyFramework.framework MyFramework.framework.dSYM | ( cd hide.app;tar xBpf -)
+ $(CC) $(CFLAGS) -o deep-bundle main.c -F. -framework MyFramework
+
+
+clean:
+ rm -rf a.out a.out.dSYM deep-bundle deep-bundle.dSYM MyFramework.framework MyFramework.framework.dSYM MyFramework MyFramework.dSYM hide.app
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/MyFramework.h b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/MyFramework.h
new file mode 100644
index 000000000000..a4536647cfc9
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/MyFramework.h
@@ -0,0 +1 @@
+int foo ();
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/TestDeepBundle.py b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/TestDeepBundle.py
new file mode 100644
index 000000000000..493c4b99d094
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/TestDeepBundle.py
@@ -0,0 +1,75 @@
+"""Test that a dSYM can be found when a binary is in a deep bundle with multiple pathname components."""
+
+from __future__ import print_function
+
+#import unittest2
+import os.path
+from time import sleep
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+exe_name = 'deep-bundle' # must match Makefile
+
+class DeepBundleTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfRemote
+ @skipUnlessDarwin
+ # This test is explicitly a dSYM test, it doesn't need to run for any other config, but
+ # the following doesn't work, fixme.
+ # @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
+
+ def setUp(self):
+ TestBase.setUp(self)
+ self.source = 'main.c'
+
+ def tearDown(self):
+ # Destroy process before TestBase.tearDown()
+ self.dbg.GetSelectedTarget().GetProcess().Destroy()
+
+ # Call super's tearDown().
+ TestBase.tearDown(self)
+
+ def test_attach_and_check_dsyms(self):
+ """Test attach to binary, see if the framework dSYM is found"""
+ exe = os.path.join(os.getcwd(), exe_name)
+ self.build()
+ popen = self.spawnSubprocess(exe)
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ # Give the inferior time to start up, dlopen a bundle, remove the bundle it linked in
+ sleep(5)
+
+ # Since the library that was dlopen()'ed is now removed, lldb will need to find the
+ # binary & dSYM via target.exec-search-paths
+ settings_str = "settings set target.exec-search-paths " + self.get_process_working_directory() + "/hide.app"
+ self.runCmd(settings_str)
+
+ self.runCmd("process attach -p " + str(popen.pid))
+
+ target = self.dbg.GetSelectedTarget()
+ self.assertTrue(target.IsValid(), 'Should have a valid Target after attaching to process')
+
+ setup_complete = target.FindFirstGlobalVariable("setup_is_complete")
+ self.assertTrue(setup_complete.GetValueAsUnsigned() == 1, 'Check that inferior process has completed setup')
+
+ # Find the bundle module, see if we found the dSYM too (they're both in "hide.app")
+ i = 0
+ found_module = False
+ while i < target.GetNumModules():
+ mod = target.GetModuleAtIndex(i)
+ if mod.GetFileSpec().GetFilename() == 'MyFramework':
+ found_module = True
+ dsym_name = mod.GetSymbolFileSpec().GetFilename()
+ self.assertTrue (dsym_name == 'MyFramework', "Check that we found the dSYM for the bundle that was loaded")
+ i=i+1
+
+ self.assertTrue(found_module, "Check that we found the framework loaded in lldb's image list")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/main.c b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/main.c
new file mode 100644
index 000000000000..19715216d6cf
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/main.c
@@ -0,0 +1,22 @@
+#include <MyFramework/MyFramework.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int setup_is_complete = 0;
+
+int main()
+{
+ system ("/bin/rm -rf MyFramework MyFramework.framework MyFramework.framework.dSYM");
+
+ setup_is_complete = 1;
+
+ // At this point we want lldb to attach to the process. If lldb attaches
+ // before we've removed the framework we're running against, it will be
+ // easy for lldb to find the binary & dSYM without using target.exec-search-paths,
+ // which is the point of this test.
+
+ for (int loop_limiter = 0; loop_limiter < 100; loop_limiter++)
+ sleep (1);
+
+ return foo();
+}
diff --git a/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/myframework.c b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/myframework.c
new file mode 100644
index 000000000000..c100f9a2c075
--- /dev/null
+++ b/packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/myframework.c
@@ -0,0 +1,4 @@
+int foo ()
+{
+ return 5;
+}
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py
index f3a18786b03a..bcb632dd4ef8 100644
--- a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py
@@ -31,6 +31,7 @@ class TestGdbRemoteSingleStep(gdbremote_testcase.GdbRemoteTestCaseBase):
"arm",
"aarch64"],
bugnumber="llvm.org/pr24739")
+ @skipIf(triple='^mips')
def test_single_step_only_steps_one_instruction_with_s_llgs(self):
self.init_llgs_test()
self.build()
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py
index 1d98b9279f4f..9d0645c5b99d 100644
--- a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py
@@ -108,6 +108,7 @@ class TestGdbRemote_vCont(gdbremote_testcase.GdbRemoteTestCaseBase):
"arm",
"aarch64"],
bugnumber="llvm.org/pr24739")
+ @skipIf(triple='^mips')
def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_llgs(self):
self.init_llgs_test()
self.build()
@@ -136,6 +137,7 @@ class TestGdbRemote_vCont(gdbremote_testcase.GdbRemoteTestCaseBase):
"arm",
"aarch64"],
bugnumber="llvm.org/pr24739")
+ @skipIf(triple='^mips')
def test_single_step_only_steps_one_instruction_with_vCont_s_thread_llgs(
self):
self.init_llgs_test()
diff --git a/scripts/lldb.swig b/scripts/lldb.swig
index 8f1b59c32d4d..8345a4b95038 100644
--- a/scripts/lldb.swig
+++ b/scripts/lldb.swig
@@ -40,7 +40,13 @@ us to override the module import logic to suit our needs. This does that.
Older swig versions will simply ignore this setting.
*/
%define MODULEIMPORT
-"from . import $module"
+"try:
+ # Try a relative import first
+ from . import $module
+except ImportError:
+ # Maybe absolute import will work (if we're being loaded from lldb, it
+ # should).
+ import $module"
%enddef
// These versions will not generate working python modules, so error out early.
#if SWIG_VERSION >= 0x030009 && SWIG_VERSION < 0x030011
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp
index b585ef9ef8ad..cfd8fcb7291d 100644
--- a/source/Commands/CommandObjectThread.cpp
+++ b/source/Commands/CommandObjectThread.cpp
@@ -42,10 +42,44 @@ using namespace lldb;
using namespace lldb_private;
//-------------------------------------------------------------------------
-// CommandObjectThreadBacktrace
+// CommandObjectIterateOverThreads
//-------------------------------------------------------------------------
class CommandObjectIterateOverThreads : public CommandObjectParsed {
+
+ class UniqueStack {
+
+ public:
+ UniqueStack(std::stack<lldb::addr_t> stack_frames, uint32_t thread_index_id)
+ : m_stack_frames(stack_frames) {
+ m_thread_index_ids.push_back(thread_index_id);
+ }
+
+ void AddThread(uint32_t thread_index_id) const {
+ m_thread_index_ids.push_back(thread_index_id);
+ }
+
+ const std::vector<uint32_t> &GetUniqueThreadIndexIDs() const {
+ return m_thread_index_ids;
+ }
+
+ lldb::tid_t GetRepresentativeThread() const {
+ return m_thread_index_ids.front();
+ }
+
+ friend bool inline operator<(const UniqueStack &lhs,
+ const UniqueStack &rhs) {
+ return lhs.m_stack_frames < rhs.m_stack_frames;
+ }
+
+ protected:
+ // Mark the thread index as mutable, as we don't care about it from a const
+ // perspective, we only care about m_stack_frames so we keep our std::set
+ // sorted.
+ mutable std::vector<uint32_t> m_thread_index_ids;
+ std::stack<lldb::addr_t> m_stack_frames;
+ };
+
public:
CommandObjectIterateOverThreads(CommandInterpreter &interpreter,
const char *name, const char *help,
@@ -57,11 +91,15 @@ public:
bool DoExecute(Args &command, CommandReturnObject &result) override {
result.SetStatus(m_success_return);
+ bool all_threads = false;
if (command.GetArgumentCount() == 0) {
Thread *thread = m_exe_ctx.GetThreadPtr();
if (!HandleOneThread(thread->GetID(), result))
return false;
return result.Succeeded();
+ } else if (command.GetArgumentCount() == 1) {
+ all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0;
+ m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0;
}
// Use tids instead of ThreadSPs to prevent deadlocking problems which
@@ -69,8 +107,7 @@ public:
// code while iterating over the (locked) ThreadSP list.
std::vector<lldb::tid_t> tids;
- if (command.GetArgumentCount() == 1 &&
- ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) {
+ if (all_threads || m_unique_stacks) {
Process *process = m_exe_ctx.GetProcessPtr();
for (ThreadSP thread_sp : process->Threads())
@@ -108,15 +145,47 @@ public:
}
}
- uint32_t idx = 0;
- for (const lldb::tid_t &tid : tids) {
- if (idx != 0 && m_add_return)
- result.AppendMessage("");
+ if (m_unique_stacks) {
+ // Iterate over threads, finding unique stack buckets.
+ std::set<UniqueStack> unique_stacks;
+ for (const lldb::tid_t &tid : tids) {
+ if (!BucketThread(tid, unique_stacks, result)) {
+ return false;
+ }
+ }
- if (!HandleOneThread(tid, result))
- return false;
+ // Write the thread id's and unique call stacks to the output stream
+ Stream &strm = result.GetOutputStream();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ for (const UniqueStack &stack : unique_stacks) {
+ // List the common thread ID's
+ const std::vector<uint32_t> &thread_index_ids =
+ stack.GetUniqueThreadIndexIDs();
+ strm.Printf("%lu thread(s) ", thread_index_ids.size());
+ for (const uint32_t &thread_index_id : thread_index_ids) {
+ strm.Printf("#%u ", thread_index_id);
+ }
+ strm.EOL();
- ++idx;
+ // List the shared call stack for this set of threads
+ uint32_t representative_thread_id = stack.GetRepresentativeThread();
+ ThreadSP thread = process->GetThreadList().FindThreadByIndexID(
+ representative_thread_id);
+ if (!HandleOneThread(thread->GetID(), result)) {
+ return false;
+ }
+ }
+ } else {
+ uint32_t idx = 0;
+ for (const lldb::tid_t &tid : tids) {
+ if (idx != 0 && m_add_return)
+ result.AppendMessage("");
+
+ if (!HandleOneThread(tid, result))
+ return false;
+
+ ++idx;
+ }
}
return result.Succeeded();
}
@@ -134,7 +203,43 @@ protected:
virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0;
+ bool BucketThread(lldb::tid_t tid, std::set<UniqueStack> &unique_stacks,
+ CommandReturnObject &result) {
+ // Grab the corresponding thread for the given thread id.
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Thread *thread = process->GetThreadList().FindThreadByID(tid).get();
+ if (thread == nullptr) {
+ result.AppendErrorWithFormat("Failed to process thread# %lu.\n", tid);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Collect the each frame's address for this call-stack
+ std::stack<lldb::addr_t> stack_frames;
+ const uint32_t frame_count = thread->GetStackFrameCount();
+ for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) {
+ const lldb::StackFrameSP frame_sp =
+ thread->GetStackFrameAtIndex(frame_index);
+ const lldb::addr_t pc = frame_sp->GetStackID().GetPC();
+ stack_frames.push(pc);
+ }
+
+ uint32_t thread_index_id = thread->GetIndexID();
+ UniqueStack new_unique_stack(stack_frames, thread_index_id);
+
+ // Try to match the threads stack to and existing entry.
+ std::set<UniqueStack>::iterator matching_stack =
+ unique_stacks.find(new_unique_stack);
+ if (matching_stack != unique_stacks.end()) {
+ matching_stack->AddThread(thread_index_id);
+ } else {
+ unique_stacks.insert(new_unique_stack);
+ }
+ return true;
+ }
+
ReturnStatus m_success_return = eReturnStatusSuccessFinishResult;
+ bool m_unique_stacks = false;
bool m_add_return = true;
};
@@ -218,9 +323,10 @@ public:
: CommandObjectIterateOverThreads(
interpreter, "thread backtrace",
"Show thread call stacks. Defaults to the current thread, thread "
- "indexes can be specified as arguments. Use the thread-index "
- "\"all\" "
- "to see all threads.",
+ "indexes can be specified as arguments.\n"
+ "Use the thread-index \"all\" to see all threads.\n"
+ "Use the thread-index \"unique\" to see threads grouped by unique "
+ "call stacks.",
nullptr,
eCommandRequiresProcess | eCommandRequiresThread |
eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
@@ -270,11 +376,14 @@ protected:
Stream &strm = result.GetOutputStream();
+ // Only dump stack info if we processing unique stacks.
+ const bool only_stacks = m_unique_stacks;
+
// Don't show source context when doing backtraces.
const uint32_t num_frames_with_source = 0;
const bool stop_format = true;
if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count,
- num_frames_with_source, stop_format)) {
+ num_frames_with_source, stop_format, only_stacks)) {
result.AppendErrorWithFormat(
"error displaying backtrace for thread: \"0x%4.4x\"\n",
thread->GetIndexID());
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 75fcedb10156..d42e4df56d8b 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -112,6 +112,12 @@ OptionEnumValueElement g_language_enumerators[] = {
"{ " \
"${module.file.basename}{`${function.name-with-args}" \
"{${frame.no-debug}${function.pc-offset}}}}"
+
+#define MODULE_WITH_FUNC_NO_ARGS \
+ "{ " \
+ "${module.file.basename}{`${function.name-without-args}" \
+ "{${frame.no-debug}${function.pc-offset}}}}"
+
#define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
#define IS_OPTIMIZED "{${function.is-optimized} [opt]}"
@@ -141,6 +147,10 @@ OptionEnumValueElement g_language_enumerators[] = {
"frame #${frame.index}: ${frame.pc}" MODULE_WITH_FUNC FILE_AND_LINE \
IS_OPTIMIZED "\\n"
+#define DEFAULT_FRAME_FORMAT_NO_ARGS \
+ "frame #${frame.index}: ${frame.pc}" MODULE_WITH_FUNC_NO_ARGS FILE_AND_LINE \
+ IS_OPTIMIZED "\\n"
+
// Three parts to this disassembly format specification:
// 1. If this is a new function/symbol (no previous symbol/function), print
// dylib`funcname:\n
@@ -186,13 +196,15 @@ static PropertyDefinition g_properties[] = {
{"auto-confirm", OptionValue::eTypeBoolean, true, false, nullptr, nullptr,
"If true all confirmation prompts will receive their default reply."},
{"disassembly-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_DISASSEMBLY_FORMAT, nullptr, "The default disassembly format "
- "string to use when disassembling "
- "instruction sequences."},
+ DEFAULT_DISASSEMBLY_FORMAT, nullptr,
+ "The default disassembly format "
+ "string to use when disassembling "
+ "instruction sequences."},
{"frame-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_FRAME_FORMAT, nullptr, "The default frame format string to use "
- "when displaying stack frame information "
- "for threads."},
+ DEFAULT_FRAME_FORMAT, nullptr,
+ "The default frame format string to use "
+ "when displaying stack frame information "
+ "for threads."},
{"notify-void", OptionValue::eTypeBoolean, true, false, nullptr, nullptr,
"Notify the user explicitly if an expression returns void (default: "
"false)."},
@@ -203,18 +215,21 @@ static PropertyDefinition g_properties[] = {
nullptr, g_language_enumerators,
"The script language to be used for evaluating user-written scripts."},
{"stop-disassembly-count", OptionValue::eTypeSInt64, true, 4, nullptr,
- nullptr, "The number of disassembly lines to show when displaying a "
- "stopped context."},
+ nullptr,
+ "The number of disassembly lines to show when displaying a "
+ "stopped context."},
{"stop-disassembly-display", OptionValue::eTypeEnum, true,
Debugger::eStopDisassemblyTypeNoDebugInfo, nullptr,
g_show_disassembly_enum_values,
"Control when to display disassembly when displaying a stopped context."},
{"stop-line-count-after", OptionValue::eTypeSInt64, true, 3, nullptr,
- nullptr, "The number of sources lines to display that come after the "
- "current source line when displaying a stopped context."},
+ nullptr,
+ "The number of sources lines to display that come after the "
+ "current source line when displaying a stopped context."},
{"stop-line-count-before", OptionValue::eTypeSInt64, true, 3, nullptr,
- nullptr, "The number of sources lines to display that come before the "
- "current source line when displaying a stopped context."},
+ nullptr,
+ "The number of sources lines to display that come before the "
+ "current source line when displaying a stopped context."},
{"stop-show-column", OptionValue::eTypeEnum, false,
eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values,
"If true, LLDB will use the column information from the debug info to "
@@ -232,19 +247,22 @@ static PropertyDefinition g_properties[] = {
{"term-width", OptionValue::eTypeSInt64, true, 80, nullptr, nullptr,
"The maximum number of columns to use for displaying text."},
{"thread-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_THREAD_FORMAT, nullptr, "The default thread format string to use "
- "when displaying thread information."},
+ DEFAULT_THREAD_FORMAT, nullptr,
+ "The default thread format string to use "
+ "when displaying thread information."},
{"thread-stop-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_THREAD_STOP_FORMAT, nullptr, "The default thread format "
- "string to usewhen displaying thread "
- "information as part of the stop display."},
+ DEFAULT_THREAD_STOP_FORMAT, nullptr,
+ "The default thread format "
+ "string to use when displaying thread "
+ "information as part of the stop display."},
{"use-external-editor", OptionValue::eTypeBoolean, true, false, nullptr,
nullptr, "Whether to use an external editor or not."},
{"use-color", OptionValue::eTypeBoolean, true, true, nullptr, nullptr,
"Whether to use Ansi color codes or not."},
{"auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, nullptr,
- nullptr, "If true, LLDB will automatically display small structs in "
- "one-liner format (default: true)."},
+ nullptr,
+ "If true, LLDB will automatically display small structs in "
+ "one-liner format (default: true)."},
{"auto-indent", OptionValue::eTypeBoolean, true, true, nullptr, nullptr,
"If true, LLDB will auto indent/outdent code. Currently only supported in "
"the REPL (default: true)."},
@@ -255,8 +273,13 @@ static PropertyDefinition g_properties[] = {
"The tab size to use when indenting code in multi-line input mode "
"(default: 4)."},
{"escape-non-printables", OptionValue::eTypeBoolean, true, true, nullptr,
- nullptr, "If true, LLDB will automatically escape non-printable and "
- "escape characters when formatting strings."},
+ nullptr,
+ "If true, LLDB will automatically escape non-printable and "
+ "escape characters when formatting strings."},
+ {"frame-format-unique", OptionValue::eTypeFormatEntity, true, 0,
+ DEFAULT_FRAME_FORMAT_NO_ARGS, nullptr,
+ "The default frame format string to use when displaying stack frame"
+ "information for threads from thread backtrace unique."},
{nullptr, OptionValue::eTypeInvalid, true, 0, nullptr, nullptr, nullptr}};
enum {
@@ -282,7 +305,8 @@ enum {
ePropertyAutoIndent,
ePropertyPrintDecls,
ePropertyTabSize,
- ePropertyEscapeNonPrintables
+ ePropertyEscapeNonPrintables,
+ ePropertyFrameFormatUnique,
};
LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;
@@ -358,6 +382,11 @@ const FormatEntity::Entry *Debugger::GetFrameFormat() const {
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
}
+const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const {
+ const uint32_t idx = ePropertyFrameFormatUnique;
+ return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
+}
+
bool Debugger::GetNotifyVoid() const {
const uint32_t idx = ePropertyNotiftVoid;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
diff --git a/source/Host/common/Symbols.cpp b/source/Host/common/Symbols.cpp
index 1d9180bf528e..fe29b9e78990 100644
--- a/source/Host/common/Symbols.cpp
+++ b/source/Host/common/Symbols.cpp
@@ -86,7 +86,6 @@ static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
path);
}
}
- size_t obj_file_path_length = strlen(path);
::strncat(path, ".dSYM/Contents/Resources/DWARF/",
sizeof(path) - strlen(path) - 1);
::strncat(path, exec_fspec->GetFilename().AsCString(),
@@ -105,38 +104,55 @@ static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
}
return true;
} else {
- path[obj_file_path_length] = '\0';
-
- char *last_dot = strrchr(path, '.');
- while (last_dot != NULL && last_dot[0]) {
- char *next_slash = strchr(last_dot, '/');
- if (next_slash != NULL) {
- *next_slash = '\0';
- ::strncat(path, ".dSYM/Contents/Resources/DWARF/",
- sizeof(path) - strlen(path) - 1);
- ::strncat(path, exec_fspec->GetFilename().AsCString(),
- sizeof(path) - strlen(path) - 1);
- dsym_fspec.SetFile(path, false);
+ FileSpec parent_dirs = exec_fspec;
+
+ // Remove the binary name from the FileSpec
+ parent_dirs.RemoveLastPathComponent();
+
+ // Add a ".dSYM" name to each directory component of the path, stripping
+ // off components. e.g. we may have a binary like
+ // /S/L/F/Foundation.framework/Versions/A/Foundation
+ // and
+ // /S/L/F/Foundation.framework.dSYM
+ //
+ // so we'll need to start with /S/L/F/Foundation.framework/Versions/A,
+ // add the .dSYM part to the "A", and if that doesn't exist, strip off
+ // the "A" and try it again with "Versions", etc., until we find a dSYM
+ // bundle or we've stripped off enough path components that there's no
+ // need to continue.
+
+ for (int i = 0; i < 4; i++) {
+ // Does this part of the path have a "." character - could it be a bundle's
+ // top level directory?
+ const char *fn = parent_dirs.GetFilename().AsCString();
+ if (fn == nullptr)
+ break;
+ if (::strchr (fn, '.') != nullptr) {
+ dsym_fspec = parent_dirs;
+ dsym_fspec.RemoveLastPathComponent();
+
+ // If the current directory name is "Foundation.framework", see if
+ // "Foundation.framework.dSYM/Contents/Resources/DWARF/Foundation"
+ // exists & has the right uuid.
+ std::string dsym_fn = fn;
+ dsym_fn += ".dSYM";
+ dsym_fspec.AppendPathComponent(dsym_fn.c_str());
+ dsym_fspec.AppendPathComponent("Contents");
+ dsym_fspec.AppendPathComponent("Resources");
+ dsym_fspec.AppendPathComponent("DWARF");
+ dsym_fspec.AppendPathComponent(exec_fspec->GetFilename().AsCString());
if (dsym_fspec.Exists() &&
- FileAtPathContainsArchAndUUID(
- dsym_fspec, module_spec.GetArchitecturePtr(),
- module_spec.GetUUIDPtr())) {
- if (log) {
- log->Printf("dSYM with matching UUID & arch found at %s",
- path);
- }
- return true;
- } else {
- *last_dot = '\0';
- char *prev_slash = strrchr(path, '/');
- if (prev_slash != NULL)
- *prev_slash = '\0';
- else
- break;
+ FileAtPathContainsArchAndUUID(
+ dsym_fspec, module_spec.GetArchitecturePtr(),
+ module_spec.GetUUIDPtr())) {
+ if (log) {
+ log->Printf("dSYM with matching UUID & arch found at %s",
+ dsym_fspec.GetPath().c_str());
+ }
+ return true;
}
- } else {
- break;
}
+ parent_dirs.RemoveLastPathComponent();
}
}
}
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index 4ef4a399290a..30fceb11c11f 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -1744,7 +1744,7 @@ void StackFrame::CalculateExecutionContext(ExecutionContext &exe_ctx) {
exe_ctx.SetContext(shared_from_this());
}
-void StackFrame::DumpUsingSettingsFormat(Stream *strm,
+void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique,
const char *frame_marker) {
if (strm == nullptr)
return;
@@ -1758,8 +1758,13 @@ void StackFrame::DumpUsingSettingsFormat(Stream *strm,
const FormatEntity::Entry *frame_format = nullptr;
Target *target = exe_ctx.GetTargetPtr();
- if (target)
- frame_format = target->GetDebugger().GetFrameFormat();
+ if (target) {
+ if (show_unique) {
+ frame_format = target->GetDebugger().GetFrameFormatUnique();
+ } else {
+ frame_format = target->GetDebugger().GetFrameFormat();
+ }
+ }
if (frame_format && FormatEntity::Format(*frame_format, s, &m_sc, &exe_ctx,
nullptr, nullptr, false, false)) {
strm->PutCString(s.GetString());
@@ -1841,11 +1846,10 @@ bool StackFrame::HasCachedData() const {
}
bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
- const char *frame_marker) {
-
+ bool show_unique, const char *frame_marker) {
if (show_frame_info) {
strm.Indent();
- DumpUsingSettingsFormat(&strm, frame_marker);
+ DumpUsingSettingsFormat(&strm, show_unique, frame_marker);
}
if (show_source) {
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 044f860ba32b..be7fa8001212 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -802,6 +802,7 @@ StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {
size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
uint32_t num_frames, bool show_frame_info,
uint32_t num_frames_with_source,
+ bool show_unique,
const char *selected_frame_marker) {
size_t num_frames_displayed = 0;
@@ -842,7 +843,7 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
if (!frame_sp->GetStatus(strm, show_frame_info,
num_frames_with_source > (first_frame - frame_idx),
- marker))
+ show_unique, marker))
break;
++num_frames_displayed;
}
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 4aba30be5f78..505d14012d65 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -1913,39 +1913,42 @@ const char *Thread::RunModeAsCString(lldb::RunMode mode) {
size_t Thread::GetStatus(Stream &strm, uint32_t start_frame,
uint32_t num_frames, uint32_t num_frames_with_source,
- bool stop_format) {
- ExecutionContext exe_ctx(shared_from_this());
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- size_t num_frames_shown = 0;
- strm.Indent();
- bool is_selected = false;
- if (process) {
- if (process->GetThreadList().GetSelectedThread().get() == this)
- is_selected = true;
- }
- strm.Printf("%c ", is_selected ? '*' : ' ');
- if (target && target->GetDebugger().GetUseExternalEditor()) {
- StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame);
- if (frame_sp) {
- SymbolContext frame_sc(
- frame_sp->GetSymbolContext(eSymbolContextLineEntry));
- if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) {
- Host::OpenFileInExternalEditor(frame_sc.line_entry.file,
- frame_sc.line_entry.line);
+ bool stop_format, bool only_stacks) {
+
+ if (!only_stacks) {
+ ExecutionContext exe_ctx(shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ strm.Indent();
+ bool is_selected = false;
+ if (process) {
+ if (process->GetThreadList().GetSelectedThread().get() == this)
+ is_selected = true;
+ }
+ strm.Printf("%c ", is_selected ? '*' : ' ');
+ if (target && target->GetDebugger().GetUseExternalEditor()) {
+ StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame);
+ if (frame_sp) {
+ SymbolContext frame_sc(
+ frame_sp->GetSymbolContext(eSymbolContextLineEntry));
+ if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) {
+ Host::OpenFileInExternalEditor(frame_sc.line_entry.file,
+ frame_sc.line_entry.line);
+ }
}
}
- }
- DumpUsingSettingsFormat(strm, start_frame, stop_format);
+ DumpUsingSettingsFormat(strm, start_frame, stop_format);
+ }
+ size_t num_frames_shown = 0;
if (num_frames > 0) {
strm.IndentMore();
const bool show_frame_info = true;
-
+ const bool show_frame_unique = only_stacks;
const char *selected_frame_marker = nullptr;
- if (num_frames == 1 ||
+ if (num_frames == 1 || only_stacks ||
(GetID() != GetProcess()->GetThreadList().GetSelectedThread()->GetID()))
strm.IndentMore();
else
@@ -1953,7 +1956,7 @@ size_t Thread::GetStatus(Stream &strm, uint32_t start_frame,
num_frames_shown = GetStackFrameList()->GetStatus(
strm, start_frame, num_frames, show_frame_info, num_frames_with_source,
- selected_frame_marker);
+ show_frame_unique, selected_frame_marker);
if (num_frames == 1)
strm.IndentLess();
strm.IndentLess();
diff --git a/source/Utility/Status.cpp b/source/Utility/Status.cpp
index 6ecc7717620b..b11a3db64e6d 100644
--- a/source/Utility/Status.cpp
+++ b/source/Utility/Status.cpp
@@ -56,10 +56,11 @@ Status::Status(const char *format, ...)
va_end(args);
}
-Status::Status(llvm::Error error)
- : m_code(0), m_type(ErrorType::eErrorTypeGeneric) {
- if (!error)
- return;
+const Status &Status::operator=(llvm::Error error) {
+ if (!error) {
+ Clear();
+ return *this;
+ }
// if the error happens to be a errno error, preserve the error code
error = llvm::handleErrors(
@@ -74,8 +75,12 @@ Status::Status(llvm::Error error)
});
// Otherwise, just preserve the message
- if (error)
+ if (error) {
+ SetErrorToGenericError();
SetErrorString(llvm::toString(std::move(error)));
+ }
+
+ return *this;
}
llvm::Error Status::ToError() const {
diff --git a/unittests/Utility/StatusTest.cpp b/unittests/Utility/StatusTest.cpp
index 03e2368c7b1b..b3f5182a5d8f 100644
--- a/unittests/Utility/StatusTest.cpp
+++ b/unittests/Utility/StatusTest.cpp
@@ -33,6 +33,9 @@ TEST(StatusTest, ErrorConstructor) {
EXPECT_TRUE(foo.Fail());
EXPECT_EQ(eErrorTypeGeneric, foo.GetType());
EXPECT_STREQ("foo", foo.AsCString());
+
+ foo = llvm::Error::success();
+ EXPECT_TRUE(foo.Success());
}
TEST(StatusTest, ErrorConversion) {