forked from OSchip/llvm-project
llgs: add proper exec support for Linux.
This change: * properly captures execs in NativeProcessLinux. * clears out all non-main-thread thread metadata in NativeProcessLinux on exec. * adds a DidExec() method to the NativeProcessProtocol delegate. * clears out the auxv data cache when we exec (on Linux). This is a small part of the llgs for local Linux debugging work going on here: https://github.com/tfiala/lldb/tree/dev-llgs-local I'm breaking it into small patches. llvm-svn: 216670
This commit is contained in:
parent
a8833f0c28
commit
a9882cee50
|
@ -325,6 +325,21 @@ NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType s
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
NativeProcessProtocol::NotifyDidExec ()
|
||||
{
|
||||
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__);
|
||||
|
||||
{
|
||||
Mutex::Locker locker (m_delegates_mutex);
|
||||
for (auto native_delegate: m_delegates)
|
||||
native_delegate->DidExec (this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Error
|
||||
NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint)
|
||||
{
|
||||
|
|
|
@ -230,6 +230,9 @@ namespace lldb_private
|
|||
|
||||
virtual void
|
||||
ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) = 0;
|
||||
|
||||
virtual void
|
||||
DidExec (NativeProcessProtocol *process) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -311,6 +314,15 @@ namespace lldb_private
|
|||
virtual Error
|
||||
GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) = 0;
|
||||
|
||||
// -----------------------------------------------------------
|
||||
/// Notify the delegate that an exec occurred.
|
||||
///
|
||||
/// Provide a mechanism for a delegate to clear out any exec-
|
||||
/// sensitive data.
|
||||
// -----------------------------------------------------------
|
||||
void
|
||||
NotifyDidExec ();
|
||||
|
||||
private:
|
||||
|
||||
void
|
||||
|
|
|
@ -1953,19 +1953,31 @@ NativeProcessLinux::MonitorCallback(void *callback_baton,
|
|||
if (ptrace_err == EINVAL)
|
||||
{
|
||||
// This is the first part of the Linux ptrace group-stop mechanism.
|
||||
// (The other thing it can conceivably be is a call on a pid that no
|
||||
// longer exists for some reason).
|
||||
// The tracer (i.e. NativeProcessLinux) is expected to inject the signal
|
||||
// into the tracee (i.e. inferior) at this point.
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() resuming from group-stop", __FUNCTION__);
|
||||
log->Printf ("NativeProcessLinux::%s resuming from group-stop", __FUNCTION__);
|
||||
|
||||
// The inferior process is in 'group-stop', so deliver the stopping signal.
|
||||
const bool signal_delivered = process->Resume (pid, info.si_signo);
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " group-stop signal delivery of signal 0x%x (%s) - %s", __FUNCTION__, pid, info.si_signo, GetUnixSignals ().GetSignalAsCString (info.si_signo), signal_delivered ? "success" : "failed");
|
||||
log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " group-stop signal delivery of signal 0x%x (%s) - %s", __FUNCTION__, pid, info.si_signo, GetUnixSignals ().GetSignalAsCString (info.si_signo), signal_delivered ? "success" : "failed");
|
||||
|
||||
assert(signal_delivered && "SIGSTOP delivery failed while in 'group-stop' state");
|
||||
if (signal_delivered)
|
||||
{
|
||||
// All is well.
|
||||
stop_monitoring = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " something looks horribly wrong - like the process we're monitoring died. Stop monitoring it.", __FUNCTION__, pid);
|
||||
|
||||
stop_monitoring = false;
|
||||
// Stop monitoring now.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2079,10 +2091,63 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
}
|
||||
|
||||
case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)):
|
||||
{
|
||||
NativeThreadProtocolSP main_thread_sp;
|
||||
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() received exec event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP);
|
||||
// FIXME stop all threads, mark thread stop reason as ThreadStopInfo.reason = eStopReasonExec;
|
||||
|
||||
// Remove all but the main thread here.
|
||||
// FIXME check if we really need to do this - how does ptrace behave under exec when multiple threads were present
|
||||
// before the exec? If we get all the detach signals right, we don't need to do this. However, it makes it clearer
|
||||
// what we should really be tracking.
|
||||
{
|
||||
Mutex::Locker locker (m_threads_mutex);
|
||||
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s exec received, stop tracking all but main thread", __FUNCTION__);
|
||||
|
||||
for (auto thread_sp : m_threads)
|
||||
{
|
||||
const bool is_main_thread = thread_sp && thread_sp->GetID () == GetID ();
|
||||
if (is_main_thread)
|
||||
{
|
||||
main_thread_sp = thread_sp;
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s found main thread with tid %" PRIu64 ", keeping", __FUNCTION__, main_thread_sp->GetID ());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s discarding non-main-thread tid %" PRIu64 " due to exec", __FUNCTION__, thread_sp->GetID ());
|
||||
}
|
||||
}
|
||||
|
||||
m_threads.clear ();
|
||||
|
||||
if (main_thread_sp)
|
||||
{
|
||||
m_threads.push_back (main_thread_sp);
|
||||
SetCurrentThreadID (main_thread_sp->GetID ());
|
||||
reinterpret_cast<NativeThreadLinux*>(main_thread_sp.get())->SetStoppedByExec ();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentThreadID (LLDB_INVALID_THREAD_ID);
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s pid %" PRIu64 "no main thread found, discarded all threads, we're in a no-thread state!", __FUNCTION__, GetID ());
|
||||
}
|
||||
}
|
||||
|
||||
// Let our delegate know we have just exec'd.
|
||||
NotifyDidExec ();
|
||||
|
||||
// If we have a main thread, indicate we are stopped.
|
||||
assert (main_thread_sp && "exec called during ptraced process but no main thread metadata tracked");
|
||||
SetState (StateType::eStateStopped);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
|
||||
{
|
||||
|
|
|
@ -34,13 +34,16 @@ namespace
|
|||
switch (stop_info.reason)
|
||||
{
|
||||
case eStopReasonSignal:
|
||||
log.Printf ("%s: %s: signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
|
||||
log.Printf ("%s: %s signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
|
||||
return;
|
||||
case eStopReasonException:
|
||||
log.Printf ("%s: %s: exception type 0x%" PRIx64, __FUNCTION__, header, stop_info.details.exception.type);
|
||||
log.Printf ("%s: %s exception type 0x%" PRIx64, __FUNCTION__, header, stop_info.details.exception.type);
|
||||
return;
|
||||
case eStopReasonExec:
|
||||
log.Printf ("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
|
||||
return;
|
||||
default:
|
||||
log.Printf ("%s: %s: invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast<uint32_t> (stop_info.reason));
|
||||
log.Printf ("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast<uint32_t> (stop_info.reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,10 +86,10 @@ NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info)
|
|||
case eStateSuspended:
|
||||
case eStateUnloaded:
|
||||
if (log)
|
||||
LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread: ");
|
||||
LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:");
|
||||
stop_info = m_stop_info;
|
||||
if (log)
|
||||
LogThreadStopInfo (*log, stop_info, "returned stop_info: ");
|
||||
LogThreadStopInfo (*log, stop_info, "returned stop_info:");
|
||||
return true;
|
||||
|
||||
case eStateInvalid:
|
||||
|
@ -245,6 +248,21 @@ NativeThreadLinux::SetStoppedBySignal (uint32_t signo)
|
|||
m_stop_info.details.signal.signo = signo;
|
||||
}
|
||||
|
||||
void
|
||||
NativeThreadLinux::SetStoppedByExec ()
|
||||
{
|
||||
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("NativeThreadLinux::%s()", __FUNCTION__);
|
||||
|
||||
const StateType new_state = StateType::eStateStopped;
|
||||
MaybeLogStateChange (new_state);
|
||||
m_state = new_state;
|
||||
|
||||
m_stop_info.reason = StopReason::eStopReasonExec;
|
||||
m_stop_info.details.signal.signo = SIGSTOP;
|
||||
}
|
||||
|
||||
void
|
||||
NativeThreadLinux::SetStoppedByBreakpoint ()
|
||||
{
|
||||
|
|
|
@ -64,6 +64,9 @@ namespace lldb_private
|
|||
void
|
||||
SetStoppedBySignal (uint32_t signo);
|
||||
|
||||
void
|
||||
SetStoppedByExec ();
|
||||
|
||||
void
|
||||
SetStoppedByBreakpoint ();
|
||||
|
||||
|
|
|
@ -1094,6 +1094,12 @@ GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessPr
|
|||
m_inferior_prev_state = state;
|
||||
}
|
||||
|
||||
void
|
||||
GDBRemoteCommunicationServer::DidExec (NativeProcessProtocol *process)
|
||||
{
|
||||
ClearProcessSpecificData ();
|
||||
}
|
||||
|
||||
GDBRemoteCommunication::PacketResult
|
||||
GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len)
|
||||
{
|
||||
|
@ -4289,3 +4295,20 @@ GDBRemoteCommunicationServer::GetNextSavedRegistersID ()
|
|||
return m_next_saved_registers_id++;
|
||||
}
|
||||
|
||||
void
|
||||
GDBRemoteCommunicationServer::ClearProcessSpecificData ()
|
||||
{
|
||||
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationServer::%s()", __FUNCTION__);
|
||||
|
||||
// Clear any auxv cached data.
|
||||
// *BSD impls should be able to do this too.
|
||||
#if defined(__linux__)
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationServer::%s clearing auxv buffer (previously %s)",
|
||||
__FUNCTION__,
|
||||
m_active_auxv_buffer_sp ? "was set" : "was not set");
|
||||
m_active_auxv_buffer_sp.reset ();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -218,6 +218,9 @@ public:
|
|||
void
|
||||
ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override;
|
||||
|
||||
void
|
||||
DidExec (lldb_private::NativeProcessProtocol *process) override;
|
||||
|
||||
protected:
|
||||
lldb::PlatformSP m_platform_sp;
|
||||
lldb::thread_t m_async_thread;
|
||||
|
@ -534,6 +537,9 @@ private:
|
|||
void
|
||||
MaybeCloseInferiorTerminalConnection ();
|
||||
|
||||
void
|
||||
ClearProcessSpecificData ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// For GDBRemoteCommunicationServer only
|
||||
//------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue