[Lldb-commits] [clang] [lldb] [llvm] Extending LLDB to work on AIX (PR #102601)

Dhruv Srivastava via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 3 22:46:56 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/4] 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 &sect) {
+  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 &sect) {
+  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 &sect);
+  static lldb::SectionType GetSectionType(llvm::StringRef sect_name,
+                                          const section_header_t &sect);
+
+  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 &reg_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 &reg_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 &reg_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 &reg_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 &reg_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 *>(&regset), 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 *>(&regset), 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 &reg_value);
+
+  virtual Status WriteRegisterRaw(uint32_t reg_index,
+                                  const RegisterValue &reg_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 &reg_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 &reg_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(),
+                                           &regset, &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(),
+                                           &regset, &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 &reg_value) override;
+
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_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 &region) {
   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 &region_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 &region_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 &regloc) {
@@ -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/4] 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/4] 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
 

>From 758ab642d0974e799ac902d8ad240a3a90aeb24d Mon Sep 17 00:00:00 2001
From: Lakshmi Surekha Kovvuri <lakshmi at aixbase.aus.stglabs.ibm.com>
Date: Fri, 30 Aug 2024 08:33:32 -0500
Subject: [PATCH 4/4] Changes made to AIX-specific files to eliminate errors
 encountered during CI when updating LLDB.

---
 .../Plugins/Process/AIX/NativeProcessAIX.cpp  | 20 ++++++++++---------
 .../Process/AIX/NativeRegisterContextAIX.cpp  |  4 ++--
 .../AIX/NativeRegisterContextAIX_ppc64.cpp    | 10 +++++-----
 .../Plugins/Process/AIX/NativeThreadAIX.cpp   |  2 +-
 .../GDBRemoteCommunicationClient.cpp          |  4 ++--
 5 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
index 882f20d30a3bf7..5b01a66b0453f5 100644
--- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
@@ -211,12 +211,14 @@ static Status EnsureFDFlags(int fd, int flags) {
 
   int status = fcntl(fd, F_GETFL);
   if (status == -1) {
-    error.SetErrorToErrno();
+    error = Status::FromErrno();
+    // error.SetErrorToErrno();
     return error;
   }
 
   if (fcntl(fd, F_SETFL, status | flags) == -1) {
-    error.SetErrorToErrno();
+    error = Status::FromErrno();
+    // error.SetErrorToErrno();
     return error;
   }
 
@@ -813,7 +815,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) {
       Status error = ResumeThread(static_cast<NativeThreadAIX &>(*thread),
                                   action->state, signo);
       if (error.Fail())
-        return Status("NativeProcessAIX::%s: failed to resume thread "
+        return Status::FromErrorStringWithFormat("NativeProcessAIX::%s: failed to resume thread "
                       "for pid %" PRIu64 ", tid %" PRIu64 ", error = %s",
                       __FUNCTION__, GetID(), thread->GetID(),
                       error.AsCString());
@@ -826,7 +828,7 @@ Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) {
       break;
 
     default:
-      return Status("NativeProcessAIX::%s (): unexpected state %s specified "
+      return Status::FromErrorStringWithFormat("NativeProcessAIX::%s (): unexpected state %s specified "
                     "for pid %" PRIu64 ", tid %" PRIu64,
                     __FUNCTION__, StateAsCString(action->state), GetID(),
                     thread->GetID());
@@ -840,7 +842,7 @@ Status NativeProcessAIX::Halt() {
   Status error;
 
   if (kill(GetID(), SIGSTOP) != 0)
-    error.SetErrorToErrno();
+    error = Status::FromErrno();
 
   return error;
 }
@@ -874,7 +876,7 @@ Status NativeProcessAIX::Signal(int signo) {
            Host::GetSignalAsCString(signo), GetID());
 
   if (kill(GetID(), signo))
-    error.SetErrorToErrno();
+    error = Status::FromErrno();
 
   return error;
 }
@@ -951,7 +953,7 @@ Status NativeProcessAIX::Kill() {
   }
 
   if (kill(GetID(), SIGKILL) != 0) {
-    error.SetErrorToErrno();
+    error = Status::FromErrno();
     return error;
   }
 
@@ -1555,7 +1557,7 @@ Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path,
       return Status();
     }
   }
-  return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
+  return Status::FromErrorStringWithFormat("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
                 module_file_spec.GetFilename().AsCString(), GetID());
 }
 
@@ -2011,7 +2013,7 @@ Status NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
   }
 
   if (errno) {
-    error.SetErrorToErrno();
+    error = Status::FromErrno();
     ret = -1;
   }
 
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
index 0859f9501c1b6a..071e55543cc3c2 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
@@ -27,7 +27,7 @@ Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index,
                                                    RegisterValue &reg_value) {
   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
   if (!reg_info)
-    return Status("register %" PRIu32 " not found", reg_index);
+    return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index);
 
   return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name,
                              reg_info->byte_size, reg_value);
@@ -82,7 +82,7 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index,
   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 "
+    return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo "
                   "for write register index %" PRIu32,
                   __FUNCTION__, reg_to_write);
 
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
index 19963737917484..0132b52dec6f2e 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
@@ -165,7 +165,7 @@ Status NativeRegisterContextAIX_ppc64::ReadRegister(
   Status error;
 
   if (!reg_info) {
-    error.SetErrorString("reg_info NULL");
+    error.FromErrorString("reg_info NULL");
     return error;
   }
 
@@ -251,7 +251,7 @@ Status NativeRegisterContextAIX_ppc64::WriteRegister(
 
   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
+    return Status::FromErrorStringWithFormat("no lldb regnum for %s", reg_info && reg_info->name
                                                ? reg_info->name
                                                : "<unknown register>");
 
@@ -389,14 +389,14 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues(
   Status error;
 
   if (!data_sp) {
-    error.SetErrorStringWithFormat(
+    error = Status::FromErrorStringWithFormat( 
         "NativeRegisterContextAIX_ppc64::%s invalid data_sp provided",
         __FUNCTION__);
     return error;
   }
 
   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
-    error.SetErrorStringWithFormat(
+    error = Status::FromErrorStringWithFormat(
         "NativeRegisterContextAIX_ppc64::%s data_sp contained mismatched "
         "data size, expected %" PRIu64 ", actual %" PRIu64,
         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
@@ -405,7 +405,7 @@ Status NativeRegisterContextAIX_ppc64::WriteAllRegisterValues(
 
   const uint8_t *src = data_sp->GetBytes();
   if (src == nullptr) {
-    error.SetErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s "
+    error = Status::FromErrorStringWithFormat("NativeRegisterContextAIX_ppc64::%s "
                                    "DataBuffer::GetBytes() returned a null "
                                    "pointer",
                                    __FUNCTION__);
diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
index e07daccdff550e..bb14b6ab4a05e8 100644
--- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
@@ -481,7 +481,7 @@ Status NativeThreadAIX::RequestStop() {
   Status err;
   errno = 0;
   if (::kill(pid, SIGSTOP) != 0) {
-    err.SetErrorToErrno();
+    err = Status::FromErrno();
     LLDB_LOGF(log,
               "NativeThreadAIX::%s kill(%" PRIu64 ", SIGSTOP) failed: %s",
               __FUNCTION__, pid, err.AsCString());
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 17926f8e4ab535..0aa68a4a09cbe9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1728,11 +1728,11 @@ Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr)
     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");
+      error.FromErrorString("qLDXINFO ret bad size");
       return error;
     }
   } else {
-    error.SetErrorString("qLDXINFO is not supported");
+    error.FromErrorString("qLDXINFO is not supported");
   }
   return error;
 }



More information about the lldb-commits mailing list