[Lldb-commits] [clang] [lldb] [llvm] Extending LLDB to work on AIX (PR #102601)
Dhruv Srivastava via lldb-commits
lldb-commits at lists.llvm.org
Thu Aug 15 23:26:36 PDT 2024
https://github.com/DhruvSrivastavaX updated https://github.com/llvm/llvm-project/pull/102601
>From 39d395f75c306a0d932a783eef039fd93d66e246 Mon Sep 17 00:00:00 2001
From: Dhruv-Srivastava <dhruv.srivastava at ibm.com>
Date: Wed, 7 Aug 2024 12:10:43 -0500
Subject: [PATCH 1/3] LLDB Support for AIX
---
clang/lib/CodeGen/CGObjCMac.cpp | 6 +-
lldb/CMakeLists.txt | 4 +
lldb/cmake/modules/LLDBConfig.cmake | 2 +-
lldb/include/lldb/Core/Module.h | 3 +
lldb/include/lldb/Core/ModuleSpec.h | 23 +-
lldb/include/lldb/Host/HostGetOpt.h | 2 +-
lldb/include/lldb/Host/HostInfo.h | 3 +
lldb/include/lldb/Host/HostInfoBase.h | 2 +-
lldb/include/lldb/Host/XML.h | 5 +
lldb/include/lldb/Host/aix/AbstractSocket.h | 25 +
lldb/include/lldb/Host/aix/Host.h | 22 +
lldb/include/lldb/Host/aix/HostInfoAIX.h | 42 +
lldb/include/lldb/Host/aix/Ptrace.h | 62 +
lldb/include/lldb/Host/aix/Support.h | 29 +
lldb/include/lldb/Host/aix/Uio.h | 23 +
lldb/include/lldb/Host/common/GetOptInc.h | 6 +-
lldb/include/lldb/Symbol/ObjectFile.h | 5 +
lldb/include/lldb/Target/ABI.h | 6 +
lldb/include/lldb/Target/DynamicLoader.h | 6 +
lldb/include/lldb/Target/Process.h | 14 +
.../lldb/Target/RegisterContextUnwind.h | 4 +
.../lldb/Target/ThreadPlanCallFunction.h | 6 +
.../lldb/Utility/StringExtractorGDBRemote.h | 1 +
lldb/include/lldb/lldb-private-enumerations.h | 1 +
lldb/source/API/CMakeLists.txt | 108 +
lldb/source/API/SBBreakpoint.cpp | 6 +-
lldb/source/API/SBBreakpointLocation.cpp | 6 +-
lldb/source/API/SBBreakpointName.cpp | 4 +-
lldb/source/Core/DynamicLoader.cpp | 10 +
lldb/source/Core/Mangled.cpp | 2 +
lldb/source/Core/Module.cpp | 12 +
lldb/source/Core/Section.cpp | 4 +
lldb/source/Expression/DWARFExpression.cpp | 10 +-
lldb/source/Host/CMakeLists.txt | 13 +
lldb/source/Host/aix/AbstractSocket.cpp | 21 +
lldb/source/Host/aix/Host.cpp | 304 +++
lldb/source/Host/aix/HostInfoAIX.cpp | 215 ++
lldb/source/Host/aix/Support.cpp | 44 +
lldb/source/Host/common/GetOptInc.cpp | 2 +-
lldb/source/Host/common/Host.cpp | 180 +-
.../source/Host/common/LICENSE.aix-netbsd.txt | 125 +
lldb/source/Host/common/XML.cpp | 3 +
.../posix/ConnectionFileDescriptorPosix.cpp | 2 +
lldb/source/Host/posix/FileSystemPosix.cpp | 2 +
lldb/source/Host/posix/MainLoopPosix.cpp | 17 +
.../Host/posix/ProcessLauncherPosixFork.cpp | 5 +
lldb/source/Initialization/CMakeLists.txt | 2 +-
.../SystemInitializerCommon.cpp | 4 +-
.../Plugins/ABI/PowerPC/ABISysV_ppc64.cpp | 131 +-
.../Plugins/ABI/PowerPC/ABISysV_ppc64.h | 6 +
.../DynamicLoader/AIX-DYLD/CMakeLists.txt | 11 +
.../AIX-DYLD/DynamicLoaderAIXDYLD.cpp | 272 +++
.../AIX-DYLD/DynamicLoaderAIXDYLD.h | 55 +
.../Plugins/DynamicLoader/CMakeLists.txt | 1 +
.../DynamicLoaderDarwinKernel.cpp | 4 +-
.../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +-
.../PPC64/EmulateInstructionPPC64.cpp | 196 +-
.../PPC64/EmulateInstructionPPC64.h | 14 +
...nstrumentationRuntimeMainThreadChecker.cpp | 2 +-
.../TSan/InstrumentationRuntimeTSan.cpp | 14 +-
.../UBSan/InstrumentationRuntimeUBSan.cpp | 2 +-
.../Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 4 +
lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +
.../MemoryHistory/asan/MemoryHistoryASan.cpp | 2 +-
.../BSD-Archive/ObjectContainerBSDArchive.cpp | 2 +-
.../Big-Archive/CMakeLists.txt | 10 +
.../Big-Archive/ObjectContainerBigArchive.cpp | 522 +++++
.../Big-Archive/ObjectContainerBigArchive.h | 177 ++
.../Plugins/ObjectContainer/CMakeLists.txt | 1 +
lldb/source/Plugins/ObjectFile/CMakeLists.txt | 1 +
.../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6 +-
.../Minidump/ObjectFileMinidump.cpp | 2 +
.../Plugins/ObjectFile/PDB/ObjectFilePDB.cpp | 15 +-
.../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 18 +-
.../Plugins/ObjectFile/XCOFF/CMakeLists.txt | 13 +
.../ObjectFile/XCOFF/ObjectFileXCOFF.cpp | 780 +++++++
.../ObjectFile/XCOFF/ObjectFileXCOFF.h | 243 ++
.../Python/OperatingSystemPython.cpp | 2 +-
.../Plugins/Platform/AIX/CMakeLists.txt | 13 +
.../Plugins/Platform/AIX/PlatformAIX.cpp | 471 ++++
.../source/Plugins/Platform/AIX/PlatformAIX.h | 74 +
lldb/source/Plugins/Platform/CMakeLists.txt | 1 +
.../source/Plugins/Process/AIX/CMakeLists.txt | 19 +
.../Plugins/Process/AIX/NativeProcessAIX.cpp | 2048 +++++++++++++++++
.../Plugins/Process/AIX/NativeProcessAIX.h | 283 +++
.../Process/AIX/NativeRegisterContextAIX.cpp | 157 ++
.../Process/AIX/NativeRegisterContextAIX.h | 133 ++
.../AIX/NativeRegisterContextAIX_ppc64.cpp | 744 ++++++
.../AIX/NativeRegisterContextAIX_ppc64.h | 138 ++
.../Plugins/Process/AIX/NativeThreadAIX.cpp | 526 +++++
.../Plugins/Process/AIX/NativeThreadAIX.h | 126 +
lldb/source/Plugins/Process/CMakeLists.txt | 3 +
.../Process/Utility/InferiorCallPOSIX.cpp | 33 +
.../Utility/RegisterInfoPOSIX_ppc64le.cpp | 4 +
.../Plugins/Process/Utility/ThreadMemory.cpp | 2 +-
.../Plugins/Process/gdb-remote/CMakeLists.txt | 5 +
.../GDBRemoteCommunicationClient.cpp | 30 +
.../gdb-remote/GDBRemoteCommunicationClient.h | 7 +
.../GDBRemoteCommunicationServerLLGS.cpp | 28 +
.../GDBRemoteCommunicationServerLLGS.h | 2 +
.../Process/gdb-remote/ProcessGDBRemote.cpp | 13 +-
.../Process/gdb-remote/ProcessGDBRemote.h | 8 +
.../Process/mach-core/ProcessMachCore.cpp | 8 +-
.../ScriptInterpreter/Python/CMakeLists.txt | 5 +
.../SymbolFile/DWARF/DWARFFormValue.cpp | 4 +
.../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 12 +-
.../MacOSX/AppleGetThreadItemInfoHandler.cpp | 2 +-
lldb/source/Symbol/DWARFCallFrameInfo.cpp | 4 +-
lldb/source/Target/ABI.cpp | 9 +
lldb/source/Target/CMakeLists.txt | 5 +
lldb/source/Target/Process.cpp | 10 +
lldb/source/Target/RegisterContextUnwind.cpp | 46 +
lldb/source/Target/ThreadPlanCallFunction.cpp | 34 +
lldb/source/Target/UnwindLLDB.cpp | 15 +
lldb/source/Utility/ArchSpec.cpp | 18 +-
.../Utility/StringExtractorGDBRemote.cpp | 2 +
lldb/test/CMakeLists.txt | 2 +-
lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +-
lldb/test/Shell/Process/TestEnvironment.test | 2 +-
lldb/tools/driver/CMakeLists.txt | 5 +
lldb/tools/driver/Driver.cpp | 5 +-
lldb/tools/lldb-dap/CMakeLists.txt | 4 +
lldb/tools/lldb-server/CMakeLists.txt | 7 +
.../lldb-server/SystemInitializerLLGS.cpp | 15 +
lldb/tools/lldb-server/lldb-gdbserver.cpp | 4 +
lldb/unittests/Host/FileSystemTest.cpp | 2 +-
lldb/unittests/Host/posix/TerminalTest.cpp | 4 +
llvm/include/llvm/Object/XCOFFObjectFile.h | 4 +-
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +-
129 files changed, 8950 insertions(+), 76 deletions(-)
create mode 100644 lldb/include/lldb/Host/aix/AbstractSocket.h
create mode 100644 lldb/include/lldb/Host/aix/Host.h
create mode 100644 lldb/include/lldb/Host/aix/HostInfoAIX.h
create mode 100644 lldb/include/lldb/Host/aix/Ptrace.h
create mode 100644 lldb/include/lldb/Host/aix/Support.h
create mode 100644 lldb/include/lldb/Host/aix/Uio.h
create mode 100644 lldb/source/Host/aix/AbstractSocket.cpp
create mode 100644 lldb/source/Host/aix/Host.cpp
create mode 100644 lldb/source/Host/aix/HostInfoAIX.cpp
create mode 100644 lldb/source/Host/aix/Support.cpp
create mode 100644 lldb/source/Host/common/LICENSE.aix-netbsd.txt
create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt
create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp
create mode 100644 lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h
create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt
create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp
create mode 100644 lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h
create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt
create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
create mode 100644 lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h
create mode 100644 lldb/source/Plugins/Platform/AIX/CMakeLists.txt
create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp
create mode 100644 lldb/source/Plugins/Platform/AIX/PlatformAIX.h
create mode 100644 lldb/source/Plugins/Process/AIX/CMakeLists.txt
create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
create mode 100644 lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
create mode 100644 lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
create mode 100644 lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 30f3911a8b03c2..fc91981db68c12 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -5052,10 +5052,14 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section,
case llvm::Triple::COFF:
assert(Section.starts_with("__") && "expected the name to begin with __");
return ("." + Section.substr(2) + "$B").str();
+ case llvm::Triple::XCOFF:
+ // Hack to allow "p 10+1" on AIX for lldb
+ assert(Section.substr(0, 2) == "__" &&
+ "expected the name to begin with __");
+ return Section.substr(2).str();
case llvm::Triple::Wasm:
case llvm::Triple::GOFF:
case llvm::Triple::SPIRV:
- case llvm::Triple::XCOFF:
case llvm::Triple::DXContainer:
llvm::report_fatal_error(
"Objective-C support is unimplemented for object file format");
diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt
index 59cdc4593463c1..2e9ae0d0b3221c 100644
--- a/lldb/CMakeLists.txt
+++ b/lldb/CMakeLists.txt
@@ -38,6 +38,10 @@ endif()
include(LLDBConfig)
include(AddLLDB)
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ add_definitions("-D__AIX__")
+endif()
+
# Define the LLDB_CONFIGURATION_xxx matching the build type.
if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" )
add_definitions(-DLLDB_CONFIGURATION_DEBUG)
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index a60921990cf775..a0f118a11984c2 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -299,7 +299,7 @@ endif()
# Figure out if lldb could use lldb-server. If so, then we'll
# ensure we build lldb-server when an lldb target is being built.
-if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows")
+if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|Windows|AIX")
set(LLDB_CAN_USE_LLDB_SERVER ON)
else()
set(LLDB_CAN_USE_LLDB_SERVER OFF)
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 5589c1c9a350dc..3829386562795c 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -196,6 +196,9 @@ class Module : public std::enable_shared_from_this<Module>,
bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset,
bool &changed);
+ bool SetLoadAddressByType(Target &target, lldb::addr_t value,
+ bool value_is_offset, bool &changed, int type_id);
+
/// \copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
///
/// \see SymbolContextScope
diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h
index 4cbbbfa8a26e13..4fe06412b6b0b8 100644
--- a/lldb/include/lldb/Core/ModuleSpec.h
+++ b/lldb/include/lldb/Core/ModuleSpec.h
@@ -21,6 +21,7 @@
#include <mutex>
#include <vector>
+#include <string.h>
namespace lldb_private {
@@ -41,8 +42,26 @@ class ModuleSpec {
}
ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch)
- : m_file(file_spec), m_arch(arch), m_object_offset(0),
- m_object_size(FileSystem::Instance().GetByteSize(file_spec)) {}
+ : m_arch(arch), m_object_offset(0) {
+ // parse object inside module format for example: /usr/ccs/lib/libc.a(shr_64.o)
+ llvm::SmallString<256> path_with_object;
+ file_spec.GetPath(path_with_object);
+ if (strstr(path_with_object.c_str(), "(") != nullptr) {
+ char *part;
+ char *str = (char *)path_with_object.c_str();
+ part = strtok(str, "()");
+ assert(part);
+ llvm::StringRef file_name(part);
+ part = strtok(nullptr, "()");
+ assert(part);
+ m_object_name = ConstString(part);
+ m_file = FileSpec(file_name);
+ m_object_size = FileSystem::Instance().GetByteSize(m_file);
+ } else {
+ m_file = file_spec;
+ m_object_size = FileSystem::Instance().GetByteSize(file_spec);
+ }
+ }
FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); }
diff --git a/lldb/include/lldb/Host/HostGetOpt.h b/lldb/include/lldb/Host/HostGetOpt.h
index 52cfdf4dbb89c2..f450e561d6afb1 100644
--- a/lldb/include/lldb/Host/HostGetOpt.h
+++ b/lldb/include/lldb/Host/HostGetOpt.h
@@ -9,7 +9,7 @@
#ifndef LLDB_HOST_HOSTGETOPT_H
#define LLDB_HOST_HOSTGETOPT_H
-#if !defined(_MSC_VER) && !defined(__NetBSD__)
+#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(__AIX__)
#include <getopt.h>
#include <unistd.h>
diff --git a/lldb/include/lldb/Host/HostInfo.h b/lldb/include/lldb/Host/HostInfo.h
index b7010d69d88e7f..156df8cf6901df 100644
--- a/lldb/include/lldb/Host/HostInfo.h
+++ b/lldb/include/lldb/Host/HostInfo.h
@@ -55,6 +55,9 @@
#elif defined(__APPLE__)
#include "lldb/Host/macosx/HostInfoMacOSX.h"
#define HOST_INFO_TYPE HostInfoMacOSX
+#elif defined(__AIX__)
+#include "lldb/Host/aix/HostInfoAIX.h"
+#define HOST_INFO_TYPE HostInfoAIX
#else
#include "lldb/Host/posix/HostInfoPosix.h"
#define HOST_INFO_TYPE HostInfoPosix
diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h
index 705aad559f3b78..29e6acf39bfb24 100644
--- a/lldb/include/lldb/Host/HostInfoBase.h
+++ b/lldb/include/lldb/Host/HostInfoBase.h
@@ -149,6 +149,7 @@ class HostInfoBase {
return {};
}
+ static bool ComputeSharedLibraryDirectory(FileSpec &file_spec);
/// Returns the distribution id of the host
///
/// This will be something like "ubuntu", "fedora", etc. on Linux.
@@ -158,7 +159,6 @@ class HostInfoBase {
static llvm::StringRef GetDistributionId() { return llvm::StringRef(); }
protected:
- static bool ComputeSharedLibraryDirectory(FileSpec &file_spec);
static bool ComputeSupportExeDirectory(FileSpec &file_spec);
static bool ComputeProcessTempFileDirectory(FileSpec &file_spec);
static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec);
diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h
index da0f9cd7aa8c06..cf359f7726d5d6 100644
--- a/lldb/include/lldb/Host/XML.h
+++ b/lldb/include/lldb/Host/XML.h
@@ -11,6 +11,11 @@
#include "lldb/Host/Config.h"
+#if defined(__AIX__)
+//FIXME for AIX
+#undef LLDB_ENABLE_LIBXML2
+#endif
+
#if LLDB_ENABLE_LIBXML2
#include <libxml/xmlreader.h>
#endif
diff --git a/lldb/include/lldb/Host/aix/AbstractSocket.h b/lldb/include/lldb/Host/aix/AbstractSocket.h
new file mode 100644
index 00000000000000..78a567a6b90953
--- /dev/null
+++ b/lldb/include/lldb/Host/aix/AbstractSocket.h
@@ -0,0 +1,25 @@
+//===-- AbstractSocket.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_AbstractSocket_h_
+#define liblldb_AbstractSocket_h_
+
+#include "lldb/Host/posix/DomainSocket.h"
+
+namespace lldb_private {
+class AbstractSocket : public DomainSocket {
+public:
+ AbstractSocket(bool child_processes_inherit);
+
+protected:
+ size_t GetNameOffset() const override;
+ void DeleteSocketFile(llvm::StringRef name) override;
+};
+}
+
+#endif // ifndef liblldb_AbstractSocket_h_
diff --git a/lldb/include/lldb/Host/aix/Host.h b/lldb/include/lldb/Host/aix/Host.h
new file mode 100644
index 00000000000000..1e3487752995fb
--- /dev/null
+++ b/lldb/include/lldb/Host/aix/Host.h
@@ -0,0 +1,22 @@
+//===-- Host.h --------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_AIX_HOST_H
+#define LLDB_HOST_AIX_HOST_H
+
+#include "lldb/lldb-types.h"
+#include <optional>
+
+namespace lldb_private {
+
+// Get PID (i.e. the primary thread ID) corresponding to the specified TID.
+std::optional<lldb::pid_t> getPIDForTID(lldb::pid_t tid);
+
+} // namespace lldb_private
+
+#endif // #ifndef LLDB_HOST_AIX_HOST_H
diff --git a/lldb/include/lldb/Host/aix/HostInfoAIX.h b/lldb/include/lldb/Host/aix/HostInfoAIX.h
new file mode 100644
index 00000000000000..ced4cf34d38a81
--- /dev/null
+++ b/lldb/include/lldb/Host/aix/HostInfoAIX.h
@@ -0,0 +1,42 @@
+//===-- HostInfoAIX.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_aix_HostInfoAIX_h_
+#define lldb_Host_aix_HostInfoAIX_h_
+
+#include "lldb/Host/posix/HostInfoPosix.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/VersionTuple.h"
+
+#include <string>
+
+namespace lldb_private {
+
+class HostInfoAIX : public HostInfoPosix {
+ friend class HostInfoBase;
+
+public:
+ static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr);
+ static void Terminate();
+
+ static llvm::VersionTuple GetOSVersion();
+ static std::optional<std::string> GetOSBuildString();
+ static llvm::StringRef GetDistributionId();
+ static FileSpec GetProgramFileSpec();
+
+protected:
+ static bool ComputeSupportExeDirectory(FileSpec &file_spec);
+ static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
+ static bool ComputeUserPluginsDirectory(FileSpec &file_spec);
+ static void ComputeHostArchitectureSupport(ArchSpec &arch_32,
+ ArchSpec &arch_64);
+};
+}
+
+#endif
diff --git a/lldb/include/lldb/Host/aix/Ptrace.h b/lldb/include/lldb/Host/aix/Ptrace.h
new file mode 100644
index 00000000000000..88928f18102d7c
--- /dev/null
+++ b/lldb/include/lldb/Host/aix/Ptrace.h
@@ -0,0 +1,62 @@
+//===-- Ptrace.h ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This file defines ptrace functions & structures
+
+#ifndef liblldb_Host_aix_Ptrace_h_
+#define liblldb_Host_aix_Ptrace_h_
+
+#include <sys/ptrace.h>
+
+#define DEBUG_PTRACE_MAXBYTES 20
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS (PT_COMMAND_MAX+1)
+#endif
+#ifndef PTRACE_SETREGS
+#define PTRACE_SETREGS (PT_COMMAND_MAX+2)
+#endif
+#ifndef PTRACE_GETFPREGS
+#define PTRACE_GETFPREGS (PT_COMMAND_MAX+3)
+#endif
+#ifndef PTRACE_SETFPREGS
+#define PTRACE_SETFPREGS (PT_COMMAND_MAX+4)
+#endif
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET 0x4204
+#endif
+#ifndef PTRACE_SETREGSET
+#define PTRACE_SETREGSET 0x4205
+#endif
+#ifndef PTRACE_GET_THREAD_AREA
+#define PTRACE_GET_THREAD_AREA (PT_COMMAND_MAX+5)
+#endif
+#ifndef PTRACE_ARCH_PRCTL
+#define PTRACE_ARCH_PRCTL (PT_COMMAND_MAX+6)
+#endif
+#ifndef ARCH_GET_FS
+#define ARCH_SET_GS 0x1001
+#define ARCH_SET_FS 0x1002
+#define ARCH_GET_FS 0x1003
+#define ARCH_GET_GS 0x1004
+#endif
+#ifndef PTRACE_PEEKMTETAGS
+#define PTRACE_PEEKMTETAGS (PT_COMMAND_MAX+7)
+#endif
+#ifndef PTRACE_POKEMTETAGS
+#define PTRACE_POKEMTETAGS (PT_COMMAND_MAX+8)
+#endif
+#ifndef PTRACE_GETVRREGS
+#define PTRACE_GETVRREGS (PT_COMMAND_MAX+9)
+#endif
+#ifndef PTRACE_GETVSRREGS
+#define PTRACE_GETVSRREGS (PT_COMMAND_MAX+10)
+#endif
+
+#endif // liblldb_Host_aix_Ptrace_h_
diff --git a/lldb/include/lldb/Host/aix/Support.h b/lldb/include/lldb/Host/aix/Support.h
new file mode 100644
index 00000000000000..27d6c2b50a35b0
--- /dev/null
+++ b/lldb/include/lldb/Host/aix/Support.h
@@ -0,0 +1,29 @@
+//===-- Support.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_AIX_SUPPORT_H
+#define LLDB_HOST_AIX_SUPPORT_H
+
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace lldb_private {
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file);
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(::pid_t pid, const llvm::Twine &file);
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(const llvm::Twine &file);
+
+} // namespace lldb_private
+
+#endif // #ifndef LLDB_HOST_AIX_SUPPORT_H
diff --git a/lldb/include/lldb/Host/aix/Uio.h b/lldb/include/lldb/Host/aix/Uio.h
new file mode 100644
index 00000000000000..acf79ecc6a1d0d
--- /dev/null
+++ b/lldb/include/lldb/Host/aix/Uio.h
@@ -0,0 +1,23 @@
+//===-- Uio.h ---------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Host_aix_Uio_h_
+#define liblldb_Host_aix_Uio_h_
+
+#include "lldb/Host/Config.h"
+#include <sys/uio.h>
+
+// We shall provide our own implementation of process_vm_readv if it is not
+// present
+#if !HAVE_PROCESS_VM_READV
+ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov,
+ unsigned long liovcnt, const struct iovec *remote_iov,
+ unsigned long riovcnt, unsigned long flags);
+#endif
+
+#endif // liblldb_Host_aix_Uio_h_
diff --git a/lldb/include/lldb/Host/common/GetOptInc.h b/lldb/include/lldb/Host/common/GetOptInc.h
index 3fb9add4795417..ebb475bfaf6b8d 100644
--- a/lldb/include/lldb/Host/common/GetOptInc.h
+++ b/lldb/include/lldb/Host/common/GetOptInc.h
@@ -11,11 +11,11 @@
#include "lldb/lldb-defines.h"
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(__AIX__)
#define REPLACE_GETOPT
#define REPLACE_GETOPT_LONG
#endif
-#if defined(_MSC_VER) || defined(__NetBSD__)
+#if defined(_MSC_VER) || defined(__NetBSD__) || defined(__AIX__)
#define REPLACE_GETOPT_LONG_ONLY
#endif
@@ -35,7 +35,7 @@ struct option {
int val;
};
-int getopt(int argc, char *const argv[], const char *optstring);
+int getopt(int argc, char *const argv[], const char *optstring) throw();
// from getopt.h
extern char *optarg;
diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index 8592323322e383..bf66ccec263d24 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -401,6 +401,11 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
return false;
}
+ virtual bool SetLoadAddressByType(Target &target, lldb::addr_t value,
+ bool value_is_offset, int type_id) {
+ return false;
+ }
+
/// Gets whether endian swapping should occur when extracting data from this
/// object file.
///
diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h
index 7b646d743346b7..281a89951ef885 100644
--- a/lldb/include/lldb/Target/ABI.h
+++ b/lldb/include/lldb/Target/ABI.h
@@ -47,6 +47,12 @@ class ABI : public PluginInterface {
lldb::addr_t returnAddress,
llvm::ArrayRef<lldb::addr_t> args) const = 0;
+ virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t tocAddress,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args) const;
+
// Prepare trivial call used from ThreadPlanFunctionCallUsingABI
// AD:
// . Because i don't want to change other ABI's this is not declared pure
diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h
index 0629e2faae7e9e..7dccd317c2dca1 100644
--- a/lldb/include/lldb/Target/DynamicLoader.h
+++ b/lldb/include/lldb/Target/DynamicLoader.h
@@ -359,6 +359,12 @@ class DynamicLoader : public PluginInterface {
lldb::addr_t base_addr,
bool base_addr_is_offset);
+ virtual void UpdateLoadedSectionsByType(lldb::ModuleSP module,
+ lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset,
+ int type_id);
+
// Utility method so base classes can share implementation of
// UpdateLoadedSections
void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr,
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index cf16fbc812aa48..886ca766112c8d 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -63,6 +63,10 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/VersionTuple.h"
+#if defined(__AIX__)
+struct ld_xinfo;
+#endif
+
namespace lldb_private {
template <typename B, typename S> struct Range;
@@ -1915,6 +1919,10 @@ class Process : public std::enable_shared_from_this<Process>,
Status GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info);
+#if defined(__AIX__)
+ Status GetLDXINFO(struct ld_xinfo *info_ptr);
+#endif
+
/// Obtain all the mapped memory regions within this process.
///
/// \param[out] region_list
@@ -2855,6 +2863,12 @@ void PruneThreadPlans();
return Status("Process::DoGetMemoryRegionInfo() not supported");
}
+#if defined(__AIX__)
+ virtual Status DoGetLDXINFO(struct ld_xinfo *info_ptr) {
+ return Status("Process::DoGetLDXINFO() not supported");
+ }
+#endif
+
/// Provide an override value in the subclass for lldb's
/// CPU-based logic for whether watchpoint exceptions are
/// received before or after an instruction executes.
diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h
index ef8ae884038663..00a95853800edd 100644
--- a/lldb/include/lldb/Target/RegisterContextUnwind.h
+++ b/lldb/include/lldb/Target/RegisterContextUnwind.h
@@ -67,6 +67,10 @@ class RegisterContextUnwind : public lldb_private::RegisterContext {
bool ReadPC(lldb::addr_t &start_pc);
+#ifdef __AIX__
+ bool ReadLR(lldb::addr_t &lr);
+#endif
+
// Indicates whether this frame *behaves* like frame zero -- the currently
// executing frame -- or not. This can be true in the middle of the stack
// above asynchronous trap handlers (sigtramp) for instance.
diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h
index cb6e7caebb4adf..7880db1592e04a 100644
--- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h
+++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h
@@ -27,6 +27,12 @@ class ThreadPlanCallFunction : public ThreadPlan {
llvm::ArrayRef<lldb::addr_t> args,
const EvaluateExpressionOptions &options);
+ ThreadPlanCallFunction(Thread &thread, const Address &function,
+ const Address &toc,
+ const CompilerType &return_type,
+ llvm::ArrayRef<lldb::addr_t> args,
+ const EvaluateExpressionOptions &options);
+
ThreadPlanCallFunction(Thread &thread, const Address &function,
const EvaluateExpressionOptions &options);
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index dd468ef5bddef0..9953bd6c24588c 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -61,6 +61,7 @@ class StringExtractorGDBRemote : public StringExtractor {
eServerPacketType_qQueryGDBServer,
eServerPacketType_qKillSpawnedProcess,
eServerPacketType_qLaunchSuccess,
+ eServerPacketType_qLDXINFO,
eServerPacketType_qModuleInfo,
eServerPacketType_qProcessInfoPID,
eServerPacketType_qSpeedTest,
diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h
index c24a3538f58dac..98c1e956bf8f7b 100644
--- a/lldb/include/lldb/lldb-private-enumerations.h
+++ b/lldb/include/lldb/lldb-private-enumerations.h
@@ -65,6 +65,7 @@ enum ArchitectureType {
eArchTypeMachO,
eArchTypeELF,
eArchTypeCOFF,
+ eArchTypeXCOFF,
kNumArchTypes
};
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index a32bc58507d8eb..3ecdb11daef7dc 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -40,6 +40,113 @@ add_custom_target(lldb-sbapi-dwarf-enums
DEPENDS ${sb_languages_file})
set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegenning")
+if(CMAKE_SYSTEM_NAME MATCHES "AIX")
+add_lldb_library(liblldb STATIC ${option_framework}
+ SBAddress.cpp
+ SBAddressRange.cpp
+ SBAddressRangeList.cpp
+ SBAttachInfo.cpp
+ SBBlock.cpp
+ SBBreakpoint.cpp
+ SBBreakpointLocation.cpp
+ SBBreakpointName.cpp
+ SBBreakpointOptionCommon.cpp
+ SBBroadcaster.cpp
+ SBCommandInterpreter.cpp
+ SBCommandInterpreterRunOptions.cpp
+ SBCommandReturnObject.cpp
+ SBCommunication.cpp
+ SBCompileUnit.cpp
+ SBSaveCoreOptions.cpp
+ SBData.cpp
+ SBDebugger.cpp
+ SBDeclaration.cpp
+ SBEnvironment.cpp
+ SBError.cpp
+ SBEvent.cpp
+ SBExecutionContext.cpp
+ SBExpressionOptions.cpp
+ SBFileSpec.cpp
+ SBFile.cpp
+ SBFileSpecList.cpp
+ SBFormat.cpp
+ SBFrame.cpp
+ SBFunction.cpp
+ SBHostOS.cpp
+ SBInstruction.cpp
+ SBInstructionList.cpp
+ SBLanguageRuntime.cpp
+ SBLaunchInfo.cpp
+ SBLineEntry.cpp
+ SBListener.cpp
+ SBMemoryRegionInfo.cpp
+ SBMemoryRegionInfoList.cpp
+ SBModule.cpp
+ SBModuleSpec.cpp
+ SBPlatform.cpp
+ SBProcess.cpp
+ SBProcessInfo.cpp
+ SBProcessInfoList.cpp
+ SBQueue.cpp
+ SBQueueItem.cpp
+ SBReproducer.cpp
+ SBScriptObject.cpp
+ SBSection.cpp
+ SBSourceManager.cpp
+ SBStatisticsOptions.cpp
+ SBStream.cpp
+ SBStringList.cpp
+ SBStructuredData.cpp
+ SBSymbol.cpp
+ SBSymbolContext.cpp
+ SBSymbolContextList.cpp
+ SBTarget.cpp
+ SBThread.cpp
+ SBThreadCollection.cpp
+ SBThreadPlan.cpp
+ SBTrace.cpp
+ SBTraceCursor.cpp
+ SBType.cpp
+ SBTypeCategory.cpp
+ SBTypeEnumMember.cpp
+ SBTypeFilter.cpp
+ SBTypeFormat.cpp
+ SBTypeNameSpecifier.cpp
+ SBTypeSummary.cpp
+ SBTypeSynthetic.cpp
+ SBValue.cpp
+ SBValueList.cpp
+ SBVariablesOptions.cpp
+ SBWatchpoint.cpp
+ SBWatchpointOptions.cpp
+ SBUnixSignals.cpp
+ SystemInitializerFull.cpp
+ ${lldb_python_wrapper}
+ ${lldb_lua_wrapper}
+
+ DEPENDS
+ lldb-sbapi-dwarf-enums
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbDataFormatters
+ lldbExpression
+ lldbHost
+ lldbInitialization
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbVersion
+ ${LLDB_ALL_PLUGINS}
+ LINK_COMPONENTS
+ Support
+
+ ${option_install_prefix}
+)
+
+else()
add_lldb_library(liblldb SHARED ${option_framework}
SBAddress.cpp
SBAddressRange.cpp
@@ -144,6 +251,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
${option_install_prefix}
)
+endif()
# lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so,
# which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index 3d908047f9455b..728fe04d14d927 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -342,7 +342,7 @@ uint32_t SBBreakpoint::GetIgnoreCount() const {
return count;
}
-void SBBreakpoint::SetThreadID(tid_t tid) {
+void SBBreakpoint::SetThreadID(lldb::tid_t tid) {
LLDB_INSTRUMENT_VA(this, tid);
BreakpointSP bkpt_sp = GetSP();
@@ -353,10 +353,10 @@ void SBBreakpoint::SetThreadID(tid_t tid) {
}
}
-tid_t SBBreakpoint::GetThreadID() {
+lldb::tid_t SBBreakpoint::GetThreadID() {
LLDB_INSTRUMENT_VA(this);
- tid_t tid = LLDB_INVALID_THREAD_ID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
BreakpointSP bkpt_sp = GetSP();
if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp
index 75b66364d4f1ae..fad9a4076a54fb 100644
--- a/lldb/source/API/SBBreakpointLocation.cpp
+++ b/lldb/source/API/SBBreakpointLocation.cpp
@@ -302,7 +302,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) {
return has_commands;
}
-void SBBreakpointLocation::SetThreadID(tid_t thread_id) {
+void SBBreakpointLocation::SetThreadID(lldb::tid_t thread_id) {
LLDB_INSTRUMENT_VA(this, thread_id);
BreakpointLocationSP loc_sp = GetSP();
@@ -313,10 +313,10 @@ void SBBreakpointLocation::SetThreadID(tid_t thread_id) {
}
}
-tid_t SBBreakpointLocation::GetThreadID() {
+lldb::tid_t SBBreakpointLocation::GetThreadID() {
LLDB_INSTRUMENT_VA(this);
- tid_t tid = LLDB_INVALID_THREAD_ID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
BreakpointLocationSP loc_sp = GetSP();
if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp
index 7f63aaf6fa7d5e..5c7c0a8f6504b0 100644
--- a/lldb/source/API/SBBreakpointName.cpp
+++ b/lldb/source/API/SBBreakpointName.cpp
@@ -347,7 +347,7 @@ bool SBBreakpointName::GetAutoContinue() {
return bp_name->GetOptions().IsAutoContinue();
}
-void SBBreakpointName::SetThreadID(tid_t tid) {
+void SBBreakpointName::SetThreadID(lldb::tid_t tid) {
LLDB_INSTRUMENT_VA(this, tid);
BreakpointName *bp_name = GetBreakpointName();
@@ -361,7 +361,7 @@ void SBBreakpointName::SetThreadID(tid_t tid) {
UpdateName(*bp_name);
}
-tid_t SBBreakpointName::GetThreadID() {
+lldb::tid_t SBBreakpointName::GetThreadID() {
LLDB_INSTRUMENT_VA(this);
BreakpointName *bp_name = GetBreakpointName();
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
index 7758a87403b5a3..ea43a7f98b69f4 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -113,6 +113,16 @@ void DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr,
UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset);
}
+void DynamicLoader::UpdateLoadedSectionsByType(lldb::ModuleSP module,
+ lldb::addr_t link_map_addr,
+ lldb::addr_t base_addr,
+ bool base_addr_is_offset,
+ int type_id) {
+ bool changed;
+ module->SetLoadAddressByType(m_process->GetTarget(), base_addr, base_addr_is_offset,
+ changed, type_id);
+}
+
void DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module,
addr_t base_addr,
bool base_addr_is_offset) {
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index 387c4fac6b0f8c..43c5b043ef7a28 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -167,12 +167,14 @@ static char *GetItaniumDemangledStr(const char *M) {
"Expected demangled_size to return length including trailing null");
}
+#if !defined(__AIX__)
if (Log *log = GetLog(LLDBLog::Demangle)) {
if (demangled_cstr)
LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);
else
LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M);
}
+#endif
return demangled_cstr;
}
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index f9d7832254f464..044a5d29978e84 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -1510,6 +1510,18 @@ bool Module::SetLoadAddress(Target &target, lldb::addr_t value,
return false;
}
+bool Module::SetLoadAddressByType(Target &target, lldb::addr_t value,
+ bool value_is_offset, bool &changed, int type_id) {
+ ObjectFile *object_file = GetObjectFile();
+ if (object_file != nullptr) {
+ changed = object_file->SetLoadAddressByType(target, value, value_is_offset, type_id);
+ return true;
+ } else {
+ changed = false;
+ }
+ return false;
+}
+
bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) {
const UUID &uuid = module_ref.GetUUID();
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
index 0763e88d4608f4..9ed55853930a67 100644
--- a/lldb/source/Core/Section.cpp
+++ b/lldb/source/Core/Section.cpp
@@ -263,6 +263,10 @@ bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr,
bool Section::ContainsFileAddress(addr_t vm_addr) const {
const addr_t file_addr = GetFileAddress();
+#ifdef __AIX__
+ if (file_addr == 0)
+ return false;
+#endif
if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) {
if (file_addr <= vm_addr) {
const addr_t offset = (vm_addr - file_addr) * m_target_byte_size;
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 444e44b3928919..c1feec990f989d 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -130,7 +130,7 @@ static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
/// Return the length in bytes of the set of operands for \p op. No guarantees
/// are made on the state of \p data after this call.
-static offset_t GetOpcodeDataSize(const DataExtractor &data,
+static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data,
const lldb::offset_t data_offset,
const uint8_t op, const DWARFUnit *dwarf_cu) {
lldb::offset_t offset = data_offset;
@@ -358,7 +358,7 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu,
error = true;
break;
}
- const offset_t op_arg_size =
+ const lldb::offset_t op_arg_size =
GetOpcodeDataSize(m_data, offset, op, dwarf_cu);
if (op_arg_size == LLDB_INVALID_OFFSET) {
error = true;
@@ -418,7 +418,7 @@ bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit *dwarf_cu,
m_data.SetData(encoder.GetDataBuffer());
return true;
}
- const offset_t op_arg_size =
+ const lldb::offset_t op_arg_size =
GetOpcodeDataSize(m_data, offset, op, dwarf_cu);
if (op_arg_size == LLDB_INVALID_OFFSET)
break;
@@ -435,7 +435,7 @@ bool DWARFExpression::ContainsThreadLocalStorage(
if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address)
return true;
- const offset_t op_arg_size =
+ const lldb::offset_t op_arg_size =
GetOpcodeDataSize(m_data, offset, op, dwarf_cu);
if (op_arg_size == LLDB_INVALID_OFFSET)
return false;
@@ -515,7 +515,7 @@ bool DWARFExpression::LinkThreadLocalStorage(
}
if (!decoded_data) {
- const offset_t op_arg_size =
+ const lldb::offset_t op_arg_size =
GetOpcodeDataSize(m_data, offset, op, dwarf_cu);
if (op_arg_size == LLDB_INVALID_OFFSET)
return false;
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index c2e091ee8555b7..5374b168819508 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -7,6 +7,11 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY)
endif()
endif()
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ remove_definitions("-D_XOPEN_SOURCE=700")
+ add_definitions("-D_ALL_SOURCE")
+endif()
+
macro(add_host_subdirectory group)
list(APPEND HOST_SOURCES ${ARGN})
source_group(${group} FILES ${ARGN})
@@ -133,6 +138,14 @@ else()
openbsd/Host.cpp
openbsd/HostInfoOpenBSD.cpp
)
+
+ elseif (CMAKE_SYSTEM_NAME MATCHES "AIX")
+ add_host_subdirectory(aix
+ aix/AbstractSocket.cpp
+ aix/Host.cpp
+ aix/HostInfoAIX.cpp
+ aix/Support.cpp
+ )
endif()
endif()
diff --git a/lldb/source/Host/aix/AbstractSocket.cpp b/lldb/source/Host/aix/AbstractSocket.cpp
new file mode 100644
index 00000000000000..bfb67d452f7ec0
--- /dev/null
+++ b/lldb/source/Host/aix/AbstractSocket.cpp
@@ -0,0 +1,21 @@
+//===-- AbstractSocket.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/aix/AbstractSocket.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+AbstractSocket::AbstractSocket(bool child_processes_inherit)
+ : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {}
+
+size_t AbstractSocket::GetNameOffset() const { return 1; }
+
+void AbstractSocket::DeleteSocketFile(llvm::StringRef name) {}
diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp
new file mode 100644
index 00000000000000..d82cb9049d389f
--- /dev/null
+++ b/lldb/source/Host/aix/Host.cpp
@@ -0,0 +1,304 @@
+//===-- source/Host/aix/Host.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
+#include "lldb/Utility/Status.h"
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/aix/Host.h"
+#include "lldb/Host/aix/Support.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+
+#include <sstream>
+#include <sys/procfs.h>
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+enum class ProcessState {
+ Unknown,
+ Dead,
+ DiskSleep,
+ Idle,
+ Paging,
+ Parked,
+ Running,
+ Sleeping,
+ TracedOrStopped,
+ Zombie,
+};
+}
+
+namespace lldb_private {
+class ProcessLaunchInfo;
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+ ProcessState &State, ::pid_t &TracerPid,
+ ::pid_t &Tgid) {
+ Log *log = GetLog(LLDBLog::Host);
+
+ auto BufferOrError = getProcFile(Pid, "status");
+ if (!BufferOrError)
+ return false;
+
+ llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+ while (!Rest.empty()) {
+ llvm::StringRef Line;
+ std::tie(Line, Rest) = Rest.split('\n');
+
+ if (Line.consume_front("Gid:")) {
+ // Real, effective, saved set, and file system GIDs. Read the first two.
+ Line = Line.ltrim();
+ uint32_t RGid, EGid;
+ Line.consumeInteger(10, RGid);
+ Line = Line.ltrim();
+ Line.consumeInteger(10, EGid);
+
+ ProcessInfo.SetGroupID(RGid);
+ ProcessInfo.SetEffectiveGroupID(EGid);
+ } else if (Line.consume_front("Uid:")) {
+ // Real, effective, saved set, and file system UIDs. Read the first two.
+ Line = Line.ltrim();
+ uint32_t RUid, EUid;
+ Line.consumeInteger(10, RUid);
+ Line = Line.ltrim();
+ Line.consumeInteger(10, EUid);
+
+ ProcessInfo.SetUserID(RUid);
+ ProcessInfo.SetEffectiveUserID(EUid);
+ } else if (Line.consume_front("PPid:")) {
+ ::pid_t PPid;
+ Line.ltrim().consumeInteger(10, PPid);
+ ProcessInfo.SetParentProcessID(PPid);
+ } else if (Line.consume_front("State:")) {
+ State = llvm::StringSwitch<ProcessState>(Line.ltrim().take_front(1))
+ .Case("D", ProcessState::DiskSleep)
+ .Case("I", ProcessState::Idle)
+ .Case("R", ProcessState::Running)
+ .Case("S", ProcessState::Sleeping)
+ .CaseLower("T", ProcessState::TracedOrStopped)
+ .Case("W", ProcessState::Paging)
+ .Case("P", ProcessState::Parked)
+ .Case("X", ProcessState::Dead)
+ .Case("Z", ProcessState::Zombie)
+ .Default(ProcessState::Unknown);
+ if (State == ProcessState::Unknown) {
+ LLDB_LOG(log, "Unknown process state {0}", Line);
+ }
+ } else if (Line.consume_front("TracerPid:")) {
+ Line = Line.ltrim();
+ Line.consumeInteger(10, TracerPid);
+ } else if (Line.consume_front("Tgid:")) {
+ Line = Line.ltrim();
+ Line.consumeInteger(10, Tgid);
+ }
+ }
+ return true;
+}
+
+static bool IsDirNumeric(const char *dname) {
+ for (; *dname; dname++) {
+ if (!isdigit(*dname))
+ return false;
+ }
+ return true;
+}
+
+static void GetProcessArgs(::pid_t pid, ProcessInstanceInfo &process_info) {
+ auto BufferOrError = getProcFile(pid, "cmdline");
+ if (!BufferOrError)
+ return;
+ std::unique_ptr<llvm::MemoryBuffer> Cmdline = std::move(*BufferOrError);
+
+ llvm::StringRef Arg0, Rest;
+ std::tie(Arg0, Rest) = Cmdline->getBuffer().split('\0');
+ process_info.SetArg0(Arg0);
+ while (!Rest.empty()) {
+ llvm::StringRef Arg;
+ std::tie(Arg, Rest) = Rest.split('\0');
+ process_info.GetArguments().AppendArgument(Arg);
+ }
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+ Log *log = GetLog(LLDBLog::Process);
+ std::string ExePath(PATH_MAX, '\0');
+ std::string Basename(PATH_MAX, '\0');
+ struct psinfo psinfoData;
+
+ // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+ llvm::SmallString<64> ProcExe;
+ (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
+
+ ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
+ if (len > 0) {
+ ExePath.resize(len);
+
+ //FIXME: hack to get basename
+ struct stat statData;
+
+ std::ostringstream oss;
+
+ oss << "/proc/" << std::dec << pid << "/psinfo";
+ assert(stat(oss.str().c_str(), &statData) == 0);
+
+ const int fd = open(oss.str().c_str(), O_RDONLY);
+ assert (fd >= 0);
+
+ ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData));
+ assert (readNum >= 0);
+
+ close (fd);
+ } else {
+ LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
+ Status(errno, eErrorTypePOSIX));
+ ExePath.resize(0);
+ }
+
+ llvm::StringRef PathRef = std::string(&(psinfoData.pr_psargs[0]));
+
+ if (!PathRef.empty()) {
+ process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
+ ArchSpec arch_spec = ArchSpec();
+ arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);
+ process_info.SetArchitecture(arch_spec);
+ }
+}
+
+static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
+ // Get the process environment.
+ auto BufferOrError = getProcFile(pid, "environ");
+ if (!BufferOrError)
+ return;
+
+ std::unique_ptr<llvm::MemoryBuffer> Environ = std::move(*BufferOrError);
+ llvm::StringRef Rest = Environ->getBuffer();
+ while (!Rest.empty()) {
+ llvm::StringRef Var;
+ std::tie(Var, Rest) = Rest.split('\0');
+ process_info.GetEnvironment().insert(Var);
+ }
+}
+
+static bool GetProcessAndStatInfo(::pid_t pid,
+ ProcessInstanceInfo &process_info,
+ ProcessState &State, ::pid_t &tracerpid) {
+ ::pid_t tgid;
+ tracerpid = 0;
+ process_info.Clear();
+
+ process_info.SetProcessID(pid);
+
+ GetExePathAndArch(pid, process_info);
+ GetProcessArgs(pid, process_info);
+ GetProcessEnviron(pid, process_info);
+
+ // Get User and Group IDs and get tracer pid.
+ if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
+ return false;
+
+ return true;
+}
+
+uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) {
+ static const char procdir[] = "/proc/";
+
+ DIR *dirproc = opendir(procdir);
+ if (dirproc) {
+ struct dirent *direntry = nullptr;
+ const uid_t our_uid = getuid();
+ const lldb::pid_t our_pid = getpid();
+ bool all_users = match_info.GetMatchAllUsers();
+
+ while ((direntry = readdir(dirproc)) != nullptr) {
+ /*
+ if (direntry->d_type != DT_DIR || !IsDirNumeric(direntry->d_name))
+ continue;
+ */
+
+ lldb::pid_t pid = atoi(direntry->d_name);
+
+ // Skip this process.
+ if (pid == our_pid)
+ continue;
+
+ ::pid_t tracerpid;
+ ProcessState State;
+ ProcessInstanceInfo process_info;
+
+ if (!GetProcessAndStatInfo(pid, process_info, State, tracerpid))
+ continue;
+
+ // Skip if process is being debugged.
+ if (tracerpid != 0)
+ continue;
+
+ if (State == ProcessState::Zombie)
+ continue;
+
+ // Check for user match if we're not matching all users and not running
+ // as root.
+ if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
+ continue;
+
+ if (match_info.Matches(process_info)) {
+ process_infos.push_back(process_info);
+ }
+ }
+
+ closedir(dirproc);
+ }
+
+ return process_infos.size();
+}
+
+bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
+ ::pid_t tracerpid;
+ ProcessState State;
+ return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
+}
+
+Environment Host::GetEnvironment() { return Environment(environ); }
+
+Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
+ return Status("unimplemented");
+}
+
+std::optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
+ ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
+ ProcessInstanceInfo process_info;
+ ProcessState state;
+
+ if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
+ tgid == LLDB_INVALID_PROCESS_ID)
+ return std::nullopt;
+ return tgid;
+}
diff --git a/lldb/source/Host/aix/HostInfoAIX.cpp b/lldb/source/Host/aix/HostInfoAIX.cpp
new file mode 100644
index 00000000000000..8bda09e01741b6
--- /dev/null
+++ b/lldb/source/Host/aix/HostInfoAIX.cpp
@@ -0,0 +1,215 @@
+//===-- HostInfoAIX.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/aix/HostInfoAIX.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/Support/Threading.h"
+
+#include <climits>
+#include <cstdio>
+#include <cstring>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <mutex>
+
+using namespace lldb_private;
+
+namespace {
+struct HostInfoAIXFields {
+ llvm::once_flag m_distribution_once_flag;
+ std::string m_distribution_id;
+ llvm::once_flag m_os_version_once_flag;
+ llvm::VersionTuple m_os_version;
+};
+} // namespace
+
+static HostInfoAIXFields *g_fields = nullptr;
+
+void HostInfoAIX::Initialize(SharedLibraryDirectoryHelper *helper) {
+ HostInfoPosix::Initialize(helper);
+
+ g_fields = new HostInfoAIXFields();
+}
+
+void HostInfoAIX::Terminate() {
+ assert(g_fields && "Missing call to Initialize?");
+ delete g_fields;
+ g_fields = nullptr;
+ HostInfoBase::Terminate();
+}
+
+llvm::VersionTuple HostInfoAIX::GetOSVersion() {
+ assert(g_fields && "Missing call to Initialize?");
+ llvm::call_once(g_fields->m_os_version_once_flag, []() {
+ struct utsname un;
+ if (uname(&un) != 0)
+ return;
+
+ llvm::StringRef release = un.release;
+ // The kernel release string can include a lot of stuff (e.g.
+ // 4.9.0-6-amd64). We're only interested in the numbered prefix.
+ release = release.substr(0, release.find_first_not_of("0123456789."));
+ g_fields->m_os_version.tryParse(release);
+ });
+
+ return g_fields->m_os_version;
+}
+
+std::optional<std::string> HostInfoAIX::GetOSBuildString() {
+ struct utsname un;
+ ::memset(&un, 0, sizeof(utsname));
+
+ if (uname(&un) < 0)
+ return std::nullopt;
+
+ return std::string(un.release);
+}
+
+llvm::StringRef HostInfoAIX::GetDistributionId() {
+ assert(g_fields && "Missing call to Initialize?");
+ // Try to run 'lbs_release -i', and use that response for the distribution
+ // id.
+ llvm::call_once(g_fields->m_distribution_once_flag, []() {
+ Log *log = GetLog(LLDBLog::Host);
+ LLDB_LOGF(log, "attempting to determine AIX distribution...");
+
+ // check if the lsb_release command exists at one of the following paths
+ const char *const exe_paths[] = {"/bin/lsb_release",
+ "/usr/bin/lsb_release"};
+
+ for (size_t exe_index = 0;
+ exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) {
+ const char *const get_distribution_info_exe = exe_paths[exe_index];
+ if (access(get_distribution_info_exe, F_OK)) {
+ // this exe doesn't exist, move on to next exe
+ LLDB_LOGF(log, "executable doesn't exist: %s",
+ get_distribution_info_exe);
+ continue;
+ }
+
+ // execute the distribution-retrieval command, read output
+ std::string get_distribution_id_command(get_distribution_info_exe);
+ get_distribution_id_command += " -i";
+
+ FILE *file = popen(get_distribution_id_command.c_str(), "r");
+ if (!file) {
+ LLDB_LOGF(log,
+ "failed to run command: \"%s\", cannot retrieve "
+ "platform information",
+ get_distribution_id_command.c_str());
+ break;
+ }
+
+ // retrieve the distribution id string.
+ char distribution_id[256] = {'\0'};
+ if (fgets(distribution_id, sizeof(distribution_id) - 1, file) !=
+ nullptr) {
+ LLDB_LOGF(log, "distribution id command returned \"%s\"",
+ distribution_id);
+
+ const char *const distributor_id_key = "Distributor ID:\t";
+ if (strstr(distribution_id, distributor_id_key)) {
+ // strip newlines
+ std::string id_string(distribution_id + strlen(distributor_id_key));
+ id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'),
+ id_string.end());
+
+ // lower case it and convert whitespace to underscores
+ std::transform(
+ id_string.begin(), id_string.end(), id_string.begin(),
+ [](char ch) { return tolower(isspace(ch) ? '_' : ch); });
+
+ g_fields->m_distribution_id = id_string;
+ LLDB_LOGF(log, "distribution id set to \"%s\"",
+ g_fields->m_distribution_id.c_str());
+ } else {
+ LLDB_LOGF(log, "failed to find \"%s\" field in \"%s\"",
+ distributor_id_key, distribution_id);
+ }
+ } else {
+ LLDB_LOGF(log,
+ "failed to retrieve distribution id, \"%s\" returned no"
+ " lines",
+ get_distribution_id_command.c_str());
+ }
+
+ // clean up the file
+ pclose(file);
+ }
+ });
+
+ return g_fields->m_distribution_id;
+}
+
+FileSpec HostInfoAIX::GetProgramFileSpec() {
+ static FileSpec g_program_filespec;
+
+ if (!g_program_filespec) {
+ char exe_path[PATH_MAX];
+ ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
+ if (len > 0) {
+ exe_path[len] = 0;
+ g_program_filespec.SetFile(exe_path, FileSpec::Style::native);
+ }
+ }
+
+ return g_program_filespec;
+}
+
+bool HostInfoAIX::ComputeSupportExeDirectory(FileSpec &file_spec) {
+ if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) &&
+ file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec))
+ return true;
+ file_spec.SetDirectory(GetProgramFileSpec().GetDirectory());
+ return !file_spec.GetDirectory().IsEmpty();
+}
+
+bool HostInfoAIX::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
+ FileSpec temp_file("/usr/" LLDB_INSTALL_LIBDIR_BASENAME "/lldb/plugins");
+ FileSystem::Instance().Resolve(temp_file);
+ file_spec.SetDirectory(temp_file.GetPath());
+ return true;
+}
+
+bool HostInfoAIX::ComputeUserPluginsDirectory(FileSpec &file_spec) {
+ // XDG Base Directory Specification
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html If
+ // XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
+ const char *xdg_data_home = getenv("XDG_DATA_HOME");
+ if (xdg_data_home && xdg_data_home[0]) {
+ std::string user_plugin_dir(xdg_data_home);
+ user_plugin_dir += "/lldb";
+ file_spec.SetDirectory(user_plugin_dir.c_str());
+ } else
+ file_spec.SetDirectory("~/.local/share/lldb");
+ return true;
+}
+
+void HostInfoAIX::ComputeHostArchitectureSupport(ArchSpec &arch_32,
+ ArchSpec &arch_64) {
+ HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64);
+
+ const char *distribution_id = GetDistributionId().data();
+
+ // On Linux, "unknown" in the vendor slot isn't what we want for the default
+ // triple. It's probably an artifact of config.guess.
+ if (arch_32.IsValid()) {
+ if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor)
+ arch_32.GetTriple().setVendorName(llvm::StringRef());
+ }
+ if (arch_64.IsValid()) {
+ if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor)
+ arch_64.GetTriple().setVendorName(llvm::StringRef());
+ }
+}
diff --git a/lldb/source/Host/aix/Support.cpp b/lldb/source/Host/aix/Support.cpp
new file mode 100644
index 00000000000000..1bf26621901270
--- /dev/null
+++ b/lldb/source/Host/aix/Support.cpp
@@ -0,0 +1,44 @@
+//===-- Support.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/aix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) {
+ Log *log = GetLog(LLDBLog::Host);
+ std::string File =
+ ("/proc/" + llvm::Twine(pid) + "/task/" + llvm::Twine(tid) + "/" + file)
+ .str();
+ auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
+ if (!Ret)
+ LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
+ return Ret;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) {
+ Log *log = GetLog(LLDBLog::Host);
+ std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str();
+ auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
+ if (!Ret)
+ LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
+ return Ret;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+lldb_private::getProcFile(const llvm::Twine &file) {
+ Log *log = GetLog(LLDBLog::Host);
+ std::string File = ("/proc/" + file).str();
+ auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
+ if (!Ret)
+ LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
+ return Ret;
+}
diff --git a/lldb/source/Host/common/GetOptInc.cpp b/lldb/source/Host/common/GetOptInc.cpp
index c2044b68732215..e0ae2aa1774b3f 100644
--- a/lldb/source/Host/common/GetOptInc.cpp
+++ b/lldb/source/Host/common/GetOptInc.cpp
@@ -409,7 +409,7 @@ static int getopt_internal(int nargc, char *const *nargv, const char *options,
* [eventually this will replace the BSD getopt]
*/
#if defined(REPLACE_GETOPT)
-int getopt(int nargc, char *const *nargv, const char *options) {
+int getopt(int nargc, char *const *nargv, const char *options) throw() {
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index e03d36e9cad4a0..2fd7111a94fb20 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -357,9 +357,183 @@ bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; }
#ifndef _WIN32
+#if defined(__AIX__)
+
+#include <stdio.h>
+extern char **p_xargv;
+
+/* Fix missing Dl_info & dladdr in AIX
+ * The code is taken from netbsd.org (src/crypto/external/bsd/openssl/dist/crypto/dso/dso_dlfcn.c)
+ * except strlcpy & strlcat (those are taken from openbsd.org (src/lib/libc/string))
+ */
+/*-
+ * See IBM's AIX Version 7.2, Technical Reference:
+ * Base Operating System and Extensions, Volume 1 and 2
+ * https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm
+ */
+#include <sys/ldr.h>
+#include <errno.h>
+
+/* strlcpy:
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
+size_t strlcpy(char *dst, const char *src, size_t dsize)
+{
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0') {
+ break;
+ }
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0) {
+ *dst = '\0'; /* NUL-terminate dst */
+ }
+ while (*src++) {
+ ;
+ }
+ }
+
+ return src - osrc - 1; /* count does not include NUL */
+}
+
+/* strlcat:
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
+ */
+size_t strlcat(char *dst, const char *src, size_t dsize)
+{
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0') {
+ dst++;
+ }
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0) {
+ return dlen + strlen(src);
+ }
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
+ n--;
+ }
+ src++;
+ }
+ *dst = '\0';
+
+ return dlen + src - osrc; /* count does not include NUL */
+}
+
+/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */
+# define DLFCN_LDINFO_SIZE 86976
+typedef struct Dl_info {
+ const char *dli_fname;
+} Dl_info;
+/*
+ * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual
+ * address of a function, which is just located in the DATA segment instead of
+ * the TEXT segment.
+ */
+static int dladdr(const void *ptr, Dl_info *dl)
+{
+ uintptr_t addr = (uintptr_t)ptr;
+ struct ld_info *ldinfos;
+ struct ld_info *next_ldi;
+ struct ld_info *this_ldi;
+
+ if ((ldinfos = (struct ld_info *)malloc(DLFCN_LDINFO_SIZE)) == NULL) {
+ dl->dli_fname = NULL;
+ return 0;
+ }
+
+ if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) {
+ /*-
+ * Error handling is done through errno and dlerror() reading errno:
+ * ENOMEM (ldinfos buffer is too small),
+ * EINVAL (invalid flags),
+ * EFAULT (invalid ldinfos ptr)
+ */
+ free((void *)ldinfos);
+ dl->dli_fname = NULL;
+ return 0;
+ }
+ next_ldi = ldinfos;
+
+ do {
+ this_ldi = next_ldi;
+ if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg)
+ && (addr < ((uintptr_t)this_ldi->ldinfo_textorg +
+ this_ldi->ldinfo_textsize)))
+ || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg)
+ && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg +
+ this_ldi->ldinfo_datasize)))) {
+ char *buffer = NULL;
+ char *member = NULL;
+ size_t buffer_sz;
+ size_t member_len;
+
+ buffer_sz = strlen(this_ldi->ldinfo_filename) + 1;
+ member = this_ldi->ldinfo_filename + buffer_sz;
+ if ((member_len = strlen(member)) > 0) {
+ buffer_sz += 1 + member_len + 1;
+ }
+ if ((buffer = (char *)malloc(buffer_sz)) != NULL) {
+ strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz);
+ if (member_len > 0) {
+ /*
+ * Need to respect a possible member name and not just
+ * returning the path name in this case. See docs:
+ * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER.
+ */
+ strlcat(buffer, "(", buffer_sz);
+ strlcat(buffer, member, buffer_sz);
+ strlcat(buffer, ")", buffer_sz);
+ }
+ dl->dli_fname = buffer;
+ }
+ break;
+ } else {
+ next_ldi = (struct ld_info *)((uintptr_t)this_ldi +
+ this_ldi->ldinfo_next);
+ }
+ } while (this_ldi->ldinfo_next);
+ free((void *)ldinfos);
+ return dl->dli_fname != NULL;
+}
+
+#endif
+
FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
FileSpec module_filespec;
#if !defined(__ANDROID__)
+#ifdef __AIX__
+ if (host_addr == reinterpret_cast<void *>(HostInfoBase::ComputeSharedLibraryDirectory)) {
+ // FIXME: AIX dladdr return "lldb" for this case
+ if (p_xargv[0]) {
+ module_filespec.SetFile(p_xargv[0], FileSpec::Style::native);
+ FileSystem::Instance().Resolve(module_filespec);
+ return module_filespec;
+ }
+ }
+#endif
Dl_info info;
if (::dladdr(host_addr, &info)) {
if (info.dli_fname) {
@@ -373,12 +547,6 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {
#endif
-#if !defined(__linux__)
-bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {
- return false;
-}
-#endif
-
struct ShellInfo {
ShellInfo() : process_reaped(false) {}
diff --git a/lldb/source/Host/common/LICENSE.aix-netbsd.txt b/lldb/source/Host/common/LICENSE.aix-netbsd.txt
new file mode 100644
index 00000000000000..9601ab43575f97
--- /dev/null
+++ b/lldb/source/Host/common/LICENSE.aix-netbsd.txt
@@ -0,0 +1,125 @@
+
+ LICENSE ISSUES
+ ==============
+
+ The OpenSSL toolkit stays under a double license, i.e. both the conditions of
+ the OpenSSL License and the original SSLeay license apply to the toolkit.
+ See below for the actual license texts.
+
+ OpenSSL License
+ ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core at openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay at cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh at cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay at cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp
index f480ef3166a443..62cac78aaac230 100644
--- a/lldb/source/Host/common/XML.cpp
+++ b/lldb/source/Host/common/XML.cpp
@@ -10,6 +10,9 @@
#include "lldb/Host/XML.h"
#include "llvm/ADT/StringExtras.h"
+#if defined(__AIX__)
+#undef LLDB_ENABLE_LIBXML2
+#endif
using namespace lldb;
using namespace lldb_private;
diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
index fceeff08ed9d36..143254bb129014 100644
--- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
+++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -721,6 +721,7 @@ ConnectionFileDescriptor::ConnectFD(llvm::StringRef s,
ConnectionStatus ConnectionFileDescriptor::ConnectFile(
llvm::StringRef s, socket_id_callback_type socket_id_callback,
Status *error_ptr) {
+#if !defined(__AIX__)
#if LLDB_ENABLE_POSIX
std::string addr_str = s.str();
// file:///PATH
@@ -753,6 +754,7 @@ ConnectionStatus ConnectionFileDescriptor::ConnectFile(
m_io_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, true);
return eConnectionStatusSuccess;
#endif // LLDB_ENABLE_POSIX
+#endif
llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
}
diff --git a/lldb/source/Host/posix/FileSystemPosix.cpp b/lldb/source/Host/posix/FileSystemPosix.cpp
index cdb76da626bc9f..a7c50f6a3c8353 100644
--- a/lldb/source/Host/posix/FileSystemPosix.cpp
+++ b/lldb/source/Host/posix/FileSystemPosix.cpp
@@ -11,7 +11,9 @@
// C includes
#include <dirent.h>
#include <fcntl.h>
+#if !defined(__AIX__)
#include <sys/mount.h>
+#endif
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp
index 5fe4d015251c8a..e5be0db4cf19b5 100644
--- a/lldb/source/Host/posix/MainLoopPosix.cpp
+++ b/lldb/source/Host/posix/MainLoopPosix.cpp
@@ -179,9 +179,21 @@ Status MainLoopPosix::RunImpl::Poll() {
read_fds.push_back(pfd);
}
+#if defined(__AIX__)
+ sigset_t origmask;
+ int timeout;
+
+ timeout = -1;
+ pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
+ int ready = poll(read_fds.data(), read_fds.size(), timeout);
+ pthread_sigmask(SIG_SETMASK, &origmask, nullptr);
+ if (ready == -1 && errno != EINTR)
+ return Status(errno, eErrorTypePOSIX);
+#else
if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
errno != EINTR)
return Status(errno, eErrorTypePOSIX);
+#endif
return Status();
}
@@ -312,8 +324,13 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
// If we're using kqueue, the signal needs to be unblocked in order to
// receive it. If using pselect/ppoll, we need to block it, and later unblock
// it as a part of the system call.
+#if defined(__AIX__)
+ //FIXME: where is signal unblocked?
+ ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set);
+#else
ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
&new_action.sa_mask, &old_set);
+#endif
assert(ret == 0 && "pthread_sigmask failed");
info.was_blocked = sigismember(&old_set, signo);
auto insert_ret = m_signals.insert({signo, info});
diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
index 0a832ebad13a75..cd106f605b1f42 100644
--- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
+++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
@@ -193,8 +193,13 @@ struct ForkLaunchInfo {
}
// Start tracing this child that is about to exec.
+#if !defined(__AIX__)
if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
ExitWithError(error_fd, "ptrace");
+#else
+ if (ptrace64(PT_TRACE_ME, 0, 0, 0, nullptr) == -1)
+ ExitWithError(error_fd, "ptrace");
+#endif
}
// Execute. We should never return...
diff --git a/lldb/source/Initialization/CMakeLists.txt b/lldb/source/Initialization/CMakeLists.txt
index c1a167826f76fd..9f94830c8509fc 100644
--- a/lldb/source/Initialization/CMakeLists.txt
+++ b/lldb/source/Initialization/CMakeLists.txt
@@ -1,4 +1,4 @@
-if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD" )
+if ( CMAKE_SYSTEM_NAME MATCHES "Linux|Android|FreeBSD|NetBSD|AIX" )
list(APPEND EXTRA_PLUGINS lldbPluginProcessPOSIX)
endif()
diff --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp
index 1a172a95aa1471..4b01442a94bacf 100644
--- a/lldb/source/Initialization/SystemInitializerCommon.cpp
+++ b/lldb/source/Initialization/SystemInitializerCommon.cpp
@@ -19,7 +19,7 @@
#include "lldb/Version/Version.h"
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
- defined(__OpenBSD__)
+ defined(__OpenBSD__) || defined(__AIX__)
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#endif
@@ -79,7 +79,7 @@ llvm::Error SystemInitializerCommon::Initialize() {
process_gdb_remote::ProcessGDBRemoteLog::Initialize();
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
- defined(__OpenBSD__)
+ defined(__OpenBSD__) || defined(__AIX__)
ProcessPOSIXLog::Initialize();
#endif
#if defined(_WIN32)
diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
index eac058701313b8..feb0d7c0e09bec 100644
--- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
+++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
@@ -156,6 +156,9 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,
if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr))
return false;
+#if defined(__AIX__)
+ assert(0);
+#else
// Read TOC pointer value.
reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
@@ -171,6 +174,132 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,
(uint64_t)reg_value);
if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error))
return false;
+#endif
+
+ // Read the current SP value.
+ reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0);
+
+ // Save current SP onto the stack.
+ LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp,
+ (uint64_t)reg_value);
+ if (!process_sp->WritePointerToMemory(sp, reg_value, error))
+ return false;
+
+ // %r1 is set to the actual stack value.
+ LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
+ return false;
+
+ // %pc is set to the address of the called function.
+
+ LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
+ return false;
+
+ return true;
+}
+
+bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,
+ addr_t func_addr, addr_t toc_addr,
+ addr_t return_addr,
+ llvm::ArrayRef<addr_t> args) const {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (log) {
+ StreamString s;
+ s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64
+ ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
+ ", return_addr = 0x%" PRIx64,
+ thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
+ (uint64_t)return_addr);
+
+ for (size_t i = 0; i < args.size(); ++i)
+ s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1),
+ args[i]);
+ s.PutCString(")");
+ log->PutString(s.GetString());
+ }
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ const RegisterInfo *reg_info = nullptr;
+
+ if (args.size() > 8) // TODO handle more than 8 arguments
+ return false;
+
+ for (size_t i = 0; i < args.size(); ++i) {
+ reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_ARG1 + i);
+ LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s",
+ static_cast<uint64_t>(i + 1), args[i], reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
+ return false;
+ }
+
+ // First, align the SP
+
+ LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64,
+ (uint64_t)sp, (uint64_t)(sp & ~0xfull));
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ sp -= 544; // allocate frame to save TOC, RA and SP.
+
+ Status error;
+ uint64_t reg_value;
+ const RegisterInfo *pc_reg_info =
+ reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo *sp_reg_info =
+ reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ ProcessSP process_sp(thread.GetProcess());
+ const RegisterInfo *lr_reg_info =
+ reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2);
+ const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12);
+
+ // Save return address onto the stack.
+ LLDB_LOGF(log,
+ "Pushing the return address onto the stack: 0x%" PRIx64
+ "(+16): 0x%" PRIx64,
+ (uint64_t)sp, (uint64_t)return_addr);
+ if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error))
+ return false;
+
+ // Write the return address to link register.
+ LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr);
+ if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr))
+ return false;
+
+ // Write target address to %r12 register.
+ LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr);
+ if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr))
+ return false;
+
+#if defined(__AIX__)
+ LLDB_LOGF(log, "Writing R2: 0x%" PRIx64, (uint64_t)toc_addr);
+ if (!reg_ctx->WriteRegisterFromUnsigned(r2_reg_info, toc_addr))
+ return false;
+#else
+ // Read TOC pointer value.
+ reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
+
+ // Write TOC pointer onto the stack.
+ uint64_t stack_offset;
+ if (GetByteOrder() == lldb::eByteOrderLittle)
+ stack_offset = 24;
+ else
+ stack_offset = 40;
+
+ LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64,
+ (uint64_t)(sp + stack_offset), (int)stack_offset,
+ (uint64_t)reg_value);
+ if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error))
+ return false;
+#endif
// Read the current SP value.
reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0);
@@ -641,7 +770,7 @@ class ReturnValueExtractor {
DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size);
- offset_t offset = 0;
+ lldb::offset_t offset = 0;
std::optional<uint64_t> byte_size = type.GetByteSize(m_process_sp.get());
if (!byte_size)
return {};
diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h
index bfa96cc0df703a..d752a8ded97483 100644
--- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h
+++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.h
@@ -23,6 +23,12 @@ class ABISysV_ppc64 : public lldb_private::RegInfoBasedABI {
lldb::addr_t returnAddress,
llvm::ArrayRef<lldb::addr_t> args) const override;
+ bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t tocAddress,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args) const override;
+
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt
new file mode 100644
index 00000000000000..02fe0d617955a0
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_definitions("-D_ALL_SOURCE")
+
+add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN
+ DynamicLoaderAIXDYLD.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp
new file mode 100644
index 00000000000000..62663974134b07
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp
@@ -0,0 +1,272 @@
+//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicLoaderAIXDYLD.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#if defined(__AIX__)
+#include <sys/ldr.h>
+#endif
+
+/*#include "llvm/ADT/Triple.h"
+*/
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD)
+
+DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process)
+ : DynamicLoader(process) {}
+
+DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default;
+
+void DynamicLoaderAIXDYLD::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderAIXDYLD::Terminate() {}
+
+llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() {
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in AIX processes.";
+}
+
+DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process,
+ bool force) {
+ bool should_create = force;
+ if (!should_create) {
+ const llvm::Triple &triple_ref =
+ process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getOS() == llvm::Triple::AIX)
+ should_create = true;
+ }
+
+ if (should_create)
+ return new DynamicLoaderAIXDYLD(process);
+
+ return nullptr;
+}
+
+void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp,
+ const ModuleSpec module_spec,
+ lldb::addr_t module_addr) {
+
+ // Resolve the module unless we already have one.
+ if (!module_sp) {
+ Status error;
+ module_sp = m_process->GetTarget().GetOrCreateModule(module_spec,
+ true /* notify */, &error);
+ if (error.Fail())
+ return;
+ }
+
+ m_loaded_modules[module_sp] = module_addr;
+ UpdateLoadedSectionsCommon(module_sp, module_addr, false);
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) {
+ Address resolved_addr;
+ if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))
+ return;
+
+ ModuleSP module_sp = resolved_addr.GetModule();
+ if (module_sp) {
+ m_loaded_modules.erase(module_sp);
+ UnloadSectionsCommon(module_sp);
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ m_process->GetTarget().ModulesDidUnload(module_list, false);
+ }
+}
+
+lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) {
+ // First, see if the load address is already cached.
+ auto it = m_loaded_modules.find(executable);
+ if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)
+ return it->second;
+
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+
+ // Second, try to get it through the process plugins. For a remote process,
+ // the remote platform will be responsible for providing it.
+ FileSpec file_spec(executable->GetPlatformFileSpec());
+ bool is_loaded = false;
+ Status status =
+ m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
+ // Servers other than lldb server could respond with a bogus address.
+ if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {
+ m_loaded_modules[executable] = load_addr;
+ return load_addr;
+ }
+
+ //// Hack to try set breakpoint
+ //Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint(0x100000638, true, false).get();
+ //dyld_break->SetCallback(DynamicLoaderAIXDYLD::NotifyBreakpointHit, this, true);
+ //dyld_break->SetBreakpointKind("hack-debug");
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool DynamicLoaderAIXDYLD::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id) {
+}
+
+void DynamicLoaderAIXDYLD::DidAttach() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__);
+
+ ModuleSP executable = GetTargetExecutable();
+
+ if (!executable.get())
+ return;
+
+ // Try to fetch the load address of the file from the process, since there
+ // could be randomization of the load address.
+ lldb::addr_t load_addr = GetLoadAddress(executable);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ // Request the process base address.
+ lldb::addr_t image_base = m_process->GetImageInfoAddress();
+ if (image_base == load_addr)
+ return;
+
+ // Rebase the process's modules if there is a mismatch.
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
+
+ ModuleList module_list;
+ module_list.Append(executable);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ auto error = m_process->LoadModules();
+ LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
+
+#if defined(__AIX__)
+ // Get struct ld_xinfo (FIXME)
+ struct ld_xinfo ldinfo[64];
+ Status status = m_process->GetLDXINFO(&(ldinfo[0]));
+ if (status.Fail()) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "LDXINFO failed: {0}", status);
+ return;
+ }
+ struct ld_xinfo *ptr = &(ldinfo[0]);
+ bool skip_current = true;
+ while (ptr != nullptr) {
+ char *pathName = (char *)ptr + ptr->ldinfo_filename;
+ char *memberName = pathName + (strlen(pathName) + 1);
+ if (!skip_current) {
+ // FIXME: buffer size
+ char pathWithMember[128] = {0};
+ if (strlen(memberName) > 0) {
+ sprintf(pathWithMember, "%s(%s)", pathName, memberName);
+ } else {
+ sprintf(pathWithMember, "%s", pathName);
+ }
+ FileSpec file(pathWithMember);
+ ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture());
+ if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) {
+ UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1);
+ UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2);
+ // FIXME: .tdata, .bss
+ }
+ } else {
+ skip_current = false;
+ }
+ if (ptr->ldinfo_next == 0) {
+ ptr = nullptr;
+ } else {
+ ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next);
+ }
+ }
+#endif
+}
+
+void DynamicLoaderAIXDYLD::DidLaunch() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__);
+
+ ModuleSP executable = GetTargetExecutable();
+ if (!executable.get())
+ return;
+
+ lldb::addr_t load_addr = GetLoadAddress(executable);
+ if (load_addr != LLDB_INVALID_ADDRESS) {
+ // Update the loaded sections so that the breakpoints can be resolved.
+ UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
+
+ ModuleList module_list;
+ module_list.Append(executable);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ auto error = m_process->LoadModules();
+ LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
+ }
+
+#if defined(__AIX__)
+ // Get struct ld_xinfo (FIXME)
+ struct ld_xinfo ldinfo[64];
+ Status status = m_process->GetLDXINFO(&(ldinfo[0]));
+ if (status.Fail()) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ LLDB_LOG(log, "LDXINFO failed: {0}", status);
+ return;
+ }
+ struct ld_xinfo *ptr = &(ldinfo[0]);
+ bool skip_current = true;
+ while (ptr != nullptr) {
+ char *pathName = (char *)ptr + ptr->ldinfo_filename;
+ char *memberName = pathName + (strlen(pathName) + 1);
+ if (!skip_current) {
+ // FIXME: buffer size
+ char pathWithMember[128] = {0};
+ if (strlen(memberName) > 0) {
+ sprintf(pathWithMember, "%s(%s)", pathName, memberName);
+ } else {
+ sprintf(pathWithMember, "%s", pathName);
+ }
+ FileSpec file(pathWithMember);
+ ModuleSpec module_spec(file, m_process->GetTarget().GetArchitecture());
+ if (ModuleSP module_sp = m_process->GetTarget().GetOrCreateModule(module_spec, true /* notify */)) {
+ UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_textorg, false, 1);
+ UpdateLoadedSectionsByType(module_sp, LLDB_INVALID_ADDRESS, (lldb::addr_t)ptr->ldinfo_dataorg, false, 2);
+ // FIXME: .tdata, .bss
+ }
+ } else {
+ skip_current = false;
+ }
+ if (ptr->ldinfo_next == 0) {
+ ptr = nullptr;
+ } else {
+ ptr = (struct ld_xinfo *)((char *)ptr + ptr->ldinfo_next);
+ }
+ }
+#endif
+}
+
+Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); }
+
+ThreadPlanSP
+DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) {
+ //FIXME
+ return ThreadPlanSP();
+}
diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h
new file mode 100644
index 00000000000000..ae4b7aca66dcc5
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h
@@ -0,0 +1,55 @@
+//===-- DynamicLoaderAIXDYLD.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/lldb-forward.h"
+
+#include <map>
+
+namespace lldb_private {
+
+class DynamicLoaderAIXDYLD : public DynamicLoader {
+public:
+ DynamicLoaderAIXDYLD(Process *process);
+
+ ~DynamicLoaderAIXDYLD() override;
+
+ static void Initialize();
+ static void Terminate();
+ static llvm::StringRef GetPluginNameStatic() { return "windows-dyld"; }
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static DynamicLoader *CreateInstance(Process *process, bool force);
+
+ void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec,
+ lldb::addr_t module_addr);
+ void OnUnloadModule(lldb::addr_t module_addr);
+
+ void DidAttach() override;
+ void DidLaunch() override;
+ Status CanLoadImage() override;
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop) override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ static bool NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+protected:
+ lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
+
+private:
+ std::map<lldb::ModuleSP, lldb::addr_t> m_loaded_modules;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H
diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
index 30607159acdc08..4f3fb693faae18 100644
--- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
+++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD)
add_subdirectory(Static)
add_subdirectory(Hexagon-DYLD)
add_subdirectory(Windows-DYLD)
+add_subdirectory(AIX-DYLD)
add_subdirectory(wasm-DYLD)
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index 20e5652c65bf88..26abea0fdd24d6 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -256,7 +256,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) {
if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8)
{
DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize());
- offset_t offset = 0;
+ lldb::offset_t offset = 0;
uint64_t addr = data.GetU64 (&offset);
if (CheckForKernelImageAtAddress(addr, process).IsValid()) {
return addr;
@@ -270,7 +270,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) {
if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4)
{
DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize());
- offset_t offset = 0;
+ lldb::offset_t offset = 0;
uint32_t addr = data.GetU32 (&offset);
if (CheckForKernelImageAtAddress(addr, process).IsValid()) {
return addr;
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 3863b6b3520db4..624848dee6ec33 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1151,7 +1151,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
// TLS data for the pthread_key on a specific thread yet. If we have we
// can re-use it since its location will not change unless the process
// execs.
- const tid_t tid = thread_sp->GetID();
+ const lldb::tid_t tid = thread_sp->GetID();
auto tid_pos = m_tid_to_tls_map.find(tid);
if (tid_pos != m_tid_to_tls_map.end()) {
auto tls_pos = tid_pos->second.find(key);
diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
index 3035c513417780..d14ae2daeb47d8 100644
--- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
+++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
@@ -146,7 +146,25 @@ EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) {
{0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI,
"addi RT, RA, SI"},
{0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD,
- "ld RT, DS(RA)"}};
+ "ld RT, DS(RA)"},
+// {0xffff0003, 0x40820000, &EmulateInstructionPPC64::EmulateBNE,
+// "bne TARGET"},
+ {0xfc000002, 0x48000000, &EmulateInstructionPPC64::EmulateB,
+ "b TARGET"},
+ {0xfc000003, 0x48000002, &EmulateInstructionPPC64::EmulateBA,
+ "ba TARGET"},
+ {0xfc000003, 0x48000003, &EmulateInstructionPPC64::EmulateBLA,
+ "bla TARGET"},
+ {0xfc000002, 0x40000000, &EmulateInstructionPPC64::EmulateBC,
+ "bc BO,BI,TARGET"},
+ {0xfc000002, 0x40000002, &EmulateInstructionPPC64::EmulateBCA,
+ "bca BO,BI,TARGET"},
+ {0xfc0007fe, 0x4c000020, &EmulateInstructionPPC64::EmulateBCLR,
+ "bclr BO,BI,BH"},
+ {0xfc0007fe, 0x4c000420, &EmulateInstructionPPC64::EmulateBCCTR,
+ "bcctr BO,BI,BH"},
+ {0xfc0007fe, 0x4c000460, &EmulateInstructionPPC64::EmulateBCTAR,
+ "bctar BO,BI,BH"}};
static const size_t k_num_ppc_opcodes = std::size(g_opcodes);
for (size_t i = 0; i < k_num_ppc_opcodes; ++i) {
@@ -169,12 +187,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) {
bool success = false;
- uint32_t orig_pc_value = 0;
+ uint64_t orig_pc_value = 0;
if (auto_advance_pc) {
orig_pc_value =
ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
if (!success)
return false;
+ LLDB_LOG(GetLog(LLDBLog::Unwind), "orig_pc_value:{0}", orig_pc_value);
}
// Call the Emulate... function.
@@ -183,11 +202,13 @@ bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) {
return false;
if (auto_advance_pc) {
- uint32_t new_pc_value =
+ uint64_t new_pc_value =
ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
if (!success)
return false;
+ LLDB_LOG(GetLog(LLDBLog::Unwind), "new_pc_value:{0}", new_pc_value);
+
if (new_pc_value == orig_pc_value) {
EmulateInstruction::Context context;
context.type = eContextAdvancePC;
@@ -389,5 +410,174 @@ bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) {
return false;
WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val);
LLDB_LOG(log, "EmulateADDI: success!");
+
+ // FIX the next-pc
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + 4;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBC(uint32_t opcode) {
+ // FIXME:32bit M
+ uint32_t M = 0;
+ uint32_t target32 = Bits32(opcode, 15, 2) << 2;
+ uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0);
+ uint32_t BO = Bits32(opcode, 25, 21);
+ bool success;
+ uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success);
+ if ((~BO) & (1U << 2))
+ ctr_value = ctr_value - 1;
+ bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1)));
+ uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success);
+ uint32_t BI = Bits32(opcode, 20, 16);
+ bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U));
+
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + 4;
+ if (ctr_ok & cond_ok)
+ next_pc = pc_value + target;
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ Log *log = GetLog(LLDBLog::Unwind);
+ LLDB_LOG(log, "EmulateBC: success!");
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBCA(uint32_t opcode) {
+ // FIXME:32bit M
+ uint32_t M = 0;
+ uint32_t target32 = Bits32(opcode, 15, 2) << 2;
+ uint64_t target = (uint64_t)target32 + ((target32 & 0x8000) ? 0xffffffffffff0000UL : 0);
+ uint32_t BO = Bits32(opcode, 25, 21);
+ bool success;
+ uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success);
+ if ((~BO) & (1U << 2))
+ ctr_value = ctr_value - 1;
+ bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1)));
+ uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success);
+ uint32_t BI = Bits32(opcode, 20, 16);
+ bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U));
+
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + 4;
+ if (ctr_ok & cond_ok)
+ next_pc = target;
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ Log *log = GetLog(LLDBLog::Unwind);
+ LLDB_LOG(log, "EmulateBCA: success!");
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBCLR(uint32_t opcode) {
+ // FIXME:32bit M
+ uint32_t M = 0;
+ uint32_t BO = Bits32(opcode, 25, 21);
+ bool success;
+ uint64_t ctr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success);
+ if ((~BO) & (1U << 2))
+ ctr_value = ctr_value - 1;
+ bool ctr_ok = (bool)(BO & (1U << 2)) | ((bool)(ctr_value != 0) ^ (bool)(BO & (1U << 1)));
+ uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success);
+ uint32_t BI = Bits32(opcode, 20, 16);
+ bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U));
+
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + 4;
+ if (ctr_ok & cond_ok) {
+ next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);
+ next_pc &= ~((1UL << 2) - 1);
+ }
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ Log *log = GetLog(LLDBLog::Unwind);
+ LLDB_LOG(log, "EmulateBCLR: success!");
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBCCTR(uint32_t opcode) {
+ // FIXME:32bit M
+ uint32_t M = 0;
+ uint32_t BO = Bits32(opcode, 25, 21);
+ bool success;
+ uint64_t cr_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_cr_ppc64le, 0, &success);
+ uint32_t BI = Bits32(opcode, 20, 16);
+ bool cond_ok = (bool)(BO & (1U << 4)) | (bool)(((cr_value >> (63 - (BI + 32))) & 1U) == ((BO >> 3) & 1U));
+
+ Log *log = GetLog(LLDBLog::Unwind);
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + 4;
+ if (cond_ok) {
+ next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_ctr_ppc64le, 0, &success);
+ next_pc &= ~((1UL << 2) - 1);
+ if (next_pc < 0x4000000) {
+ LLDB_LOGF(log, "EmulateBCCTR: next address %lx out of range, emulate by goto LR!");
+ next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);
+ }
+ }
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ LLDB_LOG(log, "EmulateBCCTR: success!");
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBCTAR(uint32_t opcode) {
+ // Not supported yet.
+ LLDB_LOG(GetLog(LLDBLog::Unwind), "EmulateBCTAR: not supported!");
+ assert(0);
+ return false;
+}
+
+bool EmulateInstructionPPC64::EmulateB(uint32_t opcode) {
+ uint32_t target32 = Bits32(opcode, 25, 2) << 2;
+ uint64_t target = (uint64_t)target32 + ((target32 & 0x2000000) ? 0xfffffffffc000000UL : 0);
+
+ bool success;
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + target;
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ Log *log = GetLog(LLDBLog::Unwind);
+ LLDB_LOG(log, "EmulateB: success!");
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBA(uint32_t opcode) {
+ Log *log = GetLog(LLDBLog::Unwind);
+
+ bool success;
+ uint64_t next_pc = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ LLDB_LOG(log, "EmulateBA: emulate by branch to lr!");
+ return true;
+}
+
+bool EmulateInstructionPPC64::EmulateBLA(uint32_t opcode) {
+ Log *log = GetLog(LLDBLog::Unwind);
+
+ bool success;
+ uint64_t pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
+ uint64_t next_pc = pc_value + 4;
+
+ Context ctx;
+ ctx.type = eContextAdjustPC;
+ WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_pc_ppc64le, next_pc);
+ LLDB_LOG(log, "EmulateBLA: emulate by branch to lr!");
return true;
}
diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
index a9424f16b0ad01..1576c9700e5572 100644
--- a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
+++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
@@ -39,6 +39,12 @@ class EmulateInstructionPPC64 : public EmulateInstruction {
return true;
case eInstructionTypePCModifying:
+#if defined(__AIX__)
+ return true;
+#else
+ return false;
+#endif
+
case eInstructionTypeAll:
return false;
}
@@ -84,6 +90,14 @@ class EmulateInstructionPPC64 : public EmulateInstruction {
bool EmulateSTD(uint32_t opcode);
bool EmulateOR(uint32_t opcode);
bool EmulateADDI(uint32_t opcode);
+ bool EmulateB(uint32_t opcode);
+ bool EmulateBA(uint32_t opcode);
+ bool EmulateBLA(uint32_t opcode);
+ bool EmulateBC(uint32_t opcode);
+ bool EmulateBCA(uint32_t opcode);
+ bool EmulateBCLR(uint32_t opcode);
+ bool EmulateBCCTR(uint32_t opcode);
+ bool EmulateBCTAR(uint32_t opcode);
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp
index b7cd2b1ac6bf6d..876e74056faceb 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp
@@ -261,7 +261,7 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo(
StructuredData::ObjectSP thread_id_obj =
info->GetObjectForDotSeparatedPath("tid");
- tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0;
+ lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0;
// We gather symbolication addresses above, so no need for HistoryThread to
// try to infer the call addresses.
diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp
index b2781aa5e7db15..7a827a3ea76f9c 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp
@@ -770,13 +770,13 @@ std::string InstrumentationRuntimeTSan::GetLocationDescription(
Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr);
}
} else if (type == "stack") {
- tid_t tid = loc->GetAsDictionary()
+ lldb::tid_t tid = loc->GetAsDictionary()
->GetValueForKey("thread_id")
->GetUnsignedIntegerValue();
result = Sprintf("Location is stack of thread %d", tid);
} else if (type == "tls") {
- tid_t tid = loc->GetAsDictionary()
+ lldb::tid_t tid = loc->GetAsDictionary()
->GetValueForKey("thread_id")
->GetUnsignedIntegerValue();
@@ -948,7 +948,7 @@ static std::string GenerateThreadName(const std::string &path,
if (path == "mops") {
size_t size =
o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue();
- tid_t thread_id =
+ lldb::tid_t thread_id =
o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue();
bool is_write =
o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue();
@@ -979,7 +979,7 @@ static std::string GenerateThreadName(const std::string &path,
}
if (path == "threads") {
- tid_t thread_id =
+ lldb::tid_t thread_id =
o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue();
result = Sprintf("Thread %zu created", thread_id);
}
@@ -987,7 +987,7 @@ static std::string GenerateThreadName(const std::string &path,
if (path == "locs") {
std::string type = std::string(
o->GetAsDictionary()->GetValueForKey("type")->GetStringValue());
- tid_t thread_id =
+ lldb::tid_t thread_id =
o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue();
int fd = o->GetObjectForDotSeparatedPath("file_descriptor")
->GetSignedIntegerValue();
@@ -1007,7 +1007,7 @@ static std::string GenerateThreadName(const std::string &path,
}
if (path == "stacks") {
- tid_t thread_id =
+ lldb::tid_t thread_id =
o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue();
result = Sprintf("Thread %" PRIu64, thread_id);
}
@@ -1034,7 +1034,7 @@ static void AddThreadsForPath(const std::string &path,
StructuredData::ObjectSP thread_id_obj =
o->GetObjectForDotSeparatedPath("thread_os_id");
- tid_t tid =
+ lldb::tid_t tid =
thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0;
ThreadSP new_thread_sp =
diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
index 1c58922e8d36c8..de9719ad4a89ef 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
@@ -321,7 +321,7 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo(
StructuredData::ObjectSP thread_id_obj =
info->GetObjectForDotSeparatedPath("tid");
- tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0;
+ lldb::tid_t tid = thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0;
// We gather symbolication addresses above, so no need for HistoryThread to
// try to infer the call addresses.
diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
index 1688fb27430a7a..690fb0d60a09a9 100644
--- a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
+++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
@@ -194,6 +194,10 @@ void JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) {
if (jit_addr == LLDB_INVALID_ADDRESS)
return;
+#if defined(__AIX__)
+ return;
+#endif
+
m_jit_descriptor_addr = GetSymbolAddress(
module_list, ConstString("__jit_debug_descriptor"), eSymbolTypeData);
if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) {
diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
index 341923108e3216..fb5bc2c58e6fb8 100644
--- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
+++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
@@ -1227,6 +1227,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider(
time_t lldb_private::formatters::GetOSXEpoch() {
static time_t epoch = 0;
if (!epoch) {
+#if !defined(__AIX__)
#ifndef _WIN32
tzset();
tm tm_epoch;
@@ -1240,6 +1241,7 @@ time_t lldb_private::formatters::GetOSXEpoch() {
tm_epoch.tm_gmtoff = 0;
tm_epoch.tm_zone = nullptr;
epoch = timegm(&tm_epoch);
+#endif
#endif
}
return epoch;
diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
index 6efd2516578ff2..fe6c5a0544be32 100644
--- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
+++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
@@ -107,7 +107,7 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp,
return;
int count = count_sp->GetValueAsUnsigned(0);
- tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1;
+ lldb::tid_t tid = tid_sp->GetValueAsUnsigned(0) + 1;
if (count <= 0)
return;
diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index 7aa5b8d81890ae..5ea55772c3aba1 100644
--- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -8,7 +8,7 @@
#include "ObjectContainerBSDArchive.h"
-#if defined(_WIN32) || defined(__ANDROID__)
+#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__)
// Defines from ar, missing on Windows
#define SARMAG 8
#define ARFMAG "`\n"
diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt
new file mode 100644
index 00000000000000..612a36265b5366
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginObjectContainerBigArchive PLUGIN
+ ObjectContainerBigArchive.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbSymbol
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp
new file mode 100644
index 00000000000000..050ad73f1d19af
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.cpp
@@ -0,0 +1,522 @@
+//===-- ObjectContainerBigArchive.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerBigArchive.h"
+
+#if defined(_WIN32) || defined(__ANDROID__) || defined(__AIX__)
+// Defines from ar, missing on Windows
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+typedef struct ar_hdr {
+ char ar_name[16];
+ char ar_date[12];
+ char ar_uid[6], ar_gid[6];
+ char ar_mode[8];
+ char ar_size[10];
+ char ar_fmag[2];
+} ar_hdr;
+#else
+#include <ar.h>
+#endif
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Support/Chrono.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ObjectContainerBigArchive)
+
+ObjectContainerBigArchive::Object::Object() : ar_name() {}
+
+void ObjectContainerBigArchive::Object::Clear() {
+ ar_name.Clear();
+ modification_time = 0;
+ uid = 0;
+ gid = 0;
+ mode = 0;
+ size = 0;
+ file_offset = 0;
+ file_size = 0;
+}
+
+lldb::offset_t
+ObjectContainerBigArchive::Object::Extract(const DataExtractor &data,
+ lldb::offset_t offset) {
+ size_t ar_name_len = 0;
+ std::string str;
+ char *err;
+
+ // File header
+ //
+ // The common format is as follows.
+ //
+ // Offset Length Name Format
+ // 0 16 File name ASCII right padded with spaces (no spaces
+ // allowed in file name)
+ // 16 12 File mod Decimal as cstring right padded with
+ // spaces
+ // 28 6 Owner ID Decimal as cstring right padded with
+ // spaces
+ // 34 6 Group ID Decimal as cstring right padded with
+ // spaces
+ // 40 8 File mode Octal as cstring right padded with
+ // spaces
+ // 48 10 File byte size Decimal as cstring right padded with
+ // spaces
+ // 58 2 File magic 0x60 0x0A
+
+ // Make sure there is enough data for the file header and bail if not
+ if (!data.ValidOffsetForDataOfSize(offset, 60))
+ return LLDB_INVALID_OFFSET;
+
+ str.assign((const char *)data.GetData(&offset, 16), 16);
+ if (llvm::StringRef(str).starts_with("#1/")) {
+ // If the name is longer than 16 bytes, or contains an embedded space then
+ // it will use this format where the length of the name is here and the
+ // name characters are after this header.
+ ar_name_len = strtoul(str.c_str() + 3, &err, 10);
+ } else {
+ // Strip off any trailing spaces.
+ const size_t last_pos = str.find_last_not_of(' ');
+ if (last_pos != std::string::npos) {
+ if (last_pos + 1 < 16)
+ str.erase(last_pos + 1);
+ }
+ ar_name.SetCString(str.c_str());
+ }
+
+ str.assign((const char *)data.GetData(&offset, 12), 12);
+ modification_time = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 6), 6);
+ uid = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 6), 6);
+ gid = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 8), 8);
+ mode = strtoul(str.c_str(), &err, 8);
+
+ str.assign((const char *)data.GetData(&offset, 10), 10);
+ size = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 2), 2);
+ if (str == ARFMAG) {
+ if (ar_name_len > 0) {
+ const void *ar_name_ptr = data.GetData(&offset, ar_name_len);
+ // Make sure there was enough data for the string value and bail if not
+ if (ar_name_ptr == nullptr)
+ return LLDB_INVALID_OFFSET;
+ str.assign((const char *)ar_name_ptr, ar_name_len);
+ ar_name.SetCString(str.c_str());
+ }
+ file_offset = offset;
+ file_size = size - ar_name_len;
+ return offset;
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
+ObjectContainerBigArchive::Archive::Archive(const lldb_private::ArchSpec &arch,
+ const llvm::sys::TimePoint<> &time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data)
+ : m_arch(arch), m_modification_time(time), m_file_offset(file_offset),
+ m_objects(), m_data(data) {}
+
+ObjectContainerBigArchive::Archive::~Archive() = default;
+
+size_t ObjectContainerBigArchive::Archive::ParseObjects() {
+ DataExtractor &data = m_data;
+ std::string str;
+ lldb::offset_t offset = 0;
+ str.assign((const char *)data.GetData(&offset, (sizeof(llvm::object::BigArchiveMagic) - 1)),
+ (sizeof(llvm::object::BigArchiveMagic) - 1));
+ if (str == llvm::object::BigArchiveMagic) {
+ llvm::Error err = llvm::Error::success();
+ llvm::object::BigArchive bigAr(llvm::MemoryBufferRef(toStringRef(m_data.GetData()), llvm::StringRef("")), err);
+ if (err)
+ return 0;
+
+ for (const llvm::object::Archive::Child &child : bigAr.children(err)) {
+ if (err)
+ continue;
+ if (!child.getParent())
+ continue;
+ Object obj;
+ obj.Clear();
+ // FIXME: check errors
+ llvm::Expected<llvm::StringRef> childNameOrErr = child.getName();
+ if (!childNameOrErr)
+ continue;
+ obj.ar_name.SetCString(childNameOrErr->str().c_str());
+ llvm::Expected<llvm::sys::TimePoint<std::chrono::seconds>> lastModifiedOrErr = child.getLastModified();
+ if (!lastModifiedOrErr)
+ continue;
+ obj.modification_time = (uint32_t)llvm::sys::toTimeT(*(lastModifiedOrErr));
+ llvm::Expected<unsigned> getUIDOrErr = child.getUID();
+ if (!getUIDOrErr)
+ continue;
+ obj.uid = (uint16_t)*getUIDOrErr;
+ llvm::Expected<unsigned> getGIDOrErr = child.getGID();
+ if (!getGIDOrErr)
+ continue;
+ obj.gid = (uint16_t)*getGIDOrErr;
+ llvm::Expected<llvm::sys::fs::perms> getAccessModeOrErr = child.getAccessMode();
+ if (!getAccessModeOrErr)
+ continue;
+ obj.mode = (uint16_t)*getAccessModeOrErr;
+ llvm::Expected<uint64_t> getRawSizeOrErr = child.getRawSize();
+ if (!getRawSizeOrErr)
+ continue;
+ obj.size = (uint32_t)*getRawSizeOrErr;
+
+ obj.file_offset = (lldb::offset_t)child.getDataOffset();
+
+ llvm::Expected<uint64_t> getSizeOrErr = child.getSize();
+ if (!getSizeOrErr)
+ continue;
+ obj.file_size = (lldb::offset_t)*getSizeOrErr;
+
+ size_t obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+ }
+ if (err)
+ return 0;
+
+ // Now sort all of the object name pointers
+ m_object_name_to_index_map.Sort();
+ }
+ return m_objects.size();
+}
+
+ObjectContainerBigArchive::Object *
+ObjectContainerBigArchive::Archive::FindObject(
+ ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) {
+ const ObjectNameToIndexMap::Entry *match =
+ m_object_name_to_index_map.FindFirstValueForName(object_name);
+ if (!match)
+ return nullptr;
+ if (object_mod_time == llvm::sys::TimePoint<>())
+ return &m_objects[match->value];
+
+ const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time);
+ if (m_objects[match->value].modification_time == object_modification_date)
+ return &m_objects[match->value];
+
+ const ObjectNameToIndexMap::Entry *next_match =
+ m_object_name_to_index_map.FindNextValueForName(match);
+ while (next_match) {
+ if (m_objects[next_match->value].modification_time ==
+ object_modification_date)
+ return &m_objects[next_match->value];
+ next_match = m_object_name_to_index_map.FindNextValueForName(next_match);
+ }
+
+ return nullptr;
+}
+
+ObjectContainerBigArchive::Archive::shared_ptr
+ObjectContainerBigArchive::Archive::FindCachedArchive(
+ const FileSpec &file, const ArchSpec &arch,
+ const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) {
+ std::lock_guard<std::recursive_mutex> guard(Archive::GetArchiveCacheMutex());
+ shared_ptr archive_sp;
+ Archive::Map &archive_map = Archive::GetArchiveCache();
+ Archive::Map::iterator pos = archive_map.find(file);
+ // Don't cache a value for "archive_map.end()" below since we might delete an
+ // archive entry...
+ while (pos != archive_map.end() && pos->first == file) {
+ bool match = true;
+ if (arch.IsValid() &&
+ !pos->second->GetArchitecture().IsCompatibleMatch(arch))
+ match = false;
+ else if (file_offset != LLDB_INVALID_OFFSET &&
+ pos->second->GetFileOffset() != file_offset)
+ match = false;
+ if (match) {
+ if (pos->second->GetModificationTime() == time) {
+ return pos->second;
+ } else {
+ // We have a file at the same path with the same architecture whose
+ // modification time doesn't match. It doesn't make sense for us to
+ // continue to use this Big archive since we cache only the object info
+ // which consists of file time info and also the file offset and file
+ // size of any contained objects. Since this information is now out of
+ // date, we won't get the correct information if we go and extract the
+ // file data, so we should remove the old and outdated entry.
+ archive_map.erase(pos);
+ pos = archive_map.find(file);
+ continue; // Continue to next iteration so we don't increment pos
+ // below...
+ }
+ }
+ ++pos;
+ }
+ return archive_sp;
+}
+
+ObjectContainerBigArchive::Archive::shared_ptr
+ObjectContainerBigArchive::Archive::ParseAndCacheArchiveForFile(
+ const FileSpec &file, const ArchSpec &arch,
+ const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset,
+ DataExtractor &data) {
+ shared_ptr archive_sp(new Archive(arch, time, file_offset, data));
+ if (archive_sp) {
+ const size_t num_objects = archive_sp->ParseObjects();
+ if (num_objects > 0) {
+ std::lock_guard<std::recursive_mutex> guard(
+ Archive::GetArchiveCacheMutex());
+ Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
+ } else {
+ archive_sp.reset();
+ }
+ }
+ return archive_sp;
+}
+
+ObjectContainerBigArchive::Archive::Map &
+ObjectContainerBigArchive::Archive::GetArchiveCache() {
+ static Archive::Map g_archive_map;
+ return g_archive_map;
+}
+
+std::recursive_mutex &
+ObjectContainerBigArchive::Archive::GetArchiveCacheMutex() {
+ static std::recursive_mutex g_archive_map_mutex;
+ return g_archive_map_mutex;
+}
+
+void ObjectContainerBigArchive::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ GetModuleSpecifications);
+}
+
+void ObjectContainerBigArchive::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+ObjectContainer *ObjectContainerBigArchive::CreateInstance(
+ const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
+ lldb::offset_t data_offset, const FileSpec *file,
+ lldb::offset_t file_offset, lldb::offset_t length) {
+ ConstString object_name(module_sp->GetObjectName());
+ if (!object_name)
+ return nullptr;
+
+ if (data_sp) {
+ // We have data, which means this is the first 512 bytes of the file Check
+ // to see if the magic bytes match and if they do, read the entire table of
+ // contents for the archive and cache it
+ DataExtractor data;
+ data.SetData(data_sp, data_offset, length);
+ if (file && data_sp && ObjectContainerBigArchive::MagicBytesMatch(data)) {
+ LLDB_SCOPED_TIMERF(
+ "ObjectContainerBigArchive::CreateInstance (module = %s, file = "
+ "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
+ module_sp->GetFileSpec().GetPath().c_str(),
+ static_cast<const void *>(file), static_cast<uint64_t>(file_offset),
+ static_cast<uint64_t>(length));
+
+ // Map the entire .a file to be sure that we don't lose any data if the
+ // file gets updated by a new build while this .a file is being used for
+ // debugging
+ DataBufferSP archive_data_sp =
+ FileSystem::Instance().CreateDataBuffer(*file, length, file_offset);
+ if (!archive_data_sp)
+ return nullptr;
+
+ lldb::offset_t archive_data_offset = 0;
+
+ Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
+ *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(),
+ file_offset));
+ std::unique_ptr<ObjectContainerBigArchive> container_up(
+ new ObjectContainerBigArchive(module_sp, archive_data_sp,
+ archive_data_offset, file, file_offset,
+ length));
+
+ if (container_up) {
+ if (archive_sp) {
+ // We already have this archive in our cache, use it
+ container_up->SetArchive(archive_sp);
+ return container_up.release();
+ } else if (container_up->ParseHeader())
+ return container_up.release();
+ }
+ }
+ } else {
+ // No data, just check for a cached archive
+ Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
+ *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(),
+ file_offset));
+ if (archive_sp) {
+ std::unique_ptr<ObjectContainerBigArchive> container_up(
+ new ObjectContainerBigArchive(module_sp, data_sp, data_offset, file,
+ file_offset, length));
+
+ if (container_up) {
+ // We already have this archive in our cache, use it
+ container_up->SetArchive(archive_sp);
+ return container_up.release();
+ }
+ }
+ }
+ return nullptr;
+}
+
+bool ObjectContainerBigArchive::MagicBytesMatch(const DataExtractor &data) {
+ uint32_t offset = 0;
+ const char *armag = (const char *)data.PeekData(offset, (sizeof(llvm::object::BigArchiveMagic) - 1));
+ if (armag && ::strncmp(armag, llvm::object::BigArchiveMagic, (sizeof(llvm::object::BigArchiveMagic) - 1)) == 0)
+ return true;
+ return false;
+}
+
+ObjectContainerBigArchive::ObjectContainerBigArchive(
+ const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
+ lldb::offset_t data_offset, const lldb_private::FileSpec *file,
+ lldb::offset_t file_offset, lldb::offset_t size)
+ : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset),
+ m_archive_sp() {}
+void ObjectContainerBigArchive::SetArchive(Archive::shared_ptr &archive_sp) {
+ m_archive_sp = archive_sp;
+}
+
+ObjectContainerBigArchive::~ObjectContainerBigArchive() = default;
+
+bool ObjectContainerBigArchive::ParseHeader() {
+ if (m_archive_sp.get() == nullptr) {
+ if (m_data.GetByteSize() > 0) {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ m_archive_sp = Archive::ParseAndCacheArchiveForFile(
+ m_file, module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(), m_offset, m_data);
+ }
+ // Clear the m_data that contains the entire archive data and let our
+ // m_archive_sp hold onto the data.
+ m_data.Clear();
+ }
+ }
+ return m_archive_sp.get() != nullptr;
+}
+
+void ObjectContainerBigArchive::Object::Dump(Stream *s) const {
+ printf("name = \"%s\"\n", ar_name.GetCString());
+ printf("mtime = 0x%8.8" PRIx32 "\n", modification_time);
+ printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size);
+ printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset,
+ file_offset);
+ printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size,
+ file_size);
+}
+
+ObjectFileSP ObjectContainerBigArchive::GetObjectFile(const FileSpec *file) {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ if (module_sp->GetObjectName() && m_archive_sp) {
+ Object *object = m_archive_sp->FindObject(
+ module_sp->GetObjectName(), module_sp->GetObjectModificationTime());
+ if (object) {
+ lldb::offset_t data_offset = object->file_offset;
+ return ObjectFile::FindPlugin(
+ module_sp, file, m_offset + object->file_offset, object->file_size,
+ m_archive_sp->GetData().GetSharedDataBuffer(), data_offset);
+ }
+ }
+ }
+ return ObjectFileSP();
+}
+
+size_t ObjectContainerBigArchive::GetModuleSpecifications(
+ const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset, lldb::offset_t file_offset,
+ lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) {
+
+ // We have data, which means this is the first 512 bytes of the file Check to
+ // see if the magic bytes match and if they do, read the entire table of
+ // contents for the archive and cache it
+ DataExtractor data;
+ data.SetData(data_sp, data_offset, data_sp->GetByteSize());
+ if (!file || !data_sp || !ObjectContainerBigArchive::MagicBytesMatch(data))
+ return 0;
+
+ const size_t initial_count = specs.GetSize();
+ llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file);
+ Archive::shared_ptr archive_sp(
+ Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset));
+ bool set_archive_arch = false;
+ if (!archive_sp) {
+ set_archive_arch = true;
+ data_sp =
+ FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset);
+ if (data_sp) {
+ data.SetData(data_sp, 0, data_sp->GetByteSize());
+ archive_sp = Archive::ParseAndCacheArchiveForFile(
+ file, ArchSpec(), file_mod_time, file_offset, data);
+ }
+ }
+
+ if (archive_sp) {
+ const size_t num_objects = archive_sp->GetNumObjects();
+ for (size_t idx = 0; idx < num_objects; ++idx) {
+ const Object *object = archive_sp->GetObjectAtIndex(idx);
+ if (object) {
+ const lldb::offset_t object_file_offset =
+ file_offset + object->file_offset;
+ if (object->file_offset < file_size && file_size > object_file_offset) {
+ if (ObjectFile::GetModuleSpecifications(
+ file, object_file_offset, file_size - object_file_offset,
+ specs)) {
+ ModuleSpec &spec =
+ specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
+ llvm::sys::TimePoint<> object_mod_time(
+ std::chrono::seconds(object->modification_time));
+ spec.GetObjectName() = object->ar_name;
+ spec.SetObjectOffset(object_file_offset);
+ spec.SetObjectSize(file_size - object_file_offset);
+ spec.GetObjectModificationTime() = object_mod_time;
+ }
+ }
+ }
+ }
+ }
+ const size_t end_count = specs.GetSize();
+ size_t num_specs_added = end_count - initial_count;
+ if (set_archive_arch && num_specs_added > 0) {
+ // The archive was created but we didn't have an architecture so we need to
+ // set it
+ for (size_t i = initial_count; i < end_count; ++i) {
+ ModuleSpec module_spec;
+ if (specs.GetModuleSpecAtIndex(i, module_spec)) {
+ if (module_spec.GetArchitecture().IsValid()) {
+ archive_sp->SetArchitecture(module_spec.GetArchitecture());
+ break;
+ }
+ }
+ }
+ }
+ return num_specs_added;
+}
diff --git a/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h
new file mode 100644
index 00000000000000..ad9b814048a87d
--- /dev/null
+++ b/lldb/source/Plugins/ObjectContainer/Big-Archive/ObjectContainerBigArchive.h
@@ -0,0 +1,177 @@
+//===-- ObjectContainerBigArchive.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H
+#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H
+
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "llvm/Support/Chrono.h"
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+class ObjectContainerBigArchive : public lldb_private::ObjectContainer {
+public:
+ ObjectContainerBigArchive(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset, lldb::offset_t length);
+
+ ~ObjectContainerBigArchive() override;
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "big-archive"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic() {
+ return "Big Archive object container reader.";
+ }
+
+ static lldb_private::ObjectContainer *
+ CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset, const lldb_private::FileSpec *file,
+ lldb::offset_t offset, lldb::offset_t length);
+
+ static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
+ lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool MagicBytesMatch(const lldb_private::DataExtractor &data);
+
+ // Member Functions
+ bool ParseHeader() override;
+
+ size_t GetNumObjects() const override {
+ if (m_archive_sp)
+ return m_archive_sp->GetNumObjects();
+ return 0;
+ }
+
+ lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override;
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+protected:
+ struct Object {
+ Object();
+
+ void Clear();
+
+ lldb::offset_t Extract(const lldb_private::DataExtractor &data,
+ lldb::offset_t offset);
+ /// Object name in the archive.
+ lldb_private::ConstString ar_name;
+
+ /// Object modification time in the archive.
+ uint32_t modification_time = 0;
+
+ /// Object user id in the archive.
+ uint16_t uid = 0;
+
+ /// Object group id in the archive.
+ uint16_t gid = 0;
+
+ /// Object octal file permissions in the archive.
+ uint16_t mode = 0;
+
+ /// Object size in bytes in the archive.
+ uint32_t size = 0;
+
+ /// File offset in bytes from the beginning of the file of the object data.
+ lldb::offset_t file_offset = 0;
+
+ /// Length of the object data.
+ lldb::offset_t file_size = 0;
+
+ void Dump(lldb_private::Stream *s) const;
+ };
+
+ class Archive {
+ public:
+ typedef std::shared_ptr<Archive> shared_ptr;
+ typedef std::multimap<lldb_private::FileSpec, shared_ptr> Map;
+
+ Archive(const lldb_private::ArchSpec &arch,
+ const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data);
+
+ ~Archive();
+
+ static Map &GetArchiveCache();
+
+ static std::recursive_mutex &GetArchiveCacheMutex();
+
+ static Archive::shared_ptr FindCachedArchive(
+ const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch,
+ const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset);
+
+ static Archive::shared_ptr ParseAndCacheArchiveForFile(
+ const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch,
+ const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data);
+
+ size_t GetNumObjects() const { return m_objects.size(); }
+
+ const Object *GetObjectAtIndex(size_t idx) {
+ if (idx < m_objects.size())
+ return &m_objects[idx];
+ return nullptr;
+ }
+
+ size_t ParseObjects();
+
+ Object *FindObject(lldb_private::ConstString object_name,
+ const llvm::sys::TimePoint<> &object_mod_time);
+
+ lldb::offset_t GetFileOffset() const { return m_file_offset; }
+
+ const llvm::sys::TimePoint<> &GetModificationTime() {
+ return m_modification_time;
+ }
+
+ const lldb_private::ArchSpec &GetArchitecture() const { return m_arch; }
+
+ void SetArchitecture(const lldb_private::ArchSpec &arch) { m_arch = arch; }
+
+ bool HasNoExternalReferences() const;
+
+ lldb_private::DataExtractor &GetData() { return m_data; }
+
+ protected:
+ typedef lldb_private::UniqueCStringMap<uint32_t> ObjectNameToIndexMap;
+ // Member Variables
+ lldb_private::ArchSpec m_arch;
+ llvm::sys::TimePoint<> m_modification_time;
+ lldb::offset_t m_file_offset;
+ std::vector<Object> m_objects;
+ ObjectNameToIndexMap m_object_name_to_index_map;
+ lldb_private::DataExtractor m_data; ///< The data for this object container
+ ///so we don't lose data if the .a files
+ ///gets modified
+ };
+
+ void SetArchive(Archive::shared_ptr &archive_sp);
+
+ Archive::shared_ptr m_archive_sp;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BIG_ARCHIVE_OBJECTCONTAINERBIGARCHIVE_H
diff --git a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt
index cda0c8151dd8a7..2492798bb13ef2 100644
--- a/lldb/source/Plugins/ObjectContainer/CMakeLists.txt
+++ b/lldb/source/Plugins/ObjectContainer/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(BSD-Archive)
+add_subdirectory(Big-Archive)
add_subdirectory(Universal-Mach-O)
add_subdirectory(Mach-O-Fileset)
diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt
index 773241c8944c8a..7abd0c96f4fd74 100644
--- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt
+++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt
@@ -6,5 +6,6 @@ add_subdirectory(Mach-O)
add_subdirectory(Minidump)
add_subdirectory(PDB)
add_subdirectory(PECOFF)
+add_subdirectory(XCOFF)
add_subdirectory(Placeholder)
add_subdirectory(wasm)
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index ce095bcc48374b..bcb6330cbb1f9c 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5673,7 +5673,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
return false;
}
-bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector<tid_t> &tids) {
+bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector<lldb::tid_t> &tids) {
tids.clear();
ModuleSP module_sp(GetModule());
if (module_sp) {
@@ -5724,8 +5724,8 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector<tid_t> &tids) {
return false;
}
StructuredData::Dictionary *thread = *maybe_thread;
- tid_t tid = LLDB_INVALID_THREAD_ID;
- if (thread->GetValueForKeyAsInteger<tid_t>("thread_id", tid))
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (thread->GetValueForKeyAsInteger<lldb::tid_t>("thread_id", tid))
if (tid == 0)
tid = LLDB_INVALID_THREAD_ID;
tids.push_back(tid);
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
index faa144bfb5f6a5..d27cdfc60de859 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp
@@ -51,7 +51,9 @@ size_t ObjectFileMinidump::GetModuleSpecifications(
const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
lldb::offset_t data_offset, lldb::offset_t file_offset,
lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
+#if !defined(__AIX__)
specs.Clear();
+#endif
return 0;
}
diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp
index f0832dbf07347a..75cc54e4f0d484 100644
--- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp
+++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp
@@ -116,18 +116,31 @@ size_t ObjectFilePDB::GetModuleSpecifications(
ModuleSpec module_spec(file);
llvm::BumpPtrAllocator allocator;
std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator);
- if (!pdb_file)
+ if (!pdb_file){
+#if !defined(__AIX__)
return initial_count;
+#else
+ return specs.GetSize() - initial_count;
+#endif
+ }
auto info_stream = pdb_file->getPDBInfoStream();
if (!info_stream) {
llvm::consumeError(info_stream.takeError());
+#if !defined(__AIX__)
return initial_count;
+#else
+ return specs.GetSize() - initial_count;
+#endif
}
auto dbi_stream = pdb_file->getPDBDbiStream();
if (!dbi_stream) {
llvm::consumeError(dbi_stream.takeError());
+#if !defined(__AIX__)
return initial_count;
+#else
+ return specs.GetSize() - initial_count;
+#endif
}
lldb_private::UUID &uuid = module_spec.GetUUID();
diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
index bda691ade8af02..db8fa78043fdca 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -252,8 +252,13 @@ size_t ObjectFilePECOFF::GetModuleSpecifications(
lldb::offset_t data_offset, lldb::offset_t file_offset,
lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
const size_t initial_count = specs.GetSize();
- if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp))
+ if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)){
+#if !defined(__AIX__)
return initial_count;
+#else
+ return specs.GetSize() - initial_count;
+#endif
+ }
Log *log = GetLog(LLDBLog::Object);
@@ -266,12 +271,21 @@ size_t ObjectFilePECOFF::GetModuleSpecifications(
if (!binary) {
LLDB_LOG_ERROR(log, binary.takeError(),
"Failed to create binary for file ({1}): {0}", file);
+#if !defined(__AIX__)
return initial_count;
+#else
+ return specs.GetSize() - initial_count;
+#endif
}
auto *COFFObj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary->get());
- if (!COFFObj)
+ if (!COFFObj){
+#if !defined(__AIX__)
return initial_count;
+#else
+ return specs.GetSize() - initial_count;
+#endif
+ }
ModuleSpec module_spec(file);
ArchSpec &spec = module_spec.GetArchitecture();
diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt
new file mode 100644
index 00000000000000..8840248574c886
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/XCOFF/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginObjectFileXCOFF PLUGIN
+ ObjectFileXCOFF.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ BinaryFormat
+ Object
+ Support
+ )
diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
new file mode 100644
index 00000000000000..a4d9ea295b4c39
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
@@ -0,0 +1,780 @@
+//===-- ObjectFileXCOFF.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFileXCOFF.h"
+
+#include <algorithm>
+#include <cassert>
+#include <unordered_map>
+#include <string.h>
+
+#include "lldb/Utility/FileSpecList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Progress.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/LZMA.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RangeMap.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ObjectFileXCOFF)
+
+char ObjectFileXCOFF::ID;
+
+// FIXME: target 64bit at this moment.
+
+// Static methods.
+void ObjectFileXCOFF::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ CreateMemoryInstance, GetModuleSpecifications);
+}
+
+void ObjectFileXCOFF::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;
+
+ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp,
+ DataBufferSP data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length) {
+ if (!data_sp) {
+ data_sp = MapFileData(*file, length, file_offset);
+ if (!data_sp)
+ return nullptr;
+ data_offset = 0;
+ }
+
+ if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length))
+ return nullptr;
+
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length) {
+ data_sp = MapFileData(*file, length, file_offset);
+ if (!data_sp)
+ return nullptr;
+ data_offset = 0;
+ }
+ auto objfile_up = std::make_unique<ObjectFileXCOFF>(
+ module_sp, data_sp, data_offset, file, file_offset, length);
+ if (!objfile_up)
+ return nullptr;
+
+ // Cache xcoff binary.
+ if (!objfile_up->CreateBinary())
+ return nullptr;
+
+ if (!objfile_up->ParseHeader())
+ //FIXME objfile leak
+ return nullptr;
+
+ UGLY_FLAG_FOR_AIX = true;
+ return objfile_up.release();
+}
+
+bool ObjectFileXCOFF::CreateBinary() {
+ if (m_binary)
+ return true;
+
+ Log *log = GetLog(LLDBLog::Object);
+
+ auto binary = llvm::object::XCOFFObjectFile::createObjectFile(llvm::MemoryBufferRef(
+ toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()),
+ file_magic::xcoff_object_64);
+ if (!binary) {
+ LLDB_LOG_ERROR(log, binary.takeError(),
+ "Failed to create binary for file ({1}): {0}", m_file);
+ return false;
+ }
+
+ // Make sure we only handle COFF format.
+ m_binary =
+ llvm::unique_dyn_cast<llvm::object::XCOFFObjectFile>(std::move(*binary));
+ if (!m_binary)
+ return false;
+
+ LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
+ this, GetModule().get(), GetModule()->GetSpecificationDescription(),
+ m_file.GetPath(), m_binary.get());
+ return true;
+}
+
+ObjectFile *ObjectFileXCOFF::CreateMemoryInstance(
+ const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,
+ const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
+ return nullptr;
+}
+
+size_t ObjectFileXCOFF::GetModuleSpecifications(
+ const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset, lldb::offset_t file_offset,
+ lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
+ const size_t initial_count = specs.GetSize();
+
+ if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
+ ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
+ ModuleSpec spec(file, arch_spec);
+ spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);
+ specs.Append(spec);
+ }
+ return specs.GetSize() - initial_count;
+}
+
+static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) {
+ switch (magic) {
+ /* TODO: 32bit not supported yet
+ case XCOFF::XCOFF32:
+ return sizeof(struct llvm::object::XCOFFFileHeader32);
+ */
+
+ case XCOFF::XCOFF64:
+ return sizeof(struct llvm::object::XCOFFFileHeader64);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp,
+ lldb::addr_t data_offset,
+ lldb::addr_t data_length) {
+ lldb_private::DataExtractor data;
+ data.SetData(data_sp, data_offset, data_length);
+ lldb::offset_t offset = 0;
+ uint16_t magic = data.GetU16(&offset);
+ return XCOFFHeaderSizeFromMagic(magic) != 0;
+}
+
+bool ObjectFileXCOFF::ParseHeader() {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ m_sect_headers.clear();
+ lldb::offset_t offset = 0;
+
+ if (ParseXCOFFHeader(m_data, &offset, m_xcoff_header)) {
+ m_data.SetAddressByteSize(GetAddressByteSize());
+ if (m_xcoff_header.auxhdrsize > 0)
+ ParseXCOFFOptionalHeader(m_data, &offset);
+ ParseSectionHeaders(offset);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ObjectFileXCOFF::ParseXCOFFHeader(lldb_private::DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ xcoff_header_t &xcoff_header) {
+ //FIXME: data.ValidOffsetForDataOfSize
+ xcoff_header.magic = data.GetU16(offset_ptr);
+ xcoff_header.nsects = data.GetU16(offset_ptr);
+ xcoff_header.modtime = data.GetU32(offset_ptr);
+ xcoff_header.symoff = data.GetU64(offset_ptr);
+ xcoff_header.auxhdrsize = data.GetU16(offset_ptr);
+ xcoff_header.flags = data.GetU16(offset_ptr);
+ xcoff_header.nsyms = data.GetU32(offset_ptr);
+ return true;
+}
+
+bool ObjectFileXCOFF::ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data,
+ lldb::offset_t *offset_ptr) {
+ lldb::offset_t init_offset = *offset_ptr;
+ //FIXME: data.ValidOffsetForDataOfSize
+ m_xcoff_aux_header.AuxMagic = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.Version = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.ReservedForDebugger = data.GetU32(offset_ptr);
+ m_xcoff_aux_header.TextStartAddr = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.DataStartAddr = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.TOCAnchorAddr = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.SecNumOfEntryPoint = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.SecNumOfText = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.SecNumOfData = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.SecNumOfTOC = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.SecNumOfLoader = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.SecNumOfBSS = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.MaxAlignOfText = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.MaxAlignOfData = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.ModuleType = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.CpuFlag = data.GetU8(offset_ptr);
+ m_xcoff_aux_header.CpuType = data.GetU8(offset_ptr);
+ m_xcoff_aux_header.TextPageSize = data.GetU8(offset_ptr);
+ m_xcoff_aux_header.DataPageSize = data.GetU8(offset_ptr);
+ m_xcoff_aux_header.StackPageSize = data.GetU8(offset_ptr);
+ m_xcoff_aux_header.FlagAndTDataAlignment = data.GetU8(offset_ptr);
+ m_xcoff_aux_header.TextSize = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.InitDataSize = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.BssDataSize = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.EntryPointAddr = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.MaxStackSize = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.MaxDataSize = data.GetU64(offset_ptr);
+ m_xcoff_aux_header.SecNumOfTData = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.SecNumOfTBSS = data.GetU16(offset_ptr);
+ m_xcoff_aux_header.XCOFF64Flag = data.GetU16(offset_ptr);
+ lldb::offset_t last_offset = *offset_ptr;
+ if ((last_offset - init_offset) < m_xcoff_header.auxhdrsize)
+ *offset_ptr += (m_xcoff_header.auxhdrsize - (last_offset - init_offset));
+ return true;
+}
+
+bool ObjectFileXCOFF::ParseSectionHeaders(
+ uint32_t section_header_data_offset) {
+ const uint32_t nsects = m_xcoff_header.nsects;
+ m_sect_headers.clear();
+
+ if (nsects > 0) {
+ const size_t section_header_byte_size = nsects * m_binary->getSectionHeaderSize();
+ lldb_private::DataExtractor section_header_data =
+ ReadImageData(section_header_data_offset, section_header_byte_size);
+
+ lldb::offset_t offset = 0;
+ //FIXME: section_header_data.ValidOffsetForDataOfSize
+ m_sect_headers.resize(nsects);
+
+ for (uint32_t idx = 0; idx < nsects; ++idx) {
+ const void *name_data = section_header_data.GetData(&offset, 8);
+ if (name_data) {
+ memcpy(m_sect_headers[idx].name, name_data, 8);
+ m_sect_headers[idx].phyaddr = section_header_data.GetU64(&offset);
+ m_sect_headers[idx].vmaddr = section_header_data.GetU64(&offset);
+ m_sect_headers[idx].size = section_header_data.GetU64(&offset);
+ m_sect_headers[idx].offset = section_header_data.GetU64(&offset);
+ m_sect_headers[idx].reloff = section_header_data.GetU64(&offset);
+ m_sect_headers[idx].lineoff = section_header_data.GetU64(&offset);
+ m_sect_headers[idx].nreloc = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].nline = section_header_data.GetU32(&offset);
+ m_sect_headers[idx].flags = section_header_data.GetU32(&offset);
+ offset += 4;
+ } else {
+ offset += (m_binary->getSectionHeaderSize() - 8);
+ }
+ }
+ }
+
+ return !m_sect_headers.empty();
+}
+
+lldb_private::DataExtractor ObjectFileXCOFF::ReadImageData(uint32_t offset, size_t size) {
+ if (!size)
+ return {};
+
+ if (m_data.ValidOffsetForDataOfSize(offset, size))
+ return lldb_private::DataExtractor(m_data, offset, size);
+
+ assert(0);
+ ProcessSP process_sp(m_process_wp.lock());
+ lldb_private::DataExtractor data;
+ if (process_sp) {
+ auto data_up = std::make_unique<DataBufferHeap>(size, 0);
+ Status readmem_error;
+ size_t bytes_read =
+ process_sp->ReadMemory(offset, data_up->GetBytes(),
+ data_up->GetByteSize(), readmem_error);
+ if (bytes_read == size) {
+ DataBufferSP buffer_sp(data_up.release());
+ data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
+ }
+ }
+ return data;
+}
+
+bool ObjectFileXCOFF::SetLoadAddress(Target &target, lldb::addr_t value,
+ bool value_is_offset) {
+ bool changed = false;
+ ModuleSP module_sp = GetModule();
+ if (module_sp) {
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ // Iterate through the object file sections to find all of the sections
+ // that have SHF_ALLOC in their flag bits.
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+ if (section_sp && !section_sp->IsThreadSpecific()) {
+ bool use_offset = false;
+ if (strcmp(section_sp->GetName().AsCString(), ".text") == 0 ||
+ strcmp(section_sp->GetName().AsCString(), ".data") == 0 ||
+ strcmp(section_sp->GetName().AsCString(), ".bss") == 0)
+ use_offset = true;
+
+ if (target.GetSectionLoadList().SetSectionLoadAddress(
+ section_sp, (use_offset ?
+ (section_sp->GetFileOffset() + value) : (section_sp->GetFileAddress() + value))))
+ ++num_loaded_sections;
+ }
+ }
+ changed = num_loaded_sections > 0;
+ }
+ }
+ return changed;
+}
+
+bool ObjectFileXCOFF::SetLoadAddressByType(Target &target, lldb::addr_t value,
+ bool value_is_offset, int type_id) {
+ bool changed = false;
+ ModuleSP module_sp = GetModule();
+ if (module_sp) {
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ // Iterate through the object file sections to find all of the sections
+ // that have SHF_ALLOC in their flag bits.
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+ if (type_id == 1 && section_sp && strcmp(section_sp->GetName().AsCString(), ".text") == 0) {
+ if (!section_sp->IsThreadSpecific()) {
+ if (target.GetSectionLoadList().SetSectionLoadAddress(
+ section_sp, section_sp->GetFileOffset() + value))
+ ++num_loaded_sections;
+ }
+ } else if (type_id == 2 && section_sp && strcmp(section_sp->GetName().AsCString(), ".data") == 0) {
+ if (!section_sp->IsThreadSpecific()) {
+ if (target.GetSectionLoadList().SetSectionLoadAddress(
+ section_sp, section_sp->GetFileAddress() + value))
+ ++num_loaded_sections;
+ }
+ }
+ }
+ changed = num_loaded_sections > 0;
+ }
+ }
+ return changed;
+}
+
+ByteOrder ObjectFileXCOFF::GetByteOrder() const {
+ return eByteOrderBig;
+}
+
+bool ObjectFileXCOFF::IsExecutable() const {
+ return true;
+}
+
+uint32_t ObjectFileXCOFF::GetAddressByteSize() const {
+ if (m_xcoff_header.magic == XCOFF::XCOFF64)
+ return 8;
+ else if (m_xcoff_header.magic == XCOFF::XCOFF32)
+ return 4;
+ return 4;
+}
+
+AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) {
+ return AddressClass::eUnknown;
+}
+
+lldb::SymbolType ObjectFileXCOFF::MapSymbolType(llvm::object::SymbolRef::Type sym_type) {
+ if (sym_type == llvm::object::SymbolRef::ST_Function)
+ return lldb::eSymbolTypeCode;
+ else if (sym_type == llvm::object::SymbolRef::ST_Data)
+ return lldb::eSymbolTypeData;
+ return lldb::eSymbolTypeInvalid;
+}
+
+void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {
+ SectionList *sect_list = GetSectionList();
+ const uint32_t num_syms = m_xcoff_header.nsyms;
+ uint32_t sidx = 0;
+ if (num_syms > 0 && m_xcoff_header.symoff > 0) {
+ const uint32_t symbol_size = XCOFF::SymbolTableEntrySize;
+ const size_t symbol_data_size = num_syms * symbol_size;
+ lldb_private::DataExtractor symtab_data =
+ ReadImageData(m_xcoff_header.symoff, symbol_data_size);
+
+ lldb::offset_t offset = 0;
+ std::string symbol_name;
+ Symbol *symbols = lldb_symtab.Resize(num_syms);
+ llvm::object::symbol_iterator SI = m_binary->symbol_begin();
+ for (uint32_t i = 0; i < num_syms; ++i, ++SI) {
+ xcoff_symbol_t symbol;
+ const uint32_t symbol_offset = offset;
+ symbol.value = symtab_data.GetU64(&offset);
+ symbol.offset = symtab_data.GetU32(&offset);
+ Expected<StringRef> symbol_name_or_err = m_binary->getStringTableEntry(symbol.offset);
+ if (!symbol_name_or_err) {
+ consumeError(symbol_name_or_err.takeError());
+ return;
+ }
+ StringRef symbol_name_str = symbol_name_or_err.get();
+ symbol_name.assign(symbol_name_str.data());
+ symbol.sect = symtab_data.GetU16(&offset);
+ symbol.type = symtab_data.GetU16(&offset);
+ symbol.storage = symtab_data.GetU8(&offset);
+ symbol.naux = symtab_data.GetU8(&offset);
+ // Allow C_HIDEXT TOC symbol, and check others.
+ if (symbol.storage == XCOFF::C_HIDEXT && strcmp(symbol_name.c_str(), "TOC") != 0) {
+ if (symbol.naux == 0)
+ continue;
+ if (symbol.naux > 1) {
+ i += symbol.naux;
+ offset += symbol.naux * symbol_size;
+ continue;
+ }
+ /* Allow XCOFF::C_HIDEXT with following SMC and AT:
+ StorageMappingClass: XMC_PR (0x0)
+ Auxiliary Type: AUX_CSECT (0xFB)
+ */
+ xcoff_sym_csect_aux_entry_t symbol_aux;
+ symbol_aux.section_or_len_low_byte = symtab_data.GetU32(&offset);
+ symbol_aux.parameter_hash_index = symtab_data.GetU32(&offset);
+ symbol_aux.type_check_sect_num = symtab_data.GetU16(&offset);
+ symbol_aux.symbol_alignment_and_type = symtab_data.GetU8(&offset);
+ symbol_aux.storage_mapping_class = symtab_data.GetU8(&offset);
+ symbol_aux.section_or_len_high_byte = symtab_data.GetU32(&offset);
+ symbol_aux.pad = symtab_data.GetU8(&offset);
+ symbol_aux.aux_type = symtab_data.GetU8(&offset);
+ offset -= symbol.naux * symbol_size;
+ if (symbol_aux.storage_mapping_class != XCOFF::XMC_PR || symbol_aux.aux_type != XCOFF::AUX_CSECT) {
+ i += symbol.naux;
+ offset += symbol.naux * symbol_size;
+ continue;
+ }
+ }
+ // Remove the dot prefix for demangle
+ if (symbol_name_str.size() > 1 && symbol_name_str.data()[0] == '.') {
+ symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str() + 1));
+ } else {
+ symbols[sidx].GetMangled().SetValue(ConstString(symbol_name.c_str()));
+ }
+ if ((int16_t)symbol.sect >= 1) {
+ Address symbol_addr(sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1)),
+ (symbol.value - sect_list->GetSectionAtIndex((size_t)(symbol.sect - 1))->GetFileAddress()));
+ symbols[sidx].GetAddressRef() = symbol_addr;
+
+ Expected<llvm::object::SymbolRef::Type> sym_type_or_err = SI->getType();
+ if (!sym_type_or_err) {
+ consumeError(sym_type_or_err.takeError());
+ return;
+ }
+ symbols[sidx].SetType(MapSymbolType(sym_type_or_err.get()));
+ }
+ ++sidx;
+
+ if (symbol.naux > 0) {
+ i += symbol.naux;
+ offset += symbol.naux * symbol_size;
+ }
+ }
+ lldb_symtab.Resize(sidx);
+ }
+}
+
+bool ObjectFileXCOFF::IsStripped() {
+ return false;
+}
+
+void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {
+ if (m_sections_up)
+ return;
+ m_sections_up = std::make_unique<SectionList>();
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+
+ const uint32_t nsects = m_sect_headers.size();
+ ModuleSP module_sp(GetModule());
+ for (uint32_t idx = 0; idx < nsects; ++idx) {
+ llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]);
+ ConstString const_sect_name(sect_name);
+ SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]);
+
+ SectionSP section_sp(new Section(
+ module_sp, // Module to which this section belongs
+ this, // Object file to which this section belongs
+ idx + 1, // Section ID is the 1 based section index.
+ const_sect_name, // Name of this section
+ section_type,
+ m_sect_headers[idx].vmaddr, // File VM address == addresses as
+ // they are found in the object file
+ m_sect_headers[idx].size, // VM size in bytes of this section
+ m_sect_headers[idx].offset, // Offset to the data for this section in the file
+ m_sect_headers[idx].size, // Size in bytes of this section as found in the file
+ 0, // FIXME: alignment
+ m_sect_headers[idx].flags)); // Flags for this section
+
+ // FIXME
+ uint32_t permissions = 0;
+ permissions |= ePermissionsReadable;
+ if (m_sect_headers[idx].flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))
+ permissions |= ePermissionsWritable;
+ if (m_sect_headers[idx].flags & XCOFF::STYP_TEXT)
+ permissions |= ePermissionsExecutable;
+ section_sp->SetPermissions(permissions);
+
+ m_sections_up->AddSection(section_sp);
+ unified_section_list.AddSection(section_sp);
+ }
+ }
+}
+
+llvm::StringRef ObjectFileXCOFF::GetSectionName(const section_header_t §) {
+ llvm::StringRef hdr_name(sect.name, std::size(sect.name));
+ hdr_name = hdr_name.split('\0').first;
+ if (hdr_name.consume_front("/")) {
+ lldb::offset_t stroff;
+ if (!to_integer(hdr_name, stroff, 10))
+ return "";
+ lldb::offset_t string_file_offset =
+ m_xcoff_header.symoff + (m_xcoff_header.nsyms * static_cast<lldb::offset_t>(XCOFF::SymbolTableEntrySize)) + stroff;
+ if (const char *name = m_data.GetCStr(&string_file_offset))
+ return name;
+ return "";
+ }
+ return hdr_name;
+}
+
+SectionType ObjectFileXCOFF::GetSectionType(llvm::StringRef sect_name,
+ const section_header_t §) {
+ if (sect.flags & XCOFF::STYP_TEXT)
+ return eSectionTypeCode;
+ if (sect.flags & XCOFF::STYP_DATA)
+ return eSectionTypeData;
+ if (sect.flags & XCOFF::STYP_BSS)
+ return eSectionTypeZeroFill;
+ if (sect.flags & XCOFF::STYP_DWARF) {
+ SectionType section_type =
+ llvm::StringSwitch<SectionType>(sect_name)
+ .Case(".dwinfo", eSectionTypeDWARFDebugInfo)
+ .Case(".dwline", eSectionTypeDWARFDebugLine)
+ .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)
+ .Default(eSectionTypeInvalid);
+
+ if (section_type != eSectionTypeInvalid)
+ return section_type;
+ }
+ return eSectionTypeOther;
+}
+
+void ObjectFileXCOFF::Dump(Stream *s) {
+}
+
+ArchSpec ObjectFileXCOFF::GetArchitecture() {
+ ArchSpec arch_spec = ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
+ return arch_spec;
+}
+
+UUID ObjectFileXCOFF::GetUUID() {
+ return UUID();
+}
+
+std::optional<FileSpec> ObjectFileXCOFF::GetDebugLink() {
+ return std::nullopt;
+}
+
+uint32_t ObjectFileXCOFF::ParseDependentModules() {
+ ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ return 0;
+
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ if (m_deps_filespec)
+ return m_deps_filespec->GetSize();
+
+ // Cache coff binary if it is not done yet.
+ if (!CreateBinary())
+ return 0;
+
+ Log *log = GetLog(LLDBLog::Object);
+ LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
+ this, GetModule().get(), GetModule()->GetSpecificationDescription(),
+ m_file.GetPath(), m_binary.get());
+
+ m_deps_filespec = FileSpecList();
+
+ auto ImportFilesOrError = m_binary->getImportFileTable();
+ if (!ImportFilesOrError) {
+ consumeError(ImportFilesOrError.takeError());
+ return 0;
+ }
+
+#if 0
+ StringRef ImportFileTable = ImportFilesOrError.get();
+ const char *CurrentStr = ImportFileTable.data();
+ const char *TableEnd = ImportFileTable.end();
+ const char *Basename = nullptr;
+
+ for (size_t StrIndex = 0; CurrentStr < TableEnd;
+ ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
+ if (StrIndex >= 3 && StrIndex % 3 == 1) {
+ // base_name
+ llvm::StringRef dll_name(CurrentStr);
+ Basename = CurrentStr;
+
+ // At this moment we only have the base name of the DLL. The full path can
+ // only be seen after the dynamic loading. Our best guess is Try to get it
+ // with the help of the object file's directory.
+ llvm::SmallString<128> dll_fullpath;
+ FileSpec dll_specs(dll_name);
+ // FIXME: hack to get libc.a loaded
+ if (strcmp(CurrentStr, "libc.a") == 0) {
+ dll_specs.GetDirectory().SetString("/usr/lib");
+ } else {
+ dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString());
+ }
+
+ if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath))
+ //m_deps_filespec->EmplaceBack(dll_fullpath);
+ m_deps_filespec->EmplaceBack("/usr/lib/libc.a(shr_64.o)");
+ else {
+ // Known DLLs or DLL not found in the object file directory.
+ m_deps_filespec->EmplaceBack(dll_name);
+ }
+ } else if (StrIndex >= 3 && StrIndex % 3 == 2) {
+ // archive_member_name
+ if (strcmp(CurrentStr, "") == 0) {
+ continue;
+ }
+ assert(strcmp(Basename, "") != 0);
+ std::map<std::string, std::vector<std::string>>::iterator iter = m_deps_base_members.find(std::string(Basename));
+ if (iter == m_deps_base_members.end()) {
+ m_deps_base_members[std::string(Basename)] = std::vector<std::string>();
+ iter = m_deps_base_members.find(std::string(Basename));
+ }
+ iter->second.push_back(std::string(CurrentStr));
+ }
+ }
+#endif
+ return m_deps_filespec->GetSize();
+}
+
+uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) {
+ auto num_modules = ParseDependentModules();
+ auto original_size = files.GetSize();
+
+ for (unsigned i = 0; i < num_modules; ++i)
+ files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i));
+
+ return files.GetSize() - original_size;
+}
+
+Address ObjectFileXCOFF::GetImageInfoAddress(Target *target) {
+ return Address();
+}
+
+lldb_private::Address ObjectFileXCOFF::GetEntryPointAddress() {
+ if (m_entry_point_address.IsValid())
+ return m_entry_point_address;
+
+ if (!ParseHeader() || !IsExecutable())
+ return m_entry_point_address;
+
+ SectionList *section_list = GetSectionList();
+ addr_t vm_addr = m_xcoff_aux_header.EntryPointAddr;
+ SectionSP section_sp(
+ section_list->FindSectionContainingFileAddress(vm_addr));
+ if (section_sp) {
+ lldb::offset_t offset_ptr = section_sp->GetFileOffset() + (vm_addr - section_sp->GetFileAddress());
+ vm_addr = m_data.GetU64(&offset_ptr);
+ }
+
+ if (!section_list)
+ m_entry_point_address.SetOffset(vm_addr);
+ else
+ m_entry_point_address.ResolveAddressUsingFileSections(vm_addr,
+ section_list);
+
+ return m_entry_point_address;
+}
+
+lldb_private::Address ObjectFileXCOFF::GetBaseAddress() {
+ return lldb_private::Address();
+}
+
+ObjectFile::Type ObjectFileXCOFF::CalculateType() {
+ if (m_xcoff_header.flags & XCOFF::F_EXEC)
+ return eTypeExecutable;
+ else if (m_xcoff_header.flags & XCOFF::F_SHROBJ)
+ return eTypeSharedLibrary;
+ return eTypeUnknown;
+}
+
+ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() {
+ return eStrataUnknown;
+}
+
+llvm::StringRef
+ObjectFileXCOFF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
+ return llvm::StringRef();
+}
+
+void ObjectFileXCOFF::RelocateSection(lldb_private::Section *section)
+{
+}
+
+std::vector<ObjectFile::LoadableData>
+ObjectFileXCOFF::GetLoadableData(Target &target) {
+ std::vector<LoadableData> loadables;
+ return loadables;
+}
+
+lldb::WritableDataBufferSP
+ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size,
+ uint64_t Offset) {
+ return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size,
+ Offset);
+}
+
+ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,
+ DataBufferSP data_sp, lldb::offset_t data_offset,
+ const FileSpec *file, lldb::offset_t file_offset,
+ lldb::offset_t length)
+ : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
+ m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(),
+ m_entry_point_address() {
+ ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header));
+ if (file)
+ m_file = *file;
+}
+
+ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,
+ DataBufferSP header_data_sp,
+ const lldb::ProcessSP &process_sp,
+ addr_t header_addr)
+ : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
+ m_xcoff_header(), m_sect_headers(), m_deps_filespec(), m_deps_base_members(),
+ m_entry_point_address() {
+ ::memset(&m_xcoff_header, 0, sizeof(m_xcoff_header));
+}
diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h
new file mode 100644
index 00000000000000..5a12d16886489d
--- /dev/null
+++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h
@@ -0,0 +1,243 @@
+//===-- ObjectFileXCOFF.h --------------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H
+#define LLDB_SOURCE_PLUGINS_OBJECTFILE_XCOFF_OBJECTFILEXCOFF_H
+
+#include <cstdint>
+
+#include <vector>
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
+#include "lldb/lldb-private.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+
+/// \class ObjectFileXCOFF
+/// Generic XCOFF object file reader.
+///
+/// This class provides a generic XCOFF (32/64 bit) reader plugin implementing
+/// the ObjectFile protocol.
+class ObjectFileXCOFF : public lldb_private::ObjectFile {
+public:
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "xcoff"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic() {
+ return "XCOFF object file reader.";
+ }
+
+ static lldb_private::ObjectFile *
+ CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp,
+ lldb::offset_t data_offset, const lldb_private::FileSpec *file,
+ lldb::offset_t file_offset, lldb::offset_t length);
+
+ static lldb_private::ObjectFile *CreateMemoryInstance(
+ const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp,
+ const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
+
+ static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
+ lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset,
+ lldb::addr_t length);
+
+ static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type);
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ // LLVM RTTI support
+ static char ID;
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || ObjectFile::isA(ClassID);
+ }
+ static bool classof(const ObjectFile *obj) { return obj->isA(&ID); }
+
+ // ObjectFile Protocol.
+ bool ParseHeader() override;
+
+ bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value,
+ bool value_is_offset) override;
+
+ bool SetLoadAddressByType(lldb_private::Target &target, lldb::addr_t value,
+ bool value_is_offset, int type_id) override;
+
+ lldb::ByteOrder GetByteOrder() const override;
+
+ bool IsExecutable() const override;
+
+ uint32_t GetAddressByteSize() const override;
+
+ lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override;
+
+ void ParseSymtab(lldb_private::Symtab &symtab) override;
+
+ bool IsStripped() override;
+
+ void CreateSections(lldb_private::SectionList &unified_section_list) override;
+
+ void Dump(lldb_private::Stream *s) override;
+
+ lldb_private::ArchSpec GetArchitecture() override;
+
+ lldb_private::UUID GetUUID() override;
+
+ /// Return the contents of the .gnu_debuglink section, if the object file
+ /// contains it.
+ std::optional<lldb_private::FileSpec> GetDebugLink();
+
+ uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;
+
+ lldb_private::Address
+ GetImageInfoAddress(lldb_private::Target *target) override;
+
+ lldb_private::Address GetEntryPointAddress() override;
+
+ lldb_private::Address GetBaseAddress() override;
+
+ ObjectFile::Type CalculateType() override;
+
+ ObjectFile::Strata CalculateStrata() override;
+
+ llvm::StringRef
+ StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override;
+
+ void RelocateSection(lldb_private::Section *section) override;
+
+ lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size);
+
+ ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp,
+ lldb::offset_t data_offset, const lldb_private::FileSpec *file,
+ lldb::offset_t offset, lldb::offset_t length);
+
+ ObjectFileXCOFF(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP header_data_sp,
+ const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
+
+protected:
+
+ typedef struct xcoff_header {
+ uint16_t magic;
+ uint16_t nsects;
+ uint32_t modtime;
+ uint64_t symoff;
+ uint32_t nsyms;
+ uint16_t auxhdrsize;
+ uint16_t flags;
+ } xcoff_header_t;
+
+ typedef struct xcoff_aux_header {
+ uint16_t AuxMagic;
+ uint16_t Version;
+ uint32_t ReservedForDebugger;
+ uint64_t TextStartAddr;
+ uint64_t DataStartAddr;
+ uint64_t TOCAnchorAddr;
+ uint16_t SecNumOfEntryPoint;
+ uint16_t SecNumOfText;
+ uint16_t SecNumOfData;
+ uint16_t SecNumOfTOC;
+ uint16_t SecNumOfLoader;
+ uint16_t SecNumOfBSS;
+ uint16_t MaxAlignOfText;
+ uint16_t MaxAlignOfData;
+ uint16_t ModuleType;
+ uint8_t CpuFlag;
+ uint8_t CpuType;
+ uint8_t TextPageSize;
+ uint8_t DataPageSize;
+ uint8_t StackPageSize;
+ uint8_t FlagAndTDataAlignment;
+ uint64_t TextSize;
+ uint64_t InitDataSize;
+ uint64_t BssDataSize;
+ uint64_t EntryPointAddr;
+ uint64_t MaxStackSize;
+ uint64_t MaxDataSize;
+ uint16_t SecNumOfTData;
+ uint16_t SecNumOfTBSS;
+ uint16_t XCOFF64Flag;
+ } xcoff_aux_header_t;
+
+ typedef struct section_header {
+ char name[8];
+ uint64_t phyaddr; // Physical Addr
+ uint64_t vmaddr; // Virtual Addr
+ uint64_t size; // Section size
+ uint64_t offset; // File offset to raw data
+ uint64_t reloff; // Offset to relocations
+ uint64_t lineoff; // Offset to line table entries
+ uint32_t nreloc; // Number of relocation entries
+ uint32_t nline; // Number of line table entries
+ uint32_t flags;
+ } section_header_t;
+
+ typedef struct xcoff_symbol {
+ uint64_t value;
+ uint32_t offset;
+ uint16_t sect;
+ uint16_t type;
+ uint8_t storage;
+ uint8_t naux;
+ } xcoff_symbol_t;
+
+ typedef struct xcoff_sym_csect_aux_entry {
+ uint32_t section_or_len_low_byte;
+ uint32_t parameter_hash_index;
+ uint16_t type_check_sect_num;
+ uint8_t symbol_alignment_and_type;
+ uint8_t storage_mapping_class;
+ uint32_t section_or_len_high_byte;
+ uint8_t pad;
+ uint8_t aux_type;
+ } xcoff_sym_csect_aux_entry_t;
+
+ static bool ParseXCOFFHeader(lldb_private::DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ xcoff_header_t &xcoff_header);
+ bool ParseXCOFFOptionalHeader(lldb_private::DataExtractor &data,
+ lldb::offset_t *offset_ptr);
+ bool ParseSectionHeaders(uint32_t offset);
+
+ std::vector<LoadableData>
+ GetLoadableData(lldb_private::Target &target) override;
+
+ static lldb::WritableDataBufferSP
+ MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size,
+ uint64_t Offset);
+ llvm::StringRef GetSectionName(const section_header_t §);
+ static lldb::SectionType GetSectionType(llvm::StringRef sect_name,
+ const section_header_t §);
+
+ uint32_t ParseDependentModules();
+ typedef std::vector<section_header_t> SectionHeaderColl;
+
+private:
+ bool CreateBinary();
+
+ xcoff_header_t m_xcoff_header;
+ xcoff_aux_header_t m_xcoff_aux_header;
+ SectionHeaderColl m_sect_headers;
+ std::unique_ptr<llvm::object::XCOFFObjectFile> m_binary;
+ lldb_private::Address m_entry_point_address;
+ std::optional<lldb_private::FileSpecList> m_deps_filespec;
+ std::map<std::string, std::vector<std::string>> m_deps_base_members;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H
diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
index e026ffefd645ee..106e38b6e25ae3 100644
--- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
+++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -227,7 +227,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(
ThreadList &old_thread_list, std::vector<bool> &core_used_map,
bool *did_create_ptr) {
ThreadSP thread_sp;
- tid_t tid = LLDB_INVALID_THREAD_ID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
if (!thread_dict.GetValueForKeyAsInteger("tid", tid))
return ThreadSP();
diff --git a/lldb/source/Plugins/Platform/AIX/CMakeLists.txt b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt
new file mode 100644
index 00000000000000..85ff0a315eabd5
--- /dev/null
+++ b/lldb/source/Plugins/Platform/AIX/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_definitions("-D_ALL_SOURCE")
+
+add_lldb_library(lldbPluginPlatformAIX PLUGIN
+ PlatformAIX.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbHost
+ lldbInterpreter
+ lldbTarget
+ lldbPluginPlatformPOSIX
+ )
diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp
new file mode 100644
index 00000000000000..b6b08b73bec413
--- /dev/null
+++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp
@@ -0,0 +1,471 @@
+//===-- PlatformAIX.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformAIX.h"
+#include "lldb/Host/Config.h"
+
+#include <cstdio>
+#if LLDB_ENABLE_POSIX
+#include <sys/utsname.h>
+#endif
+
+#include "Utility/ARM64_DWARF_Registers.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+// Define these constants from AIX mman.h for use when targeting remote aix
+// systems even when host has different values.
+
+#if defined(__AIX__)
+#include <sys/mman.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_aix;
+
+LLDB_PLUGIN_DEFINE(PlatformAIX)
+
+static uint32_t g_initialize_count = 0;
+
+
+PlatformSP PlatformAIX::CreateInstance(bool force, const ArchSpec *arch) {
+ Log *log = GetLog(LLDBLog::Platform);
+ LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
+ arch ? arch->GetArchitectureName() : "<null>",
+ arch ? arch->GetTriple().getTriple() : "<null>");
+
+ bool create = force;
+ if (!create && arch && arch->IsValid()) {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getOS()) {
+ case llvm::Triple::AIX:
+ create = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ LLDB_LOG(log, "create = {0}", create);
+ if (create) {
+ return PlatformSP(new PlatformAIX(false));
+ }
+ return PlatformSP();
+}
+
+llvm::StringRef PlatformAIX::GetPluginDescriptionStatic(bool is_host) {
+ if (is_host)
+ return "Local AIX user platform plug-in.";
+ return "Remote AIX user platform plug-in.";
+}
+
+void PlatformAIX::Initialize() {
+ PlatformPOSIX::Initialize();
+
+ if (g_initialize_count++ == 0) {
+#if defined(__AIX__)
+ PlatformSP default_platform_sp(new PlatformAIX(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform(default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin(
+ PlatformAIX::GetPluginNameStatic(false),
+ PlatformAIX::GetPluginDescriptionStatic(false),
+ PlatformAIX::CreateInstance, nullptr);
+ }
+}
+
+void PlatformAIX::Terminate() {
+ if (g_initialize_count > 0) {
+ if (--g_initialize_count == 0) {
+ PluginManager::UnregisterPlugin(PlatformAIX::CreateInstance);
+ }
+ }
+
+ PlatformPOSIX::Terminate();
+}
+
+/// Default Constructor
+PlatformAIX::PlatformAIX(bool is_host)
+ : PlatformPOSIX(is_host) // This is the local host platform
+{
+ if (is_host) {
+ ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ m_supported_architectures.push_back(hostArch);
+ if (hostArch.GetTriple().isArch64Bit()) {
+ m_supported_architectures.push_back(
+ HostInfo::GetArchitecture(HostInfo::eArchKind32));
+ }
+ } else {
+ m_supported_architectures = CreateArchList(
+ {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm,
+ llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64,
+ llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el,
+ llvm::Triple::mipsel, llvm::Triple::systemz},
+ llvm::Triple::AIX);
+ }
+}
+
+std::vector<ArchSpec>
+PlatformAIX::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);
+ return m_supported_architectures;
+}
+
+void PlatformAIX::GetStatus(Stream &strm) {
+ Platform::GetStatus(strm);
+
+#if LLDB_ENABLE_POSIX
+ // Display local kernel information only when we are running in host mode.
+ // Otherwise, we would end up printing non-AIX information (when running on
+ // Mac OS for example).
+ if (IsHost()) {
+ struct utsname un;
+
+ if (uname(&un))
+ return;
+
+ strm.Printf(" Kernel: %s\n", un.sysname);
+ strm.Printf(" Release: %s\n", un.release);
+ strm.Printf(" Version: %s\n", un.version);
+ }
+#endif
+}
+
+uint32_t
+PlatformAIX::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
+ uint32_t resume_count = 0;
+
+ // Always resume past the initial stop when we use eLaunchFlagDebug
+ if (launch_info.GetFlags().Test(eLaunchFlagDebug)) {
+ // Resume past the stop for the final exec into the true inferior.
+ ++resume_count;
+ }
+
+ // If we're not launching a shell, we're done.
+ const FileSpec &shell = launch_info.GetShell();
+ if (!shell)
+ return resume_count;
+
+ std::string shell_string = shell.GetPath();
+ // We're in a shell, so for sure we have to resume past the shell exec.
+ ++resume_count;
+
+ // Figure out what shell we're planning on using.
+ const char *shell_name = strrchr(shell_string.c_str(), '/');
+ if (shell_name == nullptr)
+ shell_name = shell_string.c_str();
+ else
+ shell_name++;
+
+ if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 ||
+ strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) {
+ // These shells seem to re-exec themselves. Add another resume.
+ ++resume_count;
+ }
+
+ return resume_count;
+}
+
+bool PlatformAIX::CanDebugProcess() {
+ if (IsHost()) {
+ return true;
+ } else {
+ // If we're connected, we can debug.
+ return IsConnected();
+ }
+}
+
+void PlatformAIX::CalculateTrapHandlerSymbolNames() {
+ m_trap_handlers.push_back(ConstString("_sigtramp"));
+ m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn"));
+ m_trap_handlers.push_back(ConstString("__restore_rt"));
+}
+
+static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) {
+ UnwindPlanSP unwind_plan_sp;
+ if (name != "__kernel_rt_sigreturn")
+ return unwind_plan_sp;
+
+ UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>();
+ row->SetOffset(0);
+
+ // In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
+ // - 128-byte siginfo struct
+ // - ucontext struct:
+ // - 8-byte long (uc_flags)
+ // - 8-byte pointer (uc_link)
+ // - 24-byte stack_t
+ // - 128-byte signal set
+ // - 8 bytes of padding because sigcontext has 16-byte alignment
+ // - sigcontext/mcontext_t
+ // [1]
+ // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c
+ int32_t offset = 128 + 8 + 8 + 24 + 128 + 8;
+ // Then sigcontext[2] is:
+ // - 8 byte fault address
+ // - 31 8 byte registers
+ // - 8 byte sp
+ // - 8 byte pc
+ // [2]
+ // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h
+
+ // Skip fault address
+ offset += 8;
+ row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x0, 0 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x1, 1 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x2, 2 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x3, 3 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x4, 4 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x5, 5 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x6, 6 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x7, 7 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x8, 8 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x9, 9 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x10, 10 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x11, 11 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x12, 12 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x13, 13 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x14, 14 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x15, 15 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x16, 16 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x17, 17 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x18, 18 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x19, 19 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x20, 20 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x21, 21 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x22, 22 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x23, 23 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x24, 24 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x25, 25 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x26, 26 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x27, 27 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x28, 28 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 29 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::x30, 30 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::sp, 31 * 8, false);
+ row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 32 * 8, false);
+
+ // The sigcontext may also contain floating point and SVE registers.
+ // However this would require a dynamic unwind plan so they are not included
+ // here.
+
+ unwind_plan_sp = std::make_shared<UnwindPlan>(eRegisterKindDWARF);
+ unwind_plan_sp->AppendRow(row);
+ unwind_plan_sp->SetSourceName("AArch64 AIX sigcontext");
+ unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
+ // Because sp is the same throughout the function
+ unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
+ unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes);
+
+ return unwind_plan_sp;
+}
+
+lldb::UnwindPlanSP
+PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple,
+ ConstString name) {
+ if (triple.isAArch64())
+ return GetAArch64TrapHanlderUnwindPlan(name);
+
+ return {};
+}
+
+MmapArgList PlatformAIX::GetMmapArgumentList(const ArchSpec &arch,
+ addr_t addr, addr_t length,
+ unsigned prot, unsigned flags,
+ addr_t fd, addr_t offset) {
+#if defined(__AIX__)
+ unsigned flags_platform = MAP_VARIABLE | MAP_PRIVATE | MAP_ANONYMOUS;
+#else
+ unsigned flags_platform = 0;
+#endif
+ MmapArgList args({addr, length, prot, flags_platform, fd, offset});
+ return args;
+}
+
+CompilerType PlatformAIX::GetSiginfoType(const llvm::Triple &triple) {
+ if (!m_type_system_up)
+ m_type_system_up.reset(new TypeSystemClang("siginfo", triple));
+ TypeSystemClang *ast = m_type_system_up.get();
+
+ bool si_errno_then_code = true;
+
+ switch (triple.getArch()) {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ // mips has si_code and si_errno swapped
+ si_errno_then_code = false;
+ break;
+ default:
+ break;
+ }
+
+ // generic types
+ CompilerType int_type = ast->GetBasicType(eBasicTypeInt);
+ CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt);
+ CompilerType short_type = ast->GetBasicType(eBasicTypeShort);
+ CompilerType long_type = ast->GetBasicType(eBasicTypeLong);
+ CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
+
+ // platform-specific types
+ CompilerType &pid_type = int_type;
+ CompilerType &uid_type = uint_type;
+ CompilerType &clock_type = long_type;
+ CompilerType &band_type = long_type;
+
+ CompilerType sigval_type = ast->CreateRecordType(
+ nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t",
+ llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
+ ast->StartTagDeclarationDefinition(sigval_type);
+ ast->AddFieldToRecordType(sigval_type, "sival_int", int_type,
+ lldb::eAccessPublic, 0);
+ ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type,
+ lldb::eAccessPublic, 0);
+ ast->CompleteTagDeclarationDefinition(sigval_type);
+
+ CompilerType sigfault_bounds_type = ast->CreateRecordType(
+ nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
+ llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
+ ast->StartTagDeclarationDefinition(sigfault_bounds_type);
+ ast->AddFieldToRecordType(sigfault_bounds_type, "_addr_bnd",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"_lower", voidp_type},
+ {"_upper", voidp_type},
+ }),
+ lldb::eAccessPublic, 0);
+ ast->AddFieldToRecordType(sigfault_bounds_type, "_pkey", uint_type,
+ lldb::eAccessPublic, 0);
+ ast->CompleteTagDeclarationDefinition(sigfault_bounds_type);
+
+ // siginfo_t
+ CompilerType siginfo_type = ast->CreateRecordType(
+ nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t",
+ llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
+ ast->StartTagDeclarationDefinition(siginfo_type);
+ ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type,
+ lldb::eAccessPublic, 0);
+
+ if (si_errno_then_code) {
+ ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type,
+ lldb::eAccessPublic, 0);
+ ast->AddFieldToRecordType(siginfo_type, "si_code", int_type,
+ lldb::eAccessPublic, 0);
+ } else {
+ ast->AddFieldToRecordType(siginfo_type, "si_code", int_type,
+ lldb::eAccessPublic, 0);
+ ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type,
+ lldb::eAccessPublic, 0);
+ }
+
+ // the structure is padded on 64-bit arches to fix alignment
+ if (triple.isArch64Bit())
+ ast->AddFieldToRecordType(siginfo_type, "__pad0", int_type,
+ lldb::eAccessPublic, 0);
+
+ // union used to hold the signal data
+ CompilerType union_type = ast->CreateRecordType(
+ nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
+ llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
+ ast->StartTagDeclarationDefinition(union_type);
+
+ ast->AddFieldToRecordType(
+ union_type, "_kill",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"si_pid", pid_type},
+ {"si_uid", uid_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ ast->AddFieldToRecordType(
+ union_type, "_timer",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"si_tid", int_type},
+ {"si_overrun", int_type},
+ {"si_sigval", sigval_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ ast->AddFieldToRecordType(
+ union_type, "_rt",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"si_pid", pid_type},
+ {"si_uid", uid_type},
+ {"si_sigval", sigval_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ ast->AddFieldToRecordType(
+ union_type, "_sigchld",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"si_pid", pid_type},
+ {"si_uid", uid_type},
+ {"si_status", int_type},
+ {"si_utime", clock_type},
+ {"si_stime", clock_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ ast->AddFieldToRecordType(
+ union_type, "_sigfault",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"si_addr", voidp_type},
+ {"si_addr_lsb", short_type},
+ {"_bounds", sigfault_bounds_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ ast->AddFieldToRecordType(
+ union_type, "_sigpoll",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"si_band", band_type},
+ {"si_fd", int_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ // NB: SIGSYS is not present on ia64 but we don't seem to support that
+ ast->AddFieldToRecordType(
+ union_type, "_sigsys",
+ ast->CreateStructForIdentifier(ConstString(),
+ {
+ {"_call_addr", voidp_type},
+ {"_syscall", int_type},
+ {"_arch", uint_type},
+ }),
+ lldb::eAccessPublic, 0);
+
+ ast->CompleteTagDeclarationDefinition(union_type);
+ ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type,
+ lldb::eAccessPublic, 0);
+
+ ast->CompleteTagDeclarationDefinition(siginfo_type);
+ return siginfo_type;
+}
diff --git a/lldb/source/Plugins/Platform/AIX/PlatformAIX.h b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h
new file mode 100644
index 00000000000000..3ae8089a48d713
--- /dev/null
+++ b/lldb/source/Plugins/Platform/AIX/PlatformAIX.h
@@ -0,0 +1,74 @@
+//===-- PlatformAIX.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H
+#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H
+
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+namespace lldb_private {
+namespace platform_aix {
+
+class PlatformAIX : public PlatformPOSIX {
+public:
+ PlatformAIX(bool is_host);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ // lldb_private::PluginInterface functions
+ static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+
+ static llvm::StringRef GetPluginNameStatic(bool is_host) {
+ return is_host ? Platform::GetHostPlatformName() : "remote-AIX";
+ }
+
+ static llvm::StringRef GetPluginDescriptionStatic(bool is_host);
+
+ llvm::StringRef GetPluginName() override {
+ return GetPluginNameStatic(IsHost());
+ }
+
+ // lldb_private::Platform functions
+ llvm::StringRef GetDescription() override {
+ return GetPluginDescriptionStatic(IsHost());
+ }
+
+ void GetStatus(Stream &strm) override;
+
+ std::vector<ArchSpec>
+ GetSupportedArchitectures(const ArchSpec &process_host_arch) override;
+
+ uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override;
+
+ bool CanDebugProcess() override;
+
+ void CalculateTrapHandlerSymbolNames() override;
+
+ lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple,
+ ConstString name) override;
+
+ MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
+ lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd,
+ lldb::addr_t offset) override;
+
+ CompilerType GetSiginfoType(const llvm::Triple &triple) override;
+
+ std::vector<ArchSpec> m_supported_architectures;
+
+private:
+ std::unique_ptr<TypeSystemClang> m_type_system_up;
+};
+
+} // namespace platform_AIX
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H
diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt
index 6869587f917eba..9d0afd97cff853 100644
--- a/lldb/source/Plugins/Platform/CMakeLists.txt
+++ b/lldb/source/Plugins/Platform/CMakeLists.txt
@@ -8,3 +8,4 @@ add_subdirectory(OpenBSD)
add_subdirectory(POSIX)
add_subdirectory(QemuUser)
add_subdirectory(Windows)
+add_subdirectory(AIX)
diff --git a/lldb/source/Plugins/Process/AIX/CMakeLists.txt b/lldb/source/Plugins/Process/AIX/CMakeLists.txt
new file mode 100644
index 00000000000000..e9d83266f5857c
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_definitions("-D_ALL_SOURCE")
+
+add_lldb_library(lldbPluginProcessAIX
+ NativeProcessAIX.cpp
+ NativeRegisterContextAIX.cpp
+ NativeRegisterContextAIX_ppc64.cpp
+ NativeThreadAIX.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbPluginProcessPOSIX
+ lldbPluginProcessUtility
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
new file mode 100644
index 00000000000000..882f20d30a3bf7
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
@@ -0,0 +1,2048 @@
+//===-- NativeProcessAIX.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessAIX.h"
+
+#include <cerrno>
+#include <cstdint>
+#include <cstring>
+#include <unistd.h>
+
+#include <fstream>
+#include <mutex>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+#include "NativeThreadAIX.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+//#include "Plugins/Process/Utility/LinuxProcMaps.h"
+//#include "Procfs.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Host/PseudoTerminal.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/aix/Ptrace.h"
+//#include "lldb/Host/linux/Host.h"
+//#include "lldb/Host/linux/Uio.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Threading.h"
+
+#include <sys/reg.h>
+#include <sys/ptrace.h>
+#include <sys/ldr.h>
+#include <sys/socket.h>
+//#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+
+#ifdef __aarch64__
+#include <asm/hwcap.h>
+#include <sys/auxv.h>
+#endif
+
+// Support hardware breakpoints in case it has not been defined
+#ifndef TRAP_HWBKPT
+#define TRAP_HWBKPT 4
+#endif
+
+#ifndef HWCAP2_MTE
+#define HWCAP2_MTE (1 << 18)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_aix;
+using namespace llvm;
+
+// Private bits we only need internally.
+
+static bool ProcessVmReadvSupported() {
+ static bool is_supported;
+ static llvm::once_flag flag;
+
+ llvm::call_once(flag, [] {
+ Log *log = GetLog(POSIXLog::Process);
+
+ uint32_t source = 0x47424742;
+ uint32_t dest = 0;
+
+ struct iovec local, remote;
+ remote.iov_base = &source;
+ local.iov_base = &dest;
+ remote.iov_len = local.iov_len = sizeof source;
+
+#if 0
+ // We shall try if cross-process-memory reads work by attempting to read a
+ // value from our own process.
+ ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0);
+ is_supported = (res == sizeof(source) && source == dest);
+ if (is_supported)
+ LLDB_LOG(log,
+ "Detected kernel support for process_vm_readv syscall. "
+ "Fast memory reads enabled.");
+ else
+ LLDB_LOG(log,
+ "syscall process_vm_readv failed (error: {0}). Fast memory "
+ "reads disabled.",
+ llvm::sys::StrError());
+#endif
+ });
+
+ return is_supported;
+}
+
+static void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) {
+ Log *log = GetLog(POSIXLog::Process);
+ if (!log)
+ return;
+
+ if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO))
+ LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec());
+ else
+ LLDB_LOG(log, "leaving STDIN as is");
+
+ if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO))
+ LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec());
+ else
+ LLDB_LOG(log, "leaving STDOUT as is");
+
+ if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO))
+ LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec());
+ else
+ LLDB_LOG(log, "leaving STDERR as is");
+
+ int i = 0;
+ for (const char **args = info.GetArguments().GetConstArgumentVector(); *args;
+ ++args, ++i)
+ LLDB_LOG(log, "arg {0}: '{1}'", i, *args);
+}
+
+static void DisplayBytes(StreamString &s, void *bytes, uint32_t count) {
+ uint8_t *ptr = (uint8_t *)bytes;
+ const uint32_t loop_count = std::min<uint32_t>(DEBUG_PTRACE_MAXBYTES, count);
+ for (uint32_t i = 0; i < loop_count; i++) {
+ s.Printf("[%x]", *ptr);
+ ptr++;
+ }
+}
+
+static void PtraceDisplayBytes(int &req, void *data, size_t data_size) {
+ Log *log = GetLog(POSIXLog::Ptrace);
+ if (!log)
+ return;
+ StreamString buf;
+
+ switch (req) {
+ case PTRACE_POKETEXT: {
+ DisplayBytes(buf, &data, 8);
+ LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData());
+ break;
+ }
+ case PTRACE_POKEDATA: {
+ DisplayBytes(buf, &data, 8);
+ LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData());
+ break;
+ }
+ case PTRACE_POKEUSER: {
+ DisplayBytes(buf, &data, 8);
+ LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData());
+ break;
+ }
+ case PTRACE_SETREGS: {
+ DisplayBytes(buf, data, data_size);
+ LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData());
+ break;
+ }
+ case PTRACE_SETFPREGS: {
+ DisplayBytes(buf, data, data_size);
+ LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData());
+ break;
+ }
+#if 0
+ case PTRACE_SETSIGINFO: {
+ DisplayBytes(buf, data, sizeof(siginfo_t));
+ LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData());
+ break;
+ }
+#endif
+ case PTRACE_SETREGSET: {
+ // Extract iov_base from data, which is a pointer to the struct iovec
+ DisplayBytes(buf, *(void **)data, data_size);
+ LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData());
+ break;
+ }
+ default: {}
+ }
+}
+
+static constexpr unsigned k_ptrace_word_size = sizeof(void *);
+static_assert(sizeof(long) >= k_ptrace_word_size,
+ "Size of long must be larger than ptrace word size");
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+ Status error;
+
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+#if 0
+static llvm::Error AddPtraceScopeNote(llvm::Error original_error) {
+ Expected<int> ptrace_scope = GetPtraceScope();
+ if (auto E = ptrace_scope.takeError()) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "error reading value of ptrace_scope: {0}", E);
+
+ // The original error is probably more interesting than not being able to
+ // read or interpret ptrace_scope.
+ return original_error;
+ }
+
+ // We only have suggestions to provide for 1-3.
+ switch (*ptrace_scope) {
+ case 1:
+ case 2:
+ return llvm::createStringError(
+ std::error_code(errno, std::generic_category()),
+ "The current value of ptrace_scope is %d, which can cause ptrace to "
+ "fail to attach to a running process. To fix this, run:\n"
+ "\tsudo sysctl -w kernel.yama.ptrace_scope=0\n"
+ "For more information, see: "
+ "https://www.kernel.org/doc/Documentation/security/Yama.txt.",
+ *ptrace_scope);
+ case 3:
+ return llvm::createStringError(
+ std::error_code(errno, std::generic_category()),
+ "The current value of ptrace_scope is 3, which will cause ptrace to "
+ "fail to attach to a running process. This value cannot be changed "
+ "without rebooting.\n"
+ "For more information, see: "
+ "https://www.kernel.org/doc/Documentation/security/Yama.txt.");
+ case 0:
+ default:
+ return original_error;
+ }
+}
+#endif
+
+NativeProcessAIX::Manager::Manager(MainLoop &mainloop)
+ : NativeProcessProtocol::Manager(mainloop) {
+ Status status;
+ m_sigchld_handle = mainloop.RegisterSignal(
+ SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+ assert(m_sigchld_handle && status.Success());
+}
+
+// Public Static Methods
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ MaybeLogLaunchInfo(launch_info);
+
+ Status status;
+ ::pid_t pid = ProcessLauncherPosixFork()
+ .LaunchProcess(launch_info, status)
+ .GetProcessId();
+ LLDB_LOG(log, "pid = {0:x}", pid);
+ if (status.Fail()) {
+ LLDB_LOG(log, "failed to launch process: {0}", status);
+ return status.ToError();
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ int wstatus = 0;
+ ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+ assert(wpid == pid);
+ UNUSED_IF_ASSERT_DISABLED(wpid);
+ if (!WIFSTOPPED(wstatus)) {
+ LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
+ WaitStatus::Decode(wstatus));
+ return llvm::make_error<StringError>("Could not sync with inferior process",
+ llvm::inconvertibleErrorCode());
+ }
+ LLDB_LOG(log, "inferior started, now in stopped state");
+
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architectrue",
+ llvm::inconvertibleErrorCode());
+ }
+ /*llvm::Expected<ArchSpec> arch_or =
+ NativeRegisterContextAIX::DetermineArchitecture(pid);
+ if (!arch_or)
+ return arch_or.takeError();*/
+
+ // Set the architecture to the exe architecture.
+ LLDB_LOG(log, "pid = {0}, detected architecture {1}", pid,
+ Info.GetArchitecture().GetArchitectureName());
+
+ return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
+ pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
+ Info.GetArchitecture(), *this, {pid}));
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessAIX::Manager::Attach(
+ lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architectrue",
+ llvm::inconvertibleErrorCode());
+ }
+ auto tids_or = NativeProcessAIX::Attach(pid);
+ if (!tids_or)
+ return tids_or.takeError();
+#if 0
+ ArrayRef<::pid_t> tids = *tids_or;
+ llvm::Expected<ArchSpec> arch_or =
+ NativeRegisterContextAIX::DetermineArchitecture(tids[0]);
+ if (!arch_or)
+ return arch_or.takeError();
+#endif
+
+ return std::unique_ptr<NativeProcessAIX>(
+ new NativeProcessAIX(pid, -1, native_delegate, Info.GetArchitecture(), *this, *tids_or));
+}
+
+lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() {
+ // punt on this for now
+ return LLDB_INVALID_ADDRESS;
+}
+
+NativeProcessAIX::Extension
+NativeProcessAIX::Manager::GetSupportedExtensions() const {
+ NativeProcessAIX::Extension supported =
+ Extension::multiprocess | Extension::fork | Extension::vfork |
+ Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
+ Extension::siginfo_read;
+
+#ifdef __aarch64__
+ // At this point we do not have a process so read auxv directly.
+ if ((getauxval(AT_HWCAP2) & HWCAP2_MTE))
+ supported |= Extension::memory_tagging;
+#endif
+
+ return supported;
+}
+
+static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
+ Log *log = GetLog(POSIXLog::Process);
+
+ int status;
+ ::pid_t wait_pid = llvm::sys::RetryAfterSignal(
+ -1, ::waitpid, -1, &status, /*__WALL | __WNOTHREAD |*/ WNOHANG);
+
+ if (wait_pid == 0)
+ return std::nullopt;
+
+ if (wait_pid == -1) {
+ Status error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid(-1, &status, _) failed: {1}", error);
+ return std::nullopt;
+ }
+
+ WaitStatus wait_status = WaitStatus::Decode(status);
+
+ LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid,
+ wait_status);
+ return std::make_pair(wait_pid, wait_status);
+}
+
+void NativeProcessAIX::Manager::SigchldHandler() {
+ Log *log = GetLog(POSIXLog::Process);
+ while (true) {
+ auto wait_result = WaitPid();
+ if (!wait_result)
+ return;
+ lldb::pid_t pid = wait_result->first;
+ WaitStatus status = wait_result->second;
+
+ // Ask each process whether it wants to handle the event. Each event should
+ // be handled by exactly one process, but thread creation events require
+ // special handling.
+ // Thread creation consists of two events (one on the parent and one on the
+ // child thread) and they can arrive in any order nondeterministically. The
+ // parent event carries the information about the child thread, but not
+ // vice-versa. This means that if the child event arrives first, it may not
+ // be handled by any process (because it doesn't know the thread belongs to
+ // it).
+ bool handled = llvm::any_of(m_processes, [&](NativeProcessAIX *process) {
+ return process->TryHandleWaitStatus(pid, status);
+ });
+ if (!handled) {
+ if (status.type == WaitStatus::Stop && status.status == SIGSTOP) {
+ // Store the thread creation event for later collection.
+ m_unowned_threads.insert(pid);
+ } else {
+ LLDB_LOG(log, "Ignoring waitpid event {0} for pid {1}", status, pid);
+ }
+ }
+ }
+}
+
+void NativeProcessAIX::Manager::CollectThread(::pid_t tid) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ if (m_unowned_threads.erase(tid))
+ return; // We've encountered this thread already.
+
+ // The TID is not tracked yet, let's wait for it to appear.
+ int status = -1;
+ LLDB_LOG(log,
+ "received clone event for tid {0}. tid not tracked yet, "
+ "waiting for it to appear...",
+ tid);
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, P_ALL/*__WALL*/);
+
+ // It's theoretically possible to get other events if the entire process was
+ // SIGKILLed before we got a chance to check this. In that case, we'll just
+ // clean everything up when we get the process exit event.
+
+ LLDB_LOG(log,
+ "waitpid({0}, &status, __WALL) => {1} (errno: {2}, status = {3})",
+ tid, wait_pid, errno, WaitStatus::Decode(status));
+}
+
+// Public Instance Methods
+
+NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate,
+ const ArchSpec &arch, Manager &manager,
+ llvm::ArrayRef<::pid_t> tids)
+ : NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager),
+ m_arch(arch) {
+ manager.AddProcess(*this);
+ if (m_terminal_fd != -1) {
+ Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ assert(status.Success());
+ }
+
+ for (const auto &tid : tids) {
+ NativeThreadAIX &thread = AddThread(tid, /*resume*/ false);
+ ThreadWasCreated(thread);
+ }
+
+ // Let our process instance know the thread has stopped.
+ SetCurrentThreadID(tids[0]);
+ SetState(StateType::eStateStopped, false);
+}
+
+llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
+ Log *log = GetLog(POSIXLog::Process);
+
+ Status status;
+ if ((status = PtraceWrapper(PT_ATTACH, pid)).Fail()) {
+ return status.ToError();
+ }
+
+ int wpid =
+ llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG);
+ if (wpid <= 0) {
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ }
+
+ LLDB_LOG(log, "adding pid = {0}", pid);
+
+ std::vector<::pid_t> tids;
+ tids.push_back(pid);
+ return std::move(tids);
+}
+
+bool NativeProcessAIX::TryHandleWaitStatus(lldb::pid_t pid,
+ WaitStatus status) {
+ if (pid == GetID() &&
+ (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal)) {
+ // The process exited. We're done monitoring. Report to delegate.
+ SetExitStatus(status, true);
+ return true;
+ }
+ if (NativeThreadAIX *thread = GetThreadByID(pid)) {
+ MonitorCallback(*thread, status);
+ return true;
+ }
+ return false;
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessAIX::MonitorCallback(NativeThreadAIX &thread,
+ WaitStatus status) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Certain activities differ based on whether the pid is the tid of the main
+ // thread.
+ const bool is_main_thread = (thread.GetID() == GetID());
+
+ // Handle when the thread exits.
+ if (status.type == WaitStatus::Exit || status.type == WaitStatus::Signal) {
+ LLDB_LOG(log,
+ "got exit status({0}) , tid = {1} ({2} main thread), process "
+ "state = {3}",
+ status, thread.GetID(), is_main_thread ? "is" : "is not",
+ GetState());
+
+ // This is a thread that exited. Ensure we're not tracking it anymore.
+ StopTrackingThread(thread);
+
+ assert(!is_main_thread && "Main thread exits handled elsewhere");
+ return;
+ }
+
+ int8_t signo = GetSignalInfo(status);
+
+ // Get details on the signal raised.
+ if (signo) {
+ // We have retrieved the signal info. Dispatch appropriately.
+ if (signo == SIGTRAP)
+ MonitorSIGTRAP(status, thread);
+ else
+ MonitorSignal(status, thread);
+ } else {
+ assert(0);
+ }
+}
+
+
+void NativeProcessAIX::MonitorSIGTRAP(const WaitStatus status,
+ NativeThreadAIX &thread) {
+ Log *log = GetLog(POSIXLog::Process);
+ const bool is_main_thread = (thread.GetID() == GetID());
+
+ NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext();
+ const RegisterInfo *pc_info = reg_ctx.GetRegisterInfoByName("pc", 0);
+ RegisterValue pc_value;
+
+ switch (status.status) {
+ case SIGTRAP:
+ // Determine the source of SIGTRAP by checking current instruction:
+ // if that is trap instruction, then this is breakpoint, otherwise
+ // this is watchpoint.
+ reg_ctx.ReadRegister(pc_info, pc_value);
+
+ MonitorBreakpoint(thread);
+ break;
+ default:
+ LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}",
+ status.status, GetID(), thread.GetID());
+ MonitorSignal(status, thread);
+ break;
+ }
+}
+
+void NativeProcessAIX::MonitorTrace(NativeThreadAIX &thread) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID());
+
+ // This thread is currently stopped.
+ thread.SetStoppedByTrace();
+
+ StopRunningThreads(thread.GetID());
+}
+
+void NativeProcessAIX::MonitorBreakpoint(NativeThreadAIX &thread) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
+ LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID());
+
+ // Mark the thread as stopped at breakpoint.
+ thread.SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(thread);
+
+ if (m_threads_stepping_with_breakpoint.find(thread.GetID()) !=
+ m_threads_stepping_with_breakpoint.end())
+ thread.SetStoppedByTrace();
+
+ StopRunningThreads(thread.GetID());
+}
+
+void NativeProcessAIX::MonitorWatchpoint(NativeThreadAIX &thread,
+ uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Watchpoints);
+ LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}",
+ thread.GetID(), wp_index);
+
+ // Mark the thread as stopped at watchpoint. The address is at
+ // (lldb::addr_t)info->si_addr if we need it.
+ thread.SetStoppedByWatchpoint(wp_index);
+
+ // We need to tell all other running threads before we notify the delegate
+ // about this stop.
+ StopRunningThreads(thread.GetID());
+}
+
+void NativeProcessAIX::MonitorSignal(const WaitStatus status,
+ NativeThreadAIX &thread) {
+ int8_t signo = GetSignalInfo(status);
+#if 0
+ const bool is_from_llgs = info.si_pid == getpid();
+#endif
+
+ Log *log = GetLog(POSIXLog::Process);
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a kill(2)
+ // or raise(3). Similarly for tgkill(2) on AIX.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+
+ // Handle the signal.
+ LLDB_LOG(log,
+ "received signal {0} ({1}) with code NA, (siginfo pid = {2}, "
+ "waitpid pid = {3})",
+ Host::GetSignalAsCString(signo), signo, thread.GetID(), GetID());
+
+#if 0
+ // Check for thread stop notification.
+ // FIXME
+ if (is_from_llgs /*&& (info.si_code == SI_TKILL)*/ && (signo == SIGSTOP)) {
+ // This is a tgkill()-based stop.
+ LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID());
+
+ // Check that we're not already marked with a stop reason. Note this thread
+ // really shouldn't already be marked as stopped - if we were, that would
+ // imply that the kernel signaled us with the thread stopping which we
+ // handled and marked as stopped, and that, without an intervening resume,
+ // we received another stop. It is more likely that we are missing the
+ // marking of a run state somewhere if we find that the thread was marked
+ // as stopped.
+ const StateType thread_state = thread.GetState();
+ if (!StateIsStoppedState(thread_state, false)) {
+ // An inferior thread has stopped because of a SIGSTOP we have sent it.
+ // Generally, these are not important stops and we don't want to report
+ // them as they are just used to stop other threads when one thread (the
+ // one with the *real* stop reason) hits a breakpoint (watchpoint,
+ // etc...). However, in the case of an asynchronous Interrupt(), this
+ // *is* the real stop reason, so we leave the signal intact if this is
+ // the thread that was chosen as the triggering thread.
+ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) {
+ if (m_pending_notification_tid == thread.GetID())
+ thread.SetStoppedBySignal(SIGSTOP, &info);
+ else
+ thread.SetStoppedWithNoReason();
+
+ SetCurrentThreadID(thread.GetID());
+ SignalIfAllThreadsStopped();
+ } else {
+ // We can end up here if stop was initiated by LLGS but by this time a
+ // thread stop has occurred - maybe initiated by another event.
+ Status error = ResumeThread(thread, thread.GetState(), 0);
+ if (error.Fail())
+ LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(),
+ error);
+ }
+ } else {
+ LLDB_LOG(log,
+ "pid {0} tid {1}, thread was already marked as a stopped "
+ "state (state={2}), leaving stop signal as is",
+ GetID(), thread.GetID(), thread_state);
+ SignalIfAllThreadsStopped();
+ }
+
+ // Done handling.
+ return;
+ }
+#endif
+
+ // Check if debugger should stop at this signal or just ignore it and resume
+ // the inferior.
+ if (m_signals_to_ignore.contains(signo) || signo == SIGCHLD) {
+ ResumeThread(thread, thread.GetState(), signo);
+ return;
+ }
+
+ // This thread is stopped.
+ LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo));
+ thread.SetStoppedBySignal(signo);
+
+ // Send a stop to the debugger after we get all other threads to stop.
+ StopRunningThreads(thread.GetID());
+}
+
+bool NativeProcessAIX::MonitorClone(NativeThreadAIX &parent,
+ lldb::pid_t child_pid, int event) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "parent_tid={0}, child_pid={1}, event={2}", parent.GetID(),
+ child_pid, event);
+
+ // WaitForCloneNotification(child_pid);
+
+ switch (event) {
+#if 0
+ case PTRACE_EVENT_CLONE: {
+ // PTRACE_EVENT_CLONE can either mean a new thread or a new process.
+ // Try to grab the new process' PGID to figure out which one it is.
+ // If PGID is the same as the PID, then it's a new process. Otherwise,
+ // it's a thread.
+ auto tgid_ret = getPIDForTID(child_pid);
+ if (tgid_ret != child_pid) {
+ // A new thread should have PGID matching our process' PID.
+ assert(!tgid_ret || tgid_ret.getValue() == GetID());
+
+ NativeThreadAIX &child_thread = AddThread(child_pid, /*resume*/ true);
+ ThreadWasCreated(child_thread);
+
+ // Resume the parent.
+ ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+ break;
+ }
+ }
+ LLVM_FALLTHROUGH;
+ case PTRACE_EVENT_FORK:
+ case PTRACE_EVENT_VFORK: {
+ bool is_vfork = event == PTRACE_EVENT_VFORK;
+ std::unique_ptr<NativeProcessAIX> child_process{new NativeProcessAIX(
+ static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch,
+ m_main_loop, {static_cast<::pid_t>(child_pid)})};
+ if (!is_vfork)
+ child_process->m_software_breakpoints = m_software_breakpoints;
+
+ Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;
+ if (bool(m_enabled_extensions & expected_ext)) {
+ m_delegate.NewSubprocess(this, std::move(child_process));
+ // NB: non-vfork clone() is reported as fork
+ parent.SetStoppedByFork(is_vfork, child_pid);
+ StopRunningThreads(parent.GetID());
+ } else {
+ child_process->Detach();
+ ResumeThread(parent, parent.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ break;
+ }
+#endif
+ default:
+ llvm_unreachable("unknown clone_info.event");
+ }
+
+ return true;
+}
+
+bool NativeProcessAIX::SupportHardwareSingleStepping() const {
+ return false;
+}
+
+Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ bool software_single_step = !SupportHardwareSingleStepping();
+
+ if (software_single_step) {
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+
+ const ResumeAction *const action =
+ resume_actions.GetActionForThread(thread->GetID(), true);
+ if (action == nullptr)
+ continue;
+
+ if (action->state == eStateStepping) {
+ Status error = SetupSoftwareSingleStepping(
+ static_cast<NativeThreadAIX &>(*thread));
+ if (error.Fail())
+ return error;
+ }
+ }
+ }
+
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+
+ const ResumeAction *const action =
+ resume_actions.GetActionForThread(thread->GetID(), true);
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread->GetID());
+ continue;
+ }
+
+ LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}",
+ action->state, GetID(), thread->GetID());
+
+ switch (action->state) {
+ case eStateRunning:
+ case eStateStepping: {
+ // Run the thread, possibly feeding it the signal.
+ const int signo = action->signal;
+ Status error = ResumeThread(static_cast<NativeThreadAIX &>(*thread),
+ action->state, signo);
+ if (error.Fail())
+ return Status("NativeProcessAIX::%s: failed to resume thread "
+ "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s",
+ __FUNCTION__, GetID(), thread->GetID(),
+ error.AsCString());
+
+ break;
+ }
+
+ case eStateSuspended:
+ case eStateStopped:
+ break;
+
+ default:
+ return Status("NativeProcessAIX::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(),
+ thread->GetID());
+ }
+ }
+
+ return Status();
+}
+
+Status NativeProcessAIX::Halt() {
+ Status error;
+
+ if (kill(GetID(), SIGSTOP) != 0)
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessAIX::Detach() {
+ Status error;
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ // Cancel out any SIGSTOPs we may have sent while stopping the process.
+ // Otherwise, the process may stop as soon as we detach from it.
+ kill(GetID(), SIGCONT);
+
+ for (const auto &thread : m_threads) {
+ Status e = Detach(thread->GetID());
+ if (e.Fail())
+ error =
+ e; // Save the error, but still attempt to detach from other threads.
+ }
+
+ return error;
+}
+
+Status NativeProcessAIX::Signal(int signo) {
+ Status error;
+
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo,
+ Host::GetSignalAsCString(signo), GetID());
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessAIX::Interrupt() {
+ // Pick a running thread (or if none, a not-dead stopped thread) as the
+ // chosen thread that will be the stop-reason thread.
+ Log *log = GetLog(POSIXLog::Process);
+
+ NativeThreadProtocol *running_thread = nullptr;
+ NativeThreadProtocol *stopped_thread = nullptr;
+
+ LLDB_LOG(log, "selecting running thread for interrupt target");
+ for (const auto &thread : m_threads) {
+ // If we have a running or stepping thread, we'll call that the target of
+ // the interrupt.
+ const auto thread_state = thread->GetState();
+ if (thread_state == eStateRunning || thread_state == eStateStepping) {
+ running_thread = thread.get();
+ break;
+ } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) {
+ // Remember the first non-dead stopped thread. We'll use that as a
+ // backup if there are no running threads.
+ stopped_thread = thread.get();
+ }
+ }
+
+ if (!running_thread && !stopped_thread) {
+ Status error("found no running/stepping or live stopped threads as target "
+ "for interrupt");
+ LLDB_LOG(log, "skipping due to error: {0}", error);
+
+ return error;
+ }
+
+ NativeThreadProtocol *deferred_signal_thread =
+ running_thread ? running_thread : stopped_thread;
+
+ LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(),
+ running_thread ? "running" : "stopped",
+ deferred_signal_thread->GetID());
+
+ StopRunningThreads(deferred_signal_thread->GetID());
+
+ return Status();
+}
+
+Status NativeProcessAIX::Kill() {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status error;
+
+ switch (m_state) {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
+ m_state);
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ if (kill(GetID(), SIGKILL) != 0) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+Status NativeProcessAIX::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ // FIXME review that the final memory region returned extends to the end of
+ // the virtual address space,
+ // with no perms if it is not mapped.
+
+ // Use an approach that reads memory regions from /proc/{pid}/maps. Assume
+ // proc maps entries are in ascending order.
+ // FIXME assert if we find differently.
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+ // We're done.
+ return Status("unsupported");
+ }
+
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ return error;
+ }
+
+ lldb::addr_t prev_base_address = 0;
+
+ // FIXME start by finding the last region that is <= target address using
+ // binary search. Data is sorted.
+ // There can be a ton of regions on pthreads apps with lots of threads.
+ for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
+ ++it) {
+ MemoryRegionInfo &proc_entry_info = it->first;
+
+ // Sanity check assumption that /proc/{pid}/maps entries are ascending.
+ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
+ "descending /proc/pid/maps entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
+ UNUSED_IF_ASSERT_DISABLED(prev_base_address);
+
+ // If the target address comes before this entry, indicate distance to next
+ // region.
+ if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetByteSize(
+ proc_entry_info.GetRange().GetRangeBase() - load_addr);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+
+ return error;
+ } else if (proc_entry_info.GetRange().Contains(load_addr)) {
+ // The target address is within the memory region we're processing here.
+ range_info = proc_entry_info;
+ return error;
+ }
+
+ // The target memory address comes somewhere after the region we just
+ // parsed.
+ }
+
+ // If we made it here, we didn't find an entry that contained the given
+ // address. Return the load_addr as start and the amount of bytes betwwen
+ // load address and the end of the memory as size.
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+Status NativeProcessAIX::PopulateMemoryRegionCache() {
+ Log *log = GetLog(POSIXLog::Process);
+
+ // If our cache is empty, pull the latest. There should always be at least
+ // one memory region if memory region handling is supported.
+ if (!m_mem_region_cache.empty()) {
+ LLDB_LOG(log, "reusing {0} cached memory region entries",
+ m_mem_region_cache.size());
+ return Status();
+ }
+
+ Status Result;
+#if 0
+ AIXMapCallback callback = [&](llvm::Expected<MemoryRegionInfo> Info) {
+ if (Info) {
+ FileSpec file_spec(Info->GetName().GetCString());
+ FileSystem::Instance().Resolve(file_spec);
+ m_mem_region_cache.emplace_back(*Info, file_spec);
+ return true;
+ }
+
+ Result = Info.takeError();
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ LLDB_LOG(log, "failed to parse proc maps: {0}", Result);
+ return false;
+ };
+
+ // AIX kernel since 2.6.14 has /proc/{pid}/smaps
+ // if CONFIG_PROC_PAGE_MONITOR is enabled
+ auto BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "smaps");
+ if (BufferOrError)
+ ParseAIXSMapRegions(BufferOrError.get()->getBuffer(), callback);
+ else {
+ BufferOrError = getProcFile(GetID(), GetCurrentThreadID(), "maps");
+ if (!BufferOrError) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return BufferOrError.getError();
+ }
+
+ ParseAIXMapRegions(BufferOrError.get()->getBuffer(), callback);
+ }
+
+ if (Result.Fail())
+ return Result;
+
+ if (m_mem_region_cache.empty()) {
+ // No entries after attempting to read them. This shouldn't happen if
+ // /proc/{pid}/maps is supported. Assume we don't support map entries via
+ // procfs.
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ LLDB_LOG(log,
+ "failed to find any procfs maps entries, assuming no support "
+ "for memory region metadata retrieval");
+ return Status("not supported");
+ }
+
+ LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps",
+ m_mem_region_cache.size(), GetID());
+
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+#endif
+ return Status();
+}
+
+void NativeProcessAIX::DoStopIDBumped(uint32_t newBumpId) {
+ Log *log = GetLog(POSIXLog::Process);
+ LLDB_LOG(log, "newBumpId={0}", newBumpId);
+ LLDB_LOG(log, "clearing {0} entries from memory region cache",
+ m_mem_region_cache.size());
+ m_mem_region_cache.clear();
+}
+
+llvm::Expected<uint64_t>
+NativeProcessAIX::Syscall(llvm::ArrayRef<uint64_t> args) {
+ PopulateMemoryRegionCache();
+ auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) {
+ return pair.first.GetExecutable() == MemoryRegionInfo::eYes &&
+ pair.first.GetShared() != MemoryRegionInfo::eYes;
+ });
+ if (region_it == m_mem_region_cache.end())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No executable memory region found!");
+
+ addr_t exe_addr = region_it->first.GetRange().GetRangeBase();
+
+ NativeThreadAIX &thread = *GetCurrentThread();
+ assert(thread.GetState() == eStateStopped);
+ NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext();
+
+ NativeRegisterContextAIX::SyscallData syscall_data =
+ *reg_ctx.GetSyscallData();
+
+ WritableDataBufferSP registers_sp;
+ if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError())
+ return std::move(Err);
+ auto restore_regs = llvm::make_scope_exit(
+ [&] { reg_ctx.WriteAllRegisterValues(registers_sp); });
+
+ llvm::SmallVector<uint8_t, 8> memory(syscall_data.Insn.size());
+ size_t bytes_read;
+ if (llvm::Error Err =
+ ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read)
+ .ToError()) {
+ return std::move(Err);
+ }
+
+ auto restore_mem = llvm::make_scope_exit(
+ [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); });
+
+ if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError())
+ return std::move(Err);
+
+ for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) {
+ if (llvm::Error Err =
+ reg_ctx
+ .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip))
+ .ToError()) {
+ return std::move(Err);
+ }
+ }
+ if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(),
+ syscall_data.Insn.size(), bytes_read)
+ .ToError())
+ return std::move(Err);
+
+ m_mem_region_cache.clear();
+
+ // With software single stepping the syscall insn buffer must also include a
+ // trap instruction to stop the process.
+ int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT;
+ if (llvm::Error Err =
+ PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError())
+ return std::move(Err);
+
+ //FIXME
+ int status;
+ ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(),
+ &status, P_ALL/*__WALL*/);
+ if (wait_pid == -1) {
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ }
+ assert((unsigned)wait_pid == thread.GetID());
+
+ uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH);
+
+ // Values larger than this are actually negative errno numbers.
+ uint64_t errno_threshold =
+ (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000;
+ if (result > errno_threshold) {
+ return llvm::errorCodeToError(
+ std::error_code(-result & 0xfff, std::generic_category()));
+ }
+
+ return result;
+}
+
+llvm::Expected<addr_t>
+NativeProcessAIX::AllocateMemory(size_t size, uint32_t permissions) {
+
+ std::optional<NativeRegisterContextAIX::MmapData> mmap_data =
+ GetCurrentThread()->GetRegisterContext().GetMmapData();
+ if (!mmap_data)
+ return llvm::make_error<UnimplementedError>();
+
+ unsigned prot = PROT_NONE;
+ assert((permissions & (ePermissionsReadable | ePermissionsWritable |
+ ePermissionsExecutable)) == permissions &&
+ "Unknown permission!");
+ if (permissions & ePermissionsReadable)
+ prot |= PROT_READ;
+ if (permissions & ePermissionsWritable)
+ prot |= PROT_WRITE;
+ if (permissions & ePermissionsExecutable)
+ prot |= PROT_EXEC;
+
+ llvm::Expected<uint64_t> Result =
+ Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE,
+ uint64_t(-1), 0});
+ if (Result)
+ m_allocated_memory.try_emplace(*Result, size);
+ return Result;
+}
+
+llvm::Error NativeProcessAIX::DeallocateMemory(lldb::addr_t addr) {
+ std::optional<NativeRegisterContextAIX::MmapData> mmap_data =
+ GetCurrentThread()->GetRegisterContext().GetMmapData();
+ if (!mmap_data)
+ return llvm::make_error<UnimplementedError>();
+
+ auto it = m_allocated_memory.find(addr);
+ if (it == m_allocated_memory.end())
+ return llvm::createStringError(llvm::errc::invalid_argument,
+ "Memory not allocated by the debugger.");
+
+ llvm::Expected<uint64_t> Result =
+ Syscall({mmap_data->SysMunmap, addr, it->second});
+ if (!Result)
+ return Result.takeError();
+
+ m_allocated_memory.erase(it);
+ return llvm::Error::success();
+}
+
+Status NativeProcessAIX::ReadMemoryTags(int32_t type, lldb::addr_t addr,
+ size_t len,
+ std::vector<uint8_t> &tags) {
+ llvm::Expected<NativeRegisterContextAIX::MemoryTaggingDetails> details =
+ GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type);
+ if (!details)
+ return Status(details.takeError());
+
+ // Ignore 0 length read
+ if (!len)
+ return Status();
+
+ // lldb will align the range it requests but it is not required to by
+ // the protocol so we'll do it again just in case.
+ // Remove tag bits too. Ptrace calls may work regardless but that
+ // is not a guarantee.
+ MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len);
+ range = details->manager->ExpandToGranule(range);
+
+ // Allocate enough space for all tags to be read
+ size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize();
+ tags.resize(num_tags * details->manager->GetTagSizeInBytes());
+
+ struct iovec tags_iovec;
+ uint8_t *dest = tags.data();
+ lldb::addr_t read_addr = range.GetRangeBase();
+
+ // This call can return partial data so loop until we error or
+ // get all tags back.
+ while (num_tags) {
+ tags_iovec.iov_base = dest;
+ tags_iovec.iov_len = num_tags;
+
+ Status error = NativeProcessAIX::PtraceWrapper(
+ details->ptrace_read_req, GetCurrentThreadID(),
+ reinterpret_cast<void *>(read_addr), static_cast<void *>(&tags_iovec),
+ 0, nullptr);
+
+ if (error.Fail()) {
+ // Discard partial reads
+ tags.resize(0);
+ return error;
+ }
+
+ size_t tags_read = tags_iovec.iov_len;
+ assert(tags_read && (tags_read <= num_tags));
+
+ dest += tags_read * details->manager->GetTagSizeInBytes();
+ read_addr += details->manager->GetGranuleSize() * tags_read;
+ num_tags -= tags_read;
+ }
+
+ return Status();
+}
+
+Status NativeProcessAIX::WriteMemoryTags(int32_t type, lldb::addr_t addr,
+ size_t len,
+ const std::vector<uint8_t> &tags) {
+ llvm::Expected<NativeRegisterContextAIX::MemoryTaggingDetails> details =
+ GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type);
+ if (!details)
+ return Status(details.takeError());
+
+ // Ignore 0 length write
+ if (!len)
+ return Status();
+
+ // lldb will align the range it requests but it is not required to by
+ // the protocol so we'll do it again just in case.
+ // Remove tag bits too. Ptrace calls may work regardless but that
+ // is not a guarantee.
+ MemoryTagManager::TagRange range(details->manager->RemoveTagBits(addr), len);
+ range = details->manager->ExpandToGranule(range);
+
+ // Not checking number of tags here, we may repeat them below
+ llvm::Expected<std::vector<lldb::addr_t>> unpacked_tags_or_err =
+ details->manager->UnpackTagsData(tags);
+ if (!unpacked_tags_or_err)
+ return Status(unpacked_tags_or_err.takeError());
+
+ llvm::Expected<std::vector<lldb::addr_t>> repeated_tags_or_err =
+ details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range);
+ if (!repeated_tags_or_err)
+ return Status(repeated_tags_or_err.takeError());
+
+ // Repack them for ptrace to use
+ llvm::Expected<std::vector<uint8_t>> final_tag_data =
+ details->manager->PackTags(*repeated_tags_or_err);
+ if (!final_tag_data)
+ return Status(final_tag_data.takeError());
+
+ struct iovec tags_vec;
+ uint8_t *src = final_tag_data->data();
+ lldb::addr_t write_addr = range.GetRangeBase();
+ // unpacked tags size because the number of bytes per tag might not be 1
+ size_t num_tags = repeated_tags_or_err->size();
+
+ // This call can partially write tags, so we loop until we
+ // error or all tags have been written.
+ while (num_tags > 0) {
+ tags_vec.iov_base = src;
+ tags_vec.iov_len = num_tags;
+
+ Status error = NativeProcessAIX::PtraceWrapper(
+ details->ptrace_write_req, GetCurrentThreadID(),
+ reinterpret_cast<void *>(write_addr), static_cast<void *>(&tags_vec), 0,
+ nullptr);
+
+ if (error.Fail()) {
+ // Don't attempt to restore the original values in the case of a partial
+ // write
+ return error;
+ }
+
+ size_t tags_written = tags_vec.iov_len;
+ assert(tags_written && (tags_written <= num_tags));
+
+ src += tags_written * details->manager->GetTagSizeInBytes();
+ write_addr += details->manager->GetGranuleSize() * tags_written;
+ num_tags -= tags_written;
+ }
+
+ return Status();
+}
+
+size_t NativeProcessAIX::UpdateThreads() {
+ // The NativeProcessAIX monitoring threads are always up to date with
+ // respect to thread state and they keep the thread list populated properly.
+ // All this method needs to do is return the thread count.
+ return m_threads.size();
+}
+
+Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return SetHardwareBreakpoint(addr, size);
+ else
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) {
+ if (hardware)
+ return RemoveHardwareBreakpoint(addr);
+ else
+ return NativeProcessProtocol::RemoveBreakpoint(addr);
+}
+
+llvm::Expected<llvm::ArrayRef<uint8_t>>
+NativeProcessAIX::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
+ // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the
+ // linux kernel does otherwise.
+ static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7};
+ static const uint8_t g_thumb_opcode[] = {0x01, 0xde};
+
+ switch (GetArchitecture().GetMachine()) {
+ case llvm::Triple::arm:
+ switch (size_hint) {
+ case 2:
+ return llvm::ArrayRef(g_thumb_opcode);
+ case 4:
+ return llvm::ArrayRef(g_arm_opcode);
+ default:
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unrecognised trap opcode size hint!");
+ }
+ default:
+ return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
+ }
+}
+
+Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) {
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ size_t remainder;
+ long data;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ for (bytes_read = 0; bytes_read < size; bytes_read += remainder) {
+ Status error = NativeProcessAIX::PtraceWrapper(
+ PT_READ_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, sizeof(data), &data);
+ if (error.Fail())
+ return error;
+
+ remainder = size - bytes_read;
+ remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder;
+
+ // Copy the data into our buffer
+ memcpy(dst, &data, remainder);
+
+ LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data);
+ addr += k_ptrace_word_size;
+ dst += k_ptrace_word_size;
+ }
+ return Status();
+}
+
+Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf,
+ size_t size, size_t &bytes_written) {
+ const unsigned char *src = static_cast<const unsigned char *>(buf);
+ size_t remainder;
+ Status error;
+
+ Log *log = GetLog(POSIXLog::Memory);
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ error = NativeProcessAIX::PtraceWrapper(
+ PT_WRITE_BLOCK, GetCurrentThreadID(), (void *)addr, nullptr, (int)size, (long *)buf);
+ if (error.Fail())
+ return error;
+
+ bytes_written = size;
+ return error;
+}
+
+int8_t NativeProcessAIX::GetSignalInfo(WaitStatus wstatus) const {
+ return wstatus.status;
+}
+
+Status NativeProcessAIX::GetEventMessage(lldb::tid_t tid,
+ unsigned long *message) {
+ //FIXME
+ return PtraceWrapper(PT_CLEAR/*PTRACE_GETEVENTMSG*/, tid, nullptr, message);
+}
+
+Status NativeProcessAIX::Detach(lldb::tid_t tid) {
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return Status();
+
+ return PtraceWrapper(PT_DETACH, tid);
+}
+
+bool NativeProcessAIX::HasThreadNoLock(lldb::tid_t thread_id) {
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ if (thread->GetID() == thread_id) {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+void NativeProcessAIX::StopTrackingThread(NativeThreadAIX &thread) {
+ Log *const log = GetLog(POSIXLog::Thread);
+ lldb::tid_t thread_id = thread.GetID();
+ LLDB_LOG(log, "tid: {0}", thread_id);
+
+ auto it = llvm::find_if(m_threads, [&](const auto &thread_up) {
+ return thread_up.get() == &thread;
+ });
+ assert(it != m_threads.end());
+ m_threads.erase(it);
+
+ NotifyTracersOfThreadDestroyed(thread_id);
+ SignalIfAllThreadsStopped();
+}
+
+void NativeProcessAIX::NotifyTracersProcessDidStop() {
+}
+
+void NativeProcessAIX::NotifyTracersProcessWillResume() {
+}
+
+Status NativeProcessAIX::NotifyTracersOfNewThread(lldb::tid_t tid) {
+ Log *log = GetLog(POSIXLog::Thread);
+ Status error;
+ return error;
+}
+
+Status NativeProcessAIX::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) {
+ Log *log = GetLog(POSIXLog::Thread);
+ Status error;
+ return error;
+}
+
+NativeThreadAIX &NativeProcessAIX::AddThread(lldb::tid_t thread_id,
+ bool resume) {
+ Log *log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(!HasThreadNoLock(thread_id) &&
+ "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty())
+ SetCurrentThreadID(thread_id);
+
+ m_threads.push_back(std::make_unique<NativeThreadAIX>(*this, thread_id));
+ NativeThreadAIX &thread =
+ static_cast<NativeThreadAIX &>(*m_threads.back());
+
+ Status tracing_error = NotifyTracersOfNewThread(thread.GetID());
+ if (tracing_error.Fail()) {
+ thread.SetStoppedByProcessorTrace(tracing_error.AsCString());
+ StopRunningThreads(thread.GetID());
+ } else if (resume)
+ ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
+ else
+ thread.SetStoppedBySignal(SIGSTOP);
+
+ return thread;
+}
+
+Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec module_file_spec(module_path);
+ FileSystem::Instance().Resolve(module_file_spec);
+
+ file_spec.Clear();
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second.GetFilename() == module_file_spec.GetFilename()) {
+ file_spec = it.second;
+ return Status();
+ }
+ }
+ return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
+ module_file_spec.GetFilename().AsCString(), GetID());
+}
+
+Status NativeProcessAIX::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ load_addr = LLDB_INVALID_ADDRESS;
+
+ NativeThreadAIX &thread = *GetCurrentThread();
+ NativeRegisterContextAIX ®_ctx = thread.GetRegisterContext();
+
+ // FIXME: buffer size
+ struct ld_xinfo info[64];
+ if (ptrace64(PT_LDXINFO, reg_ctx.GetThread().GetID(), (long long)&(info[0]), sizeof(info), nullptr) == 0) {
+ load_addr = (unsigned long)info[0].ldinfo_textorg;
+ return Status();
+ }
+ return Status("No load address found for specified file.");
+}
+
+NativeThreadAIX *NativeProcessAIX::GetThreadByID(lldb::tid_t tid) {
+ return static_cast<NativeThreadAIX *>(
+ NativeProcessProtocol::GetThreadByID(tid));
+}
+
+NativeThreadAIX *NativeProcessAIX::GetCurrentThread() {
+ return static_cast<NativeThreadAIX *>(
+ NativeProcessProtocol::GetCurrentThread());
+}
+
+Status NativeProcessAIX::ResumeThread(NativeThreadAIX &thread,
+ lldb::StateType state, int signo) {
+ Log *const log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "tid: {0}", thread.GetID());
+
+ // Before we do the resume below, first check if we have a pending stop
+ // notification that is currently waiting for all threads to stop. This is
+ // potentially a buggy situation since we're ostensibly waiting for threads
+ // to stop before we send out the pending notification, and here we are
+ // resuming one before we send out the pending stop notification.
+ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) {
+ LLDB_LOG(log,
+ "about to resume tid {0} per explicit request but we have a "
+ "pending stop notification (tid {1}) that is actively "
+ "waiting for this thread to stop. Valid sequence of events?",
+ thread.GetID(), m_pending_notification_tid);
+ }
+
+ // Request a resume. We expect this to be synchronous and the system to
+ // reflect it is running after this completes.
+ switch (state) {
+ case eStateRunning: {
+ const auto resume_result = thread.Resume(signo);
+ if (resume_result.Success())
+ SetState(eStateRunning, true);
+ return resume_result;
+ }
+ case eStateStepping: {
+ const auto step_result = thread.SingleStep(signo);
+ if (step_result.Success())
+ SetState(eStateRunning, true);
+ return step_result;
+ }
+ default:
+ LLDB_LOG(log, "Unhandled state {0}.", state);
+ llvm_unreachable("Unhandled state for resume");
+ }
+}
+
+//===----------------------------------------------------------------------===//
+
+void NativeProcessAIX::StopRunningThreads(const lldb::tid_t triggering_tid) {
+ Log *const log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "about to process event: (triggering_tid: {0})",
+ triggering_tid);
+
+ m_pending_notification_tid = triggering_tid;
+
+ // Request a stop for all the thread stops that need to be stopped and are
+ // not already known to be stopped.
+ for (const auto &thread : m_threads) {
+ if (StateIsRunningState(thread->GetState()))
+ static_cast<NativeThreadAIX *>(thread.get())->RequestStop();
+ }
+
+ SignalIfAllThreadsStopped();
+ LLDB_LOG(log, "event processing done");
+}
+
+void NativeProcessAIX::SignalIfAllThreadsStopped() {
+ if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID)
+ return; // No pending notification. Nothing to do.
+
+ for (const auto &thread_sp : m_threads) {
+ if (StateIsRunningState(thread_sp->GetState()))
+ return; // Some threads are still running. Don't signal yet.
+ }
+
+ // We have a pending notification and all threads have stopped.
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
+
+ // Clear any temporary breakpoints we used to implement software single
+ // stepping.
+ for (const auto &thread_info : m_threads_stepping_with_breakpoint) {
+ Status error = RemoveBreakpoint(thread_info.second);
+ if (error.Fail())
+ LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
+ thread_info.first, error);
+ }
+ m_threads_stepping_with_breakpoint.clear();
+
+ // Notify the delegate about the stop
+ SetCurrentThreadID(m_pending_notification_tid);
+ SetState(StateType::eStateStopped, true);
+ m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void NativeProcessAIX::ThreadWasCreated(NativeThreadAIX &thread) {
+ Log *const log = GetLog(POSIXLog::Thread);
+ LLDB_LOG(log, "tid: {0}", thread.GetID());
+
+ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID &&
+ StateIsRunningState(thread.GetState())) {
+ // We will need to wait for this new thread to stop as well before firing
+ // the notification.
+ thread.RequestStop();
+ }
+}
+
+#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"
+#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+
+static void GetRegister(lldb::pid_t pid, long long addr, void *buf) {
+ uint64_t val = 0;
+ ptrace64(PT_READ_GPR, pid, addr, 0, (int *)&val);
+ *(uint64_t *)buf = llvm::byteswap<uint64_t>(val);
+}
+
+static void SetRegister(lldb::pid_t pid, long long addr, void *buf) {
+ uint64_t val = llvm::byteswap<uint64_t>(*(uint64_t *)buf);
+ ptrace64(PT_WRITE_GPR, pid, addr, 0, (int *)&val);
+}
+
+static void GetFPRegister(lldb::pid_t pid, long long addr, void *buf) {
+ uint64_t val = 0;
+ ptrace64(PT_READ_FPR, pid, addr, 0, (int *)&val);
+ *(uint64_t *)buf = llvm::byteswap<uint64_t>(val);
+}
+
+static void GetVMRegister(lldb::tid_t tid, long long addr, void *buf) {
+ uint64_t val = 0;
+ ptrace64(PTT_READ_VEC, tid, addr, 0, (int *)&val);
+ //*(uint64_t *)buf = llvm::byteswap<uint64_t>(val);
+}
+
+static void GetVSRegister(lldb::tid_t tid, long long addr, void *buf) {
+ uint64_t val = 0;
+ ptrace64(PTT_READ_VSX, tid, addr, 0, (int *)&val);
+ //*(uint64_t *)buf = llvm::byteswap<uint64_t>(val);
+}
+
+// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets
+// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*)
+Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ void *data, size_t data_size,
+ long *result) {
+ Status error;
+ long int ret;
+
+ Log *log = GetLog(POSIXLog::Ptrace);
+
+ PtraceDisplayBytes(req, data, data_size);
+
+ errno = 0;
+
+ // for PTT_*
+ const char procdir[] = "/proc/";
+ const char lwpdir[] = "/lwp/";
+ std::string process_task_dir = procdir + std::to_string(pid) + lwpdir;
+ DIR *dirproc = opendir(process_task_dir.c_str());
+
+ lldb::tid_t tid = 0;
+ if (dirproc) {
+ struct dirent *direntry = nullptr;
+ while ((direntry = readdir(dirproc)) != nullptr) {
+ if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) {
+ continue;
+ }
+ tid = atoi(direntry->d_name);
+ break;
+ }
+ closedir(dirproc);
+ }
+
+ if (req == PTRACE_GETREGS) {
+ GetRegister(pid, GPR0, &(((GPR *)data)->r0));
+ GetRegister(pid, GPR1, &(((GPR *)data)->r1));
+ GetRegister(pid, GPR2, &(((GPR *)data)->r2));
+ GetRegister(pid, GPR3, &(((GPR *)data)->r3));
+ GetRegister(pid, GPR4, &(((GPR *)data)->r4));
+ GetRegister(pid, GPR5, &(((GPR *)data)->r5));
+ GetRegister(pid, GPR6, &(((GPR *)data)->r6));
+ GetRegister(pid, GPR7, &(((GPR *)data)->r7));
+ GetRegister(pid, GPR8, &(((GPR *)data)->r8));
+ GetRegister(pid, GPR9, &(((GPR *)data)->r9));
+ GetRegister(pid, GPR10, &(((GPR *)data)->r10));
+ GetRegister(pid, GPR11, &(((GPR *)data)->r11));
+ GetRegister(pid, GPR12, &(((GPR *)data)->r12));
+ GetRegister(pid, GPR13, &(((GPR *)data)->r13));
+ GetRegister(pid, GPR14, &(((GPR *)data)->r14));
+ GetRegister(pid, GPR15, &(((GPR *)data)->r15));
+ GetRegister(pid, GPR16, &(((GPR *)data)->r16));
+ GetRegister(pid, GPR17, &(((GPR *)data)->r17));
+ GetRegister(pid, GPR18, &(((GPR *)data)->r18));
+ GetRegister(pid, GPR19, &(((GPR *)data)->r19));
+ GetRegister(pid, GPR20, &(((GPR *)data)->r20));
+ GetRegister(pid, GPR21, &(((GPR *)data)->r21));
+ GetRegister(pid, GPR22, &(((GPR *)data)->r22));
+ GetRegister(pid, GPR23, &(((GPR *)data)->r23));
+ GetRegister(pid, GPR24, &(((GPR *)data)->r24));
+ GetRegister(pid, GPR25, &(((GPR *)data)->r25));
+ GetRegister(pid, GPR26, &(((GPR *)data)->r26));
+ GetRegister(pid, GPR27, &(((GPR *)data)->r27));
+ GetRegister(pid, GPR28, &(((GPR *)data)->r28));
+ GetRegister(pid, GPR29, &(((GPR *)data)->r29));
+ GetRegister(pid, GPR30, &(((GPR *)data)->r30));
+ GetRegister(pid, GPR31, &(((GPR *)data)->r31));
+ GetRegister(pid, IAR, &(((GPR *)data)->pc));
+ GetRegister(pid, MSR, &(((GPR *)data)->msr));
+ //FIXME: origr3/softe/trap on AIX?
+ GetRegister(pid, CTR, &(((GPR *)data)->ctr));
+ GetRegister(pid, LR, &(((GPR *)data)->lr));
+ GetRegister(pid, XER, &(((GPR *)data)->xer));
+ GetRegister(pid, CR, &(((GPR *)data)->cr));
+ } else if (req == PTRACE_SETREGS) {
+ SetRegister(pid, GPR0, &(((GPR *)data)->r0));
+ SetRegister(pid, GPR1, &(((GPR *)data)->r1));
+ SetRegister(pid, GPR2, &(((GPR *)data)->r2));
+ SetRegister(pid, GPR3, &(((GPR *)data)->r3));
+ SetRegister(pid, GPR4, &(((GPR *)data)->r4));
+ SetRegister(pid, GPR5, &(((GPR *)data)->r5));
+ SetRegister(pid, GPR6, &(((GPR *)data)->r6));
+ SetRegister(pid, GPR7, &(((GPR *)data)->r7));
+ SetRegister(pid, GPR8, &(((GPR *)data)->r8));
+ SetRegister(pid, GPR9, &(((GPR *)data)->r9));
+ SetRegister(pid, GPR10, &(((GPR *)data)->r10));
+ SetRegister(pid, GPR11, &(((GPR *)data)->r11));
+ SetRegister(pid, GPR12, &(((GPR *)data)->r12));
+ SetRegister(pid, GPR13, &(((GPR *)data)->r13));
+ SetRegister(pid, GPR14, &(((GPR *)data)->r14));
+ SetRegister(pid, GPR15, &(((GPR *)data)->r15));
+ SetRegister(pid, GPR16, &(((GPR *)data)->r16));
+ SetRegister(pid, GPR17, &(((GPR *)data)->r17));
+ SetRegister(pid, GPR18, &(((GPR *)data)->r18));
+ SetRegister(pid, GPR19, &(((GPR *)data)->r19));
+ SetRegister(pid, GPR20, &(((GPR *)data)->r20));
+ SetRegister(pid, GPR21, &(((GPR *)data)->r21));
+ SetRegister(pid, GPR22, &(((GPR *)data)->r22));
+ SetRegister(pid, GPR23, &(((GPR *)data)->r23));
+ SetRegister(pid, GPR24, &(((GPR *)data)->r24));
+ SetRegister(pid, GPR25, &(((GPR *)data)->r25));
+ SetRegister(pid, GPR26, &(((GPR *)data)->r26));
+ SetRegister(pid, GPR27, &(((GPR *)data)->r27));
+ SetRegister(pid, GPR28, &(((GPR *)data)->r28));
+ SetRegister(pid, GPR29, &(((GPR *)data)->r29));
+ SetRegister(pid, GPR30, &(((GPR *)data)->r30));
+ SetRegister(pid, GPR31, &(((GPR *)data)->r31));
+ SetRegister(pid, IAR, &(((GPR *)data)->pc));
+ SetRegister(pid, MSR, &(((GPR *)data)->msr));
+ //FIXME: origr3/softe/trap on AIX?
+ SetRegister(pid, CTR, &(((GPR *)data)->ctr));
+ SetRegister(pid, LR, &(((GPR *)data)->lr));
+ SetRegister(pid, XER, &(((GPR *)data)->xer));
+ SetRegister(pid, CR, &(((GPR *)data)->cr));
+ } else if (req == PTRACE_GETFPREGS) {
+ GetFPRegister(pid, FPR0, &(((FPR *)data)->f0));
+ GetFPRegister(pid, FPR1, &(((FPR *)data)->f1));
+ GetFPRegister(pid, FPR2, &(((FPR *)data)->f2));
+ GetFPRegister(pid, FPR3, &(((FPR *)data)->f3));
+ GetFPRegister(pid, FPR4, &(((FPR *)data)->f4));
+ GetFPRegister(pid, FPR5, &(((FPR *)data)->f5));
+ GetFPRegister(pid, FPR6, &(((FPR *)data)->f6));
+ GetFPRegister(pid, FPR7, &(((FPR *)data)->f7));
+ GetFPRegister(pid, FPR8, &(((FPR *)data)->f8));
+ GetFPRegister(pid, FPR9, &(((FPR *)data)->f9));
+ GetFPRegister(pid, FPR10, &(((FPR *)data)->f10));
+ GetFPRegister(pid, FPR11, &(((FPR *)data)->f11));
+ GetFPRegister(pid, FPR12, &(((FPR *)data)->f12));
+ GetFPRegister(pid, FPR13, &(((FPR *)data)->f13));
+ GetFPRegister(pid, FPR14, &(((FPR *)data)->f14));
+ GetFPRegister(pid, FPR15, &(((FPR *)data)->f15));
+ GetFPRegister(pid, FPR16, &(((FPR *)data)->f16));
+ GetFPRegister(pid, FPR17, &(((FPR *)data)->f17));
+ GetFPRegister(pid, FPR18, &(((FPR *)data)->f18));
+ GetFPRegister(pid, FPR19, &(((FPR *)data)->f19));
+ GetFPRegister(pid, FPR20, &(((FPR *)data)->f20));
+ GetFPRegister(pid, FPR21, &(((FPR *)data)->f21));
+ GetFPRegister(pid, FPR22, &(((FPR *)data)->f22));
+ GetFPRegister(pid, FPR23, &(((FPR *)data)->f23));
+ GetFPRegister(pid, FPR24, &(((FPR *)data)->f24));
+ GetFPRegister(pid, FPR25, &(((FPR *)data)->f25));
+ GetFPRegister(pid, FPR26, &(((FPR *)data)->f26));
+ GetFPRegister(pid, FPR27, &(((FPR *)data)->f27));
+ GetFPRegister(pid, FPR28, &(((FPR *)data)->f28));
+ GetFPRegister(pid, FPR29, &(((FPR *)data)->f29));
+ GetFPRegister(pid, FPR30, &(((FPR *)data)->f30));
+ GetFPRegister(pid, FPR31, &(((FPR *)data)->f31));
+ GetFPRegister(pid, FPSCR, &(((FPR *)data)->fpscr));
+ } else if (req == PTRACE_GETVRREGS && tid) {
+ GetVMRegister(tid, VR0, &(((VMX *)data)->vr0[0]));
+ GetVMRegister(tid, VR1, &(((VMX *)data)->vr1[0]));
+ GetVMRegister(tid, VR2, &(((VMX *)data)->vr2[0]));
+ GetVMRegister(tid, VR3, &(((VMX *)data)->vr3[0]));
+ GetVMRegister(tid, VR4, &(((VMX *)data)->vr4[0]));
+ GetVMRegister(tid, VR5, &(((VMX *)data)->vr5[0]));
+ GetVMRegister(tid, VR6, &(((VMX *)data)->vr6[0]));
+ GetVMRegister(tid, VR7, &(((VMX *)data)->vr7[0]));
+ GetVMRegister(tid, VR8, &(((VMX *)data)->vr8[0]));
+ GetVMRegister(tid, VR9, &(((VMX *)data)->vr9[0]));
+ GetVMRegister(tid, VR10, &(((VMX *)data)->vr10[0]));
+ GetVMRegister(tid, VR11, &(((VMX *)data)->vr11[0]));
+ GetVMRegister(tid, VR12, &(((VMX *)data)->vr12[0]));
+ GetVMRegister(tid, VR13, &(((VMX *)data)->vr13[0]));
+ GetVMRegister(tid, VR14, &(((VMX *)data)->vr14[0]));
+ GetVMRegister(tid, VR15, &(((VMX *)data)->vr15[0]));
+ GetVMRegister(tid, VR16, &(((VMX *)data)->vr16[0]));
+ GetVMRegister(tid, VR17, &(((VMX *)data)->vr17[0]));
+ GetVMRegister(tid, VR18, &(((VMX *)data)->vr18[0]));
+ GetVMRegister(tid, VR19, &(((VMX *)data)->vr19[0]));
+ GetVMRegister(tid, VR20, &(((VMX *)data)->vr20[0]));
+ GetVMRegister(tid, VR21, &(((VMX *)data)->vr21[0]));
+ GetVMRegister(tid, VR22, &(((VMX *)data)->vr22[0]));
+ GetVMRegister(tid, VR23, &(((VMX *)data)->vr23[0]));
+ GetVMRegister(tid, VR24, &(((VMX *)data)->vr24[0]));
+ GetVMRegister(tid, VR25, &(((VMX *)data)->vr25[0]));
+ GetVMRegister(tid, VR26, &(((VMX *)data)->vr26[0]));
+ GetVMRegister(tid, VR27, &(((VMX *)data)->vr27[0]));
+ GetVMRegister(tid, VR28, &(((VMX *)data)->vr28[0]));
+ GetVMRegister(tid, VR29, &(((VMX *)data)->vr29[0]));
+ GetVMRegister(tid, VR30, &(((VMX *)data)->vr30[0]));
+ GetVMRegister(tid, VR31, &(((VMX *)data)->vr31[0]));
+ GetVMRegister(tid, VSCR, &(((VMX *)data)->vscr[0]));
+ GetVMRegister(tid, VRSAVE, &(((VMX *)data)->vrsave));
+ } else if (req == PTRACE_GETVSRREGS && tid) {
+ GetVSRegister(tid, VSR0, &(((VSX *)data)->vs0[0]));
+ GetVSRegister(tid, VSR1, &(((VSX *)data)->vs1[0]));
+ GetVSRegister(tid, VSR2, &(((VSX *)data)->vs2[0]));
+ GetVSRegister(tid, VSR3, &(((VSX *)data)->vs3[0]));
+ GetVSRegister(tid, VSR4, &(((VSX *)data)->vs4[0]));
+ GetVSRegister(tid, VSR5, &(((VSX *)data)->vs5[0]));
+ GetVSRegister(tid, VSR6, &(((VSX *)data)->vs6[0]));
+ GetVSRegister(tid, VSR7, &(((VSX *)data)->vs7[0]));
+ GetVSRegister(tid, VSR8, &(((VSX *)data)->vs8[0]));
+ GetVSRegister(tid, VSR9, &(((VSX *)data)->vs9[0]));
+ GetVSRegister(tid, VSR10, &(((VSX *)data)->vs10[0]));
+ GetVSRegister(tid, VSR11, &(((VSX *)data)->vs11[0]));
+ GetVSRegister(tid, VSR12, &(((VSX *)data)->vs12[0]));
+ GetVSRegister(tid, VSR13, &(((VSX *)data)->vs13[0]));
+ GetVSRegister(tid, VSR14, &(((VSX *)data)->vs14[0]));
+ GetVSRegister(tid, VSR15, &(((VSX *)data)->vs15[0]));
+ GetVSRegister(tid, VSR16, &(((VSX *)data)->vs16[0]));
+ GetVSRegister(tid, VSR17, &(((VSX *)data)->vs17[0]));
+ GetVSRegister(tid, VSR18, &(((VSX *)data)->vs18[0]));
+ GetVSRegister(tid, VSR19, &(((VSX *)data)->vs19[0]));
+ GetVSRegister(tid, VSR20, &(((VSX *)data)->vs20[0]));
+ GetVSRegister(tid, VSR21, &(((VSX *)data)->vs21[0]));
+ GetVSRegister(tid, VSR22, &(((VSX *)data)->vs22[0]));
+ GetVSRegister(tid, VSR23, &(((VSX *)data)->vs23[0]));
+ GetVSRegister(tid, VSR24, &(((VSX *)data)->vs24[0]));
+ GetVSRegister(tid, VSR25, &(((VSX *)data)->vs25[0]));
+ GetVSRegister(tid, VSR26, &(((VSX *)data)->vs26[0]));
+ GetVSRegister(tid, VSR27, &(((VSX *)data)->vs27[0]));
+ GetVSRegister(tid, VSR28, &(((VSX *)data)->vs28[0]));
+ GetVSRegister(tid, VSR29, &(((VSX *)data)->vs29[0]));
+ GetVSRegister(tid, VSR30, &(((VSX *)data)->vs30[0]));
+ GetVSRegister(tid, VSR31, &(((VSX *)data)->vs31[0]));
+ GetVSRegister(tid, VSR32, &(((VSX *)data)->vs32[0]));
+ GetVSRegister(tid, VSR33, &(((VSX *)data)->vs33[0]));
+ GetVSRegister(tid, VSR34, &(((VSX *)data)->vs34[0]));
+ GetVSRegister(tid, VSR35, &(((VSX *)data)->vs35[0]));
+ GetVSRegister(tid, VSR36, &(((VSX *)data)->vs36[0]));
+ GetVSRegister(tid, VSR37, &(((VSX *)data)->vs37[0]));
+ GetVSRegister(tid, VSR38, &(((VSX *)data)->vs38[0]));
+ GetVSRegister(tid, VSR39, &(((VSX *)data)->vs39[0]));
+ GetVSRegister(tid, VSR40, &(((VSX *)data)->vs40[0]));
+ GetVSRegister(tid, VSR41, &(((VSX *)data)->vs41[0]));
+ GetVSRegister(tid, VSR42, &(((VSX *)data)->vs42[0]));
+ GetVSRegister(tid, VSR43, &(((VSX *)data)->vs43[0]));
+ GetVSRegister(tid, VSR44, &(((VSX *)data)->vs44[0]));
+ GetVSRegister(tid, VSR45, &(((VSX *)data)->vs45[0]));
+ GetVSRegister(tid, VSR46, &(((VSX *)data)->vs46[0]));
+ GetVSRegister(tid, VSR47, &(((VSX *)data)->vs47[0]));
+ GetVSRegister(tid, VSR48, &(((VSX *)data)->vs48[0]));
+ GetVSRegister(tid, VSR49, &(((VSX *)data)->vs49[0]));
+ GetVSRegister(tid, VSR50, &(((VSX *)data)->vs50[0]));
+ GetVSRegister(tid, VSR51, &(((VSX *)data)->vs51[0]));
+ GetVSRegister(tid, VSR52, &(((VSX *)data)->vs52[0]));
+ GetVSRegister(tid, VSR53, &(((VSX *)data)->vs53[0]));
+ GetVSRegister(tid, VSR54, &(((VSX *)data)->vs54[0]));
+ GetVSRegister(tid, VSR55, &(((VSX *)data)->vs55[0]));
+ GetVSRegister(tid, VSR56, &(((VSX *)data)->vs56[0]));
+ GetVSRegister(tid, VSR57, &(((VSX *)data)->vs57[0]));
+ GetVSRegister(tid, VSR58, &(((VSX *)data)->vs58[0]));
+ GetVSRegister(tid, VSR59, &(((VSX *)data)->vs59[0]));
+ GetVSRegister(tid, VSR60, &(((VSX *)data)->vs60[0]));
+ GetVSRegister(tid, VSR61, &(((VSX *)data)->vs61[0]));
+ GetVSRegister(tid, VSR62, &(((VSX *)data)->vs62[0]));
+ GetVSRegister(tid, VSR63, &(((VSX *)data)->vs63[0]));
+ } else if (req < PT_COMMAND_MAX) {
+ if (req == PT_CONTINUE) {
+#if 0
+ // Use PTT_CONTINUE
+ const char procdir[] = "/proc/";
+ const char lwpdir[] = "/lwp/";
+ std::string process_task_dir = procdir + std::to_string(pid) + lwpdir;
+ DIR *dirproc = opendir(process_task_dir.c_str());
+
+ struct ptthreads64 pts;
+ int idx = 0;
+ lldb::tid_t tid = 0;
+ if (dirproc) {
+ struct dirent *direntry = nullptr;
+ while ((direntry = readdir(dirproc)) != nullptr) {
+ if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) {
+ continue;
+ }
+ tid = atoi(direntry->d_name);
+ pts.th[idx++] = tid;
+ }
+ closedir(dirproc);
+ }
+ pts.th[idx] = 0;
+ ret = ptrace64(PTT_CONTINUE, tid, (long long)1, (int)(size_t)data, (int *)&pts);
+#else
+ int buf;
+ ptrace64(req, pid, 1, (int)(size_t)data, &buf);
+#endif
+ } else if (req == PT_READ_BLOCK) {
+ ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result);
+ } else if (req == PT_WRITE_BLOCK) {
+ ptrace64(req, pid, (long long)addr, (int)data_size, (int *)result);
+ } else if (req == PT_ATTACH) {
+ ptrace64(req, pid, 0, 0, nullptr);
+ } else if (req == PT_WATCH) {
+ ptrace64(req, pid, (long long)addr, (int)data_size, nullptr);
+ } else if (req == PT_DETACH) {
+ ptrace64(req, pid, 0, 0, nullptr);
+ } else {
+ assert(0 && "Not supported yet.");
+ }
+ } else {
+ assert(0 && "Not supported yet.");
+ }
+
+ if (errno) {
+ error.SetErrorToErrno();
+ ret = -1;
+ }
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data,
+ data_size, ret);
+
+ PtraceDisplayBytes(req, data, data_size);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+llvm::Expected<TraceSupportedResponse> NativeProcessAIX::TraceSupported() {
+ return NativeProcessProtocol::TraceSupported();
+}
+
+Error NativeProcessAIX::TraceStart(StringRef json_request, StringRef type) {
+ return NativeProcessProtocol::TraceStart(json_request, type);
+}
+
+Error NativeProcessAIX::TraceStop(const TraceStopRequest &request) {
+ return NativeProcessProtocol::TraceStop(request);
+}
+
+Expected<json::Value> NativeProcessAIX::TraceGetState(StringRef type) {
+ return NativeProcessProtocol::TraceGetState(type);
+}
+
+Expected<std::vector<uint8_t>> NativeProcessAIX::TraceGetBinaryData(
+ const TraceGetBinaryDataRequest &request) {
+ return NativeProcessProtocol::TraceGetBinaryData(request);
+}
diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
new file mode 100644
index 00000000000000..bdb6f7c500885a
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
@@ -0,0 +1,283 @@
+//===-- NativeProcessAIX.h ---------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessAIX_H_
+#define liblldb_NativeProcessAIX_H_
+
+#include <csignal>
+#include <unordered_set>
+
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "lldb/Host/aix/Support.h"
+
+#include "NativeThreadAIX.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
+
+namespace lldb_private {
+class Status;
+class Scalar;
+
+namespace process_aix {
+/// \class NativeProcessAIX
+/// Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process
+/// for debugging.
+///
+/// Changes in the inferior process state are broadcasted.
+class NativeProcessAIX : public NativeProcessProtocol,
+ private NativeProcessSoftwareSingleStep {
+public:
+ class Manager : public NativeProcessProtocol::Manager {
+ public:
+ Manager(MainLoop &mainloop);
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate) override;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
+
+ Extension GetSupportedExtensions() const override;
+
+ void AddProcess(NativeProcessAIX &process) {
+ m_processes.insert(&process);
+ }
+
+ void RemoveProcess(NativeProcessAIX &process) {
+ m_processes.erase(&process);
+ }
+
+ // Collect an event for the given tid, waiting for it if necessary.
+ void CollectThread(::pid_t tid);
+
+ private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+
+ llvm::SmallPtrSet<NativeProcessAIX *, 2> m_processes;
+
+ // Threads (events) which haven't been claimed by any process.
+ llvm::DenseSet<::pid_t> m_unowned_threads;
+
+ void SigchldHandler();
+ };
+
+ // NativeProcessProtocol Interface
+
+ ~NativeProcessAIX() override { m_manager.RemoveProcess(*this); }
+
+ Status Resume(const ResumeActionList &resume_actions) override;
+
+ Status Halt() override;
+
+ Status Detach() override;
+
+ Status Signal(int signo) override;
+
+ Status Interrupt() override;
+
+ Status Kill() override;
+
+ lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ llvm::Expected<lldb::addr_t> AllocateMemory(size_t size,
+ uint32_t permissions) override;
+
+ llvm::Error DeallocateMemory(lldb::addr_t addr) override;
+
+ Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len,
+ std::vector<uint8_t> &tags) override;
+
+ Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len,
+ const std::vector<uint8_t> &tags) override;
+
+ size_t UpdateThreads() override;
+
+ const ArchSpec &GetArchitecture() const override { return m_arch; }
+
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
+
+ Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override;
+
+ void DoStopIDBumped(uint32_t newBumpId) override;
+
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ NativeThreadAIX *GetThreadByID(lldb::tid_t id);
+ NativeThreadAIX *GetCurrentThread();
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override {
+ // Not available on this target.
+ return llvm::errc::not_supported;
+ }
+
+ /// Tracing
+ /// These methods implement the jLLDBTrace packets
+ /// \{
+ llvm::Error TraceStart(llvm::StringRef json_request,
+ llvm::StringRef type) override;
+
+ llvm::Error TraceStop(const TraceStopRequest &request) override;
+
+ llvm::Expected<llvm::json::Value>
+ TraceGetState(llvm::StringRef type) override;
+
+ llvm::Expected<std::vector<uint8_t>>
+ TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override;
+
+ llvm::Expected<TraceSupportedResponse> TraceSupported() override;
+ /// }
+
+ // Interface used by NativeRegisterContext-derived classes.
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ void *data = nullptr, size_t data_size = 0,
+ long *result = nullptr);
+
+ bool SupportHardwareSingleStepping() const;
+
+ /// Writes a siginfo_t structure corresponding to the given thread ID to the
+ /// memory region pointed to by \p siginfo.
+ int8_t GetSignalInfo(WaitStatus wstatus) const;
+
+protected:
+ llvm::Expected<llvm::ArrayRef<uint8_t>>
+ GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
+
+ llvm::Expected<uint64_t> Syscall(llvm::ArrayRef<uint64_t> args);
+
+private:
+ Manager &m_manager;
+ /*MainLoop::SignalHandleUP m_sigchld_handle;*/
+ ArchSpec m_arch;
+ /*MainLoop& m_main_loop;*/
+
+ LazyBool m_supports_mem_region = eLazyBoolCalculate;
+ std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+ lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
+
+ /// Inferior memory (allocated by us) and its size.
+ llvm::DenseMap<lldb::addr_t, lldb::addr_t> m_allocated_memory;
+
+ // Private Instance Methods
+ NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+ const ArchSpec &arch, Manager &manager,
+ llvm::ArrayRef<::pid_t> tids);
+
+ // Returns a list of process threads that we have attached to.
+ static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);
+
+ static Status SetDefaultPtraceOpts(const lldb::pid_t);
+
+ bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status);
+
+ void MonitorCallback(NativeThreadAIX &thread, WaitStatus status);
+
+ void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread);
+
+ void MonitorTrace(NativeThreadAIX &thread);
+
+ void MonitorBreakpoint(NativeThreadAIX &thread);
+
+ void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index);
+
+ void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread);
+
+ bool HasThreadNoLock(lldb::tid_t thread_id);
+
+ void StopTrackingThread(NativeThreadAIX &thread);
+
+ /// Create a new thread.
+ ///
+ /// If process tracing is enabled and the thread can't be traced, then the
+ /// thread is left stopped with a \a eStopReasonProcessorTrace status, and
+ /// then the process is stopped.
+ ///
+ /// \param[in] resume
+ /// If a tracing error didn't happen, then resume the thread after
+ /// creation if \b true, or leave it stopped with SIGSTOP if \b false.
+ NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume);
+
+ /// Start tracing a new thread if process tracing is enabled.
+ ///
+ /// Trace mechanisms should modify this method to provide automatic tracing
+ /// for new threads.
+ Status NotifyTracersOfNewThread(lldb::tid_t tid);
+
+ /// Stop tracing threads upon a destroy event.
+ ///
+ /// Trace mechanisms should modify this method to provide automatic trace
+ /// stopping for threads being destroyed.
+ Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid);
+
+ void NotifyTracersProcessWillResume() override;
+
+ void NotifyTracersProcessDidStop() override;
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread ID to the memory pointed to by @p
+ /// message.
+ Status GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ void NotifyThreadDeath(lldb::tid_t tid);
+
+ Status Detach(lldb::tid_t tid);
+
+ // This method is requests a stop on all threads which are still running. It
+ // sets up a
+ // deferred delegate notification, which will fire once threads report as
+ // stopped. The
+ // triggerring_tid will be set as the current thread (main stop reason).
+ void StopRunningThreads(lldb::tid_t triggering_tid);
+
+ // Notify the delegate if all threads have stopped.
+ void SignalIfAllThreadsStopped();
+
+ // Resume the given thread, optionally passing it the given signal. The type
+ // of resume
+ // operation (continue, single-step) depends on the state parameter.
+ Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state,
+ int signo);
+
+ void ThreadWasCreated(NativeThreadAIX &thread);
+
+ void SigchldHandler();
+
+ Status PopulateMemoryRegionCache();
+
+ // Handle a clone()-like event.
+ bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid,
+ int event);
+};
+
+} // namespace process_aix
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessAIX_H_
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
new file mode 100644
index 00000000000000..0859f9501c1b6a
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
@@ -0,0 +1,157 @@
+//===-- NativeRegisterContextAIX.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextAIX.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include "Plugins/Process/AIX/NativeProcessAIX.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/aix/Ptrace.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_aix;
+
+lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const {
+ return m_thread.GetProcess().GetByteOrder();
+}
+
+Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index,
+ RegisterValue ®_value) {
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return Status("register %" PRIu32 " not found", reg_index);
+
+ return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name,
+ reg_info->byte_size, reg_value);
+}
+
+Status
+NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index,
+ const RegisterValue ®_value) {
+ uint32_t reg_to_write = reg_index;
+ RegisterValue value_to_write = reg_value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (reg_info->invalidate_regs &&
+ (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
+ Status error;
+
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ error = ReadRegister(full_reg_info, full_value);
+ if (error.Fail())
+ return error;
+
+ lldb::ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData(
+ *full_reg_info, dst, sizeof(dst), byte_order, error);
+ if (error.Success() && dest_size) {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = reg_value.GetAsMemoryData(
+ *reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size)) {
+ // Copy the src bytes to the destination.
+ memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(*full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+
+ const RegisterInfo *const register_to_write_info_p =
+ GetRegisterInfoAtIndex(reg_to_write);
+ assert(register_to_write_info_p &&
+ "register to write does not have valid RegisterInfo");
+ if (!register_to_write_info_p)
+ return Status("NativeRegisterContextAIX::%s failed to get RegisterInfo "
+ "for write register index %" PRIu32,
+ __FUNCTION__, reg_to_write);
+
+ return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name,
+ reg_value);
+}
+
+Status NativeRegisterContextAIX::ReadGPR() {
+ return NativeProcessAIX::PtraceWrapper(
+ PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize());
+}
+
+Status NativeRegisterContextAIX::WriteGPR() {
+ return NativeProcessAIX::PtraceWrapper(
+ PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize());
+}
+
+Status NativeRegisterContextAIX::ReadFPR() {
+ return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(),
+ nullptr, GetFPRBuffer(),
+ GetFPRSize());
+}
+
+Status NativeRegisterContextAIX::WriteFPR() {
+ return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(),
+ nullptr, GetFPRBuffer(),
+ GetFPRSize());
+}
+
+Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size,
+ unsigned int regset) {
+ return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
+ static_cast<void *>(®set), buf,
+ buf_size);
+}
+
+Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size,
+ unsigned int regset) {
+ return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
+ static_cast<void *>(®set), buf,
+ buf_size);
+}
+
+Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset,
+ const char *reg_name,
+ uint32_t size,
+ RegisterValue &value) {
+ Log *log = GetLog(POSIXLog::Registers);
+
+ long data;
+ Status error = NativeProcessAIX::PtraceWrapper(
+ PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset),
+ nullptr, 0, &data);
+
+ if (error.Success())
+ // First cast to an unsigned of the same size to avoid sign extension.
+ value.SetUInt(static_cast<unsigned long>(data), size);
+
+ LLDB_LOG(log, "{0}: {1:x}", reg_name, data);
+ return error;
+}
+
+Status NativeRegisterContextAIX::DoWriteRegisterValue(
+ uint32_t offset, const char *reg_name, const RegisterValue &value) {
+ Log *log = GetLog(POSIXLog::Registers);
+
+ void *buf = reinterpret_cast<void *>(value.GetAsUInt64());
+ LLDB_LOG(log, "{0}: {1}", reg_name, buf);
+
+ return NativeProcessAIX::PtraceWrapper(
+ PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
+}
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
new file mode 100644
index 00000000000000..9c2a326856c0b7
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
@@ -0,0 +1,133 @@
+//===-- NativeRegisterContextAIX.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextAIX_h
+#define lldb_NativeRegisterContextAIX_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include "lldb/Target/MemoryTagManager.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private {
+namespace process_aix {
+
+class NativeThreadAIX;
+
+class NativeRegisterContextAIX
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ // This function is implemented in the NativeRegisterContextAIX_* subclasses
+ // to create a new instance of the host specific NativeRegisterContextAIX.
+ // The implementations can't collide as only one NativeRegisterContextAIX_*
+ // variant should be compiled into the final executable.
+ static std::unique_ptr<NativeRegisterContextAIX>
+ CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch,
+ NativeThreadAIX &native_thread);
+
+ // Invalidates cached values in register context data structures
+ virtual void InvalidateAllRegisters(){}
+
+ struct SyscallData {
+ /// The syscall instruction. If the architecture uses software
+ /// single-stepping, the instruction should also be followed by a trap to
+ /// ensure the process is stopped after the syscall.
+ llvm::ArrayRef<uint8_t> Insn;
+
+ /// Registers used for syscall arguments. The first register is used to
+ /// store the syscall number.
+ llvm::ArrayRef<uint32_t> Args;
+
+ uint32_t Result; ///< Register containing the syscall result.
+ };
+ /// Return architecture-specific data needed to make inferior syscalls, if
+ /// they are supported.
+ virtual std::optional<SyscallData> GetSyscallData() { return std::nullopt; }
+
+ struct MmapData {
+ // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the
+ // relevant architecture.
+ unsigned SysMmap; ///< mmap syscall number.
+ unsigned SysMunmap; ///< munmap syscall number
+ };
+ /// Return the architecture-specific data needed to make mmap syscalls, if
+ /// they are supported.
+ virtual std::optional<MmapData> GetMmapData() { return std::nullopt; }
+
+ struct MemoryTaggingDetails {
+ /// Object with tag handling utilities. If the function below returns
+ /// a valid structure, you can assume that this pointer is valid.
+ std::unique_ptr<MemoryTagManager> manager;
+ int ptrace_read_req; /// ptrace operation number for memory tag read
+ int ptrace_write_req; /// ptrace operation number for memory tag write
+ };
+ /// Return architecture specific data needed to use memory tags,
+ /// if they are supported.
+ virtual llvm::Expected<MemoryTaggingDetails>
+ GetMemoryTaggingDetails(int32_t type) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Architecture does not support memory tagging");
+ }
+
+protected:
+ // NB: This constructor is here only because gcc<=6.5 requires a virtual base
+ // class initializer on abstract class (even though it is never used). It can
+ // be deleted once we move to gcc>=7.0.
+ NativeRegisterContextAIX(NativeThreadProtocol &thread)
+ : NativeRegisterContextRegisterInfo(thread, nullptr) {}
+
+ lldb::ByteOrder GetByteOrder() const;
+
+ virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value);
+
+ virtual Status WriteRegisterRaw(uint32_t reg_index,
+ const RegisterValue ®_value);
+
+ virtual Status ReadRegisterSet(void *buf, size_t buf_size,
+ unsigned int regset);
+
+ virtual Status WriteRegisterSet(void *buf, size_t buf_size,
+ unsigned int regset);
+
+ virtual Status ReadGPR();
+
+ virtual Status WriteGPR();
+
+ virtual Status ReadFPR();
+
+ virtual Status WriteFPR();
+
+ virtual void *GetGPRBuffer() = 0;
+
+ virtual size_t GetGPRSize() const {
+ return GetRegisterInfoInterface().GetGPRSize();
+ }
+
+ virtual void *GetFPRBuffer() = 0;
+
+ virtual size_t GetFPRSize() = 0;
+
+ virtual uint32_t GetPtraceOffset(uint32_t reg_index) {
+ return GetRegisterInfoAtIndex(reg_index)->byte_offset;
+ }
+
+ // The Do*** functions are executed on the privileged thread and can perform
+ // ptrace
+ // operations directly.
+ virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
+ uint32_t size, RegisterValue &value);
+
+ virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name,
+ const RegisterValue &value);
+};
+
+} // namespace process_aix
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextAIX_h
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
new file mode 100644
index 00000000000000..19963737917484
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
@@ -0,0 +1,744 @@
+//===-- NativeRegisterContextAIX_ppc64.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This implementation is related to the OpenPOWER ABI for Power Architecture
+// 64-bit ELF V2 ABI
+
+#if defined(__powerpc64__)
+
+#include "NativeRegisterContextAIX_ppc64.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Host/aix/Ptrace.h"
+
+#include "Plugins/Process/AIX/NativeProcessAIX.h"
+#include "Plugins/Process/Linux/Procfs.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
+
+// System includes - They have to be included after framework includes because
+// they define some macros which collide with variable names in other modules
+#include <sys/socket.h>
+#include <sys/reg.h>
+#include <sys/ptrace.h>
+#include <sys/ldr.h>
+
+#define REG_CONTEXT_SIZE \
+ (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le))
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_aix;
+
+static const uint32_t g_gpr_regnums_ppc64le[] = {
+ gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le,
+ gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le,
+ gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le,
+ gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le,
+ gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le,
+ gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le,
+ gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le,
+ gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le,
+ gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le,
+ gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le,
+ gpr_trap_ppc64le,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static const uint32_t g_fpr_regnums_ppc64le[] = {
+ fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le,
+ fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le,
+ fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le,
+ fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le,
+ fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le,
+ fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le,
+ fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le,
+ fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le,
+ fpr_fpscr_ppc64le,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static const uint32_t g_vmx_regnums_ppc64le[] = {
+ vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le,
+ vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le,
+ vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le,
+ vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le,
+ vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le,
+ vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le,
+ vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le,
+ vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le,
+ vmx_vscr_ppc64le, vmx_vrsave_ppc64le,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static const uint32_t g_vsx_regnums_ppc64le[] = {
+ vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le,
+ vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le,
+ vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le,
+ vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le,
+ vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le,
+ vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le,
+ vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le,
+ vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le,
+ vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le,
+ vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le,
+ vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le,
+ vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le,
+ vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le,
+ vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le,
+ vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le,
+ vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+// Number of register sets provided by this context.
+static constexpr int k_num_register_sets = 4;
+
+static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le,
+ g_gpr_regnums_ppc64le},
+ {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le,
+ g_fpr_regnums_ppc64le},
+ {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le,
+ g_vmx_regnums_ppc64le},
+ {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le,
+ g_vsx_regnums_ppc64le},
+};
+
+std::unique_ptr<NativeRegisterContextAIX>
+NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX(
+ const ArchSpec &target_arch, NativeThreadAIX &native_thread) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::ppc64:
+ return std::make_unique<NativeRegisterContextAIX_ppc64>(target_arch,
+ native_thread);
+ default:
+ llvm_unreachable("have no register context for architecture");
+ }
+}
+
+NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)),
+ NativeRegisterContextAIX(native_thread) {
+ if (target_arch.GetMachine() != llvm::Triple::ppc64) {
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
+ ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le));
+ ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le));
+ ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le));
+ ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextAIX_ppc64::GetRegisterSet(uint32_t set_index) const {
+ if (set_index < k_num_register_sets)
+ return &g_reg_sets_ppc64le[set_index];
+
+ return nullptr;
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const {
+ uint32_t count = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+ count += g_reg_sets_ppc64le[set_index].num_registers;
+ return count;
+}
+
+Status NativeRegisterContextAIX_ppc64::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue ®_value) {
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsFPR(reg)) {
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ // Get pointer to m_fpr_ppc64le variable and set the data from it.
+ uint32_t fpr_offset = CalculateFprOffset(reg_info);
+ assert(fpr_offset < sizeof m_fpr_ppc64le);
+ uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
+ reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
+ eByteOrderLittle, error);
+ } else if (IsVSX(reg)) {
+ uint32_t vsx_offset = CalculateVsxOffset(reg_info);
+ assert(vsx_offset < sizeof(m_vsx_ppc64le));
+
+ if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
+ error = ReadVSX();
+ if (error.Fail())
+ return error;
+
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ uint64_t value[2];
+ uint8_t *dst, *src;
+ dst = (uint8_t *)&value;
+ src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
+ ::memcpy(dst, src, 8);
+ dst += 8;
+ src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
+ ::memcpy(dst, src, 8);
+ reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size,
+ eByteOrderLittle, error);
+ } else {
+ error = ReadVMX();
+ if (error.Fail())
+ return error;
+
+ // Get pointer to m_vmx_ppc64le variable and set the data from it.
+ uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
+ uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
+ reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
+ eByteOrderLittle, error);
+ }
+ } else if (IsVMX(reg)) {
+ error = ReadVMX();
+ if (error.Fail())
+ return error;
+
+ // Get pointer to m_vmx_ppc64le variable and set the data from it.
+ uint32_t vmx_offset = CalculateVmxOffset(reg_info);
+ assert(vmx_offset < sizeof m_vmx_ppc64le);
+ uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
+ reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
+ eByteOrderLittle, error);
+ } else if (IsGPR(reg)) {
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
+ reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
+ eByteOrderLittle, error);
+ } else {
+ return Status("failed - register wasn't recognized to be a GPR, FPR, VSX "
+ "or VMX, read strategy unknown");
+ }
+
+ return error;
+}
+
+Status NativeRegisterContextAIX_ppc64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue ®_value) {
+ Status error;
+ if (!reg_info)
+ return Status("reg_info NULL");
+
+ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg_index == LLDB_INVALID_REGNUM)
+ return Status("no lldb regnum for %s", reg_info && reg_info->name
+ ? reg_info->name
+ : "<unknown register>");
+
+ if (IsGPR(reg_index)) {
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset;
+ ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
+ *(uint64_t *)dst = llvm::byteswap<uint64_t>(*(uint64_t *)dst);
+
+ error = WriteGPR();
+ if (error.Fail())
+ return error;
+
+ return Status();
+ }
+
+ if (IsFPR(reg_index)) {
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ // Get pointer to m_fpr_ppc64le variable and set the data to it.
+ uint32_t fpr_offset = CalculateFprOffset(reg_info);
+ assert(fpr_offset < GetFPRSize());
+ uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
+ ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ return Status();
+ }
+
+ if (IsVMX(reg_index)) {
+ error = ReadVMX();
+ if (error.Fail())
+ return error;
+
+ // Get pointer to m_vmx_ppc64le variable and set the data to it.
+ uint32_t vmx_offset = CalculateVmxOffset(reg_info);
+ assert(vmx_offset < sizeof(m_vmx_ppc64le));
+ uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
+ ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
+
+ error = WriteVMX();
+ if (error.Fail())
+ return error;
+
+ return Status();
+ }
+
+ if (IsVSX(reg_index)) {
+ uint32_t vsx_offset = CalculateVsxOffset(reg_info);
+ assert(vsx_offset < sizeof(m_vsx_ppc64le));
+
+ if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
+ error = ReadVSX();
+ if (error.Fail())
+ return error;
+
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ uint64_t value[2];
+ ::memcpy(value, reg_value.GetBytes(), 16);
+ uint8_t *dst, *src;
+ src = (uint8_t *)value;
+ dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
+ ::memcpy(dst, src, 8);
+ src += 8;
+ dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
+ ::memcpy(dst, src, 8);
+
+ WriteVSX();
+ WriteFPR();
+ } else {
+ error = ReadVMX();
+ if (error.Fail())
+ return error;
+
+ // Get pointer to m_vmx_ppc64le variable and set the data from it.
+ uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
+ uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
+ ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
+ WriteVMX();
+ }
+
+ return Status();
+ }
+
+ return Status("failed - register wasn't recognized to be a GPR, FPR, VSX "
+ "or VMX, write strategy unknown");
+}
+
+Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues(
+ lldb::WritableDataBufferSP &data_sp) {
+ Status error;
+
+ data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ error = ReadFPR();
+ if (error.Fail())
+ return error;
+
+ error = ReadVMX();
+ if (error.Fail())
+ return error;
+
+ error = ReadVSX();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
+ dst += GetFPRSize();
+ ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le));
+ dst += sizeof(m_vmx_ppc64le);
+ ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le));
+
+ return error;
+}
+
+Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched "
+ "data size, expected %" PRIu64 ", actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ return error;
+ }
+
+ const uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+
+ ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
+ error = WriteGPR();
+
+ if (error.Fail())
+ return error;
+
+ src += GetGPRSize();
+ ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
+
+ error = WriteFPR();
+ if (error.Fail())
+ return error;
+
+ src += GetFPRSize();
+ ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le));
+
+ error = WriteVMX();
+ if (error.Fail())
+ return error;
+
+ src += sizeof(m_vmx_ppc64le);
+ ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le));
+ error = WriteVSX();
+
+ return error;
+}
+
+bool NativeRegisterContextAIX_ppc64::IsGPR(unsigned reg) const {
+ return reg <= k_last_gpr_ppc64le; // GPR's come first.
+}
+
+bool NativeRegisterContextAIX_ppc64::IsFPR(unsigned reg) const {
+ return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::CalculateFprOffset(
+ const RegisterInfo *reg_info) const {
+ return reg_info->byte_offset -
+ GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset;
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::CalculateVmxOffset(
+ const RegisterInfo *reg_info) const {
+ return reg_info->byte_offset -
+ GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset;
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::CalculateVsxOffset(
+ const RegisterInfo *reg_info) const {
+ return reg_info->byte_offset -
+ GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset;
+}
+
+Status NativeRegisterContextAIX_ppc64::ReadVMX() {
+ return NativeProcessAIX::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
+ nullptr, &m_vmx_ppc64le,
+ sizeof(m_vmx_ppc64le));
+}
+
+Status NativeRegisterContextAIX_ppc64::WriteVMX() {
+ //FIXME
+ int regset = 0/*NT_PPC_VMX*/;
+ return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVRREGS*/, m_thread.GetID(),
+ ®set, &m_vmx_ppc64le,
+ sizeof(m_vmx_ppc64le));
+}
+
+Status NativeRegisterContextAIX_ppc64::ReadVSX() {
+ return NativeProcessAIX::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
+ nullptr, &m_vsx_ppc64le,
+ sizeof(m_vsx_ppc64le));
+}
+
+Status NativeRegisterContextAIX_ppc64::WriteVSX() {
+ //FIXME
+ int regset = 0/*NT_PPC_VSX*/;
+ return NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PTRACE_SETVSRREGS*/, m_thread.GetID(),
+ ®set, &m_vsx_ppc64le,
+ sizeof(m_vsx_ppc64le));
+}
+
+bool NativeRegisterContextAIX_ppc64::IsVMX(unsigned reg) {
+ return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
+}
+
+bool NativeRegisterContextAIX_ppc64::IsVSX(unsigned reg) {
+ return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::NumSupportedHardwareWatchpoints() {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+
+ // Read hardware breakpoint and watchpoint information.
+ Status error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return 0;
+
+ LLDB_LOG(log, "{0}", m_max_hwp_supported);
+ return m_max_hwp_supported;
+}
+
+uint32_t NativeRegisterContextAIX_ppc64::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
+ watch_flags);
+
+ // Read hardware breakpoint and watchpoint information.
+ Status error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return LLDB_INVALID_INDEX32;
+
+ uint32_t control_value = 0, wp_index = 0;
+ lldb::addr_t real_addr = addr;
+ uint32_t rw_mode = 0;
+
+ // Check if we are setting watchpoint other than read/write/access Update
+ // watchpoint flag to match ppc64le write-read bit configuration.
+ switch (watch_flags) {
+ case eWatchpointKindWrite:
+ //FIXME
+ //rw_mode = 0/*PPC_BREAKPOINT_TRIGGER_WRITE*/;
+ watch_flags = 2;
+ break;
+ // Watchpoint read not supported
+ case eWatchpointKindRead:
+ case (eWatchpointKindRead | eWatchpointKindWrite):
+ default:
+ return LLDB_INVALID_INDEX32;
+ }
+
+ // Check if size has a valid hardware watchpoint length.
+ if (size != 8)
+ return LLDB_INVALID_INDEX32;
+
+ // Check 8-byte alignment for hardware watchpoint target address. Below is a
+ // hack to recalculate address and size in order to make sure we can watch
+ // non 8-byte aligned addresses as well.
+ if (addr & 0x07) {
+
+ addr_t begin = llvm::alignDown(addr, 8);
+ addr_t end = llvm::alignTo(addr + size, 8);
+ size = llvm::PowerOf2Ceil(end - begin);
+
+ addr = addr & (~0x07);
+ }
+
+ // Setup control value
+ control_value = watch_flags << 3;
+ control_value |= ((1 << size) - 1) << 5;
+ control_value |= (2 << 1) | 1;
+
+ // Iterate over stored watchpoints and find a free wp_index
+ wp_index = LLDB_INVALID_INDEX32;
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+ if ((m_hwp_regs[i].control & 1) == 0) {
+ wp_index = i; // Mark last free slot
+ } else if (m_hwp_regs[i].address == addr) {
+ return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
+ }
+ }
+
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return LLDB_INVALID_INDEX32;
+
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].real_addr = real_addr;
+ m_hwp_regs[wp_index].address = addr;
+ m_hwp_regs[wp_index].control = control_value;
+ //m_hwp_regs[wp_index].mode = rw_mode;
+
+ // PTRACE call to set corresponding watchpoint register.
+ error = WriteHardwareDebugRegs();
+
+ if (error.Fail()) {
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
+
+ return LLDB_INVALID_INDEX32;
+ }
+
+ return wp_index;
+}
+
+bool NativeRegisterContextAIX_ppc64::ClearHardwareWatchpoint(
+ uint32_t wp_index) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ // Read hardware breakpoint and watchpoint information.
+ Status error = ReadHardwareDebugInfo();
+
+ if (error.Fail())
+ return false;
+
+ if (wp_index >= m_max_hwp_supported)
+ return false;
+
+ // Create a backup we can revert to in case of failure.
+ lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
+ uint32_t tempControl = m_hwp_regs[wp_index].control;
+ long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
+
+ // Update watchpoint in local cache
+ m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
+ m_hwp_regs[wp_index].address = 0;
+ m_hwp_regs[wp_index].slot = 0;
+ m_hwp_regs[wp_index].mode = 0;
+
+ // Ptrace call to update hardware debug registers
+ //FIXME
+ error = NativeProcessAIX::PtraceWrapper(PT_CLEAR/*PPC_PTRACE_DELHWDEBUG*/,
+ m_thread.GetID(), 0, tempSlot);
+
+ if (error.Fail()) {
+ m_hwp_regs[wp_index].control = tempControl;
+ m_hwp_regs[wp_index].address = tempAddr;
+ m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
+
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t
+NativeRegisterContextAIX_ppc64::GetWatchpointSize(uint32_t wp_index) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
+ if (llvm::isPowerOf2_32(control + 1)) {
+ return llvm::popcount(control);
+ }
+
+ return 0;
+}
+
+bool NativeRegisterContextAIX_ppc64::WatchpointIsEnabled(
+ uint32_t wp_index) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
+}
+
+Status NativeRegisterContextAIX_ppc64::GetWatchpointHitIndex(
+ uint32_t &wp_index, lldb::addr_t trap_addr) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
+
+ uint32_t watch_size;
+ lldb::addr_t watch_addr;
+
+ for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
+ watch_size = GetWatchpointSize(wp_index);
+ watch_addr = m_hwp_regs[wp_index].address;
+
+ if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
+ trap_addr <= watch_addr + watch_size) {
+ m_hwp_regs[wp_index].hit_addr = trap_addr;
+ return Status();
+ }
+ }
+
+ wp_index = LLDB_INVALID_INDEX32;
+ return Status();
+}
+
+lldb::addr_t
+NativeRegisterContextAIX_ppc64::GetWatchpointAddress(uint32_t wp_index) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ if (wp_index >= m_max_hwp_supported)
+ return LLDB_INVALID_ADDRESS;
+
+ if (WatchpointIsEnabled(wp_index))
+ return m_hwp_regs[wp_index].real_addr;
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+NativeRegisterContextAIX_ppc64::GetWatchpointHitAddress(uint32_t wp_index) {
+ Log *log = GetLog(POSIXLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ if (wp_index >= m_max_hwp_supported)
+ return LLDB_INVALID_ADDRESS;
+
+ if (WatchpointIsEnabled(wp_index))
+ return m_hwp_regs[wp_index].hit_addr;
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+Status NativeRegisterContextAIX_ppc64::ReadHardwareDebugInfo() {
+ if (!m_refresh_hwdebug_info) {
+ return Status();
+ }
+
+ m_max_hwp_supported = 1;
+ m_max_hbp_supported = 0;
+ m_refresh_hwdebug_info = false;
+
+ return Status();
+}
+
+Status NativeRegisterContextAIX_ppc64::WriteHardwareDebugRegs() {
+ Status error;
+ long ret;
+
+ for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+ if ((m_hwp_regs[i].control & 1) == 0)
+ continue;
+
+ error = NativeProcessAIX::PtraceWrapper(PT_WATCH, m_thread.GetID(), (void *)m_hwp_regs[i].address, nullptr, 8, &ret);
+
+ if (error.Fail())
+ return error;
+
+ m_hwp_regs[i].slot = ret;
+ }
+ return error;
+}
+
+#endif // defined(__powerpc64__)
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
new file mode 100644
index 00000000000000..a29f786f2313a6
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
@@ -0,0 +1,138 @@
+//===-- NativeRegisterContextAIX_ppc64.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This implementation is related to the OpenPOWER ABI for Power Architecture
+// 64-bit ELF V2 ABI
+
+#if defined(__powerpc64__)
+
+#ifndef lldb_NativeRegisterContextAIX_ppc64_h
+#define lldb_NativeRegisterContextAIX_ppc64_h
+
+#include "Plugins/Process/AIX/NativeRegisterContextAIX.h"
+#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
+
+#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"
+#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+
+namespace lldb_private {
+namespace process_aix {
+
+class NativeProcessAIX;
+
+class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX {
+public:
+ NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread);
+
+ uint32_t GetRegisterSetCount() const override;
+
+ uint32_t GetUserRegisterCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue ®_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue ®_value) override;
+
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ // Hardware watchpoint management functions
+
+ uint32_t NumSupportedHardwareWatchpoints() override;
+
+ uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags) override;
+
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
+
+ Status GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr) override;
+
+ lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
+
+ lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
+
+ uint32_t GetWatchpointSize(uint32_t wp_index);
+
+ bool WatchpointIsEnabled(uint32_t wp_index);
+
+protected:
+ bool IsVMX(unsigned reg);
+
+ bool IsVSX(unsigned reg);
+
+ Status ReadVMX();
+
+ Status WriteVMX();
+
+ Status ReadVSX();
+
+ Status WriteVSX();
+
+ void *GetGPRBuffer() override { return &m_gpr_ppc64le; }
+
+ void *GetFPRBuffer() override { return &m_fpr_ppc64le; }
+
+ size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); }
+
+private:
+ GPR m_gpr_ppc64le; // 64-bit general purpose registers.
+ FPR m_fpr_ppc64le; // floating-point registers including extended register.
+ VMX m_vmx_ppc64le; // VMX registers.
+ VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers.
+
+ bool IsGPR(unsigned reg) const;
+
+ bool IsFPR(unsigned reg) const;
+
+ bool IsVMX(unsigned reg) const;
+
+ bool IsVSX(unsigned reg) const;
+
+ uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
+
+ uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const;
+
+ uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const;
+
+ Status ReadHardwareDebugInfo();
+
+ Status WriteHardwareDebugRegs();
+
+ // Debug register info for hardware watchpoints management.
+ struct DREG {
+ lldb::addr_t address; // Breakpoint/watchpoint address value.
+ lldb::addr_t hit_addr; // Address at which last watchpoint trigger
+ // exception occurred.
+ lldb::addr_t real_addr; // Address value that should cause target to stop.
+ uint32_t control; // Breakpoint/watchpoint control value.
+ uint32_t refcount; // Serves as enable/disable and reference counter.
+ long slot; // Saves the value returned from PTRACE_SETHWDEBUG.
+ int mode; // Defines if watchpoint is read/write/access.
+ };
+
+ std::array<DREG, 4> m_hwp_regs;
+
+ // 16 is just a maximum value, query hardware for actual watchpoint count
+ uint32_t m_max_hwp_supported = 16;
+ uint32_t m_max_hbp_supported = 16;
+ bool m_refresh_hwdebug_info = true;
+};
+
+} // namespace process_aix
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h
+
+#endif // defined(__powerpc64__)
diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
new file mode 100644
index 00000000000000..e07daccdff550e
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
@@ -0,0 +1,526 @@
+//===-- NativeThreadAIX.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadAIX.h"
+
+#include <csignal>
+#include <sstream>
+
+#include "NativeProcessAIX.h"
+#include "NativeRegisterContextAIX.h"
+
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/ADT/SmallString.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <signal.h>
+
+#if 0
+#include <sys/syscall.h>
+// Try to define a macro to encapsulate the tgkill syscall
+#define tgkill(pid, tid, sig) \
+ syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \
+ sig)
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_aix;
+
+namespace {
+void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info,
+ const char *const header) {
+ switch (stop_info.reason) {
+ case eStopReasonNone:
+ log.Printf("%s: %s no stop reason", __FUNCTION__, header);
+ return;
+ case eStopReasonTrace:
+ log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header,
+ stop_info.signo);
+ return;
+ case eStopReasonBreakpoint:
+ log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__,
+ header, stop_info.signo);
+ return;
+ case eStopReasonWatchpoint:
+ log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__,
+ header, stop_info.signo);
+ return;
+ case eStopReasonSignal:
+ log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header,
+ stop_info.signo);
+ return;
+ case eStopReasonException:
+ log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header,
+ stop_info.details.exception.type);
+ return;
+ case eStopReasonExec:
+ log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header,
+ stop_info.signo);
+ return;
+ case eStopReasonPlanComplete:
+ log.Printf("%s: %s plan complete", __FUNCTION__, header);
+ return;
+ case eStopReasonThreadExiting:
+ log.Printf("%s: %s thread exiting", __FUNCTION__, header);
+ return;
+ case eStopReasonInstrumentation:
+ log.Printf("%s: %s instrumentation", __FUNCTION__, header);
+ return;
+ case eStopReasonProcessorTrace:
+ log.Printf("%s: %s processor trace", __FUNCTION__, header);
+ return;
+ default:
+ log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header,
+ static_cast<uint32_t>(stop_info.reason));
+ }
+}
+}
+
+NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process,
+ lldb::tid_t tid)
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+ m_stop_info(),
+ m_reg_context_up(
+ NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX(
+ process.GetArchitecture(), *this)),
+ m_stop_description() {}
+
+std::string NativeThreadAIX::GetName() {
+ NativeProcessAIX &process = GetProcess();
+
+ auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm");
+ if (!BufferOrError)
+ return "";
+ return std::string(BufferOrError.get()->getBuffer().rtrim('\n'));
+}
+
+lldb::StateType NativeThreadAIX::GetState() { return m_state; }
+
+bool NativeThreadAIX::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ if (log)
+ LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:");
+ stop_info = m_stop_info;
+ description = m_stop_description;
+ if (log)
+ LogThreadStopInfo(*log, stop_info, "returned stop_info:");
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ if (log) {
+ LLDB_LOGF(log,
+ "NativeThreadAIX::%s tid %" PRIu64
+ " in state %s cannot answer stop reason",
+ __FUNCTION__, GetID(), StateAsCString(m_state));
+ }
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+Status NativeThreadAIX::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ if (!hardware)
+ return Status("not implemented");
+ if (m_state == eStateLaunching)
+ return Status();
+ Status error = RemoveWatchpoint(addr);
+ if (error.Fail())
+ return error;
+ uint32_t wp_index =
+ m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Status();
+}
+
+Status NativeThreadAIX::RemoveWatchpoint(lldb::addr_t addr) {
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Status();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (m_reg_context_up->ClearHardwareWatchpoint(wp_index))
+ return Status();
+ return Status("Clearing hardware watchpoint failed.");
+}
+
+Status NativeThreadAIX::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ if (m_state == eStateLaunching)
+ return Status();
+
+ Status error = RemoveHardwareBreakpoint(addr);
+ if (error.Fail())
+ return error;
+
+ uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size);
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware breakpoint failed.");
+
+ m_hw_break_index_map.insert({addr, bp_index});
+ return Status();
+}
+
+Status NativeThreadAIX::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ auto bp = m_hw_break_index_map.find(addr);
+ if (bp == m_hw_break_index_map.end())
+ return Status();
+
+ uint32_t bp_index = bp->second;
+ if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) {
+ m_hw_break_index_map.erase(bp);
+ return Status();
+ }
+
+ return Status("Clearing hardware breakpoint failed.");
+}
+
+Status NativeThreadAIX::Resume(uint32_t signo) {
+ const StateType new_state = StateType::eStateRunning;
+ MaybeLogStateChange(new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_description.clear();
+
+ // If watchpoints have been set, but none on this thread, then this is a new
+ // thread. So set all existing watchpoints.
+ if (m_watchpoint_index_map.empty()) {
+ NativeProcessAIX &process = GetProcess();
+
+ const auto &watchpoint_map = process.GetWatchpointMap();
+ m_reg_context_up->ClearAllHardwareWatchpoints();
+ for (const auto &pair : watchpoint_map) {
+ const auto &wp = pair.second;
+ SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware);
+ }
+ }
+
+ // Set all active hardware breakpoint on all threads.
+ if (m_hw_break_index_map.empty()) {
+ NativeProcessAIX &process = GetProcess();
+
+ const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap();
+ m_reg_context_up->ClearAllHardwareBreakpoints();
+ for (const auto &pair : hw_breakpoint_map) {
+ const auto &bp = pair.second;
+ SetHardwareBreakpoint(bp.m_addr, bp.m_size);
+ }
+ }
+
+ intptr_t data = 0;
+
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = signo;
+
+ return NativeProcessAIX::PtraceWrapper(PT_CONTINUE, GetID(), nullptr,
+ reinterpret_cast<void *>(data));
+}
+
+Status NativeThreadAIX::SingleStep(uint32_t signo) {
+ const StateType new_state = StateType::eStateStepping;
+ MaybeLogStateChange(new_state);
+ m_state = new_state;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+
+ intptr_t data = 0;
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = signo;
+
+ // If hardware single-stepping is not supported, we just do a continue. The
+ // breakpoint on the next instruction has been setup in
+ // NativeProcessAIX::Resume.
+ return NativeProcessAIX::PtraceWrapper(
+ GetProcess().SupportHardwareSingleStepping() ? PT_STEP : PT_CONTINUE,
+ m_tid, nullptr, reinterpret_cast<void *>(data));
+}
+
+void NativeThreadAIX::SetStoppedBySignal(uint32_t signo,
+ const siginfo_t *info) {
+ Log *log = GetLog(LLDBLog::Thread);
+ LLDB_LOGF(log, "NativeThreadAIX::%s called with signal 0x%02" PRIx32,
+ __FUNCTION__, signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.signo = signo;
+
+ m_stop_description.clear();
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ break;
+ }
+}
+
+void NativeThreadAIX::AnnotateSyncTagCheckFault(const siginfo_t *info) {
+ int32_t allocation_tag_type = 0;
+ switch (GetProcess().GetArchitecture().GetMachine()) {
+ default:
+ return;
+ }
+
+ auto details =
+ GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type);
+ if (!details) {
+ llvm::consumeError(details.takeError());
+ return;
+ }
+
+ // We assume that the stop description is currently:
+ // signal SIGSEGV: sync tag check fault (fault address: <addr>)
+ // Remove the closing )
+ m_stop_description.pop_back();
+
+ std::stringstream ss;
+ lldb::addr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
+ std::unique_ptr<MemoryTagManager> manager(std::move(details->manager));
+
+ ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr);
+
+ std::vector<uint8_t> allocation_tag_data;
+ // The fault address may not be granule aligned. ReadMemoryTags will granule
+ // align any range you give it, potentially making it larger.
+ // To prevent this set len to 1. This always results in a range that is at
+ // most 1 granule in size and includes fault_addr.
+ Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr,
+ 1, allocation_tag_data);
+
+ if (status.Success()) {
+ llvm::Expected<std::vector<lldb::addr_t>> allocation_tag =
+ manager->UnpackTagsData(allocation_tag_data, 1);
+ if (allocation_tag) {
+ ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")";
+ } else {
+ llvm::consumeError(allocation_tag.takeError());
+ ss << ")";
+ }
+ } else
+ ss << ")";
+
+ m_stop_description += ss.str();
+}
+
+bool NativeThreadAIX::IsStopped(int *signo) {
+ if (!StateIsStoppedState(m_state, false))
+ return false;
+
+ // If we are stopped by a signal, return the signo.
+ if (signo && m_state == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonSignal) {
+ *signo = m_stop_info.signo;
+ }
+
+ // Regardless, we are stopped.
+ return true;
+}
+
+void NativeThreadAIX::SetStopped() {
+ // On every stop, clear any cached register data structures
+ GetRegisterContext().InvalidateAllRegisters();
+
+ const StateType new_state = StateType::eStateStopped;
+ MaybeLogStateChange(new_state);
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadAIX::SetStoppedByExec() {
+ Log *log = GetLog(LLDBLog::Thread);
+ LLDB_LOGF(log, "NativeThreadAIX::%s()", __FUNCTION__);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.signo = SIGSTOP;
+}
+
+void NativeThreadAIX::SetStoppedByBreakpoint() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.signo = SIGTRAP;
+ m_stop_description.clear();
+}
+
+void NativeThreadAIX::SetStoppedByWatchpoint(uint32_t wp_index) {
+ SetStopped();
+
+ lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
+
+ std::ostringstream ostr;
+ ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " ";
+ ostr << wp_index;
+
+ /*
+ * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For
+ * example:
+ * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at
+ * 'm', then
+ * watch exception is generated even when 'n' is read/written. To handle this
+ * case,
+ * find the base address of the load/store instruction and append it in the
+ * stop-info
+ * packet.
+ */
+ ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index);
+
+ m_stop_description = ostr.str();
+
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.signo = SIGTRAP;
+}
+
+bool NativeThreadAIX::IsStoppedAtBreakpoint() {
+ return GetState() == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonBreakpoint;
+}
+
+bool NativeThreadAIX::IsStoppedAtWatchpoint() {
+ return GetState() == StateType::eStateStopped &&
+ m_stop_info.reason == StopReason::eStopReasonWatchpoint;
+}
+
+void NativeThreadAIX::SetStoppedByTrace() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.signo = SIGTRAP;
+}
+
+void NativeThreadAIX::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) {
+ SetStopped();
+
+ m_stop_info.reason =
+ is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork;
+ m_stop_info.details.fork.child_pid = child_pid;
+ m_stop_info.details.fork.child_tid = child_pid;
+}
+
+void NativeThreadAIX::SetStoppedByVForkDone() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonVForkDone;
+}
+
+void NativeThreadAIX::SetStoppedWithNoReason() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.signo = 0;
+}
+
+void NativeThreadAIX::SetStoppedByProcessorTrace(
+ llvm::StringRef description) {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonProcessorTrace;
+ m_stop_info.signo = 0;
+ m_stop_description = description.str();
+}
+
+void NativeThreadAIX::SetExited() {
+ const StateType new_state = StateType::eStateExited;
+ MaybeLogStateChange(new_state);
+ m_state = new_state;
+
+ m_stop_info.reason = StopReason::eStopReasonThreadExiting;
+}
+
+Status NativeThreadAIX::RequestStop() {
+ Log *log = GetLog(LLDBLog::Thread);
+
+ NativeProcessAIX &process = GetProcess();
+
+ lldb::pid_t pid = process.GetID();
+ lldb::tid_t tid = GetID();
+
+ LLDB_LOGF(log,
+ "NativeThreadAIX::%s requesting thread stop(pid: %" PRIu64
+ ", tid: %" PRIu64 ")",
+ __FUNCTION__, pid, tid);
+
+ Status err;
+ errno = 0;
+ if (::kill(pid, SIGSTOP) != 0) {
+ err.SetErrorToErrno();
+ LLDB_LOGF(log,
+ "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s",
+ __FUNCTION__, pid, err.AsCString());
+ }
+ return err;
+}
+
+void NativeThreadAIX::MaybeLogStateChange(lldb::StateType new_state) {
+ Log *log = GetLog(LLDBLog::Thread);
+ // If we're not logging, we're done.
+ if (!log)
+ return;
+
+ // If this is a state change to the same state, we're done.
+ lldb::StateType old_state = m_state;
+ if (new_state == old_state)
+ return;
+
+ LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}",
+ m_process.GetID(), GetID(), old_state, new_state);
+}
+
+NativeProcessAIX &NativeThreadAIX::GetProcess() {
+ return static_cast<NativeProcessAIX &>(m_process);
+}
+
+const NativeProcessAIX &NativeThreadAIX::GetProcess() const {
+ return static_cast<const NativeProcessAIX &>(m_process);
+}
+
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+NativeThreadAIX::GetSiginfo() const {
+ auto siginfo_buf =
+ llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeof(siginfo_t));
+#if 0
+ Status error =
+ GetProcess().GetSignalInfo(GetID(), siginfo_buf->getBufferStart());
+ if (!error.Success())
+ return error.ToError();
+#endif
+ return std::move(siginfo_buf);
+}
diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
new file mode 100644
index 00000000000000..706a7ce69da8eb
--- /dev/null
+++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
@@ -0,0 +1,126 @@
+//===-- NativeThreadAIX.h ----------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadAIX_H_
+#define liblldb_NativeThreadAIX_H_
+
+#include "Plugins/Process/AIX/NativeRegisterContextAIX.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include "lldb/lldb-private-forward.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <csignal>
+#include <map>
+#include <memory>
+#include <string>
+
+namespace lldb_private {
+namespace process_aix {
+
+class NativeProcessAIX;
+
+class NativeThreadAIX : public NativeThreadProtocol {
+ friend class NativeProcessAIX;
+
+public:
+ NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid);
+
+ // NativeThreadProtocol Interface
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContextAIX &GetRegisterContext() override {
+ return *m_reg_context_up;
+ }
+
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+ Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+ NativeProcessAIX &GetProcess();
+
+ const NativeProcessAIX &GetProcess() const;
+
+ llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ GetSiginfo() const override;
+
+private:
+ // Interface for friend classes
+
+ /// Resumes the thread. If \p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ Status Resume(uint32_t signo);
+
+ /// Single steps the thread. If \p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ Status SingleStep(uint32_t signo);
+
+ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+
+ /// Return true if the thread is stopped.
+ /// If stopped by a signal, indicate the signo in the signo argument.
+ /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
+ bool IsStopped(int *signo);
+
+ void SetStoppedByExec();
+
+ void SetStoppedByBreakpoint();
+
+ void SetStoppedByWatchpoint(uint32_t wp_index);
+
+ bool IsStoppedAtBreakpoint();
+
+ bool IsStoppedAtWatchpoint();
+
+ void SetStoppedByTrace();
+
+ void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid);
+
+ void SetStoppedByVForkDone();
+
+ void SetStoppedWithNoReason();
+
+ void SetStoppedByProcessorTrace(llvm::StringRef description);
+
+ void SetExited();
+
+ Status RequestStop();
+
+ // Private interface
+ void MaybeLogStateChange(lldb::StateType new_state);
+
+ void SetStopped();
+
+ /// Extend m_stop_description with logical and allocation tag values.
+ /// If there is an error along the way just add the information we were able
+ /// to get.
+ void AnnotateSyncTagCheckFault(const siginfo_t *info);
+
+ // Member Variables
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ std::unique_ptr<NativeRegisterContextAIX> m_reg_context_up;
+ std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
+ WatchpointIndexMap m_hw_break_index_map;
+};
+} // namespace process_aix
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadAIX_H_
diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt
index a51d0f7afd1759..01bb5f462eba44 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
add_subdirectory(NetBSD)
add_subdirectory(POSIX)
+elseif (CMAKE_SYSTEM_NAME MATCHES "AIX")
+ add_subdirectory(AIX)
+ add_subdirectory(POSIX)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_subdirectory(Windows/Common)
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 32c71d87c7f58c..db271357d792ae 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
function_options.include_inlines = false;
SymbolContextList sc_list;
+#if !defined(__AIX__)
process->GetTarget().GetImages().FindFunctions(
ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list);
+#else
+ process->GetTarget().GetImages().FindFunctions(
+ ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list);
+ SymbolContextList toc_list;
+ process->GetTarget().GetImages().FindSymbolsWithNameAndType(
+ ConstString("TOC"), lldb::eSymbolTypeAny, toc_list);
+
+ AddressRange toc_range;
+ if (sc_list.GetSize() > 0) {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc)) {
+ for (int i = 0; i < toc_list.GetSize(); ++i) {
+ SymbolContext tocSC;
+ if (toc_list.GetContextAtIndex(i, tocSC)) {
+ if (tocSC.module_sp == sc.module_sp) {
+ if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false,
+ toc_range)) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
const uint32_t count = sc_list.GetSize();
if (count > 0) {
SymbolContext sc;
@@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
MmapArgList args =
process->GetTarget().GetPlatform()->GetMmapArgumentList(
arch, addr, length, prot_arg, flags, fd, offset);
+#if defined(__AIX__)
+ lldb::ThreadPlanSP call_plan_sp(
+ new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(),
+ toc_range.GetBaseAddress(),
+ void_ptr_type, args, options));
+#else
lldb::ThreadPlanSP call_plan_sp(
new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(),
void_ptr_type, args, options));
+#endif
if (call_plan_sp) {
DiagnosticManager diagnostics;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp
index 159fd2856443cc..d9b41d595147f3 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp
@@ -23,6 +23,8 @@
static const lldb_private::RegisterInfo *
GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
+ //HH
+ case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
return g_register_infos_ppc64le;
default:
@@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
static uint32_t
GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
+ //HitchHike
+ case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
return static_cast<uint32_t>(sizeof(g_register_infos_ppc64le) /
sizeof(g_register_infos_ppc64le[0]));
diff --git a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
index 89ecc757a68f56..550b53688fd39e 100644
--- a/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
+++ b/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -20,7 +20,7 @@
using namespace lldb;
using namespace lldb_private;
-ThreadMemory::ThreadMemory(Process &process, tid_t tid,
+ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid,
const ValueObjectSP &thread_info_valobj_sp)
: Thread(process, tid), m_backing_thread_sp(),
m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(),
diff --git a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
index 6755999b18185e..4eddbb5ec4cfdc 100644
--- a/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
@@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs
SOURCE ProcessGDBRemoteProperties.td
TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen)
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ remove_definitions("-D_XOPEN_SOURCE=700")
+ add_definitions("-D_ALL_SOURCE")
+endif()
+
set(LLDB_PLUGINS
lldbPluginProcessUtility
)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 74e392249a94eb..b7ecf7a5dc3287 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -40,6 +40,10 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/JSON.h"
+#if defined(__AIX__)
+#include <sys/ldr.h>
+#endif
+
#if defined(HAVE_LIBCOMPRESSION)
#include <compression.h>
#endif
@@ -1710,6 +1714,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
return error;
}
+#if defined(__AIX__)
+Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr)
+{
+ Status error;
+
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO");
+ assert(packet_len < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, response) ==
+ PacketResult::Success &&
+ response.GetResponseType() == StringExtractorGDBRemote::eResponse) {
+ llvm::MutableArrayRef<uint8_t> infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64);
+ size_t got_bytes = response.GetHexBytesAvail(infoData);
+ if (got_bytes != sizeof(struct ld_xinfo)*64) {
+ error.SetErrorString("qLDXINFO ret bad size");
+ return error;
+ }
+ } else {
+ error.SetErrorString("qLDXINFO is not supported");
+ }
+ return error;
+}
+#endif
+
Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo(
lldb::addr_t addr, MemoryRegionInfo ®ion) {
Status error = LoadQXferMemoryMap();
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 898d176abc3465..520f37ac567164 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -32,6 +32,10 @@
#include "llvm/Support/VersionTuple.h"
+#if defined(__AIX__)
+struct ld_xinfo;
+#endif
+
namespace lldb_private {
namespace process_gdb_remote {
@@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info);
std::optional<uint32_t> GetWatchpointSlotCount();
+#if defined(__AIX__)
+ Status GetLDXINFO(struct ld_xinfo *info_ptr);
+#endif
std::optional<bool> GetWatchpointReportedAfter();
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index a0b08a219ae147..f019062986925e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -48,6 +48,9 @@
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
+#if defined(__AIX__)
+#include <sys/ldr.h>
+#endif
using namespace lldb;
using namespace lldb_private;
@@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
&GDBRemoteCommunicationServerLLGS::Handle_Z);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
&GDBRemoteCommunicationServerLLGS::Handle_z);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO,
+ &GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO);
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_QPassSignals,
&GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
@@ -3006,6 +3011,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
}
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) {
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ Log *log = GetLog(LLDBLog::Process);
+ LLDB_LOG(log, "qLDXINFO failed, no process available");
+ return SendErrorResponse(0xff);
+ }
+
+#if defined(__AIX__)
+ // FIXME: buffer size
+ struct ld_xinfo info[64];
+ if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) {
+ return SendErrorResponse(0xff);
+ }
+ StreamGDBRemote response;
+ response.PutBytesAsRawHex8(&(info[0]), sizeof(info));
+ return SendPacketNoLock(response.GetString());
+#else
+ return SendErrorResponse(0xff);
+#endif
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 646b6a102abf62..a464479e178de1 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS
PacketResult Handle_z(StringExtractorGDBRemote &packet);
+ PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet);
+
PacketResult Handle_s(StringExtractorGDBRemote &packet);
PacketResult Handle_qXfer(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 6f9c2cc1e4b4e8..10fbaa2b3c8372 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -92,6 +92,10 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
+#if defined(__AIX__)
+#include <sys/ldr.h>
+#endif
+
#define DEBUGSERVER_BASENAME "debugserver"
using namespace lldb;
using namespace lldb_private;
@@ -1513,7 +1517,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
ThreadList old_thread_list_copy(old_thread_list);
if (num_thread_ids > 0) {
for (size_t i = 0; i < num_thread_ids; ++i) {
- tid_t tid = m_thread_ids[i];
+ lldb::tid_t tid = m_thread_ids[i];
ThreadSP thread_sp(
old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
if (!thread_sp) {
@@ -2945,6 +2949,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr,
return error;
}
+#if defined(__AIX__)
+Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) {
+ Status error(m_gdb_comm.GetLDXINFO(info_ptr));
+ return error;
+}
+#endif
+
std::optional<uint32_t> ProcessGDBRemote::GetWatchpointSlotCount() {
return m_gdb_comm.GetWatchpointSlotCount();
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 2492795851388a..82200fbea21cd4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -37,6 +37,10 @@
#include "GDBRemoteCommunicationClient.h"
#include "GDBRemoteRegisterContext.h"
+#if defined(__AIX__)
+struct ld_xinfo;
+#endif
+
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
@@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process,
Status DoGetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo ®ion_info) override;
+#if defined(__AIX__)
+ Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override;
+#endif
+
private:
// For ProcessGDBRemote only
std::string m_partial_profile_data;
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index 1da7696c9a352a..930c707604bb38 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -593,19 +593,19 @@ bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list,
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
if (core_objfile) {
- std::set<tid_t> used_tids;
+ std::set<lldb::tid_t> used_tids;
const uint32_t num_threads = core_objfile->GetNumThreadContexts();
- std::vector<tid_t> tids;
+ std::vector<lldb::tid_t> tids;
if (core_objfile->GetCorefileThreadExtraInfos(tids)) {
assert(tids.size() == num_threads);
// Find highest tid value.
- tid_t highest_tid = 0;
+ lldb::tid_t highest_tid = 0;
for (uint32_t i = 0; i < num_threads; i++) {
if (tids[i] != LLDB_INVALID_THREAD_ID && tids[i] > highest_tid)
highest_tid = tids[i];
}
- tid_t current_unused_tid = highest_tid + 1;
+ lldb::tid_t current_unused_tid = highest_tid + 1;
for (uint32_t i = 0; i < num_threads; i++) {
if (tids[i] == LLDB_INVALID_THREAD_ID) {
tids[i] = current_unused_tid++;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 7523d65abf0f80..1ce60a0b661546 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT)
endif()
add_subdirectory(Interfaces)
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ remove_definitions("-D_XOPEN_SOURCE=700")
+ add_definitions("-D_ALL_SOURCE")
+endif()
+
add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
PythonDataObjects.cpp
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
index e1f73f1997e369..92882cfc3da310 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -500,6 +500,8 @@ dw_addr_t DWARFFormValue::Address() const {
&offset, index_size);
}
+bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;
+
std::pair<DWARFUnit *, uint64_t>
DWARFFormValue::ReferencedUnitAndOffset() const {
uint64_t value = m_value.value.uval;
@@ -512,6 +514,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const {
assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile
// unit relative or we will get this wrong
value += m_unit->GetOffset();
+ if (UGLY_FLAG_FOR_AIX)
+ value -= 8;
if (!m_unit->ContainsDIEOffset(value)) {
m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
"DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 66a762bf9b6854..6721c1895a576e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -924,6 +924,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
return *m_func_aranges_up;
}
+/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts
+ * Refer Patches: 27,28,29,30,35 and 76
+ * and modify the code accordingly. */
+
+bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;
+
llvm::Expected<DWARFUnitSP>
DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,
const DWARFDataExtractor &debug_info,
@@ -1002,6 +1008,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
uint32_t DWARFUnit::GetHeaderByteSize() const {
switch (m_header.getUnitType()) {
case llvm::dwarf::DW_UT_compile:
+ if (UGLY_FLAG_FOR_AIX)
+ return 11 + 4/*GetDWARFSizeOfOffset*/;
+ else
+ return GetVersion() < 5 ? 11 : 12;
case llvm::dwarf::DW_UT_partial:
return GetVersion() < 5 ? 11 : 12;
case llvm::dwarf::DW_UT_skeleton:
@@ -1016,7 +1026,7 @@ uint32_t DWARFUnit::GetHeaderByteSize() const {
std::optional<uint64_t>
DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {
- offset_t offset = GetStrOffsetsBase() + index * 4;
+ lldb::offset_t offset = GetStrOffsetsBase() + index * 4;
return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset);
}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
index 2064b73dc3ea5b..824528fc3acfa2 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
@@ -216,7 +216,7 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction(
AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo
AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread,
- tid_t thread_id,
+ lldb::tid_t thread_id,
addr_t page_to_free,
uint64_t page_to_free_size,
Status &error) {
diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index f3df8a2c27f5ac..de244e372579db 100644
--- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -33,7 +33,7 @@ using namespace lldb_private::dwarf;
// Used for calls when the value type is specified by a DWARF EH Frame pointer
// encoding.
static uint64_t
-GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr,
+GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr,
uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr,
addr_t data_addr) //, BSDRelocs *data_relocs) const
{
@@ -588,7 +588,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
if (cie->augmentation[0] == 'z') {
uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) {
- offset_t saved_offset = offset;
+ lldb::offset_t saved_offset = offset;
lsda_data_file_address =
GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding,
pc_rel_addr, text_addr, data_addr);
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
index 110b5c86fc4256..6df03533cda299 100644
--- a/lldb/source/Target/ABI.cpp
+++ b/lldb/source/Target/ABI.cpp
@@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
llvm_unreachable("Should never get here!");
}
+bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t tocAddress,
+ lldb::addr_t returnAddress,
+ llvm::ArrayRef<lldb::addr_t> args) const {
+ // dummy prepare trivial call
+ llvm_unreachable("Should never get here!");
+}
+
bool ABI::GetFallbackRegisterLocation(
const RegisterInfo *reg_info,
UnwindPlan::Row::RegisterLocation &unwind_regloc) {
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index a42c44b761dc56..833489b16dfd7f 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -1,3 +1,8 @@
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ remove_definitions("-D_XOPEN_SOURCE=700")
+ add_definitions("-D_ALL_SOURCE")
+endif()
+
lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs
SOURCE TargetProperties.td
TARGET LLDBTargetPropertiesGen)
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index e3c4f2ee398cc4..e31245178b2f21 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -75,6 +75,10 @@
#include "lldb/Utility/State.h"
#include "lldb/Utility/Timer.h"
+#if defined(__AIX__)
+#include <sys/ldr.h>
+#endif
+
using namespace lldb;
using namespace lldb_private;
using namespace std::chrono;
@@ -6206,6 +6210,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr,
return DoGetMemoryRegionInfo(load_addr, range_info);
}
+#if defined(__AIX__)
+Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) {
+ return DoGetLDXINFO(info_ptr);
+}
+#endif
+
Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) {
Status error;
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index a61228d092d898..57f42ea56cb18f 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -40,6 +40,9 @@
#include <cassert>
#include <memory>
+#ifdef __AIX__
+#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
+#endif
using namespace lldb;
using namespace lldb_private;
@@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol(
// Answer the question: Where did THIS frame save the CALLER frame ("previous"
// frame)'s register value?
+#ifdef __AIX__
+extern bool UGLY_HACK_NULL_TOPFRAME;
+#endif
+
enum UnwindLLDB::RegisterSearchResult
RegisterContextUnwind::SavedLocationForRegister(
uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) {
@@ -1517,6 +1524,11 @@ RegisterContextUnwind::SavedLocationForRegister(
new_regloc.type =
UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+#ifdef __AIX__
+ if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) {
+ new_regloc.location.register_number = 0x24;
+ }
+#endif
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
regloc = new_regloc;
UnwindLogMsg("supplying caller's register %s (%d) from the live "
@@ -2368,6 +2380,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) {
}
}
+#ifdef __AIX__
+bool RegisterContextUnwind::ReadLR(addr_t &lr) {
+ if (!IsValid())
+ return false;
+
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
+ GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) {
+ // A lr value of 0 or 1 is impossible in the middle of the stack -- it
+ // indicates the end of a stack walk.
+ // On the currently executing frame (or such a frame interrupted
+ // asynchronously by sigtramp et al) this may occur if code has jumped
+ // through a NULL pointer -- we want to be able to unwind past that frame
+ // to help find the bug.
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ lr = abi->FixCodeAddress(lr);
+ }
+
+ return !(m_all_registers_available == false &&
+ above_trap_handler == false && (lr == 0 || lr == 1));
+ } else {
+ return false;
+ }
+}
+#endif
+
void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) {
Log *log = GetLog(LLDBLog::Unwind);
if (!log)
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index 50dcb66b9719fe..0926579ea2930b 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction(
m_valid = true;
}
+ThreadPlanCallFunction::ThreadPlanCallFunction(
+ Thread &thread, const Address &function, const Address &toc,
+ const CompilerType &return_type,
+ llvm::ArrayRef<addr_t> args, const EvaluateExpressionOptions &options)
+ : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread,
+ eVoteNoOpinion, eVoteNoOpinion),
+ m_valid(false), m_stop_other_threads(options.GetStopOthers()),
+ m_unwind_on_error(options.DoesUnwindOnError()),
+ m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
+ m_debug_execution(options.GetDebug()),
+ m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
+ m_function_sp(0), m_takedown_done(false),
+ m_should_clear_objc_exception_bp(false),
+ m_should_clear_cxx_exception_bp(false),
+ m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) {
+ lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS;
+ ABI *abi = nullptr;
+
+ if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr))
+ return;
+
+ toc_addr = toc.GetLoadAddress(&GetTarget());
+
+ if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr,
+ toc_addr, start_load_addr, args))
+ return;
+
+ ReportRegisterState("Function call was set up. Register state was:");
+
+ m_valid = true;
+}
+
ThreadPlanCallFunction::ThreadPlanCallFunction(
Thread &thread, const Address &function,
const EvaluateExpressionOptions &options)
diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp
index f43e940492b09b..255b829738ba22 100644
--- a/lldb/source/Target/UnwindLLDB.cpp
+++ b/lldb/source/Target/UnwindLLDB.cpp
@@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() {
return m_frames.size();
}
+#ifdef __AIX__
+bool UGLY_HACK_NULL_TOPFRAME = false;
+#endif
+
bool UnwindLLDB::AddFirstFrame() {
if (m_frames.size() > 0)
return true;
@@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() {
if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc))
goto unwind_done;
+#ifdef __AIX__
+ lldb::addr_t lr;
+ if (!reg_ctx_sp->ReadLR(lr))
+ goto unwind_done;
+
+ if (first_cursor_sp->start_pc == 0) {
+ first_cursor_sp->start_pc = lr;
+ UGLY_HACK_NULL_TOPFRAME = true;
+ }
+#endif
+
// Everything checks out, so release the auto pointer value and let the
// cursor own it in its shared pointer
first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp
index 07ef435ef451d2..3868f77169cc66 100644
--- a/lldb/source/Utility/ArchSpec.cpp
+++ b/lldb/source/Utility/ArchSpec.cpp
@@ -14,6 +14,7 @@
#include "lldb/lldb-defines.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Compiler.h"
@@ -459,10 +460,22 @@ static const ArchDefinition g_coff_arch_def = {
"pe-coff",
};
+static const ArchDefinitionEntry g_xcoff_arch_entries[] = {
+ {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu},
+ {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}
+};
+
+static const ArchDefinition g_xcoff_arch_def = {
+ eArchTypeXCOFF,
+ std::size(g_xcoff_arch_entries),
+ g_xcoff_arch_entries,
+ "xcoff",
+};
+
//===----------------------------------------------------------------------===//
// Table of all ArchDefinitions
static const ArchDefinition *g_arch_definitions[] = {
- &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def};
+ &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def, &g_xcoff_arch_def};
//===----------------------------------------------------------------------===//
// Static helper functions.
@@ -903,6 +916,9 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu,
} else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) {
m_triple.setVendor(llvm::Triple::PC);
m_triple.setOS(llvm::Triple::Win32);
+ } else if (arch_type == eArchTypeXCOFF && os == llvm::Triple::AIX) {
+ m_triple.setVendor(llvm::Triple::IBM);
+ m_triple.setOS(llvm::Triple::AIX);
} else {
m_triple.setVendor(llvm::Triple::UnknownVendor);
m_triple.setOS(llvm::Triple::UnknownOS);
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 9f79d2271b1e69..dbd3236536f8cd 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_qLaunchGDBServer;
if (PACKET_MATCHES("qLaunchSuccess"))
return eServerPacketType_qLaunchSuccess;
+ if (PACKET_MATCHES("qLDXINFO"))
+ return eServerPacketType_qLDXINFO;
break;
case 'M':
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index 5ac474736eb63d..413a1e51202880 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -155,7 +155,7 @@ if(TARGET clang)
add_lldb_test_dependency(clang)
# TestFullLtoStepping depends on LTO, and only runs when the compiler is clang.
- add_lldb_test_dependency(LTO)
+ #add_lldb_test_dependency(LTO)
if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES))
set(LLDB_HAS_LIBCXX ON)
diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test
index 9dd0413be14cf0..5ed61ad33ffc44 100644
--- a/lldb/test/Shell/Expr/TestIRMemoryMap.test
+++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test
@@ -1,6 +1,6 @@
# UNSUPPORTED: system-windows
-# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t
+# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t
# RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic
# RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic
diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test
index e6d6e56fc92035..2ead258719f326 100644
--- a/lldb/test/Shell/Process/TestEnvironment.test
+++ b/lldb/test/Shell/Process/TestEnvironment.test
@@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro
The double quotes around "BAR" ensure we don't match the command.
-RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t
+RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t
RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s
RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s
diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt
index cd304a047dea6d..78617be24f7806 100644
--- a/lldb/tools/driver/CMakeLists.txt
+++ b/lldb/tools/driver/CMakeLists.txt
@@ -11,6 +11,11 @@ if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist")
endif()
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ remove_definitions("-D_XOPEN_SOURCE=700")
+ add_definitions("-D_ALL_SOURCE")
+endif()
+
add_lldb_tool(lldb
Driver.cpp
Platform.cpp
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index 14371da64f2f2f..f7eaf56738d7d0 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -639,7 +639,7 @@ void sigwinch_handler(int signo) {
}
void sigint_handler(int signo) {
-#ifdef _WIN32 // Restore handler as it is not persistent on Windows
+#if defined(_WIN32) || defined(__AIX__) // Restore handler as it is not persistent on Windows
signal(SIGINT, sigint_handler);
#endif
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
@@ -727,8 +727,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
int main(int argc, char const *argv[]) {
// Editline uses for example iswprint which is dependent on LC_CTYPE.
+ // FIXME: this caused unexpected SIGTRAP on AIX
+#ifndef __AIX__
std::setlocale(LC_ALL, "");
std::setlocale(LC_CTYPE, "");
+#endif
// Setup LLVM signal handlers and make sure we call llvm_shutdown() on
// destruction.
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index f8f0d86453f585..2fa6f6c9a53690 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD)
list(APPEND extra_libs pthread)
endif ()
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ add_definitions("-D_AIX")
+ add_definitions("-D_ALL_SOURCE")
+endif()
if(APPLE)
configure_file(
diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt
index 9030ed709a647a..0d69ae32a008fd 100644
--- a/lldb/tools/lldb-server/CMakeLists.txt
+++ b/lldb/tools/lldb-server/CMakeLists.txt
@@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
list(APPEND LLDB_PLUGINS lldbPluginProcessLinux)
endif()
+if(CMAKE_SYSTEM_NAME MATCHES "AIX")
+ list(APPEND LLDB_PLUGINS lldbPluginProcessAIX)
+endif()
+
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD)
endif()
@@ -20,6 +24,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
list(APPEND LLDB_PLUGINS lldbPluginObjectFileMachO)
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
list(APPEND LLDB_PLUGINS lldbPluginObjectFilePECOFF)
+elseif(CMAKE_SYSTEM_NAME MATCHES "AIX")
+ list(APPEND LLDB_PLUGINS lldbPluginObjectFileXCOFF)
else()
list(APPEND LLDB_PLUGINS lldbPluginObjectFileELF)
endif()
@@ -54,6 +60,7 @@ add_lldb_tool(lldb-server
lldbPluginInstructionMIPS
lldbPluginInstructionMIPS64
lldbPluginInstructionRISCV
+ lldbPluginInstructionPPC64
${LLDB_SYSTEM_LIBS}
LINK_COMPONENTS
diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
index 4233252a84dfc7..91bb2083a88b59 100644
--- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
+++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
@@ -14,6 +14,9 @@ using HostObjectFile = ObjectFileMachO;
#elif defined(_WIN32)
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
using HostObjectFile = ObjectFilePECOFF;
+#elif defined(__AIX__)
+#include "Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.h"
+using HostObjectFile = ObjectFileXCOFF;
#else
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
using HostObjectFile = ObjectFileELF;
@@ -46,6 +49,10 @@ using HostObjectFile = ObjectFileELF;
#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h"
#endif
+#if defined(__AIX__)
+#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
+#endif
+
#if defined(__riscv)
#define LLDB_TARGET_RISCV
#include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h"
@@ -75,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() {
EmulateInstructionRISCV::Initialize();
#endif
+#if defined(__AIX__)
+ EmulateInstructionPPC64::Initialize();
+#endif
+
return llvm::Error::success();
}
@@ -97,5 +108,9 @@ void SystemInitializerLLGS::Terminate() {
EmulateInstructionRISCV::Terminate();
#endif
+#if defined(__AIX__)
+ EmulateInstructionPPC64::Terminate();
+#endif
+
SystemInitializerCommon::Terminate();
}
diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 563284730bc705..2a14f4f9c82aa8 100644
--- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -45,6 +45,8 @@
#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
#elif defined(_WIN32)
#include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
+#elif defined(__AIX__)
+#include "Plugins/Process/AIX/NativeProcessAIX.h"
#endif
#ifndef LLGS_PROGRAM_NAME
@@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager;
typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager;
#elif defined(_WIN32)
typedef NativeProcessWindows::Manager NativeProcessManager;
+#elif defined(__AIX__)
+typedef process_aix::NativeProcessAIX::Manager NativeProcessManager;
#else
// Dummy implementation to make sure the code compiles
class NativeProcessManager : public NativeProcessProtocol::Manager {
diff --git a/lldb/unittests/Host/FileSystemTest.cpp b/lldb/unittests/Host/FileSystemTest.cpp
index 58887f6b2467e0..89d0f5b87171a3 100644
--- a/lldb/unittests/Host/FileSystemTest.cpp
+++ b/lldb/unittests/Host/FileSystemTest.cpp
@@ -59,7 +59,7 @@ class DummyFileSystem : public vfs::FileSystem {
return I->second;
}
ErrorOr<std::unique_ptr<vfs::File>>
- openFileForRead(const Twine &Path) override {
+ openFileForRead(const Twine &Path, bool IsText) override {
auto S = status(Path);
if (S)
return std::unique_ptr<vfs::File>(new DummyFile{*S});
diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp
index 5187a0c20a68b2..f3de92c0852b1c 100644
--- a/lldb/unittests/Host/posix/TerminalTest.cpp
+++ b/lldb/unittests/Host/posix/TerminalTest.cpp
@@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) {
TEST_F(TerminalTest, SetBaudRate) {
struct termios terminfo;
+#if (defined(__AIX__) && defined(B38400)) || !defined(__AIX__)
ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded());
ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B38400));
EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B38400));
+#endif
+#if (defined(__AIX__) && defined(B115200)) || !defined(__AIX__)
ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded());
ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B115200));
EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B115200));
+#endif
// uncommon value
#if defined(B153600)
diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h
index 5a7cd8e38f2b76..fa9c6781e24f53 100644
--- a/llvm/include/llvm/Object/XCOFFObjectFile.h
+++ b/llvm/include/llvm/Object/XCOFFObjectFile.h
@@ -542,7 +542,6 @@ class XCOFFObjectFile : public ObjectFile {
template <typename T> const T *sectionHeaderTable() const;
size_t getFileHeaderSize() const;
- size_t getSectionHeaderSize() const;
const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const;
const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const;
@@ -578,6 +577,9 @@ class XCOFFObjectFile : public ObjectFile {
void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const;
public:
+ size_t getSectionHeaderSize() const;
+ Expected<uintptr_t> getLoaderSectionAddress() const;
+
static constexpr uint64_t InvalidRelocOffset =
std::numeric_limits<uint64_t>::max();
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index bdd04b00f557bd..9c96df1bbdc541 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -251,10 +251,16 @@ Expected<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const {
return DA.getRelocatedValue(ItemSize, &Offset);
}
+bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;
+
Error DWARFUnitHeader::extract(DWARFContext &Context,
const DWARFDataExtractor &debug_info,
uint64_t *offset_ptr,
DWARFSectionKind SectionKind) {
+ if (UGLY_FLAG_FOR_AIX) {
+ // FIXME: hack to get version
+ *offset_ptr += 8;
+ }
Offset = *offset_ptr;
Error Err = Error::success();
IndexEntry = nullptr;
@@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context,
AbbrOffset = debug_info.getRelocatedValue(
FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
} else {
- AbbrOffset = debug_info.getRelocatedValue(
- FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
+ if (UGLY_FLAG_FOR_AIX) {
+ AbbrOffset = debug_info.getRelocatedValue(
+ 8, offset_ptr, nullptr, &Err);
+ } else {
+ AbbrOffset = debug_info.getRelocatedValue(
+ FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
+ }
FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err);
// Fake a unit type based on the section type. This isn't perfect,
// but distinguishing compile and type units is generally enough.
>From b1da5b1cf35829fcbf4ad6564c6005c755012e47 Mon Sep 17 00:00:00 2001
From: Dhruv-Srivastava <dhruv.srivastava at ibm.com>
Date: Wed, 7 Aug 2024 12:18:45 -0500
Subject: [PATCH 2/3] Code license notice
---
lldb/NOTICE.TXT | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 lldb/NOTICE.TXT
diff --git a/lldb/NOTICE.TXT b/lldb/NOTICE.TXT
new file mode 100644
index 00000000000000..d814272967476e
--- /dev/null
+++ b/lldb/NOTICE.TXT
@@ -0,0 +1,7 @@
+
+This product contains small piece of code to support AIX, taken from netbsd.
+
+ * LICENSE:
+ * lldb/source/Host/common/LICENSE.aix-netbsd.txt (OpenSSL License)
+ * HOMEPAGE:
+ * https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/crypto/external/bsd/openssl/dist
>From 50ad673a78029fd6c47d90317e2c61ca2b59d5c5 Mon Sep 17 00:00:00 2001
From: Dhruv-Srivastava <dhruv.srivastava at ibm.com>
Date: Wed, 7 Aug 2024 13:27:20 -0500
Subject: [PATCH 3/3] Reverting .tests
---
lldb/test/Shell/Expr/TestIRMemoryMap.test | 2 +-
lldb/test/Shell/Process/TestEnvironment.test | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/test/Shell/Expr/TestIRMemoryMap.test b/lldb/test/Shell/Expr/TestIRMemoryMap.test
index 5ed61ad33ffc44..9dd0413be14cf0 100644
--- a/lldb/test/Shell/Expr/TestIRMemoryMap.test
+++ b/lldb/test/Shell/Expr/TestIRMemoryMap.test
@@ -1,6 +1,6 @@
# UNSUPPORTED: system-windows
-# RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t
+# RUN: %clangxx_host %p/Inputs/call-function.cpp -g -o %t
# RUN: lldb-test ir-memory-map %t %S/Inputs/ir-memory-map-basic
# RUN: lldb-test ir-memory-map -host-only %t %S/Inputs/ir-memory-map-basic
diff --git a/lldb/test/Shell/Process/TestEnvironment.test b/lldb/test/Shell/Process/TestEnvironment.test
index 2ead258719f326..e6d6e56fc92035 100644
--- a/lldb/test/Shell/Process/TestEnvironment.test
+++ b/lldb/test/Shell/Process/TestEnvironment.test
@@ -3,7 +3,7 @@ UNSUPPORTED: lldb-repro
The double quotes around "BAR" ensure we don't match the command.
-RUN: %clangxx_host -std=c++11 -I/compgpfs/build/xlcit/rings/openxlC/aix/wyvern_dev/ring0/latest/opt/IBM/openxlC/17.1.2/include/c++/v1/ %p/Inputs/env.cpp -o %t
+RUN: %clangxx_host -std=c++11 %p/Inputs/env.cpp -o %t
RUN: %lldb %t -o 'process launch --environment FOO="BAR"' | FileCheck %s
RUN: %lldb %t -o 'env FOO="BAR"' -o 'process launch' | FileCheck %s
More information about the lldb-commits
mailing list