diff options
112 files changed, 2626 insertions, 2542 deletions
diff --git a/include/lldb/Core/LoadedModuleInfoList.h b/include/lldb/Core/LoadedModuleInfoList.h new file mode 100644 index 000000000000..6ba5c2813ec4 --- /dev/null +++ b/include/lldb/Core/LoadedModuleInfoList.h @@ -0,0 +1,152 @@ +//===-- LoadedModuleInfoList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LoadedModuleInfoList_h_ +#define liblldb_LoadedModuleInfoList_h_ + +// C Includes + +// C++ Includes +#include <vector> + +// Other libraries and framework includes +#include "lldb/lldb-private-forward.h" + +namespace lldb_private { +class LoadedModuleInfoList +{ +public: + + class LoadedModuleInfo + { + public: + + enum e_data_point + { + e_has_name = 0, + e_has_base , + e_has_dynamic , + e_has_link_map , + e_num + }; + + LoadedModuleInfo () + { + for (uint32_t i = 0; i < e_num; ++i) + m_has[i] = false; + }; + + void set_name (const std::string & name) + { + m_name = name; + m_has[e_has_name] = true; + } + bool get_name (std::string & out) const + { + out = m_name; + return m_has[e_has_name]; + } + + void set_base (const lldb::addr_t base) + { + m_base = base; + m_has[e_has_base] = true; + } + bool get_base (lldb::addr_t & out) const + { + out = m_base; + return m_has[e_has_base]; + } + + void set_base_is_offset (bool is_offset) + { + m_base_is_offset = is_offset; + } + bool get_base_is_offset(bool & out) const + { + out = m_base_is_offset; + return m_has[e_has_base]; + } + + void set_link_map (const lldb::addr_t addr) + { + m_link_map = addr; + m_has[e_has_link_map] = true; + } + bool get_link_map (lldb::addr_t & out) const + { + out = m_link_map; + return m_has[e_has_link_map]; + } + + void set_dynamic (const lldb::addr_t addr) + { + m_dynamic = addr; + m_has[e_has_dynamic] = true; + } + bool get_dynamic (lldb::addr_t & out) const + { + out = m_dynamic; + return m_has[e_has_dynamic]; + } + + bool has_info (e_data_point datum) const + { + assert (datum < e_num); + return m_has[datum]; + } + + bool + operator == (LoadedModuleInfo const &rhs) const + { + if (e_num != rhs.e_num) + return false; + + for (size_t i = 0; i < e_num; ++i) + { + if (m_has[i] != rhs.m_has[i]) + return false; + } + + return (m_base == rhs.m_base) && + (m_link_map == rhs.m_link_map) && + (m_dynamic == rhs.m_dynamic) && + (m_name == rhs.m_name); + } + protected: + + bool m_has[e_num]; + std::string m_name; + lldb::addr_t m_link_map; + lldb::addr_t m_base; + bool m_base_is_offset; + lldb::addr_t m_dynamic; + }; + + LoadedModuleInfoList () + : m_list () + , m_link_map (LLDB_INVALID_ADDRESS) + {} + + void add (const LoadedModuleInfo & mod) + { + m_list.push_back (mod); + } + + void clear () + { + m_list.clear (); + } + + std::vector<LoadedModuleInfo> m_list; + lldb::addr_t m_link_map; +}; +} // namespace lldb_private + +#endif // liblldb_LoadedModuleInfoList_h_ diff --git a/include/lldb/Interpreter/CommandReturnObject.h b/include/lldb/Interpreter/CommandReturnObject.h index 424ac800d14c..e3a1d9f657cb 100644 --- a/include/lldb/Interpreter/CommandReturnObject.h +++ b/include/lldb/Interpreter/CommandReturnObject.h @@ -169,6 +169,18 @@ public: void SetInteractive (bool b); + + bool + GetAbnormalStopWasExpected() const + { + return m_abnormal_stop_was_expected; + } + + void + SetAbnormalStopWasExpected(bool signal_was_expected) + { + m_abnormal_stop_was_expected = signal_was_expected; + } private: enum @@ -182,7 +194,13 @@ private: lldb::ReturnStatus m_status; bool m_did_change_process_state; - bool m_interactive; // If true, then the input handle from the debugger will be hooked up + bool m_interactive; // If true, then the input handle from the debugger will be hooked up + bool m_abnormal_stop_was_expected; // This is to support eHandleCommandFlagStopOnCrash vrs. attach. + // The attach command often ends up with the process stopped due to a signal. + // Normally that would mean stop on crash should halt batch execution, but we + // obviously don't want that for attach. Using this flag, the attach command + // (and anything else for which this is relevant) can say that the signal is + // expected, and batch command execution can continue. }; } // namespace lldb_private diff --git a/include/lldb/Symbol/ClangASTContext.h b/include/lldb/Symbol/ClangASTContext.h index 0314ce060e38..bd3a113e6cc5 100644 --- a/include/lldb/Symbol/ClangASTContext.h +++ b/include/lldb/Symbol/ClangASTContext.h @@ -573,6 +573,9 @@ public: ConstString DeclContextGetName (void *opaque_decl_ctx) override; + ConstString + DeclContextGetScopeQualifiedName (void *opaque_decl_ctx) override; + bool DeclContextIsClassMethod (void *opaque_decl_ctx, lldb::LanguageType *language_ptr, diff --git a/include/lldb/Symbol/CompilerDeclContext.h b/include/lldb/Symbol/CompilerDeclContext.h index 70399b2dbb37..9135b44323b5 100644 --- a/include/lldb/Symbol/CompilerDeclContext.h +++ b/include/lldb/Symbol/CompilerDeclContext.h @@ -128,6 +128,9 @@ public: ConstString GetName () const; + ConstString + GetScopeQualifiedName() const; + bool IsStructUnionOrClass () const; diff --git a/include/lldb/Symbol/GoASTContext.h b/include/lldb/Symbol/GoASTContext.h index 3de98da59958..09d79bacc585 100644 --- a/include/lldb/Symbol/GoASTContext.h +++ b/include/lldb/Symbol/GoASTContext.h @@ -112,6 +112,12 @@ class GoASTContext : public TypeSystem return ConstString(); } + ConstString + DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override + { + return ConstString(); + } + bool DeclContextIsClassMethod(void *opaque_decl_ctx, lldb::LanguageType *language_ptr, bool *is_instance_method_ptr, ConstString *language_object_name_ptr) override diff --git a/include/lldb/Symbol/SymbolFile.h b/include/lldb/Symbol/SymbolFile.h index e27b32d01f68..fe74ad4f933e 100644 --- a/include/lldb/Symbol/SymbolFile.h +++ b/include/lldb/Symbol/SymbolFile.h @@ -144,6 +144,7 @@ public: virtual uint32_t FindTypes (const SymbolContext& sc, const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, TypeMap& types); virtual size_t FindTypes (const std::vector<CompilerContext> &context, bool append, TypeMap& types); + virtual void GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names); // virtual uint32_t FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, TypeList& types) = 0; virtual TypeList * GetTypeList (); virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope, diff --git a/include/lldb/Symbol/TypeSystem.h b/include/lldb/Symbol/TypeSystem.h index d367bcdc0b14..9b43b9dec37b 100644 --- a/include/lldb/Symbol/TypeSystem.h +++ b/include/lldb/Symbol/TypeSystem.h @@ -151,6 +151,9 @@ public: virtual ConstString DeclContextGetName (void *opaque_decl_ctx) = 0; + virtual ConstString + DeclContextGetScopeQualifiedName (void *opaque_decl_ctx) = 0; + virtual bool DeclContextIsClassMethod (void *opaque_decl_ctx, lldb::LanguageType *language_ptr, diff --git a/include/lldb/Target/CPPLanguageRuntime.h b/include/lldb/Target/CPPLanguageRuntime.h index ac537d0ad1e5..788f4e60a493 100644 --- a/include/lldb/Target/CPPLanguageRuntime.h +++ b/include/lldb/Target/CPPLanguageRuntime.h @@ -42,9 +42,6 @@ public: bool GetObjectDescription(Stream &str, Value &value, ExecutionContextScope *exe_scope) override; - virtual size_t - GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) = 0; - protected: //------------------------------------------------------------------ diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h index 2e063c5bbccc..6bb7a3d783de 100644 --- a/include/lldb/Target/Process.h +++ b/include/lldb/Target/Process.h @@ -30,6 +30,7 @@ #include "lldb/Core/Communication.h" #include "lldb/Core/Error.h" #include "lldb/Core/Event.h" +#include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Core/ThreadSafeValue.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/StructuredData.h" @@ -1152,6 +1153,12 @@ public: return 0; } + virtual size_t + LoadModules (LoadedModuleInfoList &) + { + return 0; + } + protected: virtual JITLoaderList & GetJITLoaders (); @@ -3149,6 +3156,34 @@ public: void ResetImageToken(size_t token); + //------------------------------------------------------------------ + /// Find the next branch instruction to set a breakpoint on + /// + /// When instruction stepping through a source line, instead of + /// stepping through each instruction, we can put a breakpoint on + /// the next branch instruction (within the range of instructions + /// we are stepping through) and continue the process to there, + /// yielding significant performance benefits over instruction + /// stepping. + /// + /// @param[in] default_stop_addr + /// The address of the instruction where lldb would put a + /// breakpoint normally. + /// + /// @param[in] range_bounds + /// The range which the breakpoint must be contained within. + /// Typically a source line. + /// + /// @return + /// The address of the next branch instruction, or the end of + /// the range provided in range_bounds. If there are any + /// problems with the disassembly or getting the instructions, + /// the original default_stop_addr will be returned. + //------------------------------------------------------------------ + Address + AdvanceAddressToNextBranchInstruction (Address default_stop_addr, + AddressRange range_bounds); + protected: void SetState (lldb::EventSP &event_sp); diff --git a/include/lldb/Target/SystemRuntime.h b/include/lldb/Target/SystemRuntime.h index 54fde88c8d12..cefd72400450 100644 --- a/include/lldb/Target/SystemRuntime.h +++ b/include/lldb/Target/SystemRuntime.h @@ -275,6 +275,23 @@ public: return LLDB_INVALID_ADDRESS; } + + //------------------------------------------------------------------ + /// Retrieve the Queue kind for the queue at a thread's dispatch_qaddr. + /// + /// Retrieve the Queue kind - either eQueueKindSerial or + /// eQueueKindConcurrent, indicating that this queue processes work + /// items serially or concurrently. + /// + /// @return + /// The Queue kind, if it could be read, else eQueueKindUnknown. + //------------------------------------------------------------------ + virtual lldb::QueueKind + GetQueueKind (lldb::addr_t dispatch_qaddr) + { + return lldb::eQueueKindUnknown; + } + //------------------------------------------------------------------ /// Get the pending work items for a libdispatch Queue /// diff --git a/include/lldb/Target/Thread.h b/include/lldb/Target/Thread.h index 7aff77bd16f4..ba73e0b49da8 100644 --- a/include/lldb/Target/Thread.h +++ b/include/lldb/Target/Thread.h @@ -367,6 +367,35 @@ public: } //------------------------------------------------------------------ + /// Whether this thread can be associated with a libdispatch queue + /// + /// The Thread may know if it is associated with a libdispatch queue, + /// it may know definitively that it is NOT associated with a libdispatch + /// queue, or it may be unknown whether it is associated with a libdispatch + /// queue. + /// + /// @return + /// eLazyBoolNo if this thread is definitely not associated with a + /// libdispatch queue (e.g. on a non-Darwin system where GCD aka + /// libdispatch is not available). + /// + /// eLazyBoolYes this thread is associated with a libdispatch queue. + /// + /// eLazyBoolCalculate this thread may be associated with a libdispatch + /// queue but the thread doesn't know one way or the other. + //------------------------------------------------------------------ + virtual lldb_private::LazyBool + GetAssociatedWithLibdispatchQueue () + { + return eLazyBoolNo; + } + + virtual void + SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue) + { + } + + //------------------------------------------------------------------ /// Retrieve the Queue ID for the queue currently using this Thread /// /// If this Thread is doing work on behalf of a libdispatch/GCD queue, @@ -414,6 +443,29 @@ public: } //------------------------------------------------------------------ + /// Retrieve the Queue kind for the queue currently using this Thread + /// + /// If this Thread is doing work on behalf of a libdispatch/GCD queue, + /// retrieve the Queue kind - either eQueueKindSerial or + /// eQueueKindConcurrent, indicating that this queue processes work + /// items serially or concurrently. + /// + /// @return + /// The Queue kind, if the Thread subclass implements this, else + /// eQueueKindUnknown. + //------------------------------------------------------------------ + virtual lldb::QueueKind + GetQueueKind () + { + return lldb::eQueueKindUnknown; + } + + virtual void + SetQueueKind (lldb::QueueKind kind) + { + } + + //------------------------------------------------------------------ /// Retrieve the Queue for this thread, if any. /// /// @return @@ -451,6 +503,30 @@ public: return LLDB_INVALID_ADDRESS; } + virtual void + SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) + { + } + + //------------------------------------------------------------------ + /// Whether this Thread already has all the Queue information cached or not + /// + /// A Thread may be associated with a libdispatch work Queue at a given + /// public stop event. If so, the thread can satisify requests like + /// GetQueueLibdispatchQueueAddress, GetQueueKind, GetQueueName, and GetQueueID + /// either from information from the remote debug stub when it is initially + /// created, or it can query the SystemRuntime for that information. + /// + /// This method allows the SystemRuntime to discover if a thread has this + /// information already, instead of calling the thread to get the information + /// and having the thread call the SystemRuntime again. + //------------------------------------------------------------------ + virtual bool + ThreadHasQueueInformation () const + { + return false; + } + virtual uint32_t GetStackFrameCount() { @@ -888,6 +964,16 @@ public: /// @param[in] run_vote /// See standard meanings for the stop & run votes in ThreadPlan.h. /// + /// @param[in] continue_to_next_branch + /// Normally this will enqueue a plan that will put a breakpoint on the return address and continue + /// to there. If continue_to_next_branch is true, this is an operation not involving the user -- + /// e.g. stepping "next" in a source line and we instruction stepped into another function -- + /// so instead of putting a breakpoint on the return address, advance the breakpoint to the + /// end of the source line that is doing the call, or until the next flow control instruction. + /// If the return value from the function call is to be retrieved / displayed to the user, you must stop + /// on the return address. The return value may be stored in volatile registers which are overwritten + /// before the next branch instruction. + /// /// @return /// A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued. //------------------------------------------------------------------ @@ -898,7 +984,8 @@ public: bool stop_other_threads, Vote stop_vote, // = eVoteYes, Vote run_vote, // = eVoteNoOpinion); - uint32_t frame_idx); + uint32_t frame_idx, + bool continue_to_next_branch = false); //------------------------------------------------------------------ /// Gets the plan used to step through the code that steps from a function diff --git a/include/lldb/Target/ThreadPlanStepOut.h b/include/lldb/Target/ThreadPlanStepOut.h index ac5696357e9b..ccf829f636df 100644 --- a/include/lldb/Target/ThreadPlanStepOut.h +++ b/include/lldb/Target/ThreadPlanStepOut.h @@ -31,7 +31,8 @@ public: Vote stop_vote, Vote run_vote, uint32_t frame_idx, - LazyBool step_out_avoids_code_without_debug_info); + LazyBool step_out_avoids_code_without_debug_info, + bool continue_to_next_branch = false); ~ThreadPlanStepOut() override; diff --git a/packages/Python/lldbsuite/test/README-TestSuite b/packages/Python/lldbsuite/test/README-TestSuite index 6df4d7bd7be7..70e4c91b8894 100644 --- a/packages/Python/lldbsuite/test/README-TestSuite +++ b/packages/Python/lldbsuite/test/README-TestSuite @@ -157,3 +157,10 @@ o Writing test cases: then use SBInterpreter::HandleCommand to run the command. You get the full result text from the command in the command return object, and all the part where you are driving the debugger to the point you want to test will be more robust. + +o Attaching in test cases: + + If you need to attach to inferiors in your tests, you must make sure the inferior calls + lldb_enable_attach(), before the debugger attempts to attach. This function performs any + platform-specific processing needed to enable attaching to this process (e.g., on Linux, we + execute prctl(PR_SET_TRACER) syscall to disable protections present in some Linux systems). diff --git a/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py b/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py index 0b405091ebd1..9963cf23a8c6 100644 --- a/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py +++ b/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py @@ -51,7 +51,7 @@ class SBBreakpointCallbackCase(TestBase): @skipIfNoSBHeaders @skipIfWindows # clang-cl does not support throw or catch (llvm.org/pr24538) @expectedFlakeyFreeBSD - @expectedFlakeyLinux + @expectedFailureLinux def test_sb_api_listener_resume(self): """ Test that a process can be resumed from a non-main thread. """ self.build_and_test('driver.cpp listener_test.cpp test_listener_resume.cpp', diff --git a/packages/Python/lldbsuite/test/dosep.py b/packages/Python/lldbsuite/test/dosep.py index 51275d55c178..87a410fa090f 100644 --- a/packages/Python/lldbsuite/test/dosep.py +++ b/packages/Python/lldbsuite/test/dosep.py @@ -1149,11 +1149,6 @@ def getExpectedTimeouts(platform_name): "TestExitDuringStep.py", "TestHelloWorld.py", } - if host.startswith("win32"): - expected_timeout |= { - "TestEvents.py", - "TestThreadStates.py", - } elif target.startswith("freebsd"): expected_timeout |= { "TestBreakpointConditions.py", diff --git a/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py b/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py index b5ff88c3bba1..0a9edd2755c9 100644 --- a/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py +++ b/packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py @@ -14,21 +14,12 @@ class DriverBatchModeTest (TestBase): mydir = TestBase.compute_mydir(__file__) - @skipIfRemote # test not remote-ready llvm.org/pr24813 - @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") - @expectedFlakeyLinux("llvm.org/pr25172") - @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") - def test_driver_batch_mode(self): - """Test that the lldb driver's batch mode works correctly.""" - self.build() - self.setTearDownCleanup() - self.batch_mode() - def setUp(self): # Call super's setUp(). TestBase.setUp(self) # Our simple source filename. self.source = 'main.c' + self.victim = None def expect_string (self, string): import pexpect @@ -40,12 +31,20 @@ class DriverBatchModeTest (TestBase): except pexpect.TIMEOUT: self.fail ("Timed out waiting for '%s'"%(string)) - def batch_mode (self): + @skipIfRemote # test not remote-ready llvm.org/pr24813 + @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") + @expectedFlakeyLinux("llvm.org/pr25172") + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_batch_mode_run_crash (self): + """Test that the lldb driver's batch mode works correctly.""" + self.build() + self.setTearDownCleanup() + import pexpect exe = os.path.join(os.getcwd(), "a.out") prompt = "(lldb) " - # First time through, pass CRASH so the process will crash and stop in batch mode. + # Pass CRASH so the process will crash and stop in batch mode. run_commands = ' -b -o "break set -n main" -o "run" -o "continue" -k "frame var touch_me_not"' self.child = pexpect.spawn('%s %s %s %s -- CRASH' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) child = self.child @@ -68,7 +67,21 @@ class DriverBatchModeTest (TestBase): self.deletePexpectChild() - # Now do it again, and see make sure if we don't crash, we quit: + + @skipIfRemote # test not remote-ready llvm.org/pr24813 + @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") + @expectedFlakeyLinux("llvm.org/pr25172") + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_batch_mode_run_exit (self): + """Test that the lldb driver's batch mode works correctly.""" + self.build() + self.setTearDownCleanup() + + import pexpect + exe = os.path.join(os.getcwd(), "a.out") + prompt = "(lldb) " + + # Now do it again, and make sure if we don't crash, we quit: run_commands = ' -b -o "break set -n main" -o "run" -o "continue" ' self.child = pexpect.spawn('%s %s %s %s -- NOCRASH' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) child = self.child @@ -87,3 +100,69 @@ class DriverBatchModeTest (TestBase): index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") + def closeVictim(self): + if self.victim != None: + self.victim.close() + self.victim = None + + @skipIfRemote # test not remote-ready llvm.org/pr24813 + @expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot") + @expectedFlakeyLinux("llvm.org/pr25172") + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_batch_mode_attach_exit (self): + """Test that the lldb driver's batch mode works correctly.""" + self.build() + self.setTearDownCleanup() + + import pexpect + exe = os.path.join(os.getcwd(), "a.out") + prompt = "(lldb) " + + # Finally, start up the process by hand, attach to it, and wait for its completion. + # Attach is funny, since it looks like it stops with a signal on most Unixen so + # care must be taken not to treat that as a reason to exit batch mode. + + # Start up the process by hand and wait for it to get to the wait loop. + + self.victim = pexpect.spawn('%s WAIT' %(exe)) + if self.victim == None: + self.fail("Could not spawn ", exe, ".") + + self.addTearDownHook (self.closeVictim) + + if self.TraceOn(): + self.victim.logfile_read = sys.stdout + + self.victim.expect("PID: ([0-9]+) END") + if self.victim.match == None: + self.fail("Couldn't get the target PID.") + + victim_pid = int(self.victim.match.group(1)) + + self.victim.expect("Waiting") + + run_commands = ' -b -o "process attach -p %d" -o "breakpoint set --file %s -p \'Stop here to unset keep_waiting\' -N keep_waiting" -o "continue" -o "break delete keep_waiting" -o "expr keep_waiting = 0" -o "continue" ' % (victim_pid, self.source) + self.child = pexpect.spawn('%s %s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) + + child = self.child + # Turn on logging for what the child sends back. + if self.TraceOn(): + child.logfile_read = sys.stdout + + # We should see the "run": + self.expect_string ("attach") + + self.expect_string(prompt + "continue") + + self.expect_string(prompt + "continue") + + # Then we should see the process exit: + self.expect_string ("Process %d exited with status"%(victim_pid)) + + victim_index = self.victim.expect([pexpect.EOF, pexpect.TIMEOUT]) + self.assertTrue(victim_index == 0, "Victim didn't really exit.") + + index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) + self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") + + diff --git a/packages/Python/lldbsuite/test/driver/batch_mode/main.c b/packages/Python/lldbsuite/test/driver/batch_mode/main.c index 418160eaa36d..c85a0f272d2c 100644 --- a/packages/Python/lldbsuite/test/driver/batch_mode/main.c +++ b/packages/Python/lldbsuite/test/driver/batch_mode/main.c @@ -1,10 +1,36 @@ #include <stdio.h> #include <string.h> +#include <unistd.h> int main (int argc, char **argv) { - if (argc >= 2 && strcmp (argv[1], "CRASH") == 0) + lldb_enable_attach(); + + int do_crash = 0; + int do_wait = 0; + + int idx; + for (idx = 1; idx < argc; idx++) + { + if (strcmp(argv[idx], "CRASH") == 0) + do_crash = 1; + if (strcmp(argv[idx], "WAIT") == 0) + do_wait = 1; + } + printf("PID: %d END\n", getpid()); + + if (do_wait) + { + int keep_waiting = 1; + while (keep_waiting) + { + printf ("Waiting\n"); + sleep(1); // Stop here to unset keep_waiting + } + } + + if (do_crash) { char *touch_me_not = (char *) 0; printf ("About to crash.\n"); diff --git a/packages/Python/lldbsuite/test/functionalities/attach_resume/main.cpp b/packages/Python/lldbsuite/test/functionalities/attach_resume/main.cpp index 7cf360258546..82aad70eed56 100644 --- a/packages/Python/lldbsuite/test/functionalities/attach_resume/main.cpp +++ b/packages/Python/lldbsuite/test/functionalities/attach_resume/main.cpp @@ -4,10 +4,6 @@ #include <chrono> #include <thread> -#if defined(__linux__) -#include <sys/prctl.h> -#endif - volatile bool debugger_flag = true; // The debugger will flip this to false void *start(void *data) @@ -25,18 +21,7 @@ void *start(void *data) int main(int argc, char const *argv[]) { -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor process can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - // For now we execute on best effort basis. If this fails for - // some reason, so be it. - const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - static_cast<void> (prctl_result); -#endif -#endif + lldb_enable_attach(); static const size_t nthreads = 16; std::thread threads[nthreads]; diff --git a/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile b/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile new file mode 100644 index 000000000000..b09a579159d4 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py b/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py new file mode 100644 index 000000000000..b32c970301c9 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py @@ -0,0 +1,51 @@ +""" +Test embedded breakpoints, like `asm int 3;` in x86 or or `__debugbreak` on Windows. +""" + +from __future__ import print_function + +import os +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class DebugBreakTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIf(archs=not_in(["i386", "i686"])) + @no_debug_info_test + def test_asm_int_3(self): + """Test that intrinsics like `__debugbreak();` and `asm {"int3"}` are treated like breakpoints.""" + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + # Run the program. + target = self.dbg.CreateTarget(exe) + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + + # We've hit the first stop, so grab the frame. + self.assertEqual(process.GetState(), lldb.eStateStopped) + thread = process.GetThreadAtIndex(0) + frame = thread.GetFrameAtIndex(0) + + # We should be in funciton 'bar'. + self.assertTrue(frame.IsValid()) + function_name = frame.GetFunctionName() + self.assertTrue('bar' in function_name) + + # We should be able to evaluate the parameter foo. + value = frame.EvaluateExpression('*foo') + self.assertEqual(value.GetValueAsSigned(), 42) + + # The counter should be 1 at the first stop and increase by 2 for each + # subsequent stop. + counter = 1 + while counter < 20: + value = frame.EvaluateExpression('count') + self.assertEqual(value.GetValueAsSigned(), counter) + counter += 2 + process.Continue() + + # The inferior should exit after the last iteration. + self.assertEqual(process.GetState(), lldb.eStateExited) diff --git a/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c b/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c new file mode 100644 index 000000000000..5f936327e4ea --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c @@ -0,0 +1,29 @@ +#ifdef _MSC_VER +#include <intrin.h> +#define BREAKPOINT_INTRINSIC() __debugbreak() +#else +#define BREAKPOINT_INTRINSIC() __asm__ __volatile__ ("int3") +#endif + +int +bar(int const *foo) +{ + int count = 0, i = 0; + for (; i < 10; ++i) + { + count += 1; + BREAKPOINT_INTRINSIC(); + count += 1; + } + return *foo; +} + +int +main(int argc, char **argv) +{ + int foo = 42; + bar(&foo); + return 0; +} + + diff --git a/packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/TestDataFormatterLanguageCategoryUpdates.py b/packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/TestDataFormatterLanguageCategoryUpdates.py index b7562c4336a6..f30733d2d81a 100644 --- a/packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/TestDataFormatterLanguageCategoryUpdates.py +++ b/packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/TestDataFormatterLanguageCategoryUpdates.py @@ -21,7 +21,6 @@ class LanguageCategoryUpdatesTestCase(TestBase): # Find the line number to break at. self.line = line_number('main.cpp', '// break here') - @expectedFailureWindows("llvm.org/pr24462") # Data formatters have problems on Windows def test_with_run_command(self): """Test that LLDB correctly cleans caches when language categories change.""" # This is the function to remove the custom formats in order to have a diff --git a/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py b/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py index 69e977e6343f..950b021b69ce 100644 --- a/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py +++ b/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py @@ -16,6 +16,7 @@ class AssertingInferiorTestCase(TestBase): @expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") @expectedFailurei386("llvm.org/pr25338") + @expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386']) def test_inferior_asserting(self): """Test that lldb reliably catches the inferior asserting (command).""" self.build() @@ -30,6 +31,7 @@ class AssertingInferiorTestCase(TestBase): @expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") @expectedFailurei386("llvm.org/pr25338") + @expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386']) def test_inferior_asserting_disassemble(self): """Test that lldb reliably disassembles frames after asserting (command).""" self.build() @@ -44,6 +46,7 @@ class AssertingInferiorTestCase(TestBase): @expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") @expectedFailurei386("llvm.org/pr25338") + @expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386']) def test_inferior_asserting_expr(self): """Test that the lldb expression interpreter can read from the inferior after asserting (command).""" self.build() @@ -51,6 +54,7 @@ class AssertingInferiorTestCase(TestBase): @expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows") @expectedFailurei386("llvm.org/pr25338") + @expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386']) def test_inferior_asserting_step(self): """Test that lldb functions correctly after stepping through a call to assert().""" self.build() diff --git a/packages/Python/lldbsuite/test/functionalities/inline-stepping/TestInlineStepping.py b/packages/Python/lldbsuite/test/functionalities/inline-stepping/TestInlineStepping.py index 3bdf6ec70e34..023f6f31e395 100644 --- a/packages/Python/lldbsuite/test/functionalities/inline-stepping/TestInlineStepping.py +++ b/packages/Python/lldbsuite/test/functionalities/inline-stepping/TestInlineStepping.py @@ -16,7 +16,6 @@ class TestInlineStepping(TestBase): @add_test_categories(['pyapi']) @expectedFailureFreeBSD('llvm.org/pr17214') @expectedFailureIcc # Not really a bug. ICC combines two inlined functions. - @expectedFailureWindows("llvm.org/pr24778") # failed 1/365 dosep runs, (i386-clang), TestInlineStepping.py:237 failed to stop at first breakpoint in main @expectedFailureAll(oslist=["linux"], archs=["i386"]) def test_with_python_api(self): diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py index 53888502a3aa..1dda59ac374b 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py @@ -3,7 +3,7 @@ Test basics of mini dump debugging. """ from __future__ import print_function - +from six import iteritems import lldb @@ -83,8 +83,8 @@ class MiniDumpTestCase(TestBase): thread = process.GetThreadAtIndex(0) expected_stack = { 0: 'bar', 1: 'foo', 2: 'main' } - self.assertEqual(thread.GetNumFrames(), len(expected_stack)) - for index, name in expected_stack.iteritems(): + self.assertGreaterEqual(thread.GetNumFrames(), len(expected_stack)) + for index, name in iteritems(expected_stack): frame = thread.GetFrameAtIndex(index) self.assertTrue(frame.IsValid()) function_name = frame.GetFunctionName() diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/fizzbuzz.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/fizzbuzz.cpp index eb6476bfd9a9..295d4a1f24db 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/fizzbuzz.cpp +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/fizzbuzz.cpp @@ -1,31 +1,31 @@ -// A sample program for getting minidumps on Windows.
-
-#include <iostream>
-
-bool
-fizz(int x)
-{
- return x % 3 == 0;
-}
-
-bool
-buzz(int x)
-{
- return x % 5 == 0;
-}
-
-int
-main()
-{
- int *buggy = 0;
-
- for (int i = 1; i <= 100; ++i)
- {
- if (fizz(i)) std::cout << "fizz";
- if (buzz(i)) std::cout << "buzz";
- if (!fizz(i) && !buzz(i)) std::cout << i;
- std::cout << '\n';
- }
-
- return *buggy;
-}
+// A sample program for getting minidumps on Windows. + +#include <iostream> + +bool +fizz(int x) +{ + return x % 3 == 0; +} + +bool +buzz(int x) +{ + return x % 5 == 0; +} + +int +main() +{ + int *buggy = 0; + + for (int i = 1; i <= 100; ++i) + { + if (fizz(i)) std::cout << "fizz"; + if (buzz(i)) std::cout << "buzz"; + if (!fizz(i) && !buzz(i)) std::cout << i; + std::cout << '\n'; + } + + return *buggy; +} diff --git a/packages/Python/lldbsuite/test/functionalities/process_attach/main.cpp b/packages/Python/lldbsuite/test/functionalities/process_attach/main.cpp index 8021feac5c71..46ffacc0a840 100644 --- a/packages/Python/lldbsuite/test/functionalities/process_attach/main.cpp +++ b/packages/Python/lldbsuite/test/functionalities/process_attach/main.cpp @@ -1,28 +1,11 @@ #include <stdio.h> -#if defined(__linux__) -#include <sys/prctl.h> -#endif - #include <chrono> #include <thread> int main(int argc, char const *argv[]) { int temp; -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor process can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - int prctl_result; - - // For now we execute on best effort basis. If this fails for - // some reason, so be it. - prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - (void) prctl_result; -#endif -#endif + lldb_enable_attach(); // Waiting to be attached by the debugger. temp = 0; diff --git a/packages/Python/lldbsuite/test/functionalities/process_group/main.c b/packages/Python/lldbsuite/test/functionalities/process_group/main.c index c730c629e8b0..7e986bbac65d 100644 --- a/packages/Python/lldbsuite/test/functionalities/process_group/main.c +++ b/packages/Python/lldbsuite/test/functionalities/process_group/main.c @@ -2,10 +2,6 @@ #include <unistd.h> #include <sys/wait.h> -#if defined(__linux__) -#include <sys/prctl.h> -#endif - volatile int release_child_flag = 0; int main(int argc, char const *argv[]) @@ -61,18 +57,7 @@ int main(int argc, char const *argv[]) } else { // child -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor process can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - // For now we execute on best effort basis. If this fails for - // some reason, so be it. - const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - (void) prctl_result; -#endif -#endif + lldb_enable_attach(); while (! release_child_flag) // Wait for debugger to attach sleep(1); diff --git a/packages/Python/lldbsuite/test/functionalities/register/main.cpp b/packages/Python/lldbsuite/test/functionalities/register/main.cpp index 876dd0833e54..156515768ddb 100644 --- a/packages/Python/lldbsuite/test/functionalities/register/main.cpp +++ b/packages/Python/lldbsuite/test/functionalities/register/main.cpp @@ -8,10 +8,6 @@ //===----------------------------------------------------------------------===// #include <stdio.h> -#if defined(__linux__) -#include <sys/prctl.h> -#endif - #include <chrono> #include <thread> @@ -19,18 +15,7 @@ long double outermost_return_long_double (long double my_long_double); int main (int argc, char const *argv[]) { -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor process can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - // For now we execute on best effort basis. If this fails for - // some reason, so be it. - const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - static_cast<void> (prctl_result); -#endif -#endif + lldb_enable_attach(); char my_string[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 0}; double my_double = 1234.5678; diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp index 8434458f0648..d8f06e55a2dd 100644 --- a/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp +++ b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp @@ -4,10 +4,6 @@ using std::chrono::microseconds; -#if defined(__linux__) -#include <sys/prctl.h> -#endif - volatile int g_thread_2_continuing = 0; void * @@ -42,20 +38,7 @@ thread_2_func (void *input) int main(int argc, char const *argv[]) { -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor process can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - int prctl_result; - - // For now we execute on best effort basis. If this fails for - // some reason, so be it. - prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - (void) prctl_result; -#endif -#endif + lldb_enable_attach(); // Create a new thread std::thread thread_1(thread_1_func, nullptr); diff --git a/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py b/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py index be49a210f0f0..768e2fe4f87a 100644 --- a/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py +++ b/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py @@ -33,9 +33,7 @@ class ThreadJumpTestCase(TestBase): # The stop reason of the thread should be breakpoint 1. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 1", - substrs = ['stopped', - '* thread #1', - 'stop reason = breakpoint 1']) + substrs=['stopped', 'main.cpp:{}'.format(self.mark3), 'stop reason = breakpoint 1']) self.do_min_test(self.mark3, self.mark1, "i", "4"); # Try the int path, force it to return 'a' self.do_min_test(self.mark3, self.mark2, "i", "5"); # Try the int path, force it to return 'b' diff --git a/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py b/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py index 623c659ffa5c..4938ec50453e 100644 --- a/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py +++ b/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py @@ -19,7 +19,6 @@ class ThreadStateTestCase(TestBase): @expectedFailureDarwin("rdar://15367566") @expectedFailureFreeBSD('llvm.org/pr15824') @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained - @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly def test_state_after_breakpoint(self): """Test thread state after breakpoint.""" self.build(dictionary=self.getBuildFlags(use_cpp11=False)) diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py index b4a0b7a5dd4e..68c96a0fba75 100644 --- a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py +++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py @@ -20,7 +20,6 @@ class ThreadSpecificBreakPlusConditionTestCase(TestBase): @skipIfFreeBSD # test frequently times out or hangs @expectedFailureFreeBSD('llvm.org/pr18522') # hits break in another thread in testrun @add_test_categories(['pyapi']) - @expectedFailureWindows # Thread specific breakpoints cause the inferior to crash. @expectedFlakeyLinux # this test fails 6/100 dosep runs def test_python(self): """Test that we obey thread conditioned breakpoints.""" diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py index a419500f7a17..c0a311f7ac9e 100644 --- a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py @@ -14,7 +14,7 @@ import lldbsuite.test.lldbutil as lldbutil class NoreturnUnwind(TestBase): mydir = TestBase.compute_mydir(__file__) - @expectedFailurei386 #xfail to get buildbot green, failing config: i386 binary running on ubuntu 14.04 x86_64 + @expectedFailurei386("llvm.org/pr25338") @skipIfWindows # clang-cl does not support gcc style attributes. def test (self): """Test that we can backtrace correctly with 'noreturn' functions on the stack""" diff --git a/packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py b/packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py index dd18a6482066..f51da36b72d7 100644 --- a/packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py +++ b/packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py @@ -17,6 +17,7 @@ class TestStepOverWatchpoint(TestBase): return ['basic_process'] @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported + @expectedFailureLinux(bugnumber="llvm.org/pr26031", archs=['arm']) @expectedFailureWindows("llvm.org/pr24446") def test(self): """Test stepping over watchpoints.""" diff --git a/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py b/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py index 6bdac7024847..9301a6f9fd00 100644 --- a/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py +++ b/packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py @@ -27,6 +27,7 @@ class WatchLocationUsingWatchpointSetTestCase(TestBase): # Build dictionary to have unique executable names for each test method. @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported + @expectedFailureLinux(bugnumber="llvm.org/pr26031", archs=['arm']) @expectedFailureWindows("llvm.org/pr24446") # WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows def test_watchlocation_using_watchpoint_set(self): """Test watching a location with 'watchpoint set expression -w write -s size' option.""" diff --git a/packages/Python/lldbsuite/test/lang/objc/global_ptrs/Makefile b/packages/Python/lldbsuite/test/lang/objc/global_ptrs/Makefile new file mode 100644 index 000000000000..a1608fe5a664 --- /dev/null +++ b/packages/Python/lldbsuite/test/lang/objc/global_ptrs/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +OBJC_SOURCES := main.m +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/lang/objc/global_ptrs/TestGlobalObjects.py b/packages/Python/lldbsuite/test/lang/objc/global_ptrs/TestGlobalObjects.py new file mode 100644 index 000000000000..c4c581b9240f --- /dev/null +++ b/packages/Python/lldbsuite/test/lang/objc/global_ptrs/TestGlobalObjects.py @@ -0,0 +1,53 @@ +"""Test that a global ObjC object found before the process is started updates correctly.""" + +from __future__ import print_function + + + +import os, time +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + +class TestObjCGlobalVar(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + self.main_source = lldb.SBFileSpec("main.m") + + @skipUnlessDarwin + @add_test_categories(['pyapi']) + def test_with_python_api(self): + """Test that a global ObjC object found before the process is started updates correctly.""" + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + bkpt = target.BreakpointCreateBySourceRegex ('NSLog', self.main_source) + self.assertTrue(bkpt, VALID_BREAKPOINT) + + # Before we launch, make an SBValue for our global object pointer: + g_obj_ptr = target.FindFirstGlobalVariable("g_obj_ptr") + self.assertTrue(g_obj_ptr.GetError().Success(), "Made the g_obj_ptr") + self.assertTrue(g_obj_ptr.GetValueAsUnsigned(10) == 0, "g_obj_ptr is initially null") + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple (None, None, self.get_process_working_directory()) + + self.assertTrue(process, PROCESS_IS_VALID) + + # The stop reason of the thread should be breakpoint. + threads = lldbutil.get_threads_stopped_at_breakpoint (process, bkpt) + if len(threads) != 1: + self.fail ("Failed to stop at breakpoint 1.") + + thread = threads[0] + + dyn_value = g_obj_ptr.GetDynamicValue(lldb.eDynamicCanRunTarget) + self.assertTrue(dyn_value.GetError().Success(), "Dynamic value is valid") + self.assertTrue(dyn_value.GetObjectDescription() == "Some NSString") diff --git a/packages/Python/lldbsuite/test/lang/objc/global_ptrs/main.m b/packages/Python/lldbsuite/test/lang/objc/global_ptrs/main.m new file mode 100644 index 000000000000..977a984e06e0 --- /dev/null +++ b/packages/Python/lldbsuite/test/lang/objc/global_ptrs/main.m @@ -0,0 +1,11 @@ +#import <Foundation/Foundation.h> + +id g_obj_ptr = nil; + +int +main() +{ + g_obj_ptr = @"Some NSString"; + NSLog(@"My string was %@.", g_obj_ptr); + return 0; +} diff --git a/packages/Python/lldbsuite/test/lldbinline.py b/packages/Python/lldbsuite/test/lldbinline.py index 691a3fba6dc2..abde6e790ded 100644 --- a/packages/Python/lldbsuite/test/lldbinline.py +++ b/packages/Python/lldbsuite/test/lldbinline.py @@ -3,7 +3,6 @@ from __future__ import absolute_import # System modules import os -import sys # Third-party modules @@ -23,6 +22,7 @@ def source_type(filename): '.mm' : 'OBJCXX_SOURCES' }.get(extension, None) + class CommandParser: def __init__(self): self.breakpoints = [] @@ -34,7 +34,7 @@ class CommandParser: new_breakpoint = True if len(parts) == 2: - command = parts[1].strip() # take off whitespace + command = parts[1].strip() # take off whitespace new_breakpoint = parts[0].strip() != "" return (command, new_breakpoint) @@ -85,7 +85,7 @@ class InlineTest(TestBase): return "-N dwarf %s" % (self.mydir) else: return "-N dsym %s" % (self.mydir) - + def BuildMakefile(self): if os.path.exists("Makefile"): return @@ -116,11 +116,11 @@ class InlineTest(TestBase): if ('CXX_SOURCES' in list(categories.keys())): makefile.write("CXXFLAGS += -std=c++11\n") + makefile.write("\ncleanup:\n\trm -f Makefile *.d\n\n") makefile.write("include $(LEVEL)/Makefile.rules\n") makefile.flush() makefile.close() - @skipUnlessDarwin def __test_with_dsym(self): self.using_dsym = True diff --git a/packages/Python/lldbsuite/test/lldbtest.py b/packages/Python/lldbsuite/test/lldbtest.py index 43d02c521d18..3ad6d29a1d7a 100644 --- a/packages/Python/lldbsuite/test/lldbtest.py +++ b/packages/Python/lldbsuite/test/lldbtest.py @@ -696,10 +696,11 @@ def expectedFailurei386(bugnumber=None): def expectedFailurex86_64(bugnumber=None): return expectedFailureArch('x86_64', bugnumber) -def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None): +def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None): def fn(self): return (self.getPlatform() in oslist and self.expectedCompiler(compilers) and + (archs is None or self.getArchitecture() in archs) and (debug_info is None or self.debug_info in debug_info)) return expectedFailure(fn, bugnumber) @@ -716,8 +717,8 @@ def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None): def expectedFailureFreeBSD(bugnumber=None, compilers=None, debug_info=None): return expectedFailureOS(['freebsd'], bugnumber, compilers, debug_info=debug_info) -def expectedFailureLinux(bugnumber=None, compilers=None, debug_info=None): - return expectedFailureOS(['linux'], bugnumber, compilers, debug_info=debug_info) +def expectedFailureLinux(bugnumber=None, compilers=None, debug_info=None, archs=None): + return expectedFailureOS(['linux'], bugnumber, compilers, debug_info=debug_info, archs=archs) def expectedFailureNetBSD(bugnumber=None, compilers=None, debug_info=None): return expectedFailureOS(['netbsd'], bugnumber, compilers, debug_info=debug_info) diff --git a/packages/Python/lldbsuite/test/make/test_common.h b/packages/Python/lldbsuite/test/make/test_common.h index 6f819706366e..a1ed364574e3 100644 --- a/packages/Python/lldbsuite/test/make/test_common.h +++ b/packages/Python/lldbsuite/test/make/test_common.h @@ -1,19 +1,44 @@ -// This header is included in all the test programs (C and C++) and provides a
-// hook for dealing with platform-specifics.
-#if defined(_WIN32) || defined(_WIN64)
-#ifdef COMPILING_LLDB_TEST_DLL
-#define LLDB_TEST_API __declspec(dllexport)
-#else
-#define LLDB_TEST_API __declspec(dllimport)
-#endif
-#else
-#define LLDB_TEST_API
-#endif
-
-#if defined(__cplusplus) && defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Compiling MSVC libraries with _HAS_EXCEPTIONS=0, eliminates most but not all
-// calls to __uncaught_exception. Unfortunately, it does seem to eliminate
-// the delcaration of __uncaught_excpeiton. Including <eh.h> ensures that it is
-// declared. This may not be necessary after MSVC 12.
-#include <eh.h>
-#endif
+// This header is included in all the test programs (C and C++) and provides a +// hook for dealing with platform-specifics. +#if defined(_WIN32) || defined(_WIN64) +#ifdef COMPILING_LLDB_TEST_DLL +#define LLDB_TEST_API __declspec(dllexport) +#else +#define LLDB_TEST_API __declspec(dllimport) +#endif +#else +#define LLDB_TEST_API +#endif + +#if defined(__cplusplus) && defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0) +// Compiling MSVC libraries with _HAS_EXCEPTIONS=0, eliminates most but not all +// calls to __uncaught_exception. Unfortunately, it does seem to eliminate +// the delcaration of __uncaught_excpeiton. Including <eh.h> ensures that it is +// declared. This may not be necessary after MSVC 12. +#include <eh.h> +#endif + + +// On some systems (e.g., some versions of linux) it is not possible to attach to a process +// without it giving us special permissions. This defines the lldb_enable_attach macro, which +// should perform any such actions, if needed by the platform. This is a macro instead of a +// function to avoid the need for complex linking of the test programs. +#if defined(__linux__) +#include <sys/prctl.h> + +#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) +// For now we execute on best effort basis. If this fails for some reason, so be it. +#define lldb_enable_attach() \ + do \ + { \ + const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); \ + (void)prctl_result; \ + } while (0) + +#endif + +#else // not linux + +#define lldb_enable_attach() + +#endif diff --git a/packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassembleRawData.py b/packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassembleRawData.py index 20333abc57af..31ba44928794 100644 --- a/packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassembleRawData.py +++ b/packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassembleRawData.py @@ -21,11 +21,18 @@ class DisassembleRawDataTestCase(TestBase): def test_disassemble_raw_data(self): """Test disassembling raw bytes with the API.""" # Create a target from the debugger. - target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "x86_64") + arch = self.getArchitecture() + if re.match("mips*el",arch): + target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "mipsel") + raw_bytes = bytearray([0x21,0xf0, 0xa0, 0x03]) + elif re.match("mips",arch): + target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "mips") + raw_bytes = bytearray([0x03,0xa0, 0xf0, 0x21]) + else: + target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "x86_64") + raw_bytes = bytearray([0x48, 0x89, 0xe5]) + self.assertTrue(target, VALID_TARGET) - - raw_bytes = bytearray([0x48, 0x89, 0xe5]) - insts = target.GetInstructions(lldb.SBAddress(0, target), raw_bytes) inst = insts.GetInstructionAtIndex(0) @@ -34,6 +41,9 @@ class DisassembleRawDataTestCase(TestBase): print() print("Raw bytes: ", [hex(x) for x in raw_bytes]) print("Disassembled%s" % str(inst)) - - self.assertTrue (inst.GetMnemonic(target) == "movq") - self.assertTrue (inst.GetOperands(target) == '%' + "rsp, " + '%' + "rbp") + if re.match("mips",arch): + self.assertTrue (inst.GetMnemonic(target) == "move") + self.assertTrue (inst.GetOperands(target) == '$' + "fp, " + '$' + "sp") + else: + self.assertTrue (inst.GetMnemonic(target) == "movq") + self.assertTrue (inst.GetOperands(target) == '%' + "rsp, " + '%' + "rbp") diff --git a/packages/Python/lldbsuite/test/python_api/event/TestEvents.py b/packages/Python/lldbsuite/test/python_api/event/TestEvents.py index 0a1a0dfda7d2..51c924b2aff1 100644 --- a/packages/Python/lldbsuite/test/python_api/event/TestEvents.py +++ b/packages/Python/lldbsuite/test/python_api/event/TestEvents.py @@ -13,6 +13,7 @@ import lldbsuite.test.lldbutil as lldbutil from lldbsuite.test.lldbtest import * @skipIfDarwin # llvm.org/pr25924, sometimes generating SIGSEGV +@skipIfLinux # llvm.org/pr25924, sometimes generating SIGSEGV class EventAPITestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -25,7 +26,6 @@ class EventAPITestCase(TestBase): @add_test_categories(['pyapi']) @expectedFailureLinux("llvm.org/pr23730") # Flaky, fails ~1/10 cases - @skipIfLinux # skip to avoid crashes def test_listen_for_and_print_event(self): """Exercise SBEvent API.""" self.build() @@ -176,7 +176,7 @@ class EventAPITestCase(TestBase): @skipIfFreeBSD # llvm.org/pr21325 @add_test_categories(['pyapi']) - @expectedFlakeyLinux("llvm.org/pr23617") # Flaky, fails ~1/10 cases + @expectedFailureLinux("llvm.org/pr23617") # Flaky, fails ~1/10 cases @expectedFailureWindows("llvm.org/pr24778") def test_add_listener_to_broadcaster(self): """Exercise some SBBroadcaster APIs.""" diff --git a/packages/Python/lldbsuite/test/python_api/hello_world/main.c b/packages/Python/lldbsuite/test/python_api/hello_world/main.c index 31a041ede741..1b942d0db159 100644 --- a/packages/Python/lldbsuite/test/python_api/hello_world/main.c +++ b/packages/Python/lldbsuite/test/python_api/hello_world/main.c @@ -1,25 +1,8 @@ #include <stdio.h> -#if defined(__linux__) -#include <sys/prctl.h> -#endif - -int main(int argc, char const *argv[]) { - -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor process can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - int prctl_result; - - // For now we execute on best effort basis. If this fails for - // some reason, so be it. - prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - (void) prctl_result; -#endif -#endif +int main(int argc, char const *argv[]) +{ + lldb_enable_attach(); printf("Hello world.\n"); // Set break point at this line. if (argc == 1) diff --git a/packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py b/packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py index bc97d432406f..2de026c54eef 100644 --- a/packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py +++ b/packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py @@ -16,6 +16,8 @@ class ModuleAndSectionAPIsTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + # Py3 asserts due to a bug in SWIG. A fix for this was upstreamed into SWIG 3.0.8. + @skipIf(py_version=['>=', (3,0)], swig_version=['<', (3,0,8)]) @add_test_categories(['pyapi']) def test_module_and_section(self): """Test module and section APIs.""" diff --git a/packages/Python/lldbsuite/test/python_api/value/change_values/TestChangeValueAPI.py b/packages/Python/lldbsuite/test/python_api/value/change_values/TestChangeValueAPI.py index 77aefe05be46..f8ad97277f05 100644 --- a/packages/Python/lldbsuite/test/python_api/value/change_values/TestChangeValueAPI.py +++ b/packages/Python/lldbsuite/test/python_api/value/change_values/TestChangeValueAPI.py @@ -28,6 +28,7 @@ class ChangeValueAPITestCase(TestBase): @expectedFailureWindows("llvm.org/pr24772") @add_test_categories(['pyapi']) + @expectedFlakeyLinux("llvm.org/pr25652") def test_change_value(self): """Exercise the SBValue::SetValueFromCString API.""" d = {'EXE': self.exe_name} diff --git a/packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py b/packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py index 22d7e7ebf7e8..8b60be97bdc2 100644 --- a/packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py +++ b/packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py @@ -25,6 +25,8 @@ class ValueAsLinkedListTestCase(TestBase): # Find the line number to break at. self.line = line_number('main.cpp', '// Break at this line') + # Py3 asserts due to a bug in SWIG. A fix for this was upstreamed into SWIG 3.0.8. + @skipIf(py_version=['>=', (3,0)], swig_version=['<', (3,0,8)]) @add_test_categories(['pyapi']) def test(self): """Exercise SBValue API linked_list_iter.""" diff --git a/packages/Python/lldbsuite/test/test_categories.py b/packages/Python/lldbsuite/test/test_categories.py index e3e446091050..72b7afdf7241 100644 --- a/packages/Python/lldbsuite/test/test_categories.py +++ b/packages/Python/lldbsuite/test/test_categories.py @@ -44,7 +44,8 @@ def unique_string_match(yourentry, list): def is_supported_on_platform(category, platform): if category == "dwo": - return platform in ["linux", "freebsd", "windows"] + # -gsplit-dwarf is not implemented by clang on Windows. + return platform in ["linux", "freebsd"] elif category == "dsym": return platform in ["darwin", "macosx", "ios"] return True diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp b/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp index c65b22571596..b97c6ebc18e3 100644 --- a/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp +++ b/packages/Python/lldbsuite/test/tools/lldb-server/main.cpp @@ -20,10 +20,6 @@ int pthread_threadid_np(pthread_t,__uint64_t*); #include <sys/syscall.h> #endif -#if defined(__linux__) -#include <sys/prctl.h> -#endif - static const char *const RETVAL_PREFIX = "retval:"; static const char *const SLEEP_PREFIX = "sleep:"; static const char *const STDERR_PREFIX = "stderr:"; @@ -210,16 +206,7 @@ thread_func (void *arg) int main (int argc, char **argv) { -#if defined(__linux__) - // Immediately enable any ptracer so that we can allow the stub attach - // operation to succeed. Some Linux kernels are locked down so that - // only an ancestor can be a ptracer of a process. This disables that - // restriction. Without it, attach-related stub tests will fail. -#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY) - const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); - static_cast<void> (prctl_result); -#endif -#endif + lldb_enable_attach(); std::vector<pthread_t> threads; std::unique_ptr<uint8_t[]> heap_array_up; diff --git a/scripts/Python/python-typemaps.swig b/scripts/Python/python-typemaps.swig index ec9302a15cd7..9c4e5cecb363 100644 --- a/scripts/Python/python-typemaps.swig +++ b/scripts/Python/python-typemaps.swig @@ -26,15 +26,17 @@ } %typemap(in) lldb::tid_t { - if (PyInt_Check($input)) - $1 = PyInt_AsLong($input); - else if (PyLong_Check($input)) - $1 = PyLong_AsLongLong($input); - else - { - PyErr_SetString(PyExc_ValueError, "Expecting an integer"); - return NULL; - } + using namespace lldb_private; + if (PythonInteger::Check($input)) + { + PythonInteger py_int(PyRefType::Borrowed, $input); + $1 = static_cast<lldb::tid_t>(py_int.GetInteger()); + } + else + { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + return nullptr; + } } %typemap(typecheck) char ** { diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp index b7f894f6dcf5..a85ea179abb8 100644 --- a/source/Commands/CommandObjectProcess.cpp +++ b/source/Commands/CommandObjectProcess.cpp @@ -550,6 +550,7 @@ protected: result.AppendMessage(stream.GetData()); result.SetStatus (eReturnStatusSuccessFinishNoResult); result.SetDidChangeProcessState (true); + result.SetAbnormalStopWasExpected(true); } else { diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp index ce197ac7bd48..98a079007fba 100644 --- a/source/Core/StringList.cpp +++ b/source/Core/StringList.cpp @@ -12,7 +12,6 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/FileSpec.h" #include "lldb/Core/Log.h" -#include "lldb/Core/StreamString.h" #include <string> diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp index 0f4324f83dd6..f7ba755b5bab 100644 --- a/source/Host/common/HostInfoBase.cpp +++ b/source/Host/common/HostInfoBase.cpp @@ -409,13 +409,13 @@ HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_6 arch_32.SetTriple(triple); break; + case llvm::Triple::aarch64: case llvm::Triple::ppc64: case llvm::Triple::x86_64: arch_64.SetTriple(triple); arch_32.SetTriple(triple.get32BitArchVariant()); break; - case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::sparcv9: diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index b7cc607e8070..fd88f0d6b4be 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -3038,7 +3038,10 @@ CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string & for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) { StopReason reason = thread_sp->GetStopReason(); - if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation) + if ((reason == eStopReasonSignal + || reason == eStopReasonException + || reason == eStopReasonInstrumentation) + && !result.GetAbnormalStopWasExpected()) { should_stop = true; break; diff --git a/source/Interpreter/CommandReturnObject.cpp b/source/Interpreter/CommandReturnObject.cpp index 1b5418735069..b083c7f69f13 100644 --- a/source/Interpreter/CommandReturnObject.cpp +++ b/source/Interpreter/CommandReturnObject.cpp @@ -47,7 +47,8 @@ CommandReturnObject::CommandReturnObject () : m_err_stream (), m_status (eReturnStatusStarted), m_did_change_process_state (false), - m_interactive (true) + m_interactive (true), + m_abnormal_stop_was_expected(false) { } diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp index bc62c9fe82ee..e3da3631723e 100644 --- a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp +++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp @@ -206,6 +206,7 @@ ABISysV_mips64::PrepareTrivialCall (Thread &thread, const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0); if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); @@ -228,6 +229,13 @@ ABISysV_mips64::PrepareTrivialCall (Thread &thread, if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr)) return false; + if (log) + log->Printf("Writing r25: 0x%" PRIx64, (uint64_t)func_addr); + + // All callers of position independent functions must place the address of the called function in t9 (r25) + if (!reg_ctx->WriteRegisterFromUnsigned (r25_info, func_addr)) + return false; + return true; } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 09e874a011df..443f97ed0ba1 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -107,6 +107,7 @@ DYLDRendezvous::DYLDRendezvous(Process *process) m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(), m_previous(), + m_loaded_modules(), m_soentries(), m_added_soentries(), m_removed_soentries() @@ -181,6 +182,9 @@ DYLDRendezvous::Resolve() m_previous = m_current; m_current = info; + if (UpdateSOEntries (true)) + return true; + return UpdateSOEntries(); } @@ -191,18 +195,23 @@ DYLDRendezvous::IsValid() } bool -DYLDRendezvous::UpdateSOEntries() +DYLDRendezvous::UpdateSOEntries(bool fromRemote) { SOEntry entry; + LoadedModuleInfoList module_list; - if (m_current.map_addr == 0) + // If we can't get the SO info from the remote, return failure. + if (fromRemote && m_process->LoadModules (module_list) == 0) + return false; + + if (!fromRemote && m_current.map_addr == 0) return false; // When the previous and current states are consistent this is the first // time we have been asked to update. Just take a snapshot of the currently // loaded modules. - if (m_previous.state == eConsistent && m_current.state == eConsistent) - return TakeSnapshot(m_soentries); + if (m_previous.state == eConsistent && m_current.state == eConsistent) + return fromRemote ? SaveSOEntriesFromRemote(module_list) : TakeSnapshot(m_soentries); // If we are about to add or remove a shared object clear out the current // state and take a snapshot of the currently loaded images. @@ -215,6 +224,9 @@ DYLDRendezvous::UpdateSOEntries() return false; m_soentries.clear(); + if (fromRemote) + return SaveSOEntriesFromRemote(module_list); + m_added_soentries.clear(); m_removed_soentries.clear(); return TakeSnapshot(m_soentries); @@ -224,15 +236,133 @@ DYLDRendezvous::UpdateSOEntries() // Otherwise check the previous state to determine what to expect and update // accordingly. if (m_previous.state == eAdd) - return UpdateSOEntriesForAddition(); + return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries(); else if (m_previous.state == eDelete) - return UpdateSOEntriesForDeletion(); + return fromRemote ? RemoveSOEntriesFromRemote(module_list) : RemoveSOEntries(); return false; } - + bool -DYLDRendezvous::UpdateSOEntriesForAddition() +DYLDRendezvous::FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, + SOEntry &entry) +{ + addr_t link_map_addr; + addr_t base_addr; + addr_t dyn_addr; + std::string name; + + if (!modInfo.get_link_map (link_map_addr) || + !modInfo.get_base (base_addr) || + !modInfo.get_dynamic (dyn_addr) || + !modInfo.get_name (name)) + return false; + + entry.link_addr = link_map_addr; + entry.base_addr = base_addr; + entry.dyn_addr = dyn_addr; + + entry.file_spec.SetFile(name, false); + + UpdateBaseAddrIfNecessary(entry, name); + + // not needed if we're using ModuleInfos + entry.next = 0; + entry.prev = 0; + entry.path_addr = 0; + + return true; +} + +bool +DYLDRendezvous::SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list) +{ + for (auto const & modInfo : module_list.m_list) + { + SOEntry entry; + if (!FillSOEntryFromModuleInfo(modInfo, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + m_soentries.push_back(entry); + } + + m_loaded_modules = module_list; + return true; + +} + +bool +DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list) +{ + for (auto const & modInfo : module_list.m_list) + { + bool found = false; + for (auto const & existing : m_loaded_modules.m_list) + { + if (modInfo == existing) + { + found = true; + break; + } + } + + if (found) + continue; + + SOEntry entry; + if (!FillSOEntryFromModuleInfo(modInfo, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + m_soentries.push_back(entry); + } + + m_loaded_modules = module_list; + return true; +} + +bool +DYLDRendezvous::RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list) +{ + for (auto const & existing : m_loaded_modules.m_list) + { + bool found = false; + for (auto const & modInfo : module_list.m_list) + { + if (modInfo == existing) + { + found = true; + break; + } + } + + if (found) + continue; + + SOEntry entry; + if (!FillSOEntryFromModuleInfo(existing, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + { + auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) + return false; + + m_soentries.erase(pos); + } + } + + m_loaded_modules = module_list; + return true; +} + +bool +DYLDRendezvous::AddSOEntries() { SOEntry entry; iterator pos; @@ -263,7 +393,7 @@ DYLDRendezvous::UpdateSOEntriesForAddition() } bool -DYLDRendezvous::UpdateSOEntriesForDeletion() +DYLDRendezvous::RemoveSOEntries() { SOEntryList entry_list; iterator pos; @@ -291,7 +421,8 @@ DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) // FreeBSD and on Android it is the full path to the executable. auto triple = m_process->GetTarget().GetArchitecture().GetTriple(); - switch (triple.getOS()) { + switch (triple.getOS()) + { case llvm::Triple::FreeBSD: return entry.file_spec == m_exe_file_spec; case llvm::Triple::Linux: @@ -386,6 +517,21 @@ isLoadBiasIncorrect(Target& target, const std::string& file_path) return false; } +void +DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path) +{ + // If the load bias reported by the linker is incorrect then fetch the load address of the file + // from the proc file system. + if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) + { + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + bool is_loaded = false; + Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); + if (error.Success() && is_loaded) + entry.base_addr = load_addr; + } +} + bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) { @@ -427,16 +573,7 @@ DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) std::string file_path = ReadStringFromMemory(entry.path_addr); entry.file_spec.SetFile(file_path, false); - // If the load bias reported by the linker is incorrect then fetch the load address of the file - // from the proc file system. - if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) - { - lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - bool is_loaded = false; - Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); - if (error.Success() && is_loaded) - entry.base_addr = load_addr; - } + UpdateBaseAddrIfNecessary(entry, file_path); return true; } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index ec5af945ee7b..8498116c808f 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -20,6 +20,10 @@ #include "lldb/lldb-types.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Core/LoadedModuleInfoList.h" + +using lldb_private::LoadedModuleInfoList; + namespace lldb_private { class Process; } @@ -201,6 +205,9 @@ protected: Rendezvous m_current; Rendezvous m_previous; + /// List of currently loaded SO modules + LoadedModuleInfoList m_loaded_modules; + /// List of SOEntry objects corresponding to the current link map state. SOEntryList m_soentries; @@ -240,13 +247,29 @@ protected: /// Updates the current set of SOEntries, the set of added entries, and the /// set of removed entries. bool - UpdateSOEntries(); + UpdateSOEntries(bool fromRemote = false); + + bool + FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, + SOEntry &entry); + + bool + SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list); bool - UpdateSOEntriesForAddition(); + AddSOEntriesFromRemote(LoadedModuleInfoList &module_list); bool - UpdateSOEntriesForDeletion(); + RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list); + + bool + AddSOEntries(); + + bool + RemoveSOEntries(); + + void + UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path); bool SOEntryIsMainExecutable(const SOEntry &entry); diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index c9bc4b6487cd..f4d6b195c7f0 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -36,6 +36,7 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeList.h" @@ -570,6 +571,63 @@ FindCodeSymbolInContext } } +ConstString +FindBestAlternateMangledName +( + const ConstString &demangled, + const LanguageType &lang_type, + SymbolContext &sym_ctx +) +{ + CPlusPlusLanguage::MethodName cpp_name(demangled); + std::string scope_qualified_name = cpp_name.GetScopeQualifiedName(); + + if (!scope_qualified_name.size()) + return ConstString(); + + if (!sym_ctx.module_sp) + return ConstString(); + + SymbolVendor *sym_vendor = sym_ctx.module_sp->GetSymbolVendor(); + if (!sym_vendor) + return ConstString(); + + lldb_private::SymbolFile *sym_file = sym_vendor->GetSymbolFile(); + if (!sym_file) + return ConstString(); + + std::vector<ConstString> alternates; + sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates); + + std::vector<ConstString> param_and_qual_matches; + std::vector<ConstString> param_matches; + for (size_t i = 0; i < alternates.size(); i++) + { + ConstString alternate_mangled_name = alternates[i]; + Mangled mangled(alternate_mangled_name, true); + ConstString demangled = mangled.GetDemangledName(lang_type); + + CPlusPlusLanguage::MethodName alternate_cpp_name(demangled); + if (!cpp_name.IsValid()) + continue; + + if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) + { + if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers()) + param_and_qual_matches.push_back(alternate_mangled_name); + else + param_matches.push_back(alternate_mangled_name); + } + } + + if (param_and_qual_matches.size()) + return param_and_qual_matches[0]; // It is assumed that there will be only one! + else if (param_matches.size()) + return param_matches[0]; // Return one of them as a best match + else + return ConstString(); +} + bool ClangExpressionDeclMap::GetFunctionAddress ( @@ -603,15 +661,25 @@ ClangExpressionDeclMap::GetFunctionAddress if (Language::LanguageIsCPlusPlus(lang_type) && CPlusPlusLanguage::IsCPPMangledName(name.AsCString())) { - // 1. Demangle the name Mangled mangled(name, true); ConstString demangled = mangled.GetDemangledName(lang_type); if (demangled) { - FindCodeSymbolInContext( - demangled, m_parser_vars->m_sym_ctx, eFunctionNameTypeFull, sc_list); - sc_list_size = sc_list.GetSize(); + ConstString best_alternate_mangled_name = FindBestAlternateMangledName(demangled, lang_type, sc); + if (best_alternate_mangled_name) + { + FindCodeSymbolInContext( + best_alternate_mangled_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list); + sc_list_size = sc_list.GetSize(); + } + + if (sc_list_size == 0) + { + FindCodeSymbolInContext( + demangled, m_parser_vars->m_sym_ctx, eFunctionNameTypeFull, sc_list); + sc_list_size = sc_list.GetSize(); + } } } } diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 37b7bd1d2c84..509c594280a0 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -36,7 +36,6 @@ #include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompilerType.h" -#include "lldb/Target/CPPLanguageRuntime.h" #include <map> @@ -230,36 +229,6 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun, { std::vector<lldb_private::ConstString> alternates; bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr); - if (!found_it) - { - if (log) - log->Printf("Address of function \"%s\" not found.\n", name.GetCString()); - // Check for an alternate mangling for names from the standard library. - // For example, "std::basic_string<...>" has an alternate mangling scheme per - // the Itanium C++ ABI. - lldb::ProcessSP process_sp = m_data_allocator.GetTarget()->GetProcessSP(); - if (process_sp) - { - lldb_private::CPPLanguageRuntime *cpp_runtime = process_sp->GetCPPLanguageRuntime(); - if (cpp_runtime && cpp_runtime->GetAlternateManglings(name, alternates)) - { - for (size_t i = 0; i < alternates.size(); ++i) - { - const lldb_private::ConstString &alternate_name = alternates[i]; - if (log) - log->Printf("Looking up address of function \"%s\" with alternate name \"%s\"", - name.GetCString(), alternate_name.GetCString()); - if ((found_it = m_decl_map->GetFunctionAddress (alternate_name, fun_addr))) - { - if (log) - log->Printf("Found address of function \"%s\" with alternate name \"%s\"", - name.GetCString(), alternate_name.GetCString()); - break; - } - } - } - } - } if (!found_it) { diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp index 28eba093f317..9c09d383beae 100644 --- a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -549,45 +549,45 @@ EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name) //---------------------------------------------------------------------- // Branch instructions //---------------------------------------------------------------------- - { "BEQ", &EmulateInstructionMIPS64::Emulate_BEQ, "BEQ rs,rt,offset" }, - { "BNE", &EmulateInstructionMIPS64::Emulate_BNE, "BNE rs,rt,offset" }, - { "BEQL", &EmulateInstructionMIPS64::Emulate_BEQL, "BEQL rs,rt,offset" }, - { "BNEL", &EmulateInstructionMIPS64::Emulate_BNEL, "BNEL rs,rt,offset" }, - { "BGEZALL", &EmulateInstructionMIPS64::Emulate_BGEZALL, "BGEZALL rt,offset" }, + { "BEQ", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BEQ rs,rt,offset" }, + { "BNE", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BNE rs,rt,offset" }, + { "BEQL", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BEQL rs,rt,offset" }, + { "BNEL", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BNEL rs,rt,offset" }, + { "BGEZALL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BGEZALL rt,offset" }, { "BAL", &EmulateInstructionMIPS64::Emulate_BAL, "BAL offset" }, - { "BGEZAL", &EmulateInstructionMIPS64::Emulate_BGEZAL, "BGEZAL rs,offset" }, + { "BGEZAL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BGEZAL rs,offset" }, { "BALC", &EmulateInstructionMIPS64::Emulate_BALC, "BALC offset" }, { "BC", &EmulateInstructionMIPS64::Emulate_BC, "BC offset" }, - { "BGEZ", &EmulateInstructionMIPS64::Emulate_BGEZ, "BGEZ rs,offset" }, - { "BLEZALC", &EmulateInstructionMIPS64::Emulate_BLEZALC, "BLEZALC rs,offset" }, - { "BGEZALC", &EmulateInstructionMIPS64::Emulate_BGEZALC, "BGEZALC rs,offset" }, - { "BLTZALC", &EmulateInstructionMIPS64::Emulate_BLTZALC, "BLTZALC rs,offset" }, - { "BGTZALC", &EmulateInstructionMIPS64::Emulate_BGTZALC, "BGTZALC rs,offset" }, - { "BEQZALC", &EmulateInstructionMIPS64::Emulate_BEQZALC, "BEQZALC rs,offset" }, - { "BNEZALC", &EmulateInstructionMIPS64::Emulate_BNEZALC, "BNEZALC rs,offset" }, - { "BEQC", &EmulateInstructionMIPS64::Emulate_BEQC, "BEQC rs,rt,offset" }, - { "BNEC", &EmulateInstructionMIPS64::Emulate_BNEC, "BNEC rs,rt,offset" }, - { "BLTC", &EmulateInstructionMIPS64::Emulate_BLTC, "BLTC rs,rt,offset" }, - { "BGEC", &EmulateInstructionMIPS64::Emulate_BGEC, "BGEC rs,rt,offset" }, - { "BLTUC", &EmulateInstructionMIPS64::Emulate_BLTUC, "BLTUC rs,rt,offset" }, - { "BGEUC", &EmulateInstructionMIPS64::Emulate_BGEUC, "BGEUC rs,rt,offset" }, - { "BLTZC", &EmulateInstructionMIPS64::Emulate_BLTZC, "BLTZC rt,offset" }, - { "BLEZC", &EmulateInstructionMIPS64::Emulate_BLEZC, "BLEZC rt,offset" }, - { "BGEZC", &EmulateInstructionMIPS64::Emulate_BGEZC, "BGEZC rt,offset" }, - { "BGTZC", &EmulateInstructionMIPS64::Emulate_BGTZC, "BGTZC rt,offset" }, - { "BEQZC", &EmulateInstructionMIPS64::Emulate_BEQZC, "BEQZC rt,offset" }, - { "BNEZC", &EmulateInstructionMIPS64::Emulate_BNEZC, "BNEZC rt,offset" }, - { "BGEZL", &EmulateInstructionMIPS64::Emulate_BGEZL, "BGEZL rt,offset" }, - { "BGTZ", &EmulateInstructionMIPS64::Emulate_BGTZ, "BGTZ rt,offset" }, - { "BGTZL", &EmulateInstructionMIPS64::Emulate_BGTZL, "BGTZL rt,offset" }, - { "BLEZ", &EmulateInstructionMIPS64::Emulate_BLEZ, "BLEZ rt,offset" }, - { "BLEZL", &EmulateInstructionMIPS64::Emulate_BLEZL, "BLEZL rt,offset" }, - { "BLTZ", &EmulateInstructionMIPS64::Emulate_BLTZ, "BLTZ rt,offset" }, - { "BLTZAL", &EmulateInstructionMIPS64::Emulate_BLTZAL, "BLTZAL rt,offset" }, - { "BLTZALL", &EmulateInstructionMIPS64::Emulate_BLTZALL, "BLTZALL rt,offset" }, - { "BLTZL", &EmulateInstructionMIPS64::Emulate_BLTZL, "BLTZL rt,offset" }, - { "BOVC", &EmulateInstructionMIPS64::Emulate_BOVC, "BOVC rs,rt,offset" }, - { "BNVC", &EmulateInstructionMIPS64::Emulate_BNVC, "BNVC rs,rt,offset" }, + { "BGEZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGEZ rs,offset" }, + { "BLEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BLEZALC rs,offset" }, + { "BGEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BGEZALC rs,offset" }, + { "BLTZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BLTZALC rs,offset" }, + { "BGTZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BGTZALC rs,offset" }, + { "BEQZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BEQZALC rs,offset" }, + { "BNEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BNEZALC rs,offset" }, + { "BEQC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BEQC rs,rt,offset" }, + { "BNEC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BNEC rs,rt,offset" }, + { "BLTC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BLTC rs,rt,offset" }, + { "BGEC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BGEC rs,rt,offset" }, + { "BLTUC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BLTUC rs,rt,offset" }, + { "BGEUC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BGEUC rs,rt,offset" }, + { "BLTZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BLTZC rt,offset" }, + { "BLEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BLEZC rt,offset" }, + { "BGEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BGEZC rt,offset" }, + { "BGTZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BGTZC rt,offset" }, + { "BEQZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BEQZC rt,offset" }, + { "BNEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BNEZC rt,offset" }, + { "BGEZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGEZL rt,offset" }, + { "BGTZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGTZ rt,offset" }, + { "BGTZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGTZL rt,offset" }, + { "BLEZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLEZ rt,offset" }, + { "BLEZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLEZL rt,offset" }, + { "BLTZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLTZ rt,offset" }, + { "BLTZAL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BLTZAL rt,offset" }, + { "BLTZALL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BLTZALL rt,offset" }, + { "BLTZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLTZL rt,offset" }, + { "BOVC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BOVC rs,rt,offset" }, + { "BNVC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BNVC rs,rt,offset" }, { "J", &EmulateInstructionMIPS64::Emulate_J, "J target" }, { "JAL", &EmulateInstructionMIPS64::Emulate_JAL, "JAL target" }, { "JALX", &EmulateInstructionMIPS64::Emulate_JAL, "JALX target" }, @@ -597,16 +597,16 @@ EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name) { "JIC", &EmulateInstructionMIPS64::Emulate_JIC, "JIC rt,offset" }, { "JR", &EmulateInstructionMIPS64::Emulate_JR, "JR target" }, { "JR_HB", &EmulateInstructionMIPS64::Emulate_JR, "JR.HB target" }, - { "BC1F", &EmulateInstructionMIPS64::Emulate_BC1F, "BC1F cc, offset" }, - { "BC1T", &EmulateInstructionMIPS64::Emulate_BC1T, "BC1T cc, offset" }, - { "BC1FL", &EmulateInstructionMIPS64::Emulate_BC1FL, "BC1FL cc, offset" }, - { "BC1TL", &EmulateInstructionMIPS64::Emulate_BC1TL, "BC1TL cc, offset" }, + { "BC1F", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1F cc, offset" }, + { "BC1T", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1T cc, offset" }, + { "BC1FL", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1FL cc, offset" }, + { "BC1TL", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1TL cc, offset" }, { "BC1EQZ", &EmulateInstructionMIPS64::Emulate_BC1EQZ, "BC1EQZ ft, offset" }, { "BC1NEZ", &EmulateInstructionMIPS64::Emulate_BC1NEZ, "BC1NEZ ft, offset" }, - { "BC1ANY2F", &EmulateInstructionMIPS64::Emulate_BC1ANY2F, "BC1ANY2F cc, offset" }, - { "BC1ANY2T", &EmulateInstructionMIPS64::Emulate_BC1ANY2T, "BC1ANY2T cc, offset" }, - { "BC1ANY4F", &EmulateInstructionMIPS64::Emulate_BC1ANY4F, "BC1ANY4F cc, offset" }, - { "BC1ANY4T", &EmulateInstructionMIPS64::Emulate_BC1ANY4T, "BC1ANY4T cc, offset" }, + { "BC1ANY2F", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY2F cc, offset" }, + { "BC1ANY2T", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY2T cc, offset" }, + { "BC1ANY4F", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY4F cc, offset" }, + { "BC1ANY4T", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY4T cc, offset" }, { "BNZ_B", &EmulateInstructionMIPS64::Emulate_BNZB, "BNZ.b wt,s16" }, { "BNZ_H", &EmulateInstructionMIPS64::Emulate_BNZH, "BNZ.h wt,s16" }, { "BNZ_W", &EmulateInstructionMIPS64::Emulate_BNZW, "BNZ.w wt,s16" }, @@ -907,107 +907,20 @@ EmulateInstructionMIPS64::Emulate_LD (llvm::MCInst& insn) return false; } -bool -EmulateInstructionMIPS64::Emulate_BEQ (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target, rs_val, rt_val; - - /* - * BEQ rs, rt, offset - * condition <- (GPR[rs] = GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - * else - * PC = PC + 4 - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val == rt_val) - target = pc + offset; - else - target = pc + 8; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BNE (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target, rs_val, rt_val; - - /* - * BNE rs, rt, offset - * condition <- (GPR[rs] != GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val != rt_val) - target = pc + offset; - else - target = pc + 8; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} +/* + Emulate below MIPS branch instructions. + BEQ, BNE : Branch on condition + BEQL, BNEL : Branch likely +*/ bool -EmulateInstructionMIPS64::Emulate_BEQL (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_BXX_3ops (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; - int64_t offset, pc, target, rs_val, rt_val; + int64_t offset, pc, rs_val, rt_val, target = 0; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); - /* - * BEQL rs, rt, offset - * condition <- (GPR[rs] = GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); offset = insn.getOperand(2).getImm(); @@ -1024,290 +937,26 @@ EmulateInstructionMIPS64::Emulate_BEQL (llvm::MCInst& insn) if (!success) return false; - if (rs_val == rt_val) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BNEL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target, rs_val, rt_val; - - /* - * BNEL rs, rt, offset - * condition <- (GPR[rs] != GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val != rt_val) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEZL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGEZL rs, offset - * condition <- (GPR[rs] >= 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val >= 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTZL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLTZL rs, offset - * condition <- (GPR[rs] < 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val < 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGTZL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGTZL rs, offset - * condition <- (GPR[rs] > 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val > 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLEZL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLEZL rs, offset - * condition <- (GPR[rs] <= 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val <= 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGTZ (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGTZ rs, offset - * condition <- (GPR[rs] > 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val > 0) - target = pc + offset; - else - target = pc + 8; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLEZ (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLEZ rs, offset - * condition <- (GPR[rs] <= 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val <= 0) - target = pc + offset; - else - target = pc + 8; + if (!strcasecmp (op_name, "BEQ") || + !strcasecmp (op_name, "BEQL")) + { + if (rs_val == rt_val) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BNE") || + !strcasecmp (op_name, "BNEL")) + { + if (rs_val != rt_val) + target = pc + offset; + else + target = pc + 8; + } Context context; context.type = eContextRelativeBranchImmediate; + context.SetImmediate (offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; @@ -1315,20 +964,20 @@ EmulateInstructionMIPS64::Emulate_BLEZ (llvm::MCInst& insn) return true; } +/* + Emulate below MIPS Non-Compact conditional branch and link instructions. + BLTZAL, BGEZAL : + BLTZALL, BGEZALL : Branch likely +*/ bool -EmulateInstructionMIPS64::Emulate_BLTZ (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_Bcond_Link (llvm::MCInst& insn) { bool success = false; uint32_t rs; - int64_t offset, pc, target; + int64_t offset, pc, target = 0; int64_t rs_val; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); - /* - * BLTZ rs, offset - * condition <- (GPR[rs] < 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); @@ -1340,52 +989,24 @@ EmulateInstructionMIPS64::Emulate_BLTZ (llvm::MCInst& insn) if (!success) return false; - if (rs_val < 0) - target = pc + offset; - else - target = pc + 8; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEZALL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGEZALL rt, offset - * condition <- (GPR[rs] >= 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val >= 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ + if (!strcasecmp (op_name, "BLTZAL") || + !strcasecmp (op_name, "BLTZALL")) + { + if (rs_val < 0) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BGEZAL") || + !strcasecmp (op_name, "BGEZALL")) + { + if (rs_val >= 0) + target = pc + offset; + else + target = pc + 8; + } Context context; - context.type = eContextRelativeBranchImmediate; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; @@ -1458,65 +1079,18 @@ EmulateInstructionMIPS64::Emulate_BALC (llvm::MCInst& insn) return true; } +/* + Emulate below MIPS conditional branch and link instructions. + BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches +*/ bool -EmulateInstructionMIPS64::Emulate_BGEZAL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGEZAL rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] >= 0) - * if condition then - * RA = PC + 8 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - Context context; - - if ((int64_t) rs_val >= 0) - target = pc + offset; - else - target = pc + 8; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTZAL (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_Bcond_Link_C (llvm::MCInst& insn) { bool success = false; uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; + int64_t offset, pc, rs_val, target = 0; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); - /* - * BLTZAL rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] < 0) - * if condition then - * RA = PC + 8 - * PC = PC + offset - */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); @@ -1528,271 +1102,51 @@ EmulateInstructionMIPS64::Emulate_BLTZAL (llvm::MCInst& insn) if (!success) return false; - Context context; - - if ((int64_t) rs_val < 0) - target = pc + offset; - else - target = pc + 8; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTZALL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLTZALL rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] < 0) - * if condition then - * RA = PC + 8 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - Context context; - - if (rs_val < 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) - return false; - - return true; -} - - -bool -EmulateInstructionMIPS64::Emulate_BLEZALC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLEZALC rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] <= 0) - * if condition then - * RA = PC + 4 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - Context context; - - if (rs_val <= 0) - target = pc + offset; - else - target = pc + 4; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEZALC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGEZALC rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] >= 0) - * if condition then - * RA = PC + 4 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - Context context; - - if (rs_val >= 0) - target = pc + offset; - else - target = pc + 4; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTZALC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLTZALC rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] < 0) - * if condition then - * RA = PC + 4 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - Context context; - - if (rs_val < 0) - target = pc + offset; - else - target = pc + 4; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGTZALC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGTZALC rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] > 0) - * if condition then - * RA = PC + 4 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - Context context; - - if (rs_val > 0) - target = pc + offset; - else - target = pc + 4; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BEQZALC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target, rs_val; - - /* - * BEQZALC rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] == 0) - * if condition then - * RA = PC + 4 - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; + if (!strcasecmp (op_name, "BLEZALC")) + { + if (rs_val <= 0) + target = pc + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BGEZALC")) + { + if (rs_val >= 0) + target = pc + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BLTZALC")) + { + if (rs_val < 0) + target = pc + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BGTZALC")) + { + if (rs_val > 0) + target = pc + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BEQZALC")) + { + if (rs_val == 0) + target = pc + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BNEZALC")) + { + if (rs_val != 0) + target = pc + offset; + else + target = pc + 4; + } Context context; - if (rs_val == 0) - target = pc + offset; - else - target = pc + 4; - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; @@ -1802,21 +1156,19 @@ EmulateInstructionMIPS64::Emulate_BEQZALC (llvm::MCInst& insn) return true; } +/* + Emulate below MIPS branch instructions. + BLTZL, BGEZL, BGTZL, BLEZL : Branch likely + BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches +*/ bool -EmulateInstructionMIPS64::Emulate_BNEZALC (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_BXX_2ops (llvm::MCInst& insn) { bool success = false; uint32_t rs; - int64_t offset, pc, target, rs_val; + int64_t offset, pc, rs_val, target = 0; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); - /* - * BNEZALC rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] != 0) - * if condition then - * RA = PC + 4 - * PC = PC + offset - */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); @@ -1828,53 +1180,42 @@ EmulateInstructionMIPS64::Emulate_BNEZALC (llvm::MCInst& insn) if (!success) return false; - Context context; - - if (rs_val != 0) - target = pc + offset; - else - target = pc + 4; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEZ (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target, rs_val; - - /* - * BGEZ rs,offset - * offset = sign_ext (offset << 2) - * condition <- (GPR[rs] >= 0) - * if condition then - * PC = PC + offset - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; + if (!strcasecmp (op_name, "BLTZL") || + !strcasecmp (op_name, "BLTZ")) + { + if (rs_val < 0) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BGEZL") || + !strcasecmp (op_name, "BGEZ")) + { + if (rs_val >= 0) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BGTZL") || + !strcasecmp (op_name, "BGTZ")) + { + if (rs_val > 0) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BLEZL") || + !strcasecmp (op_name, "BLEZ")) + { + if (rs_val <= 0) + target = pc + offset; + else + target = pc + 8; + } Context context; - - if (rs_val >= 0) - target = pc + offset; - else - target = pc + 8; + context.type = eContextRelativeBranchImmediate; + context.SetImmediate (offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; @@ -1909,502 +1250,6 @@ EmulateInstructionMIPS64::Emulate_BC (llvm::MCInst& insn) return true; } -bool -EmulateInstructionMIPS64::Emulate_BEQC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target, rs_val, rt_val; - - /* - * BEQC rs, rt, offset - * condition <- (GPR[rs] = GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val == rt_val) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BNEC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target, rs_val, rt_val; - - /* - * BNEC rs, rt, offset - * condition <- (GPR[rs] != GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val != rt_val) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target; - int64_t rs_val, rt_val; - - /* - * BLTC rs, rt, offset - * condition <- (GPR[rs] < GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val < rt_val) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target; - int64_t rs_val, rt_val; - - /* - * BGEC rs, rt, offset - * condition <- (GPR[rs] > GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val > rt_val) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTUC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target; - uint64_t rs_val, rt_val; - - /* - * BLTUC rs, rt, offset - * condition <- (GPR[rs] < GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val < rt_val) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEUC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target; - uint64_t rs_val, rt_val; - - /* - * BGEUC rs, rt, offset - * condition <- (GPR[rs] > GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - rt_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (rs_val > rt_val) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLTZC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLTZC rs, offset - * condition <- (GPR[rs] < 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val < 0) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BLEZC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BLEZC rs, offset - * condition <- (GPR[rs] <= 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val <= 0) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGEZC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGEZC rs, offset - * condition <- (GPR[rs] >= 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val >= 0) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BGTZC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - int64_t rs_val; - - /* - * BGTZC rs, offset - * condition <- (GPR[rs] > 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val > 0) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BEQZC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - uint64_t rs_val; - - /* - * BEQZC rs, offset - * condition <- (GPR[rs] = 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val == 0) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BNEZC (llvm::MCInst& insn) -{ - bool success = false; - uint32_t rs; - int64_t offset, pc, target; - uint64_t rs_val; - - /* - * BNEZC rs, offset - * condition <- (GPR[rs] != 0) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ - rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); - if (!success) - return false; - - if (rs_val != 0) - target = pc + 4 + offset; - else - target = pc + 4; - - Context context; - context.type = eContextRelativeBranchImmediate; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - static int IsAdd64bitOverflow (int64_t a, int64_t b) { @@ -2412,20 +1257,19 @@ IsAdd64bitOverflow (int64_t a, int64_t b) return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0); } +/* + Emulate below MIPS branch instructions. + BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch instructions with no delay slot +*/ bool -EmulateInstructionMIPS64::Emulate_BOVC (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_BXX_3ops_C (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; - int64_t offset, pc, target; - int64_t rs_val, rt_val; + int64_t offset, pc, rs_val, rt_val, target = 0; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); + uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); - /* - * BOVC rs, rt, offset - * condition <- overflow(GPR[rs] + GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); offset = insn.getOperand(2).getImm(); @@ -2442,13 +1286,66 @@ EmulateInstructionMIPS64::Emulate_BOVC (llvm::MCInst& insn) if (!success) return false; - if (IsAdd64bitOverflow (rs_val, rt_val)) - target = pc + offset; - else - target = pc + 4; + if (!strcasecmp (op_name, "BEQC")) + { + if (rs_val == rt_val) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BNEC")) + { + if (rs_val != rt_val) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BLTC")) + { + if (rs_val < rt_val) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BGEC")) + { + if (rs_val >= rt_val) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BLTUC")) + { + if (rs_val < rt_val) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BGEUC")) + { + if ((uint32_t)rs_val >= (uint32_t)rt_val) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BOVC")) + { + if (IsAdd64bitOverflow (rs_val, rt_val)) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BNVC")) + { + if (!IsAdd64bitOverflow (rs_val, rt_val)) + target = pc + 4 + offset; + else + target = pc + 4; + } Context context; context.type = eContextRelativeBranchImmediate; + context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; @@ -2456,23 +1353,22 @@ EmulateInstructionMIPS64::Emulate_BOVC (llvm::MCInst& insn) return true; } +/* + Emulate below MIPS branch instructions. + BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches +*/ bool -EmulateInstructionMIPS64::Emulate_BNVC (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_BXX_2ops_C (llvm::MCInst& insn) { bool success = false; - uint32_t rs, rt; - int64_t offset, pc, target; - int64_t rs_val, rt_val; + uint32_t rs; + int64_t offset, pc, target = 0; + int64_t rs_val; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); + uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); - /* - * BNVC rs, rt, offset - * condition <- overflow(GPR[rs] + GPR[rt]) - * if condition then - * PC = PC + sign_ext (offset << 2) - */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - offset = insn.getOperand(2).getImm(); + offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) @@ -2482,17 +1378,52 @@ EmulateInstructionMIPS64::Emulate_BNVC (llvm::MCInst& insn) if (!success) return false; - rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); - if (!success) - return false; - - if (! IsAdd64bitOverflow (rs_val, rt_val)) - target = pc + offset; - else - target = pc + 4; + if (!strcasecmp (op_name, "BLTZC")) + { + if (rs_val < 0) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BLEZC")) + { + if (rs_val <= 0) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BGEZC")) + { + if (rs_val >= 0) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BGTZC")) + { + if (rs_val > 0) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BEQZC")) + { + if (rs_val == 0) + target = pc + 4 + offset; + else + target = pc + 4; + } + else if (!strcasecmp (op_name, "BNEZC")) + { + if (rs_val != 0) + target = pc + 4 + offset; + else + target = pc + 4; + } Context context; context.type = eContextRelativeBranchImmediate; + context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; @@ -2684,95 +1615,19 @@ EmulateInstructionMIPS64::Emulate_JR (llvm::MCInst& insn) return true; } +/* + Emulate Branch on FP True/False + BC1F, BC1FL : Branch on FP False (L stands for branch likely) + BC1T, BC1TL : Branch on FP True (L stands for branch likely) +*/ bool -EmulateInstructionMIPS64::Emulate_BC1F (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_FP_branch (llvm::MCInst& insn) { bool success = false; uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1F cc, offset - * condition <- (FPConditionCode(cc) == 0) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ - cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); - if (!success) - return false; - - /* fcsr[23], fcsr[25-31] are vaild condition bits */ - fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - - if ((fcsr & (1 << cc)) == 0) - target = pc + offset; - else - target = pc + 8; - - Context context; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; + int64_t pc, offset, target = 0; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BC1T (llvm::MCInst& insn) -{ - bool success = false; - uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1T cc, offset - * condition <- (FPConditionCode(cc) != 0) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ - cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); - if (!success) - return false; - - /* fcsr[23], fcsr[25-31] are vaild condition bits */ - fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - - if ((fcsr & (1 << cc)) != 0) - target = pc + offset; - else - target = pc + 8; - - Context context; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BC1FL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t cc, fcsr; - int64_t target, pc, offset; - /* * BC1F cc, offset * condition <- (FPConditionCode(cc) == 0) @@ -2782,48 +1637,7 @@ EmulateInstructionMIPS64::Emulate_BC1FL (llvm::MCInst& insn) */ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); - if (!success) - return false; - - /* fcsr[23], fcsr[25-31] are vaild condition bits */ - fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - - if ((fcsr & (1 << cc)) == 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - - Context context; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BC1TL (llvm::MCInst& insn) -{ - bool success = false; - uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1T cc, offset - * condition <- (FPConditionCode(cc) != 0) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ - cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; @@ -2835,11 +1649,23 @@ EmulateInstructionMIPS64::Emulate_BC1TL (llvm::MCInst& insn) /* fcsr[23], fcsr[25-31] are vaild condition bits */ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - if ((fcsr & (1 << cc)) != 0) - target = pc + offset; - else - target = pc + 8; /* skip delay slot */ - + if (!strcasecmp (op_name, "BC1F") || + !strcasecmp (op_name, "BC1FL")) + { + if ((fcsr & (1 << cc)) == 0) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BC1T") || + !strcasecmp (op_name, "BC1TL")) + { + if ((fcsr & (1 << cc)) != 0) + target = pc + offset; + else + target = pc + 8; + } + Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) @@ -2926,109 +1752,19 @@ EmulateInstructionMIPS64::Emulate_BC1NEZ (llvm::MCInst& insn) return true; } +/* + Emulate MIPS-3D Branch instructions + BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes False/True + BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes False/True +*/ bool -EmulateInstructionMIPS64::Emulate_BC1ANY2F (llvm::MCInst& insn) +EmulateInstructionMIPS64::Emulate_3D_branch (llvm::MCInst& insn) { bool success = false; uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1ANY2F cc, offset - * condition <- (FPConditionCode(cc) == 0 - * || FPConditionCode(cc+1) == 0) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ - cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); - if (!success) - return false; - - /* fcsr[23], fcsr[25-31] are vaild condition bits */ - fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - - /* if any one bit is 0 */ - if (((fcsr >> cc) & 3) != 3) - target = pc + offset; - else - target = pc + 8; - - Context context; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BC1ANY2T (llvm::MCInst& insn) -{ - bool success = false; - uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1ANY2T cc, offset - * condition <- (FPConditionCode(cc) == 1 - * || FPConditionCode(cc+1) == 1) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ - cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); - if (!success) - return false; - - /* fcsr[23], fcsr[25-31] are vaild condition bits */ - fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - - /* if any one bit is 1 */ - if (((fcsr >> cc) & 3) != 0) - target = pc + offset; - else - target = pc + 8; - - Context context; + int64_t pc, offset, target = 0; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BC1ANY4F (llvm::MCInst& insn) -{ - bool success = false; - uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1ANY4F cc, offset - * condition <- (FPConditionCode(cc) == 0 - * || FPConditionCode(cc+1) == 0) - * || FPConditionCode(cc+2) == 0) - * || FPConditionCode(cc+3) == 0) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); @@ -3043,57 +1779,39 @@ EmulateInstructionMIPS64::Emulate_BC1ANY4F (llvm::MCInst& insn) /* fcsr[23], fcsr[25-31] are vaild condition bits */ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); - /* if any one bit is 0 */ - if (((fcsr >> cc) & 0xf) != 0xf) - target = pc + offset; - else - target = pc + 8; - - Context context; - - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) - return false; - - return true; -} - -bool -EmulateInstructionMIPS64::Emulate_BC1ANY4T (llvm::MCInst& insn) -{ - bool success = false; - uint32_t cc, fcsr; - int64_t target, pc, offset; - - /* - * BC1ANY4T cc, offset - * condition <- (FPConditionCode(cc) == 1 - * || FPConditionCode(cc+1) == 1) - * || FPConditionCode(cc+2) == 1) - * || FPConditionCode(cc+3) == 1) - * if condition then - * offset = sign_ext (offset) - * PC = PC + offset - */ - cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); - offset = insn.getOperand(1).getImm(); - - pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); - if (!success) - return false; - - fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); - if (!success) - return false; - - /* fcsr[23], fcsr[25-31] are vaild condition bits */ - fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); + if (!strcasecmp (op_name, "BC1ANY2F")) + { + /* if any one bit is 0 */ + if (((fcsr >> cc) & 3) != 3) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BC1ANY2T")) + { + /* if any one bit is 1 */ + if (((fcsr >> cc) & 3) != 0) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BC1ANY4F")) + { + /* if any one bit is 0 */ + if (((fcsr >> cc) & 0xf) != 0xf) + target = pc + offset; + else + target = pc + 8; + } + else if (!strcasecmp (op_name, "BC1ANY4T")) + { + /* if any one bit is 1 */ + if (((fcsr >> cc) & 0xf) != 0) + target = pc + offset; + else + target = pc + 8; + } - /* if any one bit is 1 */ - if (((fcsr >> cc) & 0xf) != 0) - target = pc + offset; - else - target = pc + 8; - Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) diff --git a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h index e0b20792ae1f..4ca274c9874b 100644 --- a/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h +++ b/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h @@ -133,121 +133,37 @@ protected: Emulate_LDST_Reg (llvm::MCInst& insn); bool - Emulate_BEQ (llvm::MCInst& insn); + Emulate_BXX_3ops (llvm::MCInst& insn); bool - Emulate_BNE (llvm::MCInst& insn); + Emulate_BXX_3ops_C (llvm::MCInst& insn); bool - Emulate_BEQL (llvm::MCInst& insn); + Emulate_BXX_2ops (llvm::MCInst& insn); bool - Emulate_BNEL (llvm::MCInst& insn); + Emulate_BXX_2ops_C (llvm::MCInst& insn); bool - Emulate_BGEZALL (llvm::MCInst& insn); + Emulate_Bcond_Link_C (llvm::MCInst& insn); bool - Emulate_BAL (llvm::MCInst& insn); - - bool - Emulate_BGEZAL (llvm::MCInst& insn); - - bool - Emulate_BALC (llvm::MCInst& insn); - - bool - Emulate_BC (llvm::MCInst& insn); - - bool - Emulate_BGEZ (llvm::MCInst& insn); - - bool - Emulate_BLEZALC (llvm::MCInst& insn); - - bool - Emulate_BGEZALC (llvm::MCInst& insn); - - bool - Emulate_BLTZALC (llvm::MCInst& insn); - - bool - Emulate_BGTZALC (llvm::MCInst& insn); - - bool - Emulate_BEQZALC (llvm::MCInst& insn); - - bool - Emulate_BNEZALC (llvm::MCInst& insn); - - bool - Emulate_BEQC (llvm::MCInst& insn); - - bool - Emulate_BNEC (llvm::MCInst& insn); - - bool - Emulate_BLTC (llvm::MCInst& insn); - - bool - Emulate_BGEC (llvm::MCInst& insn); - - bool - Emulate_BLTUC (llvm::MCInst& insn); - - bool - Emulate_BGEUC (llvm::MCInst& insn); - - bool - Emulate_BLTZC (llvm::MCInst& insn); - - bool - Emulate_BLEZC (llvm::MCInst& insn); + Emulate_Bcond_Link (llvm::MCInst& insn); bool - Emulate_BGEZC (llvm::MCInst& insn); + Emulate_FP_branch (llvm::MCInst& insn); bool - Emulate_BGTZC (llvm::MCInst& insn); + Emulate_3D_branch (llvm::MCInst& insn); bool - Emulate_BEQZC (llvm::MCInst& insn); - - bool - Emulate_BNEZC (llvm::MCInst& insn); - - bool - Emulate_BGEZL (llvm::MCInst& insn); - - bool - Emulate_BGTZ (llvm::MCInst& insn); - - bool - Emulate_BGTZL (llvm::MCInst& insn); - - bool - Emulate_BLEZ (llvm::MCInst& insn); - - bool - Emulate_BLEZL (llvm::MCInst& insn); - - bool - Emulate_BLTZ (llvm::MCInst& insn); - - bool - Emulate_BLTZAL (llvm::MCInst& insn); - - bool - Emulate_BLTZALL (llvm::MCInst& insn); - - bool - Emulate_BLTZL (llvm::MCInst& insn); + Emulate_BAL (llvm::MCInst& insn); bool - Emulate_BOVC (llvm::MCInst& insn); + Emulate_BALC (llvm::MCInst& insn); bool - Emulate_BNVC (llvm::MCInst& insn); + Emulate_BC (llvm::MCInst& insn); bool Emulate_J (llvm::MCInst& insn); @@ -268,36 +184,12 @@ protected: Emulate_JR (llvm::MCInst& insn); bool - Emulate_BC1F (llvm::MCInst& insn); - - bool - Emulate_BC1T (llvm::MCInst& insn); - - bool - Emulate_BC1FL (llvm::MCInst& insn); - - bool - Emulate_BC1TL (llvm::MCInst& insn); - - bool Emulate_BC1EQZ (llvm::MCInst& insn); bool Emulate_BC1NEZ (llvm::MCInst& insn); bool - Emulate_BC1ANY2F (llvm::MCInst& insn); - - bool - Emulate_BC1ANY2T (llvm::MCInst& insn); - - bool - Emulate_BC1ANY4F (llvm::MCInst& insn); - - bool - Emulate_BC1ANY4T (llvm::MCInst& insn); - - bool Emulate_BNZB (llvm::MCInst& insn); bool diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index a554aa57d58e..09031e2f8064 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -296,6 +296,22 @@ CPlusPlusLanguage::MethodName::GetQualifiers () return m_qualifiers; } +std::string +CPlusPlusLanguage::MethodName::GetScopeQualifiedName () +{ + if (!m_parsed) + Parse(); + if (m_basename.empty() || m_context.empty()) + return std::string(); + + std::string res; + res += m_context; + res += "::"; + res += m_basename; + + return res; +} + bool CPlusPlusLanguage::IsCPPMangledName (const char *name) { diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 1a8c0f6938a5..f0fc07e20066 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -89,6 +89,9 @@ public: { return m_full; } + + std::string + GetScopeQualifiedName (); llvm::StringRef GetBasename (); diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index a5fa004493a2..8e2cfb5570d9 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -319,46 +319,6 @@ ItaniumABILanguageRuntime::IsVTableName (const char *name) return false; } -static std::map<ConstString, std::vector<ConstString> >& -GetAlternateManglingPrefixes() -{ - static std::map<ConstString, std::vector<ConstString> > g_alternate_mangling_prefixes; - return g_alternate_mangling_prefixes; -} - - -size_t -ItaniumABILanguageRuntime::GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) -{ - if (!mangled) - return static_cast<size_t>(0); - - alternates.clear(); - const char *mangled_cstr = mangled.AsCString(); - std::map<ConstString, std::vector<ConstString> >& alternate_mangling_prefixes = GetAlternateManglingPrefixes(); - for (std::map<ConstString, std::vector<ConstString> >::iterator it = alternate_mangling_prefixes.begin(); - it != alternate_mangling_prefixes.end(); - ++it) - { - const char *prefix_cstr = it->first.AsCString(); - if (strncmp(mangled_cstr, prefix_cstr, strlen(prefix_cstr)) == 0) - { - const std::vector<ConstString> &alternate_prefixes = it->second; - for (size_t i = 0; i < alternate_prefixes.size(); ++i) - { - std::string alternate_mangling(alternate_prefixes[i].AsCString()); - alternate_mangling.append(mangled_cstr + strlen(prefix_cstr)); - - alternates.push_back(ConstString(alternate_mangling.c_str())); - } - - return alternates.size(); - } - } - - return static_cast<size_t>(0); -} - //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ @@ -382,17 +342,6 @@ ItaniumABILanguageRuntime::Initialize() PluginManager::RegisterPlugin (GetPluginNameStatic(), "Itanium ABI for the C++ language", CreateInstance); - - // Alternate manglings for std::basic_string<...> - std::vector<ConstString> basic_string_alternates; - basic_string_alternates.push_back(ConstString("_ZNSs")); - basic_string_alternates.push_back(ConstString("_ZNKSs")); - std::map<ConstString, std::vector<ConstString> >& alternate_mangling_prefixes = GetAlternateManglingPrefixes(); - - alternate_mangling_prefixes[ConstString("_ZNSbIcSt17char_traits<char>St15allocator<char>E")] = - basic_string_alternates; - alternate_mangling_prefixes[ConstString("_ZNKSbIcSt17char_traits<char>St15allocator<char>E")] = - basic_string_alternates; } void diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index 519a3cee36d6..c06b9863a9bf 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h @@ -80,9 +80,6 @@ namespace lldb_private { lldb::SearchFilterSP CreateExceptionSearchFilter() override; - size_t - GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) override; - //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index cdb95250b2f4..2810b24cb7a4 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -69,7 +69,20 @@ AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj) if (!valobj.ResolveValue(val.GetScalar())) return false; - ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); + // Value Objects may not have a process in their ExecutionContextRef. But we need to have one + // in the ref we pass down to eventually call description. Get it from the target if it isn't + // present. + ExecutionContext exe_ctx; + if (valobj.GetProcessSP()) + { + exe_ctx = ExecutionContext(valobj.GetExecutionContextRef()); + } + else + { + exe_ctx.SetContext(valobj.GetTargetSP(), true); + if (!exe_ctx.HasProcessScope()) + return false; + } return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); } diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 8c485d97bdc9..584449430829 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -405,9 +405,18 @@ AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value, Address &address, Value::ValueType &value_type) { - // The Runtime is attached to a particular process, you shouldn't pass in a value from another process. - assert (in_value.GetProcessSP().get() == m_process); + // We should never get here with a null process... assert (m_process != NULL); + + // The Runtime is attached to a particular process, you shouldn't pass in a value from another process. + // Note, however, the process might be NULL (e.g. if the value was made with SBTarget::EvaluateExpression...) + // in which case it is sufficient if the target's match: + + Process *process = in_value.GetProcessSP().get(); + if (process) + assert (process == m_process); + else + assert (in_value.GetTargetSP().get() == m_process->CalculateTarget().get()); class_type_or_name.Clear(); value_type = Value::ValueType::eValueTypeScalar; diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 5d82ded50882..8e5d31b66350 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -235,16 +235,28 @@ struct RenderScriptRuntime::AllocationDetails } }; - // Header for reading and writing allocation contents - // to a binary file. + // The FileHeader struct specifies the header we use for writing allocations to a binary file. + // Our format begins with the ASCII characters "RSAD", identifying the file as an allocation dump. + // Member variables dims and hdr_size are then written consecutively, immediately followed by an instance of + // the ElementHeader struct. Because Elements can contain subelements, there may be more than one instance + // of the ElementHeader struct. With this first instance being the root element, and the other instances being + // the root's descendants. To identify which instances are an ElementHeader's children, each struct + // is immediately followed by a sequence of consecutive offsets to the start of its child structs. + // These offsets are 4 bytes in size, and the 0 offset signifies no more children. struct FileHeader { uint8_t ident[4]; // ASCII 'RSAD' identifying the file - uint16_t hdr_size; // Header size in bytes, for backwards compatability - uint16_t type; // DataType enum - uint32_t kind; // DataKind enum uint32_t dims[3]; // Dimensions - uint32_t element_size; // Size of a single element, including padding + uint16_t hdr_size; // Header size in bytes, including all element headers + }; + + struct ElementHeader + { + uint16_t type; // DataType enum + uint32_t kind; // DataKind enum + uint32_t element_size; // Size of a single element, including padding + uint16_t vector_size; // Vector width + uint32_t array_size; // Number of elements in array }; // Monotonically increasing from 1 @@ -286,7 +298,6 @@ struct RenderScriptRuntime::AllocationDetails } }; - const ConstString & RenderScriptRuntime::Element::GetFallbackStructName() { @@ -2084,37 +2095,62 @@ RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const // Cast start of buffer to FileHeader and use pointer to read metadata void* file_buffer = data_sp->GetBytes(); - const AllocationDetails::FileHeader* head = static_cast<AllocationDetails::FileHeader*>(file_buffer); + if (file_buffer == NULL || data_sp->GetByteSize() < + (sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader))) + { + strm.Printf("Error: File %s does not contain enough data for header", filename); + strm.EOL(); + return false; + } + const AllocationDetails::FileHeader* file_header = static_cast<AllocationDetails::FileHeader*>(file_buffer); - // Advance buffer past header - file_buffer = static_cast<uint8_t*>(file_buffer) + head->hdr_size; + // Check file starts with ascii characters "RSAD" + if (file_header->ident[0] != 'R' || file_header->ident[1] != 'S' || file_header->ident[2] != 'A' + || file_header->ident[3] != 'D') + { + strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?"); + strm.EOL(); + return false; + } + + // Look at the type of the root element in the header + AllocationDetails::ElementHeader root_element_header; + memcpy(&root_element_header, static_cast<uint8_t*>(file_buffer) + sizeof(AllocationDetails::FileHeader), + sizeof(AllocationDetails::ElementHeader)); if (log) log->Printf("RenderScriptRuntime::LoadAllocation - header type %u, element size %u", - head->type, head->element_size); + root_element_header.type, root_element_header.element_size); // Check if the target allocation and file both have the same number of bytes for an Element - if (*alloc->element.datum_size.get() != head->element_size) + if (*alloc->element.datum_size.get() != root_element_header.element_size) { strm.Printf("Warning: Mismatched Element sizes - file %u bytes, allocation %u bytes", - head->element_size, *alloc->element.datum_size.get()); + root_element_header.element_size, *alloc->element.datum_size.get()); strm.EOL(); } - // Check if the target allocation and file both have the same integral type - const unsigned int type = static_cast<unsigned int>(*alloc->element.type.get()); - if (type != head->type) + // Check if the target allocation and file both have the same type + const unsigned int alloc_type = static_cast<unsigned int>(*alloc->element.type.get()); + const unsigned int file_type = root_element_header.type; + + if (file_type > Element::RS_TYPE_FONT) + { + strm.Printf("Warning: File has unknown allocation type"); + strm.EOL(); + } + else if (alloc_type != file_type) { // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array - unsigned int printable_target_type_index = type; - unsigned int printable_head_type_index = head->type; - if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) + unsigned int printable_target_type_index = alloc_type; + unsigned int printable_head_type_index = file_type; + if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT) printable_target_type_index = static_cast<Element::DataType>( - (type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); + (alloc_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); - if (head->type >= Element::RS_TYPE_ELEMENT && head->type <= Element::RS_TYPE_FONT) + if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT) printable_head_type_index = static_cast<Element::DataType>( - (head->type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); + (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); const char* file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; const char* target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; @@ -2124,8 +2160,11 @@ RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const strm.EOL(); } + // Advance buffer past header + file_buffer = static_cast<uint8_t*>(file_buffer) + file_header->hdr_size; + // Calculate size of allocation data in file - size_t length = data_sp->GetByteSize() - head->hdr_size; + size_t length = data_sp->GetByteSize() - file_header->hdr_size; // Check if the target allocation and file both have the same total data size. const unsigned int alloc_size = *alloc->size.get(); @@ -2154,6 +2193,62 @@ RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const return true; } +// Function takes as parameters a byte buffer, which will eventually be written to file as the element header, +// an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset. +// Return value is the new offset after writing the element into the buffer. +// Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's children. +size_t +RenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem) +{ + // File struct for an element header with all the relevant details copied from elem. + // We assume members are valid already. + AllocationDetails::ElementHeader elem_header; + elem_header.type = *elem.type.get(); + elem_header.kind = *elem.type_kind.get(); + elem_header.element_size = *elem.datum_size.get(); + elem_header.vector_size = *elem.type_vec_size.get(); + elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0; + const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); + + // Copy struct into buffer and advance offset + // We assume that header_buffer has been checked for NULL before this method is called + memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); + offset += elem_header_size; + + // Starting offset of child ElementHeader struct + size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t)); + for (const RenderScriptRuntime::Element& child : elem.children) + { + // Recursively populate the buffer with the element header structs of children. + // Then save the offsets where they were set after the parent element header. + memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + child_offset = PopulateElementHeaders(header_buffer, child_offset, child); + } + + // Zero indicates no more children + memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); + + return child_offset; +} + +// Given an Element object this function returns the total size needed in the file header to store the element's details. +// Taking into account the size of the element header struct, plus the offsets to all the element's children. +// Function is recursive so that the size of all ancestors is taken into account. +size_t +RenderScriptRuntime::CalculateElementHeaderSize(const Element& elem) +{ + size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator + size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details + + // Calculate recursively for all descendants + for (const Element& child : elem.children) + size += CalculateElementHeaderSize(child); + + return size; +} + // Function copies allocation contents into a binary file. // This file can then be loaded later into a different allocation. // There is a header, FileHeader, before the allocation data containing meta-data. @@ -2209,17 +2304,44 @@ RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const // Create the file header AllocationDetails::FileHeader head; head.ident[0] = 'R'; head.ident[1] = 'S'; head.ident[2] = 'A'; head.ident[3] = 'D'; - head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader)); - head.type = static_cast<uint16_t>(*alloc->element.type.get()); - head.kind = static_cast<uint32_t>(*alloc->element.type_kind.get()); head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); - head.element_size = static_cast<uint32_t>(*alloc->element.datum_size.get()); + + const size_t element_header_size = CalculateElementHeaderSize(alloc->element); + assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large"); + head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size); // Write the file header size_t num_bytes = sizeof(AllocationDetails::FileHeader); - Error err = file.Write(static_cast<const void*>(&head), num_bytes); + if (log) + log->Printf("RenderScriptRuntime::SaveAllocation - Writing File Header, 0x%zX bytes", num_bytes); + + Error err = file.Write(&head, num_bytes); + if (!err.Success()) + { + strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); + strm.EOL(); + return false; + } + + // Create the headers describing the element type of the allocation. + std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]); + if (element_header_buffer == nullptr) + { + strm.Printf("Internal Error: Couldn't allocate %zu bytes on the heap", element_header_size); + strm.EOL(); + return false; + } + + PopulateElementHeaders(element_header_buffer, 0, alloc->element); + + // Write headers for allocation element type to file + num_bytes = element_header_size; + if (log) + log->Printf("RenderScriptRuntime::SaveAllocation - Writing Element Headers, 0x%zX bytes", num_bytes); + + err = file.Write(element_header_buffer.get(), num_bytes); if (!err.Success()) { strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); @@ -2230,7 +2352,7 @@ RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const // Write allocation data to file num_bytes = static_cast<size_t>(*alloc->size.get()); if (log) - log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%" PRIx64 " bytes from %p", (uint64_t) num_bytes, (void*) buffer.get()); + log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%zX bytes", num_bytes); err = file.Write(buffer.get(), num_bytes); if (!err.Success()) diff --git a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h index 0ca268c93b00..2fe439017bbc 100644 --- a/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ b/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -207,10 +207,6 @@ public: void Status(Stream &strm) const; - size_t GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) override { - return static_cast<size_t>(0); - } - void ModulesDidLoad(const ModuleList &module_list) override; bool LoadAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr); @@ -335,6 +331,9 @@ private: static bool GetFrameVarAsUnsigned(const lldb::StackFrameSP, const char* var_name, uint64_t& val); void FindStructTypeName(Element& elem, StackFrame* frame_ptr); + size_t PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem); + size_t CalculateElementHeaderSize(const Element& elem); + // // Helper functions for jitting the runtime // diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 1d63ced787e0..b16a2cda10f7 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -330,15 +330,15 @@ mipsVariantFromElfFlags(const elf::elf_word e_flags, uint32_t endian) { case llvm::ELF::EF_MIPS_ARCH_1: case llvm::ELF::EF_MIPS_ARCH_2: - case llvm::ELF::EF_MIPS_ARCH_3: - case llvm::ELF::EF_MIPS_ARCH_4: - case llvm::ELF::EF_MIPS_ARCH_5: case llvm::ELF::EF_MIPS_ARCH_32: return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32el : ArchSpec::eMIPSSubType_mips32; case llvm::ELF::EF_MIPS_ARCH_32R2: return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r2el : ArchSpec::eMIPSSubType_mips32r2; case llvm::ELF::EF_MIPS_ARCH_32R6: return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r6el : ArchSpec::eMIPSSubType_mips32r6; + case llvm::ELF::EF_MIPS_ARCH_3: + case llvm::ELF::EF_MIPS_ARCH_4: + case llvm::ELF::EF_MIPS_ARCH_5: case llvm::ELF::EF_MIPS_ARCH_64: return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64el : ArchSpec::eMIPSSubType_mips64; case llvm::ELF::EF_MIPS_ARCH_64R2: @@ -954,9 +954,6 @@ ObjectFileELF::GetAddressByteSize() const return m_data.GetAddressByteSize(); } -// Top 16 bits of the `Symbol` flags are available. -#define ARM_ELF_SYM_IS_THUMB (1 << 16) - AddressClass ObjectFileELF::GetAddressClass (addr_t file_addr) { @@ -2190,7 +2187,6 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, // symbol.st_value to produce the final symbol_value // that we store in the symtab. symbol_value_offset = -1; - additional_flags = ARM_ELF_SYM_IS_THUMB; m_address_class_map[symbol.st_value^1] = eAddressClassCodeAlternateISA; } else diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index 31752fed5b42..79653fc62686 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #include "NativeRegisterContextLinux_arm.h" @@ -16,8 +16,12 @@ #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" +#include "Plugins/Process/Linux/Procfs.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" +#include <elf.h> +#include <sys/socket.h> + #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr)) #ifndef PTRACE_GETVFPREGS @@ -169,6 +173,8 @@ g_reg_sets_arm[k_num_register_sets] = { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } }; +#if defined(__arm__) + NativeRegisterContextLinux* NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, NativeThreadProtocol &native_thread, @@ -177,6 +183,8 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx); } +#endif // defined(__arm__) + NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch, NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx) : @@ -919,14 +927,14 @@ NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_inde ctrl_buf = &m_hwp_regs[hwb_index].control; error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, - m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1), + m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) -((hwb_index << 1) + 1), addr_buf, sizeof(unsigned int)); if (error.Fail()) return error; error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, - m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2), + m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) -((hwb_index << 1) + 2), ctrl_buf, sizeof(unsigned int)); } else @@ -935,14 +943,14 @@ NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_inde ctrl_buf = &m_hwp_regs[hwb_index].control; error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, - m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1), + m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) ((hwb_index << 1) + 1), addr_buf, sizeof(unsigned int)); if (error.Fail()) return error; error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, - m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2), + m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) ((hwb_index << 1) + 2), ctrl_buf, sizeof(unsigned int)); } @@ -957,11 +965,33 @@ NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info) } Error +NativeRegisterContextLinux_arm::DoReadRegisterValue(uint32_t offset, + const char* reg_name, + uint32_t size, + RegisterValue &value) +{ + // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android devices (always return + // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR register set instead. + // This approach is about 4 times slower but the performance overhead is negligible in + // comparision to processing time in lldb-server. + assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); + if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) + return Error("Register isn't fit into the size of the GPR area"); + + Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); + if (error.Fail()) + return error; + + value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]); + return Error(); +} + +Error NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset, const char* reg_name, const RegisterValue &value) { - // PTRACE_POKEUSER don't work in the aarch64 liux kernel used on android devices (always return + // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android devices (always return // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify // the requested register and write it back. This approach is about 4 times slower but the // performance overhead is negligible in comparision to processing time in lldb-server. @@ -995,23 +1025,67 @@ NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset, } Error +NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) +{ +#ifdef __arm__ + return NativeRegisterContextLinux::DoReadGPR(buf, buf_size); +#else // __aarch64__ + struct iovec ioVec; + ioVec.iov_base = buf; + ioVec.iov_len = buf_size; + + return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS); +#endif // __arm__ +} + +Error +NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) +{ +#ifdef __arm__ + return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size); +#else // __aarch64__ + struct iovec ioVec; + ioVec.iov_base = buf; + ioVec.iov_len = buf_size; + + return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS); +#endif // __arm__ +} + +Error NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) { +#ifdef __arm__ return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(), nullptr, buf, buf_size); +#else // __aarch64__ + struct iovec ioVec; + ioVec.iov_base = buf; + ioVec.iov_len = buf_size; + + return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP); +#endif // __arm__ } Error NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) { +#ifdef __arm__ return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(), nullptr, buf, buf_size); +#else // __aarch64__ + struct iovec ioVec; + ioVec.iov_base = buf; + ioVec.iov_len = buf_size; + + return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP); +#endif // __arm__ } -#endif // defined(__arm__) +#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h index 611b36ad4db1..349564970428 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#if defined(__arm__) // arm register context only needed on arm devices +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #ifndef lldb_NativeRegisterContextLinux_arm_h #define lldb_NativeRegisterContextLinux_arm_h @@ -91,11 +91,23 @@ namespace process_linux { protected: Error + DoReadRegisterValue(uint32_t offset, + const char* reg_name, + uint32_t size, + RegisterValue &value) override; + + Error DoWriteRegisterValue(uint32_t offset, const char* reg_name, const RegisterValue &value) override; Error + DoReadGPR(void *buf, size_t buf_size) override; + + Error + DoWriteGPR(void *buf, size_t buf_size) override; + + Error DoReadFPR(void *buf, size_t buf_size) override; Error @@ -182,4 +194,4 @@ namespace process_linux { #endif // #ifndef lldb_NativeRegisterContextLinux_arm_h -#endif // defined(__arm__) +#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index e4d26fc640f3..22cdbb40d15c 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -9,6 +9,7 @@ #if defined (__arm64__) || defined (__aarch64__) +#include "NativeRegisterContextLinux_arm.h" #include "NativeRegisterContextLinux_arm64.h" // C Includes @@ -23,6 +24,7 @@ #include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" // System includes - They have to be included after framework includes because they define some @@ -142,7 +144,19 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx) { - return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx); + Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS); + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx); + case llvm::Triple::aarch64: + return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx); + default: + if (log) + log->Printf("NativeRegisterContextLinux::%s() have no register context for architecture: %s\n", __FUNCTION__, + target_arch.GetTriple().getArchName().str().c_str()); + return nullptr; + } } NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch, diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index 3cfeaf5546bc..54d6f721c9d8 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -1388,7 +1388,15 @@ NativeRegisterContextLinux_mips64::DoReadRegisterValue(uint32_t offset, { lldb_private::ArchSpec arch; if (m_thread.GetProcess()->GetArchitecture(arch)) - value.SetBytes((void *)(((unsigned char *)®s) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips)), arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8, arch.GetByteOrder()); + { + void* target_address = ((uint8_t*)®s) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips); + uint32_t target_size; + if ((::strcmp(reg_name, "sr") == 0) || (::strcmp(reg_name, "cause") == 0) || (::strcmp(reg_name, "config5") == 0)) + target_size = 4; + else + target_size = arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8; + value.SetBytes(target_address, target_size, arch.GetByteOrder()); + } else error.SetErrorString("failed to get architecture"); } diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index bd3978cc0ab4..ebeba8c46a74 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -72,6 +72,7 @@ lldb_private::InferiorCallMmap (Process *process, options.SetTryAllThreads(true); options.SetDebug (false); options.SetTimeoutUsec(500000); + options.SetTrapExceptions(false); addr_t prot_arg, flags_arg = 0; if (prot == eMmapProtNone) @@ -172,6 +173,7 @@ lldb_private::InferiorCallMunmap (Process *process, options.SetTryAllThreads(true); options.SetDebug (false); options.SetTimeoutUsec(500000); + options.SetTrapExceptions(false); AddressRange munmap_range; if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) @@ -214,7 +216,8 @@ lldb_private::InferiorCallMunmap (Process *process, bool lldb_private::InferiorCall (Process *process, const Address *address, - addr_t &returned_func) + addr_t &returned_func, + bool trap_exceptions) { Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL || address == NULL) @@ -227,6 +230,7 @@ lldb_private::InferiorCall (Process *process, options.SetTryAllThreads(true); options.SetDebug (false); options.SetTimeoutUsec(500000); + options.SetTrapExceptions(trap_exceptions); ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h index e56e95c43773..d10e8490d809 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.h +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h @@ -31,7 +31,8 @@ bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr, bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length); -bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func); +bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func, + bool trap_exceptions = false); } // namespace lldb_private diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 278a1d5dabf6..efda0edb70c9 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -265,9 +265,32 @@ RegisterContextLLDB::InitializeZerothFrame() if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { - UnwindLogMsg ("could not read CFA register for this frame."); - m_frame_type = eNotAValidFrame; - return; + // Try the fall back unwind plan since the + // full unwind plan failed. + FuncUnwindersSP func_unwinders_sp; + UnwindPlanSP call_site_unwind_plan; + bool cfa_status = false; + + if (m_sym_ctx_valid) + { + func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); + } + + if(func_unwinders_sp.get() != nullptr) + call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(), m_current_offset_backed_up_one); + + if (call_site_unwind_plan.get() != nullptr) + { + m_fallback_unwind_plan_sp = call_site_unwind_plan; + if(TryFallbackUnwindPlan()) + cfa_status = true; + } + if (!cfa_status) + { + UnwindLogMsg ("could not read CFA value for first frame."); + m_frame_type = eNotAValidFrame; + return; + } } UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan", diff --git a/source/Plugins/Process/Windows/Live/IDebugDelegate.h b/source/Plugins/Process/Windows/Live/IDebugDelegate.h index 0e7849bb8ffe..6d864de7ed42 100644 --- a/source/Plugins/Process/Windows/Live/IDebugDelegate.h +++ b/source/Plugins/Process/Windows/Live/IDebugDelegate.h @@ -1,46 +1,46 @@ -//===-- IDebugDelegate.h ----------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_Plugins_Process_Windows_IDebugDelegate_H_
-#define liblldb_Plugins_Process_Windows_IDebugDelegate_H_
-
-#include "ForwardDecl.h"
-#include "lldb/lldb-forward.h"
-#include "lldb/lldb-types.h"
-#include <string>
-
-namespace lldb_private
-{
-class Error;
-class HostThread;
-
-//----------------------------------------------------------------------
-// IDebugDelegate
-//
-// IDebugDelegate defines an interface which allows implementors to receive
-// notification of events that happen in a debugged process.
-//----------------------------------------------------------------------
-class IDebugDelegate
-{
- public:
- virtual ~IDebugDelegate() {}
-
- virtual void OnExitProcess(uint32_t exit_code) = 0;
- virtual void OnDebuggerConnected(lldb::addr_t image_base) = 0;
- virtual ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) = 0;
- virtual void OnCreateThread(const HostThread &thread) = 0;
- virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 0;
- virtual void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) = 0;
- virtual void OnUnloadDll(lldb::addr_t module_addr) = 0;
- virtual void OnDebugString(const std::string &string) = 0;
- virtual void OnDebuggerError(const Error &error, uint32_t type) = 0;
-};
-}
-
-#endif
+//===-- IDebugDelegate.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_IDebugDelegate_H_ +#define liblldb_Plugins_Process_Windows_IDebugDelegate_H_ + +#include "ForwardDecl.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" +#include <string> + +namespace lldb_private +{ +class Error; +class HostThread; + +//---------------------------------------------------------------------- +// IDebugDelegate +// +// IDebugDelegate defines an interface which allows implementors to receive +// notification of events that happen in a debugged process. +//---------------------------------------------------------------------- +class IDebugDelegate +{ + public: + virtual ~IDebugDelegate() {} + + virtual void OnExitProcess(uint32_t exit_code) = 0; + virtual void OnDebuggerConnected(lldb::addr_t image_base) = 0; + virtual ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) = 0; + virtual void OnCreateThread(const HostThread &thread) = 0; + virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 0; + virtual void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) = 0; + virtual void OnUnloadDll(lldb::addr_t module_addr) = 0; + virtual void OnDebugString(const std::string &string) = 0; + virtual void OnDebuggerError(const Error &error, uint32_t type) = 0; +}; +} + +#endif diff --git a/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp b/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp index 55102cc12ebb..855289d67bc7 100644 --- a/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp +++ b/source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp @@ -550,56 +550,74 @@ ProcessWindowsLive::RefreshStateAfterStop() if (!stop_thread) return; - RegisterContextSP register_context = stop_thread->GetRegisterContext(); - - // The current EIP is AFTER the BP opcode, which is one byte. - uint64_t pc = register_context->GetPC() - 1; - if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT) + switch (active_exception->GetExceptionCode()) { - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); + case EXCEPTION_SINGLE_STEP: + { + stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); + stop_thread->SetStopInfo(stop_info); + WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u", + stop_thread->GetID()); + stop_thread->SetStopInfo(stop_info); + return; + } - if (site) + case EXCEPTION_BREAKPOINT: { - WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "RefreshStateAfterStop detected breakpoint in process %I64u at " - "address 0x%I64x with breakpoint site %d", - m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); + RegisterContextSP register_context = stop_thread->GetRegisterContext(); - if (site->ValidForThisThread(stop_thread.get())) - { - WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.", - site->GetID(), stop_thread->GetID()); + // The current EIP is AFTER the BP opcode, which is one byte. + uint64_t pc = register_context->GetPC() - 1; - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( - *stop_thread, site->GetID()); - register_context->SetPC(pc); + BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); + if (site) + { + WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "RefreshStateAfterStop detected breakpoint in process %I64u at " + "address 0x%I64x with breakpoint site %d", + m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); + + if (site->ValidForThisThread(stop_thread.get())) + { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "Breakpoint site %d is valid for this thread (0x%I64x), creating stop info.", + site->GetID(), stop_thread->GetID()); + + stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( + *stop_thread, site->GetID()); + register_context->SetPC(pc); + } + else + { + WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, + "Breakpoint site %d is not valid for this thread, creating empty stop info.", + site->GetID()); + } + stop_thread->SetStopInfo(stop_info); + return; } else { + // The thread hit a hard-coded breakpoint like an `int 3` or `__debugbreak()`. WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION, - "Breakpoint site %d is not valid for this thread, creating empty stop info.", - site->GetID()); + "No breakpoint site matches for this thread. __debugbreak()? " + "Creating stop info with the exception."); + // FALLTHROUGH: We'll treat this as a generic exception record in the default case. } } - stop_thread->SetStopInfo(stop_info); - } - else if (active_exception->GetExceptionCode() == EXCEPTION_SINGLE_STEP) - { - stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); - stop_thread->SetStopInfo(stop_info); - WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u", - stop_thread->GetID()); - } - else - { - std::string desc; - llvm::raw_string_ostream desc_stream(desc); - desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8) - << " encountered at address " << llvm::format_hex(pc, 8); - stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str()); - stop_thread->SetStopInfo(stop_info); - WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str()); + + default: + { + std::string desc; + llvm::raw_string_ostream desc_stream(desc); + desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8) + << " encountered at address " + << llvm::format_hex(active_exception->GetExceptionAddress(), 8); + stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str()); + stop_thread->SetStopInfo(stop_info); + WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str()); + return; + } } } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 5c7f6caca511..c0ea9cceea2e 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -101,6 +101,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : m_supports_QEnvironment (true), m_supports_QEnvironmentHexEncoded (true), m_supports_qSymbol (true), + m_qSymbol_requests_done (false), + m_supports_qModuleInfo (true), m_supports_jThreadsInfo (true), m_curr_pid (LLDB_INVALID_PROCESS_ID), m_curr_tid (LLDB_INVALID_THREAD_ID), @@ -376,6 +378,8 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; m_supports_qSymbol = true; + m_qSymbol_requests_done = false; + m_supports_qModuleInfo = true; m_host_arch.Clear(); m_os_version_major = UINT32_MAX; m_os_version_minor = UINT32_MAX; @@ -4284,6 +4288,9 @@ GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, const lldb_private::ArchSpec& arch_spec, ModuleSpec &module_spec) { + if (!m_supports_qModuleInfo) + return false; + std::string module_path = module_file_spec.GetPath (false); if (module_path.empty ()) return false; @@ -4299,8 +4306,14 @@ GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success) return false; - if (response.IsErrorResponse () || response.IsUnsupportedResponse ()) + if (response.IsErrorResponse ()) + return false; + + if (response.IsUnsupportedResponse ()) + { + m_supports_qModuleInfo = false; return false; + } std::string name; std::string value; @@ -4432,11 +4445,42 @@ GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString ob // qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded). // LLDB may provide the value by sending another qSymbol packet // in the form of"qSymbol:<sym_value>:<sym_name>". +// +// Three examples: +// +// lldb sends: qSymbol:: +// lldb receives: OK +// Remote gdb stub does not need to know the addresses of any symbols, lldb does not +// need to ask again in this session. +// +// lldb sends: qSymbol:: +// lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 +// lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473 +// lldb receives: OK +// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does not know +// the address at this time. lldb needs to send qSymbol:: again when it has more +// solibs loaded. +// +// lldb sends: qSymbol:: +// lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 +// lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473 +// lldb receives: OK +// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says that it +// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it does not +// need any more symbols. lldb does not need to ask again in this session. void GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) { - if (m_supports_qSymbol) + // Set to true once we've resolved a symbol to an address for the remote stub. + // If we get an 'OK' response after this, the remote stub doesn't need any more + // symbols and we can stop asking. + bool symbol_response_provided = false; + + // Is this the inital qSymbol:: packet? + bool first_qsymbol_query = true; + + if (m_supports_qSymbol && m_qSymbol_requests_done == false) { Mutex::Locker locker; if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) @@ -4448,9 +4492,15 @@ GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) { if (response.IsOKResponse()) { + if (symbol_response_provided || first_qsymbol_query) + { + m_qSymbol_requests_done = true; + } + // We are done serving symbols requests return; } + first_qsymbol_query = false; if (response.IsUnsupportedResponse()) { @@ -4530,7 +4580,14 @@ GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) packet.Clear(); packet.PutCString("qSymbol:"); if (symbol_load_addr != LLDB_INVALID_ADDRESS) + { packet.Printf("%" PRIx64, symbol_load_addr); + symbol_response_provided = true; + } + else + { + symbol_response_provided = false; + } packet.PutCString(":"); packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); continue; // go back to the while loop and send "packet" and wait for another response diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index d2df214d0dba..311b0f3267c8 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -619,6 +619,8 @@ protected: m_supports_QEnvironment:1, m_supports_QEnvironmentHexEncoded:1, m_supports_qSymbol:1, + m_qSymbol_requests_done:1, + m_supports_qModuleInfo:1, m_supports_jThreadsInfo:1; lldb::pid_t m_curr_pid; diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index be380a442e3c..856ea35aef99 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -173,118 +173,6 @@ namespace { } // anonymous namespace end -class ProcessGDBRemote::GDBLoadedModuleInfoList -{ -public: - - class LoadedModuleInfo - { - public: - - enum e_data_point - { - e_has_name = 0, - e_has_base , - e_has_dynamic , - e_has_link_map , - e_num - }; - - LoadedModuleInfo () - { - for (uint32_t i = 0; i < e_num; ++i) - m_has[i] = false; - } - - void set_name (const std::string & name) - { - m_name = name; - m_has[e_has_name] = true; - } - bool get_name (std::string & out) const - { - out = m_name; - return m_has[e_has_name]; - } - - void set_base (const lldb::addr_t base) - { - m_base = base; - m_has[e_has_base] = true; - } - bool get_base (lldb::addr_t & out) const - { - out = m_base; - return m_has[e_has_base]; - } - - void set_base_is_offset (bool is_offset) - { - m_base_is_offset = is_offset; - } - bool get_base_is_offset(bool & out) const - { - out = m_base_is_offset; - return m_has[e_has_base]; - } - - void set_link_map (const lldb::addr_t addr) - { - m_link_map = addr; - m_has[e_has_link_map] = true; - } - bool get_link_map (lldb::addr_t & out) const - { - out = m_link_map; - return m_has[e_has_link_map]; - } - - void set_dynamic (const lldb::addr_t addr) - { - m_dynamic = addr; - m_has[e_has_dynamic] = true; - } - bool get_dynamic (lldb::addr_t & out) const - { - out = m_dynamic; - return m_has[e_has_dynamic]; - } - - bool has_info (e_data_point datum) - { - assert (datum < e_num); - return m_has[datum]; - } - - protected: - - bool m_has[e_num]; - std::string m_name; - lldb::addr_t m_link_map; - lldb::addr_t m_base; - bool m_base_is_offset; - lldb::addr_t m_dynamic; - }; - - GDBLoadedModuleInfoList () - : m_list () - , m_link_map (LLDB_INVALID_ADDRESS) - {} - - void add (const LoadedModuleInfo & mod) - { - m_list.push_back (mod); - } - - void clear () - { - m_list.clear (); - } - - std::vector<LoadedModuleInfo> m_list; - lldb::addr_t m_link_map; -}; - // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. @@ -2034,6 +1922,8 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, const std::vector<addr_t> &exc_data, addr_t thread_dispatch_qaddr, bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid + LazyBool associated_with_dispatch_queue, + addr_t dispatch_queue_t, std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) @@ -2074,10 +1964,15 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr); // Check if the GDB server was able to provide the queue name, kind and serial number if (queue_vars_valid) - gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial); + gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial, dispatch_queue_t, associated_with_dispatch_queue); else gdb_thread->ClearQueueInfo(); + gdb_thread->SetAssociatedWithLibdispatchQueue (associated_with_dispatch_queue); + + if (dispatch_queue_t != LLDB_INVALID_ADDRESS) + gdb_thread->SetQueueLibdispatchQueueAddress (dispatch_queue_t); + // Make sure we update our thread stop reason just once if (!thread_sp->StopInfoIsUpToDate()) { @@ -2248,9 +2143,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) static ConstString g_key_metype("metype"); static ConstString g_key_medata("medata"); static ConstString g_key_qaddr("qaddr"); + static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); + static ConstString g_key_associated_with_dispatch_queue("associated_with_dispatch_queue"); static ConstString g_key_queue_name("qname"); static ConstString g_key_queue_kind("qkind"); - static ConstString g_key_queue_serial("qserial"); + static ConstString g_key_queue_serial_number("qserialnum"); static ConstString g_key_registers("registers"); static ConstString g_key_memory("memory"); static ConstString g_key_address("address"); @@ -2270,9 +2167,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; ExpeditedRegisterMap expedited_register_map; bool queue_vars_valid = false; + addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; + LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; std::string queue_name; QueueKind queue_kind = eQueueKindUnknown; - uint64_t queue_serial = 0; + uint64_t queue_serial_number = 0; // Iterate through all of the thread dictionary key/value pairs from the structured data dictionary thread_dict->ForEach([this, @@ -2286,9 +2185,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) &exc_data, &thread_dispatch_qaddr, &queue_vars_valid, + &associated_with_dispatch_queue, + &dispatch_queue_t, &queue_name, &queue_kind, - &queue_serial] + &queue_serial_number] (ConstString key, StructuredData::Object* object) -> bool { if (key == g_key_tid) @@ -2340,12 +2241,27 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) queue_kind = eQueueKindConcurrent; } } - else if (key == g_key_queue_serial) + else if (key == g_key_queue_serial_number) { - queue_serial = object->GetIntegerValue(0); - if (queue_serial != 0) + queue_serial_number = object->GetIntegerValue(0); + if (queue_serial_number != 0) queue_vars_valid = true; } + else if (key == g_key_dispatch_queue_t) + { + dispatch_queue_t = object->GetIntegerValue(0); + if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS) + queue_vars_valid = true; + } + else if (key == g_key_associated_with_dispatch_queue) + { + queue_vars_valid = true; + bool associated = object->GetBooleanValue (); + if (associated) + associated_with_dispatch_queue = eLazyBoolYes; + else + associated_with_dispatch_queue = eLazyBoolNo; + } else if (key == g_key_reason) { reason = object->GetStringValue(); @@ -2416,9 +2332,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) exc_data, thread_dispatch_qaddr, queue_vars_valid, + associated_with_dispatch_queue, + dispatch_queue_t, queue_name, queue_kind, - queue_serial); + queue_serial_number); } StateType @@ -2461,9 +2379,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) std::vector<addr_t> exc_data; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid + addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; + LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; std::string queue_name; QueueKind queue_kind = eQueueKindUnknown; - uint64_t queue_serial = 0; + uint64_t queue_serial_number = 0; ExpeditedRegisterMap expedited_register_map; while (stop_packet.GetNameColonValue(key, value)) { @@ -2554,6 +2474,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) { thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16); } + else if (key.compare("dispatch_queue_t") == 0) + { + queue_vars_valid = true; + dispatch_queue_t = StringConvert::ToUInt64 (value.c_str(), 0, 16); + } else if (key.compare("qname") == 0) { queue_vars_valid = true; @@ -2577,10 +2502,10 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) queue_kind = eQueueKindConcurrent; } } - else if (key.compare("qserial") == 0) + else if (key.compare("qserialnum") == 0) { - queue_serial = StringConvert::ToUInt64 (value.c_str(), 0, 0); - if (queue_serial != 0) + queue_serial_number = StringConvert::ToUInt64 (value.c_str(), 0, 0); + if (queue_serial_number != 0) queue_vars_valid = true; } else if (key.compare("reason") == 0) @@ -2678,9 +2603,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) exc_data, thread_dispatch_qaddr, queue_vars_valid, + associated_with_dispatch_queue, + dispatch_queue_t, queue_name, queue_kind, - queue_serial); + queue_serial_number); return eStateStopped; } @@ -3051,7 +2978,7 @@ ProcessGDBRemote::GetImageInfoAddress() // the loaded module list can also provides a link map address if (addr == LLDB_INVALID_ADDRESS) { - GDBLoadedModuleInfoList list; + LoadedModuleInfoList list; if (GetLoadedModuleList (list).Success()) addr = list.m_link_map; } @@ -4703,7 +4630,7 @@ ProcessGDBRemote::GetGDBServerRegisterInfo () } Error -ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) +ProcessGDBRemote::GetLoadedModuleList (LoadedModuleInfoList & list) { // Make sure LLDB has an XML parser it can use first if (!XMLDocument::XMLEnabled()) @@ -4747,7 +4674,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - GDBLoadedModuleInfoList::LoadedModuleInfo module; + LoadedModuleInfoList::LoadedModuleInfo module; library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { @@ -4817,7 +4744,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) return Error(); root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - GDBLoadedModuleInfoList::LoadedModuleInfo module; + LoadedModuleInfoList::LoadedModuleInfo module; llvm::StringRef name = library.GetAttributeValue("name"); module.set_name(name.str()); @@ -4879,19 +4806,18 @@ ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_a } size_t -ProcessGDBRemote::LoadModules () +ProcessGDBRemote::LoadModules (LoadedModuleInfoList &module_list) { using lldb_private::process_gdb_remote::ProcessGDBRemote; // request a list of loaded libraries from GDBServer - GDBLoadedModuleInfoList module_list; if (GetLoadedModuleList (module_list).Fail()) return 0; // get a list of all the modules ModuleList new_modules; - for (GDBLoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) + for (LoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) { std::string mod_name; lldb::addr_t mod_base; @@ -4942,6 +4868,14 @@ ProcessGDBRemote::LoadModules () } return new_modules.GetSize(); + +} + +size_t +ProcessGDBRemote::LoadModules () +{ + LoadedModuleInfoList module_list; + return LoadModules (module_list); } Error diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 54749827d6ac..b48edd836a74 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -27,6 +27,7 @@ #include "lldb/Core/StringList.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" +#include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Host/HostThread.h" #include "lldb/lldb-private-forward.h" #include "lldb/Utility/StringExtractor.h" @@ -245,6 +246,9 @@ public: uint32_t &update) override; size_t + LoadModules(LoadedModuleInfoList &module_list) override; + + size_t LoadModules() override; Error @@ -261,8 +265,6 @@ protected: friend class GDBRemoteCommunicationClient; friend class GDBRemoteRegisterContext; - class GDBLoadedModuleInfoList; - //------------------------------------------------------------------ /// Broadcaster event bits definitions. //------------------------------------------------------------------ @@ -429,6 +431,8 @@ protected: const std::vector<lldb::addr_t> &exc_data, lldb::addr_t thread_dispatch_qaddr, bool queue_vars_valid, + lldb_private::LazyBool associated_with_libdispatch_queue, + lldb::addr_t dispatch_queue_t, std::string &queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial); @@ -461,7 +465,7 @@ protected: // Query remote GDBServer for a detailed loaded library list Error - GetLoadedModuleList (GDBLoadedModuleInfoList &); + GetLoadedModuleList (LoadedModuleInfoList &); lldb::ModuleSP LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr, bool value_is_offset); diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 9b410d8b5b8c..a4af12c492c1 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -41,8 +41,10 @@ ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) : m_thread_name (), m_dispatch_queue_name (), m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS), - m_queue_kind(eQueueKindUnknown), - m_queue_serial(0) + m_dispatch_queue_t (LLDB_INVALID_ADDRESS), + m_queue_kind (eQueueKindUnknown), + m_queue_serial_number (LLDB_INVALID_QUEUE_ID), + m_associated_with_libdispatch_queue (eLazyBoolCalculate) { ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, @@ -73,15 +75,19 @@ ThreadGDBRemote::ClearQueueInfo () { m_dispatch_queue_name.clear(); m_queue_kind = eQueueKindUnknown; - m_queue_serial = 0; + m_queue_serial_number = 0; + m_dispatch_queue_t = LLDB_INVALID_ADDRESS; + m_associated_with_libdispatch_queue = eLazyBoolCalculate; } void -ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial) +ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial, addr_t dispatch_queue_t, LazyBool associated_with_libdispatch_queue) { m_dispatch_queue_name = queue_name; m_queue_kind = queue_kind; - m_queue_serial = queue_serial; + m_queue_serial_number = queue_serial; + m_dispatch_queue_t = dispatch_queue_t; + m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; } @@ -100,7 +106,10 @@ ThreadGDBRemote::GetQueueName () } // Always re-fetch the dispatch queue name since it can change - if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return nullptr; + + if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { ProcessSP process_sp (GetProcess()); if (process_sp) @@ -118,6 +127,35 @@ ThreadGDBRemote::GetQueueName () return NULL; } +QueueKind +ThreadGDBRemote::GetQueueKind () +{ + // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) + { + return m_queue_kind; + } + + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return eQueueKindUnknown; + + if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + { + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) + m_queue_kind = runtime->GetQueueKind (m_thread_dispatch_qaddr); + return m_queue_kind; + } + } + return eQueueKindUnknown; +} + + queue_id_t ThreadGDBRemote::GetQueueID () { @@ -125,9 +163,12 @@ ThreadGDBRemote::GetQueueID () // with valid information that was gleaned from the stop reply packet. In this case we trust // that the info is valid in m_dispatch_queue_name without refetching it if (CachedQueueInfoIsValid()) - return m_queue_serial; + return m_queue_serial_number; + + if (m_associated_with_libdispatch_queue == eLazyBoolNo) + return LLDB_INVALID_QUEUE_ID; - if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { ProcessSP process_sp (GetProcess()); if (process_sp) @@ -161,20 +202,54 @@ ThreadGDBRemote::GetQueue () addr_t ThreadGDBRemote::GetQueueLibdispatchQueueAddress () { - addr_t dispatch_queue_t_addr = LLDB_INVALID_ADDRESS; - if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS) { - ProcessSP process_sp (GetProcess()); - if (process_sp) + if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { - SystemRuntime *runtime = process_sp->GetSystemRuntime (); - if (runtime) + ProcessSP process_sp (GetProcess()); + if (process_sp) { - dispatch_queue_t_addr = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr); + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) + { + m_dispatch_queue_t = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr); + } } } } - return dispatch_queue_t_addr; + return m_dispatch_queue_t; +} + +void +ThreadGDBRemote::SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) +{ + m_dispatch_queue_t = dispatch_queue_t; +} + +bool +ThreadGDBRemote::ThreadHasQueueInformation () const +{ + if (m_thread_dispatch_qaddr != 0 + && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS + && m_dispatch_queue_t != LLDB_INVALID_ADDRESS + && m_queue_kind != eQueueKindUnknown + && m_queue_serial_number != 0) + { + return true; + } + return false; +} + +LazyBool +ThreadGDBRemote::GetAssociatedWithLibdispatchQueue () +{ + return m_associated_with_libdispatch_queue; +} + +void +ThreadGDBRemote::SetAssociatedWithLibdispatchQueue (LazyBool associated_with_libdispatch_queue) +{ + m_associated_with_libdispatch_queue = associated_with_libdispatch_queue; } StructuredData::ObjectSP diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 24693ba891cc..d7619f491e66 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -46,6 +46,9 @@ public: const char * GetQueueName () override; + lldb::QueueKind + GetQueueKind () override; + lldb::queue_id_t GetQueueID () override; @@ -55,6 +58,12 @@ public: lldb::addr_t GetQueueLibdispatchQueueAddress () override; + void + SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) override; + + bool + ThreadHasQueueInformation () const override; + lldb::RegisterContextSP GetRegisterContext () override; @@ -98,7 +107,13 @@ public: ClearQueueInfo (); void - SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial); + SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial, lldb::addr_t dispatch_queue_t, lldb_private::LazyBool associated_with_libdispatch_queue); + + lldb_private::LazyBool + GetAssociatedWithLibdispatchQueue () override; + + void + SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue) override; StructuredData::ObjectSP FetchThreadExtendedInfo () override; @@ -109,8 +124,10 @@ protected: std::string m_thread_name; std::string m_dispatch_queue_name; lldb::addr_t m_thread_dispatch_qaddr; + lldb::addr_t m_dispatch_queue_t; lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread - uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread + uint64_t m_queue_serial_number; // Queue info from stop reply/stop info for thread + lldb_private::LazyBool m_associated_with_libdispatch_queue; bool PrivateSetRegisterValue (uint32_t reg, diff --git a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 3107677ee948..23bacc932c03 100644 --- a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -77,6 +77,10 @@ PythonObject::GetObjectType() const return PyObjectType::Dictionary; if (PythonString::Check(m_py_obj)) return PyObjectType::String; +#if PY_MAJOR_VERSION >= 3 + if (PythonBytes::Check(m_py_obj)) + return PyObjectType::Bytes; +#endif if (PythonInteger::Check(m_py_obj)) return PyObjectType::Integer; if (PythonFile::Check(m_py_obj)) @@ -210,6 +214,8 @@ PythonObject::CreateStructuredObject() const return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray(); case PyObjectType::String: return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); + case PyObjectType::Bytes: + return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); case PyObjectType::None: return StructuredData::ObjectSP(); default: @@ -220,6 +226,104 @@ PythonObject::CreateStructuredObject() const //---------------------------------------------------------------------- // PythonString //---------------------------------------------------------------------- +PythonBytes::PythonBytes() : PythonObject() +{ +} + +PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject() +{ + SetBytes(bytes); +} + +PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject() +{ + SetBytes(llvm::ArrayRef<uint8_t>(bytes, length)); +} + +PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject() +{ + Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string +} + +PythonBytes::PythonBytes(const PythonBytes &object) : PythonObject(object) +{ +} + +PythonBytes::~PythonBytes() +{ +} + +bool +PythonBytes::Check(PyObject *py_obj) +{ + if (!py_obj) + return false; + if (PyBytes_Check(py_obj)) + return true; + return false; +} + +void +PythonBytes::Reset(PyRefType type, PyObject *py_obj) +{ + // Grab the desired reference type so that if we end up rejecting + // `py_obj` it still gets decremented if necessary. + PythonObject result(type, py_obj); + + if (!PythonBytes::Check(py_obj)) + { + PythonObject::Reset(); + return; + } + + // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls + // back into the virtual implementation. + PythonObject::Reset(PyRefType::Borrowed, result.get()); +} + +llvm::ArrayRef<uint8_t> +PythonBytes::GetBytes() const +{ + if (!IsValid()) + return llvm::ArrayRef<uint8_t>(); + + Py_ssize_t size; + char *c; + + PyBytes_AsStringAndSize(m_py_obj, &c, &size); + return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size); +} + +size_t +PythonBytes::GetSize() const +{ + if (!IsValid()) + return 0; + return PyBytes_Size(m_py_obj); +} + +void +PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) +{ + const char *data = reinterpret_cast<const char *>(bytes.data()); + PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size()); + PythonObject::Reset(PyRefType::Owned, py_bytes); +} + +StructuredData::StringSP +PythonBytes::CreateStructuredString() const +{ + StructuredData::StringSP result(new StructuredData::String); + Py_ssize_t size; + char *c; + PyBytes_AsStringAndSize(m_py_obj, &c, &size); + result->SetValue(std::string(c, size)); + return result; +} + +//---------------------------------------------------------------------- +// PythonString +//---------------------------------------------------------------------- PythonString::PythonString(PyRefType type, PyObject *py_obj) : PythonObject() diff --git a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index c9d17c0f0fad..06264b66c283 100644 --- a/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -23,8 +23,11 @@ #include "lldb/Host/File.h" #include "lldb/Interpreter/OptionValue.h" +#include "llvm/ADT/ArrayRef.h" + namespace lldb_private { +class PythonBytes; class PythonString; class PythonList; class PythonDictionary; @@ -71,6 +74,7 @@ enum class PyObjectType Dictionary, List, String, + Bytes, Module, Callable, Tuple, @@ -256,6 +260,39 @@ protected: PyObject* m_py_obj; }; +class PythonBytes : public PythonObject +{ +public: + PythonBytes(); + explicit PythonBytes(llvm::ArrayRef<uint8_t> bytes); + PythonBytes(const uint8_t *bytes, size_t length); + PythonBytes(PyRefType type, PyObject *o); + PythonBytes(const PythonBytes &object); + + ~PythonBytes() override; + + static bool + Check(PyObject *py_obj); + + // Bring in the no-argument base class version + using PythonObject::Reset; + + void + Reset(PyRefType type, PyObject *py_obj) override; + + llvm::ArrayRef<uint8_t> + GetBytes() const; + + size_t + GetSize() const; + + void + SetBytes(llvm::ArrayRef<uint8_t> stringbytes); + + StructuredData::StringSP + CreateStructuredString() const; +}; + class PythonString : public PythonObject { public: diff --git a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index b1dd34b46f69..19ad86db240a 100644 --- a/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1692,10 +1692,10 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData(StructuredData::ObjectSP o PyErr_Clear(); } - assert(PythonString::Check(py_return.get()) && "get_register_data returned unknown object type!"); + assert(PythonBytes::Check(py_return.get()) && "get_register_data returned unknown object type!"); - PythonString result_string(PyRefType::Borrowed, py_return.get()); - return result_string.CreateStructuredString(); + PythonBytes result(PyRefType::Borrowed, py_return.get()); + return result.CreateStructuredString(); } StructuredData::DictionarySP diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.h b/source/Plugins/SymbolFile/DWARF/DIERef.h index a5484db6bd6c..3df07d511749 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.h +++ b/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -33,6 +33,18 @@ struct DIERef lldb::user_id_t GetUID() const; + bool + operator< (const DIERef &ref) const + { + return die_offset < ref.die_offset; + } + + bool + operator< (const DIERef &ref) + { + return die_offset < ref.die_offset; + } + dw_offset_t cu_offset; dw_offset_t die_offset; }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 68a0285b69df..74b54d614aa2 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2928,7 +2928,7 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, if (member_byte_offset >= parent_byte_size) { - if (member_array_size != 1) + if (member_array_size != 1 && (member_array_size != 0 || member_byte_offset > parent_byte_size)) { module_sp->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which extends beyond the bounds of 0x%8.8" PRIx64, die.GetID(), diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 0ed4d05be5c2..2088864bf6b1 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1065,12 +1065,17 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec const char * cu_comp_dir = resolveCompDir(cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr)); const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, DW_INVALID_OFFSET); - - // All file indexes in DWARF are one based and a file of index zero is - // supposed to be the compile unit itself. - support_files.Append (*sc.comp_unit); - - return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files); + if (stmt_list != DW_INVALID_OFFSET) + { + // All file indexes in DWARF are one based and a file of index zero is + // supposed to be the compile unit itself. + support_files.Append (*sc.comp_unit); + return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), + get_debug_line_data(), + cu_comp_dir, + stmt_list, + support_files); + } } } return false; @@ -2927,6 +2932,40 @@ SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inli return sc_list.GetSize() - original_size; } +void +SymbolFileDWARF::GetMangledNamesForFunction (const std::string &scope_qualified_name, + std::vector<ConstString> &mangled_names) +{ + DWARFDebugInfo* info = DebugInfo(); + uint32_t num_comp_units = 0; + if (info) + num_comp_units = info->GetNumCompileUnits(); + + for (uint32_t i = 0; i < num_comp_units; i++) + { + DWARFCompileUnit *cu = info->GetCompileUnitAtIndex(i); + if (cu == nullptr) + continue; + + SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(); + if (dwo) + dwo->GetMangledNamesForFunction(scope_qualified_name, mangled_names); + } + + NameToOffsetMap::iterator iter = m_function_scope_qualified_name_map.find(scope_qualified_name); + if (iter == m_function_scope_qualified_name_map.end()) + return; + + DIERefSetSP set_sp = (*iter).second; + std::set<DIERef>::iterator set_iter; + for (set_iter = set_sp->begin(); set_iter != set_sp->end(); set_iter++) + { + DWARFDIE die = DebugInfo()->GetDIE (*set_iter); + mangled_names.push_back(ConstString(die.GetMangledName())); + } +} + + uint32_t SymbolFileDWARF::FindTypes (const SymbolContext& sc, const ConstString &name, @@ -3751,6 +3790,24 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, const DWARFDIE &die, bool * TypeList* type_list = GetTypeList(); if (type_list) type_list->Insert(type_sp); + + if (die.Tag() == DW_TAG_subprogram) + { + DIERef die_ref = die.GetDIERef(); + std::string scope_qualified_name(GetDeclContextForUID(die.GetID()).GetScopeQualifiedName().AsCString("")); + if (scope_qualified_name.size()) + { + NameToOffsetMap::iterator iter = m_function_scope_qualified_name_map.find(scope_qualified_name); + if (iter != m_function_scope_qualified_name_map.end()) + (*iter).second->insert(die_ref); + else + { + DIERefSetSP new_set(new std::set<DIERef>); + new_set->insert(die_ref); + m_function_scope_qualified_name_map.emplace(std::make_pair(scope_qualified_name, new_set)); + } + } + } } } } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index c2e78a417b7a..be097595346e 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -208,6 +208,10 @@ public: bool append, lldb_private::SymbolContextList& sc_list) override; + void + GetMangledNamesForFunction (const std::string &scope_qualified_name, + std::vector<lldb_private::ConstString> &mangled_names) override; + uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, @@ -577,6 +581,9 @@ protected: m_fetched_external_modules:1; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; + typedef std::shared_ptr<std::set<DIERef> > DIERefSetSP; + typedef std::unordered_map<std::string, DIERefSetSP> NameToOffsetMap; + NameToOffsetMap m_function_scope_qualified_name_map; std::unique_ptr<DWARFDebugRanges> m_ranges; UniqueDWARFASTTypeMap m_unique_ast_type_map; DIEToTypePtr m_die_to_type; diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index b11a06760325..1097ef36960e 100644 --- a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -725,14 +725,26 @@ SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list) for (ThreadSP thread_sp : m_process->Threads()) { - if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) + if (thread_sp->GetAssociatedWithLibdispatchQueue () != eLazyBoolNo) { - if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL) + if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) { - QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName())); - queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress())); - queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress()); - queue_list.AddQueue (queue_sp); + if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL) + { + QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName())); + if (thread_sp->ThreadHasQueueInformation ()) + { + queue_sp->SetKind (thread_sp->GetQueueKind ()); + queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress()); + queue_list.AddQueue (queue_sp); + } + else + { + queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress())); + queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress()); + queue_list.AddQueue (queue_sp); + } + } } } } diff --git a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h index 5976bed57cf6..8fe15fa4d8a5 100644 --- a/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h +++ b/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h @@ -104,8 +104,8 @@ public: void CompleteQueueItem(lldb_private::QueueItem *queue_item, lldb::addr_t item_ref) override; - virtual lldb::QueueKind - GetQueueKind (lldb::addr_t dispatch_queue_addr); + lldb::QueueKind + GetQueueKind (lldb::addr_t dispatch_queue_addr) override; void AddThreadExtendedInfoPacketHints(lldb_private::StructuredData::ObjectSP dict) override; diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index 7e4c696a36d4..76f0b48d69e9 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -155,6 +155,7 @@ private: bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset); bool ret_pattern_p (); bool pop_rbp_pattern_p (); + bool leave_pattern_p (); bool call_next_insn_pattern_p(); uint32_t extract_4 (uint8_t *b); bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno); @@ -492,6 +493,14 @@ AssemblyParse_x86::pop_rbp_pattern_p () return (*p == 0x5d); } +// leave [0xc9] +bool +AssemblyParse_x86::leave_pattern_p () +{ + uint8_t *p = m_cur_insn_bytes; + return (*p == 0xc9); +} + // call $0 [0xe8 0x0 0x0 0x0 0x0] bool AssemblyParse_x86::call_next_insn_pattern_p () @@ -780,8 +789,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) if (machine_regno == (int)m_machine_fp_regnum) { - row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, - row->GetCFAValue().GetOffset()); + row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, row->GetCFAValue().GetOffset()); } in_epilogue = true; @@ -792,12 +800,35 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) // we need to add a new row of instructions. if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) { - row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, - current_sp_bytes_offset_from_cfa); + row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa); row_updated = true; } } + // The LEAVE instruction moves the value from rbp into rsp and pops + // a value off the stack into rbp (restoring the caller's rbp value). + // It is the opposite of ENTER, or 'push rbp, mov rsp rbp'. + else if (leave_pattern_p ()) + { + // We're going to copy the value in rbp into rsp, so re-set the sp offset + // based on the CFAValue. Also, adjust it to recognize that we're popping + // the saved rbp value off the stack. + current_sp_bytes_offset_from_cfa = row->GetCFAValue().GetOffset(); + current_sp_bytes_offset_from_cfa -= m_wordsize; + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); + + // rbp is restored to the caller's value + saved_registers[m_machine_fp_regnum] = false; + row->RemoveRegisterInfo (m_lldb_fp_regnum); + + // cfa is now in terms of rsp again. + row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, row->GetCFAValue().GetOffset()); + row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa); + + in_epilogue = true; + row_updated = true; + } + else if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno) @@ -1137,15 +1168,15 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin // The only case we care about is epilogue: // [0x5d] pop %rbp/%ebp // => [0xc3] ret - if (pop_rbp_pattern_p ()) + if (pop_rbp_pattern_p () || leave_pattern_p ()) { if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, 1, error) != static_cast<size_t>(-1) && ret_pattern_p ()) { row->SetOffset (offset); - row->GetCFAValue().SetIsRegisterPlusOffset ( - first_row->GetCFAValue().GetRegisterNumber(), m_wordsize); + row->GetCFAValue().SetIsRegisterPlusOffset (first_row->GetCFAValue().GetRegisterNumber(), + m_wordsize); UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp index 8b11c239aabf..621bd1615f80 100644 --- a/source/Symbol/ClangASTContext.cpp +++ b/source/Symbol/ClangASTContext.cpp @@ -4158,6 +4158,7 @@ ClangASTContext::GetTypeClass (lldb::opaque_compiler_type_t type) case clang::Type::Decltype: break; case clang::Type::TemplateSpecialization: break; case clang::Type::Atomic: break; + case clang::Type::Pipe: break; // pointer type decayed from an array or function type. case clang::Type::Decayed: break; @@ -4891,6 +4892,7 @@ ClangASTContext::GetEncoding (lldb::opaque_compiler_type_t type, uint64_t &count case clang::Type::TemplateSpecialization: case clang::Type::Atomic: case clang::Type::Adjusted: + case clang::Type::Pipe: break; // pointer type decayed from an array or function type. @@ -5008,6 +5010,7 @@ ClangASTContext::GetFormat (lldb::opaque_compiler_type_t type) case clang::Type::TemplateSpecialization: case clang::Type::Atomic: case clang::Type::Adjusted: + case clang::Type::Pipe: break; // pointer type decayed from an array or function type. @@ -9969,6 +9972,18 @@ ClangASTContext::DeclContextGetName (void *opaque_decl_ctx) return ConstString(); } +ConstString +ClangASTContext::DeclContextGetScopeQualifiedName (void *opaque_decl_ctx) +{ + if (opaque_decl_ctx) + { + clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx); + if (named_decl) + return ConstString(llvm::StringRef(named_decl->getQualifiedNameAsString())); + } + return ConstString(); +} + bool ClangASTContext::DeclContextIsClassMethod (void *opaque_decl_ctx, lldb::LanguageType *language_ptr, diff --git a/source/Symbol/CompilerDeclContext.cpp b/source/Symbol/CompilerDeclContext.cpp index e44cee67284c..8bee1b48753a 100644 --- a/source/Symbol/CompilerDeclContext.cpp +++ b/source/Symbol/CompilerDeclContext.cpp @@ -38,6 +38,15 @@ CompilerDeclContext::GetName () const return ConstString(); } +ConstString +CompilerDeclContext::GetScopeQualifiedName () const +{ + if (IsValid()) + return m_type_system->DeclContextGetScopeQualifiedName(m_opaque_decl_ctx); + else + return ConstString(); +} + bool CompilerDeclContext::IsStructUnionOrClass () const { diff --git a/source/Symbol/LineTable.cpp b/source/Symbol/LineTable.cpp index 01c171886430..f9a42a7d14af 100644 --- a/source/Symbol/LineTable.cpp +++ b/source/Symbol/LineTable.cpp @@ -143,6 +143,13 @@ LineTable::InsertSequence (LineSequence* sequence) entry_collection::iterator end_pos = m_entries.end(); LineTable::Entry::LessThanBinaryPredicate less_than_bp(this); entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp); + + // We should never insert a sequence in the middle of another sequence + if (pos != begin_pos) { + while (pos < end_pos && !((pos - 1)->is_terminal_entry)) + pos++; + } + #ifdef LLDB_CONFIGURATION_DEBUG // If we aren't inserting at the beginning, the previous entry should // terminate a sequence. diff --git a/source/Symbol/SymbolFile.cpp b/source/Symbol/SymbolFile.cpp index 51e35048d5cd..82bbceb9610a 100644 --- a/source/Symbol/SymbolFile.cpp +++ b/source/Symbol/SymbolFile.cpp @@ -134,6 +134,12 @@ SymbolFile::FindFunctions (const RegularExpression& regex, bool include_inlines, return 0; } +void +SymbolFile::GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names) +{ + return; +} + uint32_t SymbolFile::FindTypes (const SymbolContext& sc, const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, TypeMap& types) { diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index 311c695860fe..e4fe419660e2 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -6515,3 +6515,65 @@ Process::ResetImageToken(size_t token) if (token < m_image_tokens.size()) m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN; } + +Address +Process::AdvanceAddressToNextBranchInstruction (Address default_stop_addr, AddressRange range_bounds) +{ + Target &target = GetTarget(); + DisassemblerSP disassembler_sp; + InstructionList *insn_list = NULL; + + Address retval = default_stop_addr; + + if (target.GetUseFastStepping() == false) + return retval; + if (default_stop_addr.IsValid() == false) + return retval; + + ExecutionContext exe_ctx (this); + const char *plugin_name = nullptr; + const char *flavor = nullptr; + const bool prefer_file_cache = true; + disassembler_sp = Disassembler::DisassembleRange(target.GetArchitecture(), + plugin_name, + flavor, + exe_ctx, + range_bounds, + prefer_file_cache); + if (disassembler_sp.get()) + insn_list = &disassembler_sp->GetInstructionList(); + + if (insn_list == NULL) + { + return retval; + } + + size_t insn_offset = insn_list->GetIndexOfInstructionAtAddress (default_stop_addr); + if (insn_offset == UINT32_MAX) + { + return retval; + } + + uint32_t branch_index = insn_list->GetIndexOfNextBranchInstruction (insn_offset, target); + if (branch_index == UINT32_MAX) + { + return retval; + } + + if (branch_index > insn_offset) + { + Address next_branch_insn_address = insn_list->GetInstructionAtIndex (branch_index)->GetAddress(); + if (next_branch_insn_address.IsValid() && range_bounds.ContainsFileAddress (next_branch_insn_address)) + { + retval = next_branch_insn_address; + } + } + + if (disassembler_sp.get()) + { + // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions. + disassembler_sp->GetInstructionList().Clear(); + } + + return retval; +} diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp index 9f9da9726605..551e48000936 100644 --- a/source/Target/Thread.cpp +++ b/source/Target/Thread.cpp @@ -1591,7 +1591,7 @@ Thread::QueueThreadPlanForStepOut(bool abort_other_plans, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - LazyBool step_out_avoids_code_withoug_debug_info) + LazyBool step_out_avoids_code_without_debug_info) { ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, addr_context, @@ -1600,7 +1600,7 @@ Thread::QueueThreadPlanForStepOut(bool abort_other_plans, stop_vote, run_vote, frame_idx, - step_out_avoids_code_withoug_debug_info)); + step_out_avoids_code_without_debug_info)); if (thread_plan_sp->ValidatePlan(nullptr)) { @@ -1620,7 +1620,8 @@ Thread::QueueThreadPlanForStepOutNoShouldStop(bool abort_other_plans, bool stop_other_threads, Vote stop_vote, Vote run_vote, - uint32_t frame_idx) + uint32_t frame_idx, + bool continue_to_next_branch) { ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut (*this, addr_context, @@ -1629,7 +1630,8 @@ Thread::QueueThreadPlanForStepOutNoShouldStop(bool abort_other_plans, stop_vote, run_vote, frame_idx, - eLazyBoolNo)); + eLazyBoolNo, + continue_to_next_branch)); ThreadPlanStepOut *new_plan = static_cast<ThreadPlanStepOut *>(thread_plan_sp.get()); new_plan->ClearShouldStopHereCallbacks(); diff --git a/source/Target/ThreadPlanShouldStopHere.cpp b/source/Target/ThreadPlanShouldStopHere.cpp index 88f8db2bd7e7..55aaaf00b569 100644 --- a/source/Target/ThreadPlanShouldStopHere.cpp +++ b/source/Target/ThreadPlanShouldStopHere.cpp @@ -135,7 +135,8 @@ ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan, stop_others, eVoteNo, eVoteNoOpinion, - frame_index); + frame_index, + true); return return_plan_sp; } diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp index 92403cb92ed3..82b823be62e2 100644 --- a/source/Target/ThreadPlanStepOut.cpp +++ b/source/Target/ThreadPlanStepOut.cpp @@ -18,6 +18,7 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ABI.h" #include "lldb/Target/Process.h" @@ -44,7 +45,8 @@ ThreadPlanStepOut::ThreadPlanStepOut Vote stop_vote, Vote run_vote, uint32_t frame_idx, - LazyBool step_out_avoids_code_without_debug_info + LazyBool step_out_avoids_code_without_debug_info, + bool continue_to_next_branch ) : ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote), ThreadPlanShouldStopHere (this), @@ -86,7 +88,8 @@ ThreadPlanStepOut::ThreadPlanStepOut eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1, - eLazyBoolNo)); + eLazyBoolNo, + continue_to_next_branch)); static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr); m_step_out_to_inline_plan_sp->SetPrivate(true); } @@ -101,7 +104,27 @@ ThreadPlanStepOut::ThreadPlanStepOut // Find the return address and set a breakpoint there: // FIXME - can we do this more securely if we know first_insn? - m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess()->GetTarget()); + Address return_address (return_frame_sp->GetFrameCodeAddress()); + if (continue_to_next_branch) + { + SymbolContext return_address_sc; + AddressRange range; + Address return_address_decr_pc = return_address; + if (return_address_decr_pc.GetOffset() > 0) + return_address_decr_pc.Slide (-1); + + return_address_decr_pc.CalculateSymbolContext (&return_address_sc, lldb::eSymbolContextLineEntry); + if (return_address_sc.line_entry.IsValid()) + { + range = return_address_sc.line_entry.GetSameLineContiguousAddressRange(); + if (range.GetByteSize() > 0) + { + return_address = m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction (return_address, + range); + } + } + } + m_return_addr = return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); if (m_return_addr == LLDB_INVALID_ADDRESS) return; diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp index 08655be24395..2e731a845788 100644 --- a/source/Target/ThreadPlanStepOverRange.cpp +++ b/source/Target/ThreadPlanStepOverRange.cpp @@ -185,7 +185,8 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr) stop_others, eVoteNo, eVoteNoOpinion, - 0); + 0, + true); break; } else diff --git a/tools/debugserver/source/RNBRemote.cpp b/tools/debugserver/source/RNBRemote.cpp index dadf479ce81b..6dddb046acc5 100644 --- a/tools/debugserver/source/RNBRemote.cpp +++ b/tools/debugserver/source/RNBRemote.cpp @@ -2547,6 +2547,7 @@ debugserver_regnum_with_fixed_width_hex_register_value (std::ostream& ostrm, void RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo (nub_process_t pid, nub_addr_t dispatch_qaddr, + nub_addr_t &dispatch_queue_t, std::string &queue_name, uint64_t &queue_width, uint64_t &queue_serialnum) const @@ -2557,17 +2558,17 @@ RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo (nub_process_t pid, if (IsValid() && dispatch_qaddr != INVALID_NUB_ADDRESS && dispatch_qaddr != 0) { - nub_addr_t dispatch_queue_addr = DNBProcessMemoryReadPointer (pid, dispatch_qaddr); - if (dispatch_queue_addr) + dispatch_queue_t = DNBProcessMemoryReadPointer (pid, dispatch_qaddr); + if (dispatch_queue_t) { - queue_width = DNBProcessMemoryReadInteger (pid, dispatch_queue_addr + dqo_width, dqo_width_size, 0); - queue_serialnum = DNBProcessMemoryReadInteger (pid, dispatch_queue_addr + dqo_serialnum, dqo_serialnum_size, 0); + queue_width = DNBProcessMemoryReadInteger (pid, dispatch_queue_t + dqo_width, dqo_width_size, 0); + queue_serialnum = DNBProcessMemoryReadInteger (pid, dispatch_queue_t + dqo_serialnum, dqo_serialnum_size, 0); if (dqo_version >= 4) { // libdispatch versions 4+, pointer to dispatch name is in the // queue structure. - nub_addr_t pointer_to_label_address = dispatch_queue_addr + dqo_label; + nub_addr_t pointer_to_label_address = dispatch_queue_t + dqo_label; nub_addr_t label_addr = DNBProcessMemoryReadPointer (pid, pointer_to_label_address); if (label_addr) queue_name = std::move(DNBProcessMemoryReadCString (pid, label_addr)); @@ -2576,7 +2577,7 @@ RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo (nub_process_t pid, { // libdispatch versions 1-3, dispatch name is a fixed width char array // in the queue structure. - queue_name = std::move(DNBProcessMemoryReadCStringFixed(pid, dispatch_queue_addr + dqo_label, dqo_label_size)); + queue_name = std::move(DNBProcessMemoryReadCStringFixed(pid, dispatch_queue_t + dqo_label, dqo_label_size)); } } } @@ -2700,36 +2701,6 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid) } } - thread_identifier_info_data_t thread_ident_info; - if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info)) - { - if (thread_ident_info.dispatch_qaddr != 0) - { - ostrm << "qaddr:" << std::hex << thread_ident_info.dispatch_qaddr << ';'; - const DispatchQueueOffsets *dispatch_queue_offsets = GetDispatchQueueOffsets(); - if (dispatch_queue_offsets) - { - std::string queue_name; - uint64_t queue_width = 0; - uint64_t queue_serialnum = 0; - dispatch_queue_offsets->GetThreadQueueInfo(pid, thread_ident_info.dispatch_qaddr, queue_name, queue_width, queue_serialnum); - if (!queue_name.empty()) - { - ostrm << "qname:"; - append_hex_value(ostrm, queue_name.data(), queue_name.size(), false); - ostrm << ';'; - } - if (queue_width == 1) - ostrm << "qkind:serial;"; - else if (queue_width > 1) - ostrm << "qkind:concurrent;"; - - if (queue_serialnum > 0) - ostrm << "qserial:" << DECIMAL << queue_serialnum << ';'; - } - } - } - // If a 'QListThreadsInStopReply' was sent to enable this feature, we // will send all thread IDs back in the "threads" key whose value is // a list of hex thread IDs separated by commas: @@ -2811,7 +2782,6 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid) } } - if (g_num_reg_entries == 0) InitializeRegisters (); @@ -5190,7 +5160,18 @@ RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) std::string queue_name; uint64_t queue_width = 0; uint64_t queue_serialnum = 0; - dispatch_queue_offsets->GetThreadQueueInfo(pid, thread_ident_info.dispatch_qaddr, queue_name, queue_width, queue_serialnum); + nub_addr_t dispatch_queue_t = INVALID_NUB_ADDRESS; + dispatch_queue_offsets->GetThreadQueueInfo(pid, thread_ident_info.dispatch_qaddr, dispatch_queue_t, queue_name, queue_width, queue_serialnum); + if (dispatch_queue_t == 0 && queue_name.empty() && queue_serialnum == 0) + { + thread_dict_sp->AddBooleanItem ("associated_with_dispatch_queue", false); + } + else + { + thread_dict_sp->AddBooleanItem ("associated_with_dispatch_queue", true); + } + if (dispatch_queue_t != INVALID_NUB_ADDRESS && dispatch_queue_t != 0) + thread_dict_sp->AddIntegerItem("dispatch_queue_t", dispatch_queue_t); if (!queue_name.empty()) thread_dict_sp->AddStringItem("qname", queue_name); if (queue_width == 1) @@ -5198,7 +5179,7 @@ RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) else if (queue_width > 1) thread_dict_sp->AddStringItem("qkind", "concurrent"); if (queue_serialnum > 0) - thread_dict_sp->AddIntegerItem("qserial", queue_serialnum); + thread_dict_sp->AddIntegerItem("qserialnum", queue_serialnum); } } } diff --git a/tools/debugserver/source/RNBRemote.h b/tools/debugserver/source/RNBRemote.h index 9d30106d5b82..68dd8c52ea38 100644 --- a/tools/debugserver/source/RNBRemote.h +++ b/tools/debugserver/source/RNBRemote.h @@ -373,6 +373,7 @@ protected: void GetThreadQueueInfo (nub_process_t pid, nub_addr_t dispatch_qaddr, + nub_addr_t &dispatch_queue_t, std::string &queue_name, uint64_t &queue_width, uint64_t &queue_serialnum) const; diff --git a/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp b/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp index 5c6925179c6a..605f0233e876 100644 --- a/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp +++ b/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp @@ -203,6 +203,27 @@ TEST_F(PythonDataObjectsTest, TestPythonInteger) EXPECT_EQ(7, constructed_int.GetInteger()); } +TEST_F(PythonDataObjectsTest, TestPythonBytes) +{ + static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes"; + PyObject *py_bytes = PyBytes_FromString(test_bytes); + EXPECT_TRUE(PythonBytes::Check(py_bytes)); + PythonBytes python_bytes(PyRefType::Owned, py_bytes); + EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType()); + +#if PY_MAJOR_VERSION < 3 + EXPECT_TRUE(PythonString::Check(py_bytes)); + EXPECT_EQ(PyObjectType::String, python_bytes.GetObjectType()); +#else + EXPECT_FALSE(PythonString::Check(py_bytes)); + EXPECT_NE(PyObjectType::String, python_bytes.GetObjectType()); +#endif + + llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes(); + EXPECT_EQ(bytes.size(), strlen(test_bytes)); + EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size())); +} + TEST_F(PythonDataObjectsTest, TestPythonString) { // Test that strings behave correctly when wrapped by a PythonString. diff --git a/www/lldb-coding-conventions.html b/www/lldb-coding-conventions.html index 7cd959ccf9de..c3702decb31e 100644 --- a/www/lldb-coding-conventions.html +++ b/www/lldb-coding-conventions.html @@ -22,20 +22,20 @@ <p>The LLDB coding conventions differ in a few important respects from LLVM.</p> - <p>
- Note that <a href="http://clang.llvm.org/docs/ClangFormat.html">clang-format</a> will deal with
- most of this for you, as such is suggested to run on patches before uploading. Note however that
- clang-format is not smart enough to detect instances of humans intentionally trying to line variables
- up on a particular column boundary, and it will reformat them to remove this "extraneous" whitespace.
- While this is usually the correct behavior, LLDB does have many uses of manually aligned types and
- fields, so please be aware of this behavior of clang-format when editing this type of code.
- </p>
- <p>
- <b>Important</b>: Where not explicitly outlined below, assume that the
- <a href="http://llvm.org/docs/CodingStandards.html">LLVM Coding Conventions</a> are to be followed.
- </p>
-
- <h3>Source code width:</h3>
+ <p> + Note that <a href="http://clang.llvm.org/docs/ClangFormat.html">clang-format</a> will deal with + most of this for you, as such is suggested to run on patches before uploading. Note however that + clang-format is not smart enough to detect instances of humans intentionally trying to line variables + up on a particular column boundary, and it will reformat them to remove this "extraneous" whitespace. + While this is usually the correct behavior, LLDB does have many uses of manually aligned types and + fields, so please be aware of this behavior of clang-format when editing this type of code. + </p> + <p> + <b>Important</b>: Where not explicitly outlined below, assume that the + <a href="http://llvm.org/docs/CodingStandards.html">LLVM Coding Conventions</a> are to be followed. + </p> + + <h3>Source code width:</h3> <p>lldb does not follow the 80 character line restriction llvm imposes. In our experience, trying to fit C++ code into an 80 character line results in code that is awkward to read, and the time spent trying to find good indentation points to diff --git a/www/lldb-gdb.html b/www/lldb-gdb.html index 74b153dafa06..60cd718d5255 100755 --- a/www/lldb-gdb.html +++ b/www/lldb-gdb.html @@ -307,6 +307,15 @@ Stop hook #1 added.<br> </td> </tr> + <tr><td class="header" colspan="2">Run until we hit line <b>12</b> or control leaves the current function.</td></tr> + <tr> + <td class="content"> + <b>(gdb)</b> until 12 + </td> + <td class="content"> + <b>(lldb)</b> thread until 12 + </td> + </tr> </table> <p> diff --git a/www/source.html b/www/source.html index a92fdb5856ac..86a3bda10a76 100755 --- a/www/source.html +++ b/www/source.html @@ -29,53 +29,53 @@ <p> For non-Mac platforms, and for MacOSX building with CMake (not Xcode), you should check out your sources to adhere to the following directory structure: - <pre><tt>
- llvm
- |
- `-- tools
- |
- +-- clang
- |
- `-- lldb
- </tt></pre>
+ <pre><tt> + llvm + | + `-- tools + | + +-- clang + | + `-- lldb + </tt></pre> </p> - <p>
- For MacOSX building from Xcode, simply checkout LLDB and then build from Xcode. The Xcode project will
- automatically detect that it is a fresh checkout, and checkout LLVM and clang automatically. Unlike other
- platforms / build systems, it will use the following directory structure.
- <pre><tt>
- lldb
- |
- `-- llvm
- |
- +-- tools
- |
- `-- clang
- </tt>
- </pre>
- So updating your checkout will consist of updating lldb, llvm, and clang in these locations.
- </p>
- <p>
- Refer to the <a href="build.html">Build Instructions</a> for more detailed instructions on how to build for a particular
- platform / build system combination.
+ <p> + For MacOSX building from Xcode, simply checkout LLDB and then build from Xcode. The Xcode project will + automatically detect that it is a fresh checkout, and checkout LLVM and clang automatically. Unlike other + platforms / build systems, it will use the following directory structure. + <pre><tt> + lldb + | + `-- llvm + | + +-- tools + | + `-- clang + </tt> + </pre> + So updating your checkout will consist of updating lldb, llvm, and clang in these locations. + </p> + <p> + Refer to the <a href="build.html">Build Instructions</a> for more detailed instructions on how to build for a particular + platform / build system combination. </p> </div> </div> <div class="post"> <h1 class ="postheader">Contributing to LLDB</h1> <div class="postcontent"> - <p>
- Please refer to the <a href="http://llvm.org/docs/DeveloperPolicy.html">LLVM Developer Policy</a>
- for information about authoring and uploading a patch. LLDB differs from the LLVM Developer Policy in
- the following respects.
- <ul>
- <li>Coding conventions. Refer to <a href="lldb-coding-conventions.html">LLDB Coding Conventions</a>.</li>
- <li>
- Test infrastructure. It is still important to submit tests with your patches, but LLDB uses a different
- system for tests. Refer to the lldb/test folder on disk for examples of how to write tests.
- </li>
- </ul>
- For anything not explicitly listed here, assume that LLDB follows the LLVM policy.
+ <p> + Please refer to the <a href="http://llvm.org/docs/DeveloperPolicy.html">LLVM Developer Policy</a> + for information about authoring and uploading a patch. LLDB differs from the LLVM Developer Policy in + the following respects. + <ul> + <li>Coding conventions. Refer to <a href="lldb-coding-conventions.html">LLDB Coding Conventions</a>.</li> + <li> + Test infrastructure. It is still important to submit tests with your patches, but LLDB uses a different + system for tests. Refer to the lldb/test folder on disk for examples of how to write tests. + </li> + </ul> + For anything not explicitly listed here, assume that LLDB follows the LLVM policy. </p> </div> <div class="postfooter"></div> |