LLDB mainline
NativeProcessAIX.cpp
Go to the documentation of this file.
1//===-- NativeProcessAIX.cpp ----------------------------------------------===//
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#include "NativeProcessAIX.h"
11#include "lldb/Host/Host.h"
12#include "lldb/Host/HostInfo.h"
17#include "lldb/Utility/Log.h"
18#include "lldb/Utility/State.h"
19#include "lldb/Utility/Status.h"
20#include "llvm/Support/Errno.h"
21#include "llvm/Support/Error.h"
22#include <cerrno>
23#include <cstdint>
24#include <cstring>
25#include <sstream>
26#include <string>
27#include <sys/ptrace.h>
28#include <unistd.h>
29
30using namespace lldb;
31using namespace lldb_private;
32using namespace lldb_private::process_aix;
33using namespace llvm;
34
35static constexpr unsigned k_ptrace_word_size = sizeof(void *);
36static_assert(sizeof(long) >= k_ptrace_word_size,
37 "Size of long must be larger than ptrace word size");
38
39// Simple helper function to ensure flags are enabled on the given file
40// descriptor.
41static llvm::Error SetFDFlags(int fd, int flags) {
42 int status = fcntl(fd, F_GETFL);
43 if (status == -1)
44 return errorCodeToError(errnoAsErrorCode());
45 if (fcntl(fd, F_SETFL, status | flags) == -1)
46 return errorCodeToError(errnoAsErrorCode());
47 return Error::success();
48}
49
51 : NativeProcessProtocol::Manager(mainloop) {
52 Status status;
54 SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
55 assert(m_sigchld_handle && status.Success());
56}
57
58// Public Static Methods
59
60llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
62 NativeDelegate &native_delegate) {
64
65 Status status;
67 .LaunchProcess(launch_info, status)
68 .GetProcessId();
69 LLDB_LOG(log, "pid = {0:x}", pid);
70 if (status.Fail()) {
71 LLDB_LOG(log, "failed to launch process: {0}", status);
72 return status.ToError();
73 }
74
75 // Wait for the child process to trap on its call to execve.
76 int wstatus = 0;
77 ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
78 assert(wpid == pid);
80 if (!WIFSTOPPED(wstatus)) {
81 LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
82 WaitStatus::Decode(wstatus));
83 return llvm::createStringError("Could not sync with inferior process");
84 }
85 LLDB_LOG(log, "inferior started, now in stopped state");
86
87 return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
88 pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
89 HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, {pid}));
90}
91
92llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
96 LLDB_LOG(log, "pid = {0:x}", pid);
97
98 auto tids_or = NativeProcessAIX::Attach(pid);
99 if (!tids_or)
100 return tids_or.takeError();
101
102 return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
103 pid, -1, native_delegate,
104 HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, *tids_or));
105}
106
110
111static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
113
114 int status;
115 ::pid_t wait_pid =
116 llvm::sys::RetryAfterSignal(-1, ::waitpid, -1, &status, WNOHANG);
117
118 if (wait_pid == 0)
119 return std::nullopt;
120
121 if (wait_pid == -1) {
123 LLDB_LOG(log, "waitpid(-1, &status, _) failed: {0}", error);
124 return std::nullopt;
125 }
126
127 WaitStatus wait_status = WaitStatus::Decode(status);
128
129 LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid,
130 wait_status);
131 return std::make_pair(wait_pid, wait_status);
132}
133
135 while (true) {
136 auto wait_result = WaitPid();
137 if (!wait_result)
138 return;
139 }
140}
141
143
144// Public Instance Methods
145
147 NativeDelegate &delegate,
148 const ArchSpec &arch, Manager &manager,
149 llvm::ArrayRef<::pid_t> tids)
150 : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager),
151 m_arch(arch) {
152 manager.AddProcess(*this);
153 if (m_terminal_fd != -1)
155
156 // Let our process instance know the thread has stopped.
157 SetCurrentThreadID(tids[0]);
159}
160
161llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
163 Status status;
164 if (llvm::Error err = PtraceWrapper(PT_ATTACH, pid).takeError())
165 return err;
166
167 int wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG);
168 if (wpid <= 0)
169 return llvm::errorCodeToError(errnoAsErrorCode());
170 LLDB_LOG(log, "adding pid = {0}", pid);
171
172 return std::vector<::pid_t>{pid};
173}
174
176
178 return Status("unsupported");
179}
180
181Status NativeProcessAIX::Halt() { return Status("unsupported"); }
182
183Status NativeProcessAIX::Detach() { return Status("unsupported"); }
184
185Status NativeProcessAIX::Signal(int signo) { return Status("unsupported"); }
186
187Status NativeProcessAIX::Interrupt() { return Status("unsupported"); }
188
190
192 LLDB_LOG(log, "pid {0}", GetID());
193
195
196 switch (m_state) {
202 // Nothing to do - the process is already dead.
203 LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
204 m_state);
205 return error;
206
214 // We can try to kill a process in these states.
215 break;
216 }
217
218 llvm::Expected<int> result =
219 PtraceWrapper(PT_KILL, GetID(), nullptr, nullptr, 0);
220 if (!result) {
221 std::string error_string = std::string("Kill failed for process. error: ") +
222 llvm::toString(result.takeError());
223 error.FromErrorString(error_string.c_str());
224 }
225 return error;
226}
227
229 size_t &bytes_read) {
230 return Status("unsupported");
231}
232
234 size_t size, size_t &bytes_written) {
235 return Status("unsupported");
236}
237
239 // The NativeProcessAIX monitoring threads are always up to date with
240 // respect to thread state and they keep the thread list populated properly.
241 // All this method needs to do is return the thread count.
242 return m_threads.size();
243}
244
246 FileSpec &file_spec) {
247 return Status("unsupported");
248}
249
251 bool hardware) {
252 if (hardware)
253 return SetHardwareBreakpoint(addr, size);
254 return SetSoftwareBreakpoint(addr, size);
255}
256
258 if (hardware)
259 return RemoveHardwareBreakpoint(addr);
261}
262
264 return PtraceWrapper(PT_DETACH, tid).takeError();
265}
266
267llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
268 void *addr, void *data,
269 size_t data_size) {
270 int ret;
271
273 switch (req) {
274 case PT_ATTACH:
275 case PT_DETACH:
276 case PT_KILL:
277 ret = ptrace64(req, pid, 0, 0, nullptr);
278 break;
279 default:
280 llvm_unreachable("PT_ request not supported yet.");
281 }
282
283 LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data,
284 data_size, ret);
285
286 if (ret == -1) {
287 LLDB_LOG(log, "ptrace() failed");
288 return llvm::errorCodeToError(errnoAsErrorCode());
289 }
290 return ret;
291}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
static std::optional< std::pair< lldb::pid_t, WaitStatus > > WaitPid()
static constexpr unsigned k_ptrace_word_size
static llvm::Error SetFDFlags(int fd, int flags)
An architecture specification class.
Definition ArchSpec.h:32
A file utility class.
Definition FileSpec.h:57
lldb::pid_t GetProcessId() const
SignalHandleUP RegisterSignal(int signo, const Callback &callback, Status &error)
NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, NativeDelegate &delegate)
Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint)
void SetState(lldb::StateType state, bool notify_delegates=true)
std::vector< std::unique_ptr< NativeThreadProtocol > > m_threads
virtual Status RemoveBreakpoint(lldb::addr_t addr, bool hardware=false)
virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size)
virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr)
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) override
int ReleasePrimaryFileDescriptor()
Release the primary file descriptor.
An error handling class.
Definition Status.h:118
llvm::Error takeError()
Definition Status.h:170
llvm::Error ToError() const
FIXME: Replace all uses with takeError() instead.
Definition Status.cpp:138
bool Fail() const
Test for error condition.
Definition Status.cpp:293
bool Success() const
Test for success condition.
Definition Status.cpp:303
llvm::Expected< std::unique_ptr< NativeProcessProtocol > > Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate) override
Launch a process for debugging.
llvm::Expected< std::unique_ptr< NativeProcessProtocol > > Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override
Attach to an existing process.
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) override
static llvm::Expected< std::vector<::pid_t > > Attach(::pid_t pid)
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override
Status RemoveBreakpoint(lldb::addr_t addr, bool hardware=false) override
static llvm::Expected< int > PtraceWrapper(int req, lldb::pid_t pid, void *addr=nullptr, void *data=nullptr, size_t data_size=0)
Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) override
Status Signal(int signo) override
Sends a process a UNIX signal signal.
Status Interrupt() override
Tells a process to interrupt all operations as if by a Ctrl-C.
Status Resume(const ResumeActionList &resume_actions) override
NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, Manager &manager, llvm::ArrayRef<::pid_t > tids)
Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override
#define UNUSED_IF_ASSERT_DISABLED(x)
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
MainLoopPosix MainLoop
Definition MainLoop.h:20
@ eStateUnloaded
Process is object is valid, but not currently loaded.
@ eStateConnected
Process is connected to remote debug services, but not launched or attached to anything yet.
@ eStateDetached
Process has been detached and can't be examined.
@ eStateStopped
Process or thread is stopped and can be examined.
@ eStateSuspended
Process or thread is in a suspended state as far as the debugger is concerned while other processes o...
@ eStateRunning
Process or thread is running and can't be examined.
@ eStateLaunching
Process is in the process of launching.
@ eStateAttaching
Process is currently trying to attach.
@ eStateExited
Process has exited and can't be examined.
@ eStateStepping
Process or thread is in the process of stepping and can not be examined.
@ eStateCrashed
Process or thread has crashed and can be examined.
@ eErrorTypePOSIX
POSIX error codes.
uint64_t pid_t
Definition lldb-types.h:83
uint64_t addr_t
Definition lldb-types.h:80
uint64_t tid_t
Definition lldb-types.h:84
static WaitStatus Decode(int wstatus)
#define O_NONBLOCK