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#define DECLARE_REGISTER_INFOS_PPC64_STRUCT
31#undef DECLARE_REGISTER_INFOS_PPC64_STRUCT
32
33using namespace lldb;
34using namespace lldb_private;
35using namespace lldb_private::process_aix;
36using namespace llvm;
37
38static constexpr unsigned k_ptrace_word_size = sizeof(void *);
39static_assert(sizeof(long) >= k_ptrace_word_size,
40 "Size of long must be larger than ptrace word size");
41
42// Simple helper function to ensure flags are enabled on the given file
43// descriptor.
44static llvm::Error SetFDFlags(int fd, int flags) {
45 int status = fcntl(fd, F_GETFL);
46 if (status == -1)
47 return errorCodeToError(errnoAsErrorCode());
48 if (fcntl(fd, F_SETFL, status | flags) == -1)
49 return errorCodeToError(errnoAsErrorCode());
50 return Error::success();
51}
52
54 : NativeProcessProtocol::Manager(mainloop) {
55 Status status;
57 SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
58 assert(m_sigchld_handle && status.Success());
59}
60
61// Public Static Methods
62
63llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
65 NativeDelegate &native_delegate) {
67
68 Status status;
70 .LaunchProcess(launch_info, status)
71 .GetProcessId();
72 LLDB_LOG(log, "pid = {0:x}", pid);
73 if (status.Fail()) {
74 LLDB_LOG(log, "failed to launch process: {0}", status);
75 return status.ToError();
76 }
77
78 // Wait for the child process to trap on its call to execve.
79 int wstatus = 0;
80 ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
81 assert(wpid == pid);
83 if (!WIFSTOPPED(wstatus)) {
84 LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
85 WaitStatus::Decode(wstatus));
86 return llvm::createStringError("could not sync with inferior process");
87 }
88 LLDB_LOG(log, "inferior started, now in stopped state");
89
91 if (!Host::GetProcessInfo(pid, Info)) {
92 return llvm::make_error<StringError>("Cannot get process architecture",
93 llvm::inconvertibleErrorCode());
94 }
95
96 // Set the architecture to the exe architecture.
97 LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid,
98 Info.GetArchitecture().GetArchitectureName());
99
100 return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
101 pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
102 Info.GetArchitecture(), *this, {pid}));
103}
104
105llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
109 LLDB_LOG(log, "pid = {0:x}", pid);
110
111 auto tids_or = NativeProcessAIX::Attach(pid);
112 if (!tids_or)
113 return tids_or.takeError();
114
115 return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
116 pid, -1, native_delegate,
117 HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, *tids_or));
118}
119
123
124static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
126
127 int status;
128 ::pid_t wait_pid =
129 llvm::sys::RetryAfterSignal(-1, ::waitpid, -1, &status, WNOHANG);
130
131 if (wait_pid == 0)
132 return std::nullopt;
133
134 if (wait_pid == -1) {
136 LLDB_LOG(log, "waitpid(-1, &status, _) failed: {0}", error);
137 return std::nullopt;
138 }
139
140 WaitStatus wait_status = WaitStatus::Decode(status);
141
142 LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid,
143 wait_status);
144 return std::make_pair(wait_pid, wait_status);
145}
146
148 while (true) {
149 auto wait_result = WaitPid();
150 if (!wait_result)
151 return;
152 }
153}
154
156
157// Public Instance Methods
158
160 NativeDelegate &delegate,
161 const ArchSpec &arch, Manager &manager,
162 llvm::ArrayRef<::pid_t> tids)
163 : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager),
164 m_arch(arch) {
165 manager.AddProcess(*this);
166 if (m_terminal_fd != -1)
168
169 // Let our process instance know the thread has stopped.
170 SetCurrentThreadID(tids[0]);
172}
173
174llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
176 Status status;
177 if (llvm::Error err = PtraceWrapper(PT_ATTACH, pid).takeError())
178 return err;
179
180 int wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG);
181 if (wpid <= 0)
182 return llvm::errorCodeToError(errnoAsErrorCode());
183 LLDB_LOG(log, "adding pid = {0}", pid);
184
185 return std::vector<::pid_t>{pid};
186}
187
189
191 return Status("unsupported");
192}
193
194Status NativeProcessAIX::Halt() { return Status("unsupported"); }
195
196Status NativeProcessAIX::Detach() { return Status("unsupported"); }
197
198Status NativeProcessAIX::Signal(int signo) { return Status("unsupported"); }
199
200Status NativeProcessAIX::Interrupt() { return Status("unsupported"); }
201
203
205 LLDB_LOG(log, "pid {0}", GetID());
206
208
209 switch (m_state) {
215 // Nothing to do - the process is already dead.
216 LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
217 m_state);
218 return error;
219
227 // We can try to kill a process in these states.
228 break;
229 }
230
231 llvm::Expected<int> result =
232 PtraceWrapper(PT_KILL, GetID(), nullptr, nullptr, 0);
233 if (!result) {
234 std::string error_string = std::string("Kill failed for process. error: ") +
235 llvm::toString(result.takeError());
236 error.FromErrorString(error_string.c_str());
237 }
238 return error;
239}
240
242 size_t &bytes_read) {
243 return Status("unsupported");
244}
245
247 size_t size, size_t &bytes_written) {
248 return Status("unsupported");
249}
250
252 // The NativeProcessAIX monitoring threads are always up to date with
253 // respect to thread state and they keep the thread list populated properly.
254 // All this method needs to do is return the thread count.
255 return m_threads.size();
256}
257
258Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name,
259 lldb::addr_t &load_addr) {
260 return Status("unsupported");
261}
262
264 FileSpec &file_spec) {
265 return Status("unsupported");
266}
267
269 bool hardware) {
270 if (hardware)
271 return SetHardwareBreakpoint(addr, size);
272 return SetSoftwareBreakpoint(addr, size);
273}
274
276 if (hardware)
277 return RemoveHardwareBreakpoint(addr);
279}
280
282 return PtraceWrapper(PT_DETACH, tid).takeError();
283}
284
285template <typename GPR_T, typename PTSPRS_T>
286int GetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
287 PTSPRS_T sprs;
288
289 int ret = ptrace64(req, tid, reinterpret_cast<long long>(&sprs), 0, 0);
290
291 if (ret != -1) {
292 gpr->cr = sprs.pt_cr;
293 gpr->msr = sprs.pt_msr;
294 gpr->xer = sprs.pt_xer;
295 gpr->lr = sprs.pt_lr;
296 gpr->ctr = sprs.pt_ctr;
297 gpr->pc = sprs.pt_iar;
298 }
299 return ret;
300}
301
302template <typename GPR_T, typename PTSPRS_T>
303int SetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
304 PTSPRS_T sprs;
305
306 sprs.pt_cr = gpr->cr;
307 sprs.pt_msr = gpr->msr;
308 sprs.pt_xer = gpr->xer;
309 sprs.pt_lr = gpr->lr;
310 sprs.pt_ctr = gpr->ctr;
311 sprs.pt_iar = gpr->pc;
312
313 return ptrace64(req, tid, reinterpret_cast<long long>(&sprs), 0, 0);
314}
315
316llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
317 void *addr, void *data,
318 size_t data_size) {
319 int ret = 0;
321 // PTT_* requests require a thread ID (TID).
322 // Each entry under /proc/<pid>/lwp/ represents a thread,
323 // and the directory name corresponds to its thread ID (TID).
324 // A process may contain multiple threads.
325 // TODO: With multi-threading support, iterate over all entries to enumerate
326 // available TIDs and retrieve the target debugging thread ID.
327 llvm::SmallString<128> proc_lwp_dir;
328 llvm::sys::path::append(proc_lwp_dir, "/proc/", std::to_string(pid), "/lwp/");
329
330 lldb::tid_t tid = 0;
331 std::error_code ec;
332 bool result;
333 if (!llvm::sys::fs::is_directory(proc_lwp_dir, result) && result) {
334 for (sys::fs::directory_iterator it(proc_lwp_dir, ec), end;
335 it != end && !ec; it.increment(ec)) {
336 llvm::StringRef name = llvm::sys::path::filename(it->path());
337
338 if (name == "." || name == "..")
339 continue;
340
341 if (!name.getAsInteger(10, tid)) {
342 break;
343 }
344 }
345 }
346
347 switch (req) {
348 // On AIX, ptrace exposes differently. GPRs and SPRs are handled via separate
349 // requests: PTT_READ_GPRS reads only GPRs & PTT_READ_SPRS is required to
350 // fetch SPRs. Similarly, writes are also split across:
351 // PTT_WRITE_GPRS & PTT_WRITE_SPRS.
352 case PTT_READ_GPRS:
353 if (data_size == sizeof(GPR_PPC)) // 32bit SPRs read
354 ret = GetSPRs<GPR_PPC, ptsprs>(PTT_READ_SPRS, tid,
355 static_cast<GPR_PPC *>(data));
356 else if (data_size == sizeof(GPR_PPC64)) // 64bit SPRs read
357 ret = GetSPRs<GPR_PPC64, ptxsprs>(PTT_READ_SPRS, tid,
358 static_cast<GPR_PPC64 *>(data));
359
360 if (ret != -1)
361 ret = ptrace64(req, tid, reinterpret_cast<long long>(data), 0,
362 0); // read GPRs
363 break;
364
365 case PTT_WRITE_GPRS:
366 if (data_size == sizeof(GPR_PPC)) // 32bit SPRs write
367 ret = SetSPRs<GPR_PPC, ptsprs>(PTT_WRITE_SPRS, tid,
368 static_cast<GPR_PPC *>(data));
369 else if (data_size == sizeof(GPR_PPC64)) // 64bit SPRS write
370 ret = SetSPRs<GPR_PPC64, ptxsprs>(PTT_WRITE_SPRS, tid,
371 static_cast<GPR_PPC64 *>(data));
372
373 if (ret != -1)
374 ret = ptrace64(req, tid, reinterpret_cast<long long>(data), 0,
375 0); // write GPRs
376 break;
377 case PT_ATTACH:
378 case PT_DETACH:
379 case PT_KILL:
380 ret = ptrace64(req, pid, 0, 0, nullptr);
381 break;
382 default:
383 llvm_unreachable("PT_ request not supported yet.");
384 }
385
386 LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data,
387 data_size, ret);
388
389 if (ret == -1) {
390 LLDB_LOG(log, "ptrace() failed");
391 return llvm::errorCodeToError(errnoAsErrorCode());
392 }
393 return ret;
394}
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:364
static std::optional< std::pair< lldb::pid_t, WaitStatus > > WaitPid()
static constexpr unsigned k_ptrace_word_size
int GetSPRs(int req, lldb::tid_t tid, GPR_T *gpr)
static llvm::Error SetFDFlags(int fd, int flags)
int SetSPRs(int req, lldb::tid_t tid, GPR_T *gpr)
An architecture specification class.
Definition ArchSpec.h:32
A file utility class.
Definition FileSpec.h:57
lldb::pid_t GetProcessId() const
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
Definition aix/Host.cpp:211
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
Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) 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:327
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