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::make_error<StringError>("Could not sync with inferior process",
84 llvm::inconvertibleErrorCode());
85 }
86 LLDB_LOG(log, "inferior started, now in stopped state");
87
88 return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
89 pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
90 HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, {pid}));
91}
92
93llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
97 LLDB_LOG(log, "pid = {0:x}", pid);
98
99 auto tids_or = NativeProcessAIX::Attach(pid);
100 if (!tids_or)
101 return tids_or.takeError();
102
103 return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
104 pid, -1, native_delegate,
105 HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, *tids_or));
106}
107
111
112static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
114
115 int status;
116 ::pid_t wait_pid =
117 llvm::sys::RetryAfterSignal(-1, ::waitpid, -1, &status, WNOHANG);
118
119 if (wait_pid == 0)
120 return std::nullopt;
121
122 if (wait_pid == -1) {
124 LLDB_LOG(log, "waitpid(-1, &status, _) failed: {0}", error);
125 return std::nullopt;
126 }
127
128 WaitStatus wait_status = WaitStatus::Decode(status);
129
130 LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid,
131 wait_status);
132 return std::make_pair(wait_pid, wait_status);
133}
134
136 while (true) {
137 auto wait_result = WaitPid();
138 if (!wait_result)
139 return;
140 }
141}
142
144
145// Public Instance Methods
146
148 NativeDelegate &delegate,
149 const ArchSpec &arch, Manager &manager,
150 llvm::ArrayRef<::pid_t> tids)
151 : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager),
152 m_arch(arch) {
153 manager.AddProcess(*this);
154 if (m_terminal_fd != -1)
156
157 // Let our process instance know the thread has stopped.
158 SetCurrentThreadID(tids[0]);
160}
161
162llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
164 Status status;
165 if (llvm::Error err = PtraceWrapper(PT_ATTACH, pid).takeError())
166 return err;
167
168 int wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG);
169 if (wpid <= 0)
170 return llvm::errorCodeToError(errnoAsErrorCode());
171 LLDB_LOG(log, "adding pid = {0}", pid);
172
173 return std::vector<::pid_t>{pid};
174}
175
177
179 return Status("unsupported");
180}
181
182Status NativeProcessAIX::Halt() { return Status("unsupported"); }
183
184Status NativeProcessAIX::Detach() { return Status("unsupported"); }
185
186Status NativeProcessAIX::Signal(int signo) { return Status("unsupported"); }
187
188Status NativeProcessAIX::Interrupt() { return Status("unsupported"); }
189
190Status NativeProcessAIX::Kill() { return Status("unsupported"); }
191
193 size_t &bytes_read) {
194 return Status("unsupported");
195}
196
198 size_t size, size_t &bytes_written) {
199 return Status("unsupported");
200}
201
203 // The NativeProcessAIX monitoring threads are always up to date with
204 // respect to thread state and they keep the thread list populated properly.
205 // All this method needs to do is return the thread count.
206 return m_threads.size();
207}
208
210 FileSpec &file_spec) {
211 return Status("unsupported");
212}
213
215 bool hardware) {
216 if (hardware)
217 return SetHardwareBreakpoint(addr, size);
218 return SetSoftwareBreakpoint(addr, size);
219}
220
222 if (hardware)
223 return RemoveHardwareBreakpoint(addr);
225}
226
228 return PtraceWrapper(PT_DETACH, tid).takeError();
229}
230
231llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
232 void *addr, void *data,
233 size_t data_size) {
234 int ret;
235
237 switch (req) {
238 case PT_ATTACH:
239 case PT_DETACH:
240 ret = ptrace64(req, pid, 0, 0, nullptr);
241 break;
242 default:
243 llvm_unreachable("PT_ request not supported yet.");
244 }
245
246 LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data,
247 data_size, ret);
248
249 if (ret == -1) {
250 LLDB_LOG(log, "ptrace() failed");
251 return llvm::errorCodeToError(errnoAsErrorCode());
252 }
253 return ret;
254}
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:31
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:139
bool Fail() const
Test for error condition.
Definition Status.cpp:294
bool Success() const
Test for success condition.
Definition Status.cpp:304
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
@ eStateStopped
Process or thread is stopped 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