[Lldb-commits] [lldb] r235494 - Fix signle stepping on arm when multiple thread is involved

Tamas Berghammer tberghammer at google.com
Wed Apr 22 03:00:23 PDT 2015


Author: tberghammer
Date: Wed Apr 22 05:00:23 2015
New Revision: 235494

URL: http://llvm.org/viewvc/llvm-project?rev=235494&view=rev
Log:
Fix signle stepping on arm when multiple thread is involved

On linux-arm we use software single stepping where setting the new
breakpoint is only possible while the process is in stopped state.
This CL moves the setup code for single stepping form the SigneStep
operation into the Resum method to avoid an error when the process
already started when we want to step one of the thread.

Differential revision: http://reviews.llvm.org/D9108

Modified:
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=235494&r1=235493&r2=235494&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Wed Apr 22 05:00:23 2015
@@ -2782,6 +2782,178 @@ NativeProcessLinux::MonitorSignal(const
                                  });
 }
 
+namespace {
+
+struct EmulatorBaton
+{
+    NativeProcessLinux* m_process;
+    NativeRegisterContext* m_reg_context;
+    RegisterValue m_pc;
+    RegisterValue m_flags;
+
+    EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) : 
+            m_process(process), m_reg_context(reg_context) {}
+};
+
+} // anonymous namespace
+
+static size_t
+ReadMemoryCallback (EmulateInstruction *instruction,
+                    void *baton,
+                    const EmulateInstruction::Context &context, 
+                    lldb::addr_t addr, 
+                    void *dst,
+                    size_t length)
+{
+    EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+    lldb::addr_t bytes_read;
+    emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
+    return bytes_read;
+}
+
+static bool
+ReadRegisterCallback (EmulateInstruction *instruction,
+                      void *baton,
+                      const RegisterInfo *reg_info,
+                      RegisterValue &reg_value)
+{
+    EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+    // The emulator only fill in the dwarf regsiter numbers (and in some case
+    // the generic register numbers). Get the full register info from the
+    // register context based on the dwarf register numbers.
+    const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo(
+            eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
+
+    Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
+    return error.Success();
+}
+
+static bool
+WriteRegisterCallback (EmulateInstruction *instruction,
+                       void *baton,
+                       const EmulateInstruction::Context &context,
+                       const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value)
+{
+    EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+    switch (reg_info->kinds[eRegisterKindGeneric])
+    {
+    case LLDB_REGNUM_GENERIC_PC:
+        emulator_baton->m_pc = reg_value;
+        break;
+    case LLDB_REGNUM_GENERIC_FLAGS:
+        emulator_baton->m_flags = reg_value;
+        break;
+    }
+
+    return true;
+}
+
+static size_t
+WriteMemoryCallback (EmulateInstruction *instruction,
+                     void *baton,
+                     const EmulateInstruction::Context &context, 
+                     lldb::addr_t addr, 
+                     const void *dst,
+                     size_t length)
+{
+    return length;
+}
+
+static lldb::addr_t
+ReadFlags (NativeRegisterContext* regsiter_context)
+{
+    const RegisterInfo* flags_info = regsiter_context->GetRegisterInfo(
+            eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+    return regsiter_context->ReadRegisterAsUnsigned(flags_info, LLDB_INVALID_ADDRESS);
+}
+
+Error
+NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadProtocolSP thread_sp)
+{
+    Error error;
+    NativeRegisterContextSP register_context_sp = thread_sp->GetRegisterContext();
+
+    std::unique_ptr<EmulateInstruction> emulator_ap(
+        EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, nullptr));
+
+    if (emulator_ap == nullptr)
+        return Error("Instruction emulator not found!");
+
+    EmulatorBaton baton(this, register_context_sp.get());
+    emulator_ap->SetBaton(&baton);
+    emulator_ap->SetReadMemCallback(&ReadMemoryCallback);
+    emulator_ap->SetReadRegCallback(&ReadRegisterCallback);
+    emulator_ap->SetWriteMemCallback(&WriteMemoryCallback);
+    emulator_ap->SetWriteRegCallback(&WriteRegisterCallback);
+
+    if (!emulator_ap->ReadInstruction())
+        return Error("Read instruction failed!");
+
+    lldb::addr_t next_pc;
+    lldb::addr_t next_flags;
+    if (emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC))
+    {
+        next_pc = baton.m_pc.GetAsUInt64();
+        if (baton.m_flags.GetType() != RegisterValue::eTypeInvalid)
+            next_flags = baton.m_flags.GetAsUInt32();
+        else
+            next_flags = ReadFlags (register_context_sp.get());
+    }
+    else if (baton.m_pc.GetType() == RegisterValue::eTypeInvalid)
+    {
+        // Emulate instruction failed and it haven't changed PC. Advance PC
+        // with the size of the current opcode because the emulation of all
+        // PC modifying instruction should be successful. The failure most
+        // likely caused by a not supported instruction which don't modify PC.
+        next_pc = register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize();
+        next_flags = ReadFlags (register_context_sp.get());
+    }
+    else
+    {
+        // The instruction emulation failed after it modified the PC. It is an
+        // unknown error where we can't continue because the next instruction is
+        // modifying the PC but we don't  know how.
+        return Error ("Instruction emulation failed unexpectedly.");
+    }
+
+    if (m_arch.GetMachine() == llvm::Triple::arm)
+    {
+        if (next_flags & 0x20)
+        {
+            // Thumb mode
+            error = SetSoftwareBreakpoint(next_pc, 2);
+        }
+        else
+        {
+            // Arm mode
+            error = SetSoftwareBreakpoint(next_pc, 4);
+        }
+    }
+    else
+    {
+        // No size hint is given for the next breakpoint
+        error = SetSoftwareBreakpoint(next_pc, 0);
+    }
+
+
+    if (error.Fail())
+        return error;
+
+    m_threads_stepping_with_breakpoint.insert({thread_sp->GetID(), next_pc});
+
+    return Error();
+}
+
+bool
+NativeProcessLinux::SupportHardwareSingleStepping() const
+{
+    return m_arch.GetMachine() != llvm::Triple::arm;
+}
+
 Error
 NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
 {
@@ -2794,9 +2966,29 @@ NativeProcessLinux::Resume (const Resume
     int deferred_signo = 0;
     NativeThreadProtocolSP deferred_signal_thread_sp;
     bool stepping = false;
+    bool software_single_step = !SupportHardwareSingleStepping();
 
     Mutex::Locker locker (m_threads_mutex);
 
+    if (software_single_step)
+    {
+        for (auto thread_sp : m_threads)
+        {
+            assert (thread_sp && "thread list should not contain NULL threads");
+
+            const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
+            if (action == nullptr)
+                continue;
+
+            if (action->state == eStateStepping)
+            {
+                Error error = SetupSoftwareSingleStepping(thread_sp);
+                if (error.Fail())
+                    return error;
+            }
+        }
+    }
+
     for (auto thread_sp : m_threads)
     {
         assert (thread_sp && "thread list should not contain NULL threads");
@@ -2845,7 +3037,13 @@ NativeProcessLinux::Resume (const Resume
                                                    [=](lldb::tid_t tid_to_step, bool supress_signal)
                                                    {
                                                        std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetStepping ();
-                                                       const auto step_result = SingleStep (tid_to_step,(signo > 0 && !supress_signal) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
+
+                                                       Error step_result;
+                                                       if (software_single_step)
+                                                           step_result = Resume (tid_to_step, (signo > 0 && !supress_signal) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
+                                                       else
+                                                           step_result = SingleStep (tid_to_step,(signo > 0 && !supress_signal) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
+
                                                        assert (step_result.Success() && "SingleStep() failed");
                                                        if (step_result.Success())
                                                            SetState(eStateStepping, true);
@@ -3700,171 +3898,6 @@ NativeProcessLinux::Resume (lldb::tid_t
     return op.GetError();
 }
 
-#if defined(__arm__)
-
-namespace {
-
-struct EmulatorBaton
-{
-    NativeProcessLinux* m_process;
-    NativeRegisterContext* m_reg_context;
-    RegisterValue m_pc;
-    RegisterValue m_cpsr;
-
-    EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) : 
-            m_process(process), m_reg_context(reg_context) {}
-};
-
-} // anonymous namespace
-
-static size_t
-ReadMemoryCallback (EmulateInstruction *instruction,
-                    void *baton,
-                    const EmulateInstruction::Context &context, 
-                    lldb::addr_t addr, 
-                    void *dst,
-                    size_t length)
-{
-    EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
-
-    lldb::addr_t bytes_read;
-    emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
-    return bytes_read;
-}
-
-static bool
-ReadRegisterCallback (EmulateInstruction *instruction,
-                      void *baton,
-                      const RegisterInfo *reg_info,
-                      RegisterValue &reg_value)
-{
-    EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
-
-    // The emulator only fill in the dwarf regsiter numbers (and in some case
-    // the generic register numbers). Get the full register info from the
-    // register context based on the dwarf register numbers.
-    const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo(
-            eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
-
-    Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
-    return error.Success();
-}
-
-static bool
-WriteRegisterCallback (EmulateInstruction *instruction,
-                       void *baton,
-                       const EmulateInstruction::Context &context,
-                       const RegisterInfo *reg_info,
-                       const RegisterValue &reg_value)
-{
-    EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
-
-    switch (reg_info->kinds[eRegisterKindGeneric])
-    {
-    case LLDB_REGNUM_GENERIC_PC:
-        emulator_baton->m_pc = reg_value;
-        break;
-    case LLDB_REGNUM_GENERIC_FLAGS:
-        emulator_baton->m_cpsr = reg_value;
-        break;
-    }
-
-    return true;
-}
-
-static size_t
-WriteMemoryCallback (EmulateInstruction *instruction,
-                     void *baton,
-                     const EmulateInstruction::Context &context, 
-                     lldb::addr_t addr, 
-                     const void *dst,
-                     size_t length)
-{
-    return length;
-}
-
-static lldb::addr_t
-ReadCpsr (NativeRegisterContext* regsiter_context)
-{
-    const RegisterInfo* cpsr_info = regsiter_context->GetRegisterInfo(
-            eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
-    return regsiter_context->ReadRegisterAsUnsigned(cpsr_info, LLDB_INVALID_ADDRESS);
-}
-
-Error
-NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
-{
-    Error error;
-    NativeRegisterContextSP register_context_sp = GetThreadByID(tid)->GetRegisterContext();
-
-    std::unique_ptr<EmulateInstruction> emulator_ap(
-        EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, nullptr));
-
-    if (emulator_ap == nullptr)
-        return Error("Instruction emulator not found!");
-
-    EmulatorBaton baton(this, register_context_sp.get());
-    emulator_ap->SetBaton(&baton);
-    emulator_ap->SetReadMemCallback(&ReadMemoryCallback);
-    emulator_ap->SetReadRegCallback(&ReadRegisterCallback);
-    emulator_ap->SetWriteMemCallback(&WriteMemoryCallback);
-    emulator_ap->SetWriteRegCallback(&WriteRegisterCallback);
-
-    if (!emulator_ap->ReadInstruction())
-        return Error("Read instruction failed!");
-
-    lldb::addr_t next_pc;
-    lldb::addr_t next_cpsr;
-    if (emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC))
-    {
-        next_pc = baton.m_pc.GetAsUInt32();
-        if (baton.m_cpsr.GetType() != RegisterValue::eTypeInvalid)
-            next_cpsr = baton.m_cpsr.GetAsUInt32();
-        else
-            next_cpsr = ReadCpsr (register_context_sp.get());
-    }
-    else if (baton.m_pc.GetType() == RegisterValue::eTypeInvalid)
-    {
-        // Emulate instruction failed and it haven't changed PC. Advance PC
-        // with the size of the current opcode because the emulation of all
-        // PC modifying instruction should be successful. The failure most
-        // likely caused by a not supported instruction which don't modify PC.
-        next_pc = register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize();
-        next_cpsr = ReadCpsr (register_context_sp.get());
-    }
-    else
-    {
-        // The instruction emulation failed after it modified the PC. It is an
-        // unknown error where we can't continue because the next instruction is
-        // modifying the PC but we don't  know how.
-        return Error ("Instruction emulation failed unexpectedly.");
-    }
-
-    if (next_cpsr & 0x20)
-    {
-        // Thumb mode
-        error = SetBreakpoint(next_pc, 2, false);
-    }
-    else
-    {
-        // Arm mode
-        error = SetBreakpoint(next_pc, 4, false);
-    }
-
-    if (error.Fail())
-        return error;
-
-    m_threads_stepping_with_breakpoint.insert({tid, next_pc});
-
-    error = Resume(tid, signo);
-    if (error.Fail())
-        return error;
-
-    return Error();
-}
-
-#else // defined(__arm__)
-
 Error
 NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
 {
@@ -3873,8 +3906,6 @@ NativeProcessLinux::SingleStep(lldb::tid
     return op.GetError();
 }
 
-#endif // defined(__arm__)
-
 Error
 NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo)
 {

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=235494&r1=235493&r2=235494&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Wed Apr 22 05:00:23 2015
@@ -277,6 +277,12 @@ namespace process_linux {
         void
         MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited);
 
+        bool
+        SupportHardwareSingleStepping() const;
+
+        Error
+        SetupSoftwareSingleStepping(NativeThreadProtocolSP thread_sp);
+
 #if 0
         static ::ProcessMessage::CrashReason
         GetCrashReasonForSIGSEGV(const siginfo_t *info);





More information about the lldb-commits mailing list