| //===-- NativeProcessLinux.h ---------------------------------- -*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef liblldb_NativeProcessLinux_H_ | |
| #define liblldb_NativeProcessLinux_H_ | |
| #include <csignal> | |
| #include <unordered_set> | |
| #include "lldb/Host/Debug.h" | |
| #include "lldb/Host/HostThread.h" | |
| #include "lldb/Host/linux/Support.h" | |
| #include "lldb/Target/MemoryRegionInfo.h" | |
| #include "lldb/Utility/ArchSpec.h" | |
| #include "lldb/Utility/FileSpec.h" | |
| #include "lldb/lldb-types.h" | |
| #include "NativeThreadLinux.h" | |
| #include "Plugins/Process/POSIX/NativeProcessELF.h" | |
| #include "ProcessorTrace.h" | |
| namespace lldb_private { | |
| class Status; | |
| class Scalar; | |
| namespace process_linux { | |
| /// \class NativeProcessLinux | |
| /// Manages communication with the inferior (debugee) process. | |
| /// | |
| /// Upon construction, this class prepares and launches an inferior process | |
| /// for debugging. | |
| /// | |
| /// Changes in the inferior process state are broadcasted. | |
| class NativeProcessLinux : public NativeProcessELF { | |
| public: | |
| class Factory : public NativeProcessProtocol::Factory { | |
| public: | |
| llvm::Expected<std::unique_ptr<NativeProcessProtocol>> | |
| Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, | |
| MainLoop &mainloop) const override; | |
| llvm::Expected<std::unique_ptr<NativeProcessProtocol>> | |
| Attach(lldb::pid_t pid, NativeDelegate &native_delegate, | |
| MainLoop &mainloop) const override; | |
| }; | |
| // NativeProcessProtocol Interface | |
| Status Resume(const ResumeActionList &resume_actions) override; | |
| Status Halt() override; | |
| Status Detach() override; | |
| Status Signal(int signo) override; | |
| Status Interrupt() override; | |
| Status Kill() override; | |
| Status GetMemoryRegionInfo(lldb::addr_t load_addr, | |
| MemoryRegionInfo &range_info) override; | |
| Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, | |
| size_t &bytes_read) override; | |
| Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, | |
| size_t &bytes_written) override; | |
| Status AllocateMemory(size_t size, uint32_t permissions, | |
| lldb::addr_t &addr) override; | |
| Status DeallocateMemory(lldb::addr_t addr) override; | |
| size_t UpdateThreads() override; | |
| const ArchSpec &GetArchitecture() const override { return m_arch; } | |
| Status SetBreakpoint(lldb::addr_t addr, uint32_t size, | |
| bool hardware) override; | |
| Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; | |
| void DoStopIDBumped(uint32_t newBumpId) override; | |
| Status GetLoadedModuleFileSpec(const char *module_path, | |
| FileSpec &file_spec) override; | |
| Status GetFileLoadAddress(const llvm::StringRef &file_name, | |
| lldb::addr_t &load_addr) override; | |
| NativeThreadLinux *GetThreadByID(lldb::tid_t id); | |
| llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> | |
| GetAuxvData() const override { | |
| return getProcFile(GetID(), "auxv"); | |
| } | |
| lldb::user_id_t StartTrace(const TraceOptions &config, | |
| Status &error) override; | |
| Status StopTrace(lldb::user_id_t traceid, | |
| lldb::tid_t thread) override; | |
| Status GetData(lldb::user_id_t traceid, lldb::tid_t thread, | |
| llvm::MutableArrayRef<uint8_t> &buffer, | |
| size_t offset = 0) override; | |
| Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread, | |
| llvm::MutableArrayRef<uint8_t> &buffer, | |
| size_t offset = 0) override; | |
| Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override; | |
| // Interface used by NativeRegisterContext-derived classes. | |
| static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, | |
| void *data = nullptr, size_t data_size = 0, | |
| long *result = nullptr); | |
| bool SupportHardwareSingleStepping() const; | |
| protected: | |
| llvm::Expected<llvm::ArrayRef<uint8_t>> | |
| GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; | |
| private: | |
| MainLoop::SignalHandleUP m_sigchld_handle; | |
| ArchSpec m_arch; | |
| LazyBool m_supports_mem_region = eLazyBoolCalculate; | |
| std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache; | |
| lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; | |
| // List of thread ids stepping with a breakpoint with the address of | |
| // the relevan breakpoint | |
| std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint; | |
| // Private Instance Methods | |
| NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, | |
| const ArchSpec &arch, MainLoop &mainloop, | |
| llvm::ArrayRef<::pid_t> tids); | |
| // Returns a list of process threads that we have attached to. | |
| static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid); | |
| static Status SetDefaultPtraceOpts(const lldb::pid_t); | |
| void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status); | |
| void WaitForNewThread(::pid_t tid); | |
| void MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread); | |
| void MonitorTrace(NativeThreadLinux &thread); | |
| void MonitorBreakpoint(NativeThreadLinux &thread); | |
| void MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index); | |
| void MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, | |
| bool exited); | |
| Status SetupSoftwareSingleStepping(NativeThreadLinux &thread); | |
| bool HasThreadNoLock(lldb::tid_t thread_id); | |
| bool StopTrackingThread(lldb::tid_t thread_id); | |
| NativeThreadLinux &AddThread(lldb::tid_t thread_id); | |
| /// Writes a siginfo_t structure corresponding to the given thread ID to the | |
| /// memory region pointed to by \p siginfo. | |
| Status GetSignalInfo(lldb::tid_t tid, void *siginfo); | |
| /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) | |
| /// corresponding to the given thread ID to the memory pointed to by @p | |
| /// message. | |
| Status GetEventMessage(lldb::tid_t tid, unsigned long *message); | |
| void NotifyThreadDeath(lldb::tid_t tid); | |
| Status Detach(lldb::tid_t tid); | |
| // This method is requests a stop on all threads which are still running. It | |
| // sets up a | |
| // deferred delegate notification, which will fire once threads report as | |
| // stopped. The | |
| // triggerring_tid will be set as the current thread (main stop reason). | |
| void StopRunningThreads(lldb::tid_t triggering_tid); | |
| // Notify the delegate if all threads have stopped. | |
| void SignalIfAllThreadsStopped(); | |
| // Resume the given thread, optionally passing it the given signal. The type | |
| // of resume | |
| // operation (continue, single-step) depends on the state parameter. | |
| Status ResumeThread(NativeThreadLinux &thread, lldb::StateType state, | |
| int signo); | |
| void ThreadWasCreated(NativeThreadLinux &thread); | |
| void SigchldHandler(); | |
| Status PopulateMemoryRegionCache(); | |
| lldb::user_id_t StartTraceGroup(const TraceOptions &config, | |
| Status &error); | |
| // This function is intended to be used to stop tracing | |
| // on a thread that exited. | |
| Status StopTracingForThread(lldb::tid_t thread); | |
| // The below function as the name suggests, looks up a ProcessorTrace | |
| // instance from the m_processor_trace_monitor map. In the case of | |
| // process tracing where the traceid passed would map to the complete | |
| // process, it is mandatory to provide a threadid to obtain a trace | |
| // instance (since ProcessorTrace is tied to a thread). In the other | |
| // scenario that an individual thread is being traced, just the traceid | |
| // is sufficient to obtain the actual ProcessorTrace instance. | |
| llvm::Expected<ProcessorTraceMonitor &> | |
| LookupProcessorTraceInstance(lldb::user_id_t traceid, lldb::tid_t thread); | |
| // Stops tracing on individual threads being traced. Not intended | |
| // to be used to stop tracing on complete process. | |
| Status StopProcessorTracingOnThread(lldb::user_id_t traceid, | |
| lldb::tid_t thread); | |
| // Intended to stop tracing on complete process. | |
| // Should not be used for stopping trace on | |
| // individual threads. | |
| void StopProcessorTracingOnProcess(); | |
| llvm::DenseMap<lldb::tid_t, ProcessorTraceMonitorUP> | |
| m_processor_trace_monitor; | |
| // Set for tracking threads being traced under | |
| // same process user id. | |
| llvm::DenseSet<lldb::tid_t> m_pt_traced_thread_group; | |
| lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID; | |
| TraceOptions m_pt_process_trace_config; | |
| }; | |
| } // namespace process_linux | |
| } // namespace lldb_private | |
| #endif // #ifndef liblldb_NativeProcessLinux_H_ |