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