/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Host/common/NativeProcessProtocol.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | static NativeThreadProtocol &thread_list_adapter(I &iter) { |
56 | 0 | assert(*iter); |
57 | 0 | return **iter; |
58 | 0 | } |
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 | 0 | uint32_t permissions) { |
138 | 0 | return llvm::make_error<UnimplementedError>(); |
139 | 0 | } |
140 | | |
141 | 0 | virtual llvm::Error DeallocateMemory(lldb::addr_t addr) { |
142 | 0 | return llvm::make_error<UnimplementedError>(); |
143 | 0 | } |
144 | | |
145 | | virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0; |
146 | | |
147 | | virtual llvm::Expected<std::vector<SVR4LibraryInfo>> |
148 | 0 | GetLoadedSVR4Libraries() { |
149 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
150 | 0 | "Not implemented"); |
151 | 0 | } |
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 | 0 | lldb::pid_t GetID() const { return m_pid; } |
185 | | |
186 | | lldb::StateType GetState() const; |
187 | | |
188 | 0 | bool IsRunning() const { |
189 | 0 | return m_state == lldb::eStateRunning || IsStepping(); |
190 | 0 | } |
191 | | |
192 | 0 | bool IsStepping() const { return m_state == lldb::eStateStepping; } |
193 | | |
194 | 0 | bool CanResume() const { return m_state == lldb::eStateStopped; } |
195 | | |
196 | 0 | lldb::ByteOrder GetByteOrder() const { |
197 | 0 | return GetArchitecture().GetByteOrder(); |
198 | 0 | } |
199 | | |
200 | 0 | uint32_t GetAddressByteSize() const { |
201 | 0 | return GetArchitecture().GetAddressByteSize(); |
202 | 0 | } |
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 | 0 | void SetCurrentThreadID(lldb::tid_t tid) { m_current_thread_id = tid; } |
218 | | |
219 | 0 | lldb::tid_t GetCurrentThreadID() const { return m_current_thread_id; } |
220 | | |
221 | 0 | NativeThreadProtocol *GetCurrentThread() { |
222 | 0 | return GetThreadByID(m_current_thread_id); |
223 | 0 | } |
224 | | |
225 | 0 | ThreadIterable Threads() const { |
226 | 0 | return ThreadIterable(m_threads, m_threads_mutex); |
227 | 0 | } |
228 | | |
229 | | // Access to inferior stdio |
230 | 0 | 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 | 8 | 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 | 0 | 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 | 0 | virtual Extension GetSupportedExtensions() const { return {}; } |
331 | | |
332 | | protected: |
333 | | MainLoop &m_mainloop; |
334 | | }; |
335 | | |
336 | | /// Notify tracers that the target process will resume |
337 | 0 | virtual void NotifyTracersProcessWillResume() {} |
338 | | |
339 | | /// Notify tracers that the target process just stopped |
340 | 0 | 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 | 0 | llvm::StringRef type) { |
360 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
361 | 0 | "Unsupported tracing type '%s'", |
362 | 0 | type.data()); |
363 | 0 | } |
364 | | |
365 | | /// \copydoc Process::TraceStop(const TraceStopRequest &) |
366 | 0 | virtual llvm::Error TraceStop(const TraceStopRequest &request) { |
367 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
368 | 0 | "Unsupported tracing type '%s'", |
369 | 0 | request.type.data()); |
370 | 0 | } |
371 | | |
372 | | /// \copydoc Process::TraceGetState(llvm::StringRef type) |
373 | | virtual llvm::Expected<llvm::json::Value> |
374 | 0 | TraceGetState(llvm::StringRef type) { |
375 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
376 | 0 | "Unsupported tracing type '%s'", |
377 | 0 | type.data()); |
378 | 0 | } |
379 | | |
380 | | /// \copydoc Process::TraceGetBinaryData(const TraceGetBinaryDataRequest &) |
381 | | virtual llvm::Expected<std::vector<uint8_t>> |
382 | 0 | TraceGetBinaryData(const TraceGetBinaryDataRequest &request) { |
383 | 0 | return llvm::createStringError( |
384 | 0 | llvm::inconvertibleErrorCode(), |
385 | 0 | "Unsupported data kind '%s' for the '%s' tracing technology", |
386 | 0 | request.kind.c_str(), request.type.c_str()); |
387 | 0 | } |
388 | | |
389 | | /// \copydoc Process::TraceSupported() |
390 | 0 | virtual llvm::Expected<TraceSupportedResponse> TraceSupported() { |
391 | 0 | return llvm::make_error<UnimplementedError>(); |
392 | 0 | } |
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 | 0 | virtual void SetEnabledExtensions(Extension flags) { |
400 | 0 | m_enabled_extensions = flags; |
401 | 0 | } |
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 | 0 | virtual llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) { |
412 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
413 | 0 | "Not implemented"); |
414 | 0 | } |
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 | 0 | 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 |