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"
10#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
11#include "lldb/Host/Host.h"
12#include "lldb/Host/HostInfo.h"
13#include "lldb/Host/HostProcess.h"
14#include "lldb/Host/ProcessLaunchInfo.h"
15#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
16#include "lldb/Symbol/ObjectFile.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: fd, F_GETFL);
43 if (status == -1)
44 return errorCodeToError(EC: errnoAsErrorCode());
45 if (fcntl(fd: fd, F_SETFL, status | flags) == -1)
46 return errorCodeToError(EC: errnoAsErrorCode());
47 return Error::success();
48}
49
50NativeProcessAIX::Manager::Manager(MainLoop &mainloop)
51 : NativeProcessProtocol::Manager(mainloop) {
52 Status status;
53 m_sigchld_handle = mainloop.RegisterSignal(
54 SIGCHLD, callback: [this](MainLoopBase &) { SigchldHandler(); }, error&: status);
55 assert(m_sigchld_handle && status.Success());
56}
57
58// Public Static Methods
59
60llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
61NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info,
62 NativeDelegate &native_delegate) {
63 Log *log = GetLog(mask: POSIXLog::Process);
64
65 Status status;
66 ::pid_t pid = ProcessLauncherPosixFork()
67 .LaunchProcess(launch_info, error&: 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);
79 UNUSED_IF_ASSERT_DISABLED(wpid);
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>(Args: "Could not sync with inferior process",
84 Args: 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(arch_kind: HostInfo::eArchKind64), *this, {pid}));
91}
92
93llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
94NativeProcessAIX::Manager::Attach(
95 lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
96 Log *log = GetLog(mask: POSIXLog::Process);
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(arch_kind: HostInfo::eArchKind64), *this, *tids_or));
106}
107
108lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() {
109 return LLDB_INVALID_ADDRESS;
110}
111
112static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
113 Log *log = GetLog(mask: POSIXLog::Process);
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) {
123 Status error(errno, eErrorTypePOSIX);
124 LLDB_LOG(log, "waitpid(-1, &status, _) failed: {0}", error);
125 return std::nullopt;
126 }
127
128 WaitStatus wait_status = WaitStatus::Decode(wstatus: status);
129
130 LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid,
131 wait_status);
132 return std::make_pair(x&: wait_pid, y&: wait_status);
133}
134
135void NativeProcessAIX::Manager::SigchldHandler() {
136 while (true) {
137 auto wait_result = WaitPid();
138 if (!wait_result)
139 return;
140 }
141}
142
143void NativeProcessAIX::Manager::CollectThread(::pid_t tid) {}
144
145// Public Instance Methods
146
147NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd,
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(process&: *this);
154 if (m_terminal_fd != -1)
155 cantFail(Err: SetFDFlags(fd: m_terminal_fd, O_NONBLOCK));
156
157 // Let our process instance know the thread has stopped.
158 SetCurrentThreadID(tids[0]);
159 SetState(state: StateType::eStateStopped, notify_delegates: false);
160}
161
162llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
163 Log *log = GetLog(mask: POSIXLog::Process);
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(EC: errnoAsErrorCode());
171 LLDB_LOG(log, "adding pid = {0}", pid);
172
173 return std::vector<::pid_t>{pid};
174}
175
176bool NativeProcessAIX::SupportHardwareSingleStepping() const { return false; }
177
178Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) {
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
192Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
193 size_t &bytes_read) {
194 return Status("unsupported");
195}
196
197Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf,
198 size_t size, size_t &bytes_written) {
199 return Status("unsupported");
200}
201
202size_t NativeProcessAIX::UpdateThreads() {
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
209Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path,
210 FileSpec &file_spec) {
211 return Status("unsupported");
212}
213
214Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size,
215 bool hardware) {
216 if (hardware)
217 return SetHardwareBreakpoint(addr, size);
218 return SetSoftwareBreakpoint(addr, size_hint: size);
219}
220
221Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) {
222 if (hardware)
223 return RemoveHardwareBreakpoint(addr);
224 return NativeProcessProtocol::RemoveBreakpoint(addr);
225}
226
227llvm::Error NativeProcessAIX::Detach(lldb::tid_t tid) {
228 return PtraceWrapper(PT_DETACH, pid: 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
236 Log *log = GetLog(mask: POSIXLog::Ptrace);
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(EC: errnoAsErrorCode());
252 }
253 return ret;
254}
255

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp