1 | //===-- NativeProcessProtocol.h ---------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLDB_HOST_COMMON_NATIVEPROCESSPROTOCOL_H |
10 | #define LLDB_HOST_COMMON_NATIVEPROCESSPROTOCOL_H |
11 | |
12 | #include "NativeBreakpointList.h" |
13 | #include "NativeThreadProtocol.h" |
14 | #include "NativeWatchpointList.h" |
15 | #include "lldb/Host/Host.h" |
16 | #include "lldb/Host/MainLoop.h" |
17 | #include "lldb/Utility/ArchSpec.h" |
18 | #include "lldb/Utility/Iterable.h" |
19 | #include "lldb/Utility/Status.h" |
20 | #include "lldb/Utility/TraceGDBRemotePackets.h" |
21 | #include "lldb/Utility/UnimplementedError.h" |
22 | #include "lldb/lldb-private-forward.h" |
23 | #include "lldb/lldb-types.h" |
24 | #include "llvm/ADT/ArrayRef.h" |
25 | #include "llvm/ADT/DenseSet.h" |
26 | #include "llvm/ADT/StringRef.h" |
27 | #include "llvm/Support/Error.h" |
28 | #include "llvm/Support/MemoryBuffer.h" |
29 | #include <mutex> |
30 | #include <optional> |
31 | #include <unordered_map> |
32 | #include <vector> |
33 | |
34 | namespace lldb_private { |
35 | LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); |
36 | |
37 | class MemoryRegionInfo; |
38 | class ResumeActionList; |
39 | |
40 | struct SVR4LibraryInfo { |
41 | std::string name; |
42 | lldb::addr_t link_map; |
43 | lldb::addr_t base_addr; |
44 | lldb::addr_t ld_addr; |
45 | lldb::addr_t next; |
46 | }; |
47 | |
48 | // NativeProcessProtocol |
49 | class NativeProcessProtocol { |
50 | public: |
51 | virtual ~NativeProcessProtocol() = default; |
52 | |
53 | typedef std::vector<std::unique_ptr<NativeThreadProtocol>> thread_collection; |
54 | template <typename I> |
55 | static NativeThreadProtocol &thread_list_adapter(I &iter) { |
56 | assert(*iter); |
57 | return **iter; |
58 | } |
59 | typedef LockingAdaptedIterable<thread_collection, NativeThreadProtocol &, |
60 | thread_list_adapter, std::recursive_mutex> |
61 | ThreadIterable; |
62 | |
63 | virtual Status Resume(const ResumeActionList &resume_actions) = 0; |
64 | |
65 | virtual Status Halt() = 0; |
66 | |
67 | virtual Status Detach() = 0; |
68 | |
69 | /// Sends a process a UNIX signal \a signal. |
70 | /// |
71 | /// \return |
72 | /// Returns an error object. |
73 | virtual Status Signal(int signo) = 0; |
74 | |
75 | /// Tells a process to interrupt all operations as if by a Ctrl-C. |
76 | /// |
77 | /// The default implementation will send a local host's equivalent of |
78 | /// a SIGSTOP to the process via the NativeProcessProtocol::Signal() |
79 | /// operation. |
80 | /// |
81 | /// \return |
82 | /// Returns an error object. |
83 | virtual Status Interrupt(); |
84 | |
85 | virtual Status Kill() = 0; |
86 | |
87 | // Tells a process not to stop the inferior on given signals and just |
88 | // reinject them back. |
89 | virtual Status IgnoreSignals(llvm::ArrayRef<int> signals); |
90 | |
91 | // Memory and memory region functions |
92 | |
93 | virtual Status GetMemoryRegionInfo(lldb::addr_t load_addr, |
94 | MemoryRegionInfo &range_info); |
95 | |
96 | virtual Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, |
97 | size_t &bytes_read) = 0; |
98 | |
99 | Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, |
100 | size_t &bytes_read); |
101 | |
102 | virtual Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, |
103 | std::vector<uint8_t> &tags); |
104 | |
105 | virtual Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, |
106 | const std::vector<uint8_t> &tags); |
107 | |
108 | /// Reads a null terminated string from memory. |
109 | /// |
110 | /// Reads up to \p max_size bytes of memory until it finds a '\0'. |
111 | /// If a '\0' is not found then it reads max_size-1 bytes as a string and a |
112 | /// '\0' is added as the last character of the \p buffer. |
113 | /// |
114 | /// \param[in] addr |
115 | /// The address in memory to read from. |
116 | /// |
117 | /// \param[in] buffer |
118 | /// An allocated buffer with at least \p max_size size. |
119 | /// |
120 | /// \param[in] max_size |
121 | /// The maximum number of bytes to read from memory until it reads the |
122 | /// string. |
123 | /// |
124 | /// \param[out] total_bytes_read |
125 | /// The number of bytes read from memory into \p buffer. |
126 | /// |
127 | /// \return |
128 | /// Returns a StringRef backed up by the \p buffer passed in. |
129 | llvm::Expected<llvm::StringRef> |
130 | ReadCStringFromMemory(lldb::addr_t addr, char *buffer, size_t max_size, |
131 | size_t &total_bytes_read); |
132 | |
133 | virtual Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, |
134 | size_t &bytes_written) = 0; |
135 | |
136 | virtual llvm::Expected<lldb::addr_t> AllocateMemory(size_t size, |
137 | uint32_t permissions) { |
138 | return llvm::make_error<UnimplementedError>(); |
139 | } |
140 | |
141 | virtual llvm::Error DeallocateMemory(lldb::addr_t addr) { |
142 | return llvm::make_error<UnimplementedError>(); |
143 | } |
144 | |
145 | virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0; |
146 | |
147 | virtual llvm::Expected<std::vector<SVR4LibraryInfo>> |
148 | GetLoadedSVR4Libraries() { |
149 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
150 | Msg: "Not implemented" ); |
151 | } |
152 | |
153 | virtual bool IsAlive() const; |
154 | |
155 | virtual size_t UpdateThreads() = 0; |
156 | |
157 | virtual const ArchSpec &GetArchitecture() const = 0; |
158 | |
159 | // Breakpoint functions |
160 | virtual Status SetBreakpoint(lldb::addr_t addr, uint32_t size, |
161 | bool hardware) = 0; |
162 | |
163 | virtual Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false); |
164 | |
165 | // Hardware Breakpoint functions |
166 | virtual const HardwareBreakpointMap &GetHardwareBreakpointMap() const; |
167 | |
168 | virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size); |
169 | |
170 | virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr); |
171 | |
172 | // Watchpoint functions |
173 | virtual const NativeWatchpointList::WatchpointMap &GetWatchpointMap() const; |
174 | |
175 | virtual std::optional<std::pair<uint32_t, uint32_t>> |
176 | GetHardwareDebugSupportInfo() const; |
177 | |
178 | virtual Status SetWatchpoint(lldb::addr_t addr, size_t size, |
179 | uint32_t watch_flags, bool hardware); |
180 | |
181 | virtual Status RemoveWatchpoint(lldb::addr_t addr); |
182 | |
183 | // Accessors |
184 | lldb::pid_t GetID() const { return m_pid; } |
185 | |
186 | lldb::StateType GetState() const; |
187 | |
188 | bool IsRunning() const { |
189 | return m_state == lldb::eStateRunning || IsStepping(); |
190 | } |
191 | |
192 | bool IsStepping() const { return m_state == lldb::eStateStepping; } |
193 | |
194 | bool CanResume() const { return m_state == lldb::eStateStopped; } |
195 | |
196 | lldb::ByteOrder GetByteOrder() const { |
197 | return GetArchitecture().GetByteOrder(); |
198 | } |
199 | |
200 | uint32_t GetAddressByteSize() const { |
201 | return GetArchitecture().GetAddressByteSize(); |
202 | } |
203 | |
204 | virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> |
205 | GetAuxvData() const = 0; |
206 | |
207 | // Exit Status |
208 | virtual std::optional<WaitStatus> GetExitStatus(); |
209 | |
210 | virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange); |
211 | |
212 | // Access to threads |
213 | NativeThreadProtocol *GetThreadAtIndex(uint32_t idx); |
214 | |
215 | NativeThreadProtocol *GetThreadByID(lldb::tid_t tid); |
216 | |
217 | void SetCurrentThreadID(lldb::tid_t tid) { m_current_thread_id = tid; } |
218 | |
219 | lldb::tid_t GetCurrentThreadID() const { return m_current_thread_id; } |
220 | |
221 | NativeThreadProtocol *GetCurrentThread() { |
222 | return GetThreadByID(tid: m_current_thread_id); |
223 | } |
224 | |
225 | ThreadIterable Threads() const { |
226 | return ThreadIterable(m_threads, m_threads_mutex); |
227 | } |
228 | |
229 | // Access to inferior stdio |
230 | virtual int GetTerminalFileDescriptor() { return m_terminal_fd; } |
231 | |
232 | // Stop id interface |
233 | |
234 | uint32_t GetStopID() const; |
235 | |
236 | // Callbacks for low-level process state changes |
237 | class NativeDelegate { |
238 | public: |
239 | virtual ~NativeDelegate() = default; |
240 | |
241 | virtual void InitializeDelegate(NativeProcessProtocol *process) = 0; |
242 | |
243 | virtual void ProcessStateChanged(NativeProcessProtocol *process, |
244 | lldb::StateType state) = 0; |
245 | |
246 | virtual void DidExec(NativeProcessProtocol *process) = 0; |
247 | |
248 | virtual void |
249 | NewSubprocess(NativeProcessProtocol *parent_process, |
250 | std::unique_ptr<NativeProcessProtocol> child_process) = 0; |
251 | }; |
252 | |
253 | virtual Status GetLoadedModuleFileSpec(const char *module_path, |
254 | FileSpec &file_spec) = 0; |
255 | |
256 | virtual Status GetFileLoadAddress(const llvm::StringRef &file_name, |
257 | lldb::addr_t &load_addr) = 0; |
258 | |
259 | /// Extension flag constants, returned by Manager::GetSupportedExtensions() |
260 | /// and passed to SetEnabledExtension() |
261 | enum class Extension { |
262 | multiprocess = (1u << 0), |
263 | fork = (1u << 1), |
264 | vfork = (1u << 2), |
265 | pass_signals = (1u << 3), |
266 | auxv = (1u << 4), |
267 | libraries_svr4 = (1u << 5), |
268 | memory_tagging = (1u << 6), |
269 | savecore = (1u << 7), |
270 | siginfo_read = (1u << 8), |
271 | |
272 | LLVM_MARK_AS_BITMASK_ENUM(siginfo_read) |
273 | }; |
274 | |
275 | class Manager { |
276 | public: |
277 | Manager(MainLoop &mainloop) : m_mainloop(mainloop) {} |
278 | Manager(const Manager &) = delete; |
279 | Manager &operator=(const Manager &) = delete; |
280 | |
281 | virtual ~Manager(); |
282 | |
283 | /// Launch a process for debugging. |
284 | /// |
285 | /// \param[in] launch_info |
286 | /// Information required to launch the process. |
287 | /// |
288 | /// \param[in] native_delegate |
289 | /// The delegate that will receive messages regarding the |
290 | /// inferior. Must outlive the NativeProcessProtocol |
291 | /// instance. |
292 | /// |
293 | /// \param[in] mainloop |
294 | /// The mainloop instance with which the process can register |
295 | /// callbacks. Must outlive the NativeProcessProtocol |
296 | /// instance. |
297 | /// |
298 | /// \return |
299 | /// A NativeProcessProtocol shared pointer if the operation succeeded or |
300 | /// an error object if it failed. |
301 | virtual llvm::Expected<std::unique_ptr<NativeProcessProtocol>> |
302 | Launch(ProcessLaunchInfo &launch_info, |
303 | NativeDelegate &native_delegate) = 0; |
304 | |
305 | /// Attach to an existing process. |
306 | /// |
307 | /// \param[in] pid |
308 | /// pid of the process locatable |
309 | /// |
310 | /// \param[in] native_delegate |
311 | /// The delegate that will receive messages regarding the |
312 | /// inferior. Must outlive the NativeProcessProtocol |
313 | /// instance. |
314 | /// |
315 | /// \param[in] mainloop |
316 | /// The mainloop instance with which the process can register |
317 | /// callbacks. Must outlive the NativeProcessProtocol |
318 | /// instance. |
319 | /// |
320 | /// \return |
321 | /// A NativeProcessProtocol shared pointer if the operation succeeded or |
322 | /// an error object if it failed. |
323 | virtual llvm::Expected<std::unique_ptr<NativeProcessProtocol>> |
324 | Attach(lldb::pid_t pid, NativeDelegate &native_delegate) = 0; |
325 | |
326 | /// Get the bitmask of extensions supported by this process plugin. |
327 | /// |
328 | /// \return |
329 | /// A NativeProcessProtocol::Extension bitmask. |
330 | virtual Extension GetSupportedExtensions() const { return {}; } |
331 | |
332 | protected: |
333 | MainLoop &m_mainloop; |
334 | }; |
335 | |
336 | /// Notify tracers that the target process will resume |
337 | virtual void NotifyTracersProcessWillResume() {} |
338 | |
339 | /// Notify tracers that the target process just stopped |
340 | virtual void NotifyTracersProcessDidStop() {} |
341 | |
342 | /// Start tracing a process or its threads. |
343 | /// |
344 | /// \param[in] json_params |
345 | /// JSON object with the information of what and how to trace. |
346 | /// In the case of gdb-remote, this object should conform to the |
347 | /// jLLDBTraceStart packet. |
348 | /// |
349 | /// This object should have a string entry called "type", which is the |
350 | /// tracing technology name. |
351 | /// |
352 | /// \param[in] type |
353 | /// Tracing technology type, as described in the \a json_params. |
354 | /// |
355 | /// \return |
356 | /// \a llvm::Error::success if the operation was successful, or an |
357 | /// \a llvm::Error otherwise. |
358 | virtual llvm::Error TraceStart(llvm::StringRef json_params, |
359 | llvm::StringRef type) { |
360 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
361 | Fmt: "Unsupported tracing type '%s'" , |
362 | Vals: type.data()); |
363 | } |
364 | |
365 | /// \copydoc Process::TraceStop(const TraceStopRequest &) |
366 | virtual llvm::Error TraceStop(const TraceStopRequest &request) { |
367 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
368 | Fmt: "Unsupported tracing type '%s'" , |
369 | Vals: request.type.data()); |
370 | } |
371 | |
372 | /// \copydoc Process::TraceGetState(llvm::StringRef type) |
373 | virtual llvm::Expected<llvm::json::Value> |
374 | TraceGetState(llvm::StringRef type) { |
375 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
376 | Fmt: "Unsupported tracing type '%s'" , |
377 | Vals: type.data()); |
378 | } |
379 | |
380 | /// \copydoc Process::TraceGetBinaryData(const TraceGetBinaryDataRequest &) |
381 | virtual llvm::Expected<std::vector<uint8_t>> |
382 | TraceGetBinaryData(const TraceGetBinaryDataRequest &request) { |
383 | return llvm::createStringError( |
384 | EC: llvm::inconvertibleErrorCode(), |
385 | Fmt: "Unsupported data kind '%s' for the '%s' tracing technology" , |
386 | Vals: request.kind.c_str(), Vals: request.type.c_str()); |
387 | } |
388 | |
389 | /// \copydoc Process::TraceSupported() |
390 | virtual llvm::Expected<TraceSupportedResponse> TraceSupported() { |
391 | return llvm::make_error<UnimplementedError>(); |
392 | } |
393 | |
394 | /// Method called in order to propagate the bitmap of protocol |
395 | /// extensions supported by the client. |
396 | /// |
397 | /// \param[in] flags |
398 | /// The bitmap of enabled extensions. |
399 | virtual void SetEnabledExtensions(Extension flags) { |
400 | m_enabled_extensions = flags; |
401 | } |
402 | |
403 | /// Write a core dump (without crashing the program). |
404 | /// |
405 | /// \param[in] path_hint |
406 | /// Suggested core dump path (optional, can be empty). |
407 | /// |
408 | /// \return |
409 | /// Path to the core dump if successfully written, an error |
410 | /// otherwise. |
411 | virtual llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) { |
412 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
413 | Msg: "Not implemented" ); |
414 | } |
415 | |
416 | protected: |
417 | struct SoftwareBreakpoint { |
418 | uint32_t ref_count; |
419 | llvm::SmallVector<uint8_t, 4> saved_opcodes; |
420 | llvm::ArrayRef<uint8_t> breakpoint_opcodes; |
421 | }; |
422 | |
423 | std::unordered_map<lldb::addr_t, SoftwareBreakpoint> m_software_breakpoints; |
424 | lldb::pid_t m_pid; |
425 | |
426 | std::vector<std::unique_ptr<NativeThreadProtocol>> m_threads; |
427 | lldb::tid_t m_current_thread_id = LLDB_INVALID_THREAD_ID; |
428 | mutable std::recursive_mutex m_threads_mutex; |
429 | |
430 | lldb::StateType m_state = lldb::eStateInvalid; |
431 | mutable std::recursive_mutex m_state_mutex; |
432 | |
433 | std::optional<WaitStatus> m_exit_status; |
434 | |
435 | NativeDelegate &m_delegate; |
436 | NativeWatchpointList m_watchpoint_list; |
437 | HardwareBreakpointMap m_hw_breakpoints_map; |
438 | int m_terminal_fd; |
439 | uint32_t m_stop_id = 0; |
440 | |
441 | // Set of signal numbers that LLDB directly injects back to inferior without |
442 | // stopping it. |
443 | llvm::DenseSet<int> m_signals_to_ignore; |
444 | |
445 | // Extensions enabled per the last SetEnabledExtensions() call. |
446 | Extension m_enabled_extensions; |
447 | |
448 | // lldb_private::Host calls should be used to launch a process for debugging, |
449 | // and then the process should be attached to. When attaching to a process |
450 | // lldb_private::Host calls should be used to locate the process to attach |
451 | // to, and then this function should be called. |
452 | NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, |
453 | NativeDelegate &delegate); |
454 | |
455 | void SetID(lldb::pid_t pid) { m_pid = pid; } |
456 | |
457 | // interface for state handling |
458 | void SetState(lldb::StateType state, bool notify_delegates = true); |
459 | |
460 | // Derived classes need not implement this. It can be used as a hook to |
461 | // clear internal caches that should be invalidated when stop ids change. |
462 | // |
463 | // Note this function is called with the state mutex obtained by the caller. |
464 | virtual void DoStopIDBumped(uint32_t newBumpId); |
465 | |
466 | // interface for software breakpoints |
467 | |
468 | Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint); |
469 | Status RemoveSoftwareBreakpoint(lldb::addr_t addr); |
470 | |
471 | virtual llvm::Expected<llvm::ArrayRef<uint8_t>> |
472 | GetSoftwareBreakpointTrapOpcode(size_t size_hint); |
473 | |
474 | /// Return the offset of the PC relative to the software breakpoint that was hit. If an |
475 | /// architecture (e.g. arm) reports breakpoint hits before incrementing the PC, this offset |
476 | /// will be 0. If an architecture (e.g. intel) reports breakpoints hits after incrementing the |
477 | /// PC, this offset will be the size of the breakpoint opcode. |
478 | virtual size_t GetSoftwareBreakpointPCOffset(); |
479 | |
480 | // Adjust the thread's PC after hitting a software breakpoint. On |
481 | // architectures where the PC points after the breakpoint instruction, this |
482 | // resets it to point to the breakpoint itself. |
483 | void FixupBreakpointPCAsNeeded(NativeThreadProtocol &thread); |
484 | |
485 | /// Notify the delegate that an exec occurred. |
486 | /// |
487 | /// Provide a mechanism for a delegate to clear out any exec- |
488 | /// sensitive data. |
489 | virtual void NotifyDidExec(); |
490 | |
491 | NativeThreadProtocol *GetThreadByIDUnlocked(lldb::tid_t tid); |
492 | |
493 | private: |
494 | void SynchronouslyNotifyProcessStateChanged(lldb::StateType state); |
495 | llvm::Expected<SoftwareBreakpoint> |
496 | EnableSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint); |
497 | }; |
498 | } // namespace lldb_private |
499 | |
500 | #endif // LLDB_HOST_COMMON_NATIVEPROCESSPROTOCOL_H |
501 | |