Skip to content

Commit ec95ce3

Browse files
[lldb][AIX] Added base files for NativeProcess Support for AIX (#118160)
This PR is in reference to porting LLDB on AIX. Link to discussions on llvm discourse and github: 1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640 2. #101657 The complete changes for porting are present in this draft PR: #102601 Added base files for NativeProcess Support for AIX. Will be adding further support in consequent incremental PR.
1 parent 11d35a0 commit ec95ce3

File tree

6 files changed

+412
-1
lines changed

6 files changed

+412
-1
lines changed

lldb/cmake/modules/LLDBConfig.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ endif()
292292

293293
# Figure out if lldb could use lldb-server. If so, then we'll
294294
# ensure we build lldb-server when an lldb target is being built.
295-
if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows")
295+
if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows")
296296
set(LLDB_CAN_USE_LLDB_SERVER ON)
297297
else()
298298
set(LLDB_CAN_USE_LLDB_SERVER OFF)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
add_lldb_library(lldbPluginProcessAIX
2+
NativeProcessAIX.cpp
3+
4+
LINK_LIBS
5+
lldbCore
6+
lldbHost
7+
lldbSymbol
8+
lldbTarget
9+
lldbUtility
10+
lldbPluginProcessPOSIX
11+
lldbPluginProcessUtility
12+
LINK_COMPONENTS
13+
Support
14+
)
15+
16+
target_compile_definitions(lldbPluginProcessAIX PRIVATE "-D_ALL_SOURCE")
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
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+
30+
using namespace lldb;
31+
using namespace lldb_private;
32+
using namespace lldb_private::process_aix;
33+
using namespace llvm;
34+
35+
static constexpr unsigned k_ptrace_word_size = sizeof(void *);
36+
static_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.
41+
static 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+
50+
NativeProcessAIX::Manager::Manager(MainLoop &mainloop)
51+
: NativeProcessProtocol::Manager(mainloop) {
52+
Status status;
53+
m_sigchld_handle = mainloop.RegisterSignal(
54+
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
55+
assert(m_sigchld_handle && status.Success());
56+
}
57+
58+
// Public Static Methods
59+
60+
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
61+
NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info,
62+
NativeDelegate &native_delegate) {
63+
Log *log = GetLog(POSIXLog::Process);
64+
65+
Status status;
66+
::pid_t pid = ProcessLauncherPosixFork()
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);
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>("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+
93+
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
94+
NativeProcessAIX::Manager::Attach(
95+
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
96+
Log *log = GetLog(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(HostInfo::eArchKind64), *this, *tids_or));
106+
}
107+
108+
lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() {
109+
return LLDB_INVALID_ADDRESS;
110+
}
111+
112+
static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
113+
Log *log = GetLog(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(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+
135+
void NativeProcessAIX::Manager::SigchldHandler() {
136+
while (true) {
137+
auto wait_result = WaitPid();
138+
if (!wait_result)
139+
return;
140+
}
141+
}
142+
143+
void NativeProcessAIX::Manager::CollectThread(::pid_t tid) {}
144+
145+
// Public Instance Methods
146+
147+
NativeProcessAIX::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(*this);
154+
if (m_terminal_fd != -1)
155+
cantFail(SetFDFlags(m_terminal_fd, O_NONBLOCK));
156+
157+
// Let our process instance know the thread has stopped.
158+
SetCurrentThreadID(tids[0]);
159+
SetState(StateType::eStateStopped, false);
160+
}
161+
162+
llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
163+
Log *log = GetLog(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(errnoAsErrorCode());
171+
LLDB_LOG(log, "adding pid = {0}", pid);
172+
173+
return std::vector<::pid_t>{pid};
174+
}
175+
176+
bool NativeProcessAIX::SupportHardwareSingleStepping() const { return false; }
177+
178+
Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) {
179+
return Status("unsupported");
180+
}
181+
182+
Status NativeProcessAIX::Halt() { return Status("unsupported"); }
183+
184+
Status NativeProcessAIX::Detach() { return Status("unsupported"); }
185+
186+
Status NativeProcessAIX::Signal(int signo) { return Status("unsupported"); }
187+
188+
Status NativeProcessAIX::Interrupt() { return Status("unsupported"); }
189+
190+
Status NativeProcessAIX::Kill() { return Status("unsupported"); }
191+
192+
Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
193+
size_t &bytes_read) {
194+
return Status("unsupported");
195+
}
196+
197+
Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf,
198+
size_t size, size_t &bytes_written) {
199+
return Status("unsupported");
200+
}
201+
202+
size_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+
209+
Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path,
210+
FileSpec &file_spec) {
211+
return Status("unsupported");
212+
}
213+
214+
Status 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);
219+
}
220+
221+
Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) {
222+
if (hardware)
223+
return RemoveHardwareBreakpoint(addr);
224+
return NativeProcessProtocol::RemoveBreakpoint(addr);
225+
}
226+
227+
llvm::Error NativeProcessAIX::Detach(lldb::tid_t tid) {
228+
return PtraceWrapper(PT_DETACH, tid).takeError();
229+
}
230+
231+
llvm::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(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(errnoAsErrorCode());
252+
}
253+
return ret;
254+
}

0 commit comments

Comments
 (0)