Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][AIX] Added PlatformAIX plugin #121273

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lldb/source/Plugins/Platform/AIX/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
add_definitions("-D_ALL_SOURCE")

add_lldb_library(lldbPluginPlatformAIX PLUGIN
PlatformAIX.cpp

LINK_LIBS
lldbBreakpoint
lldbCore
lldbHost
lldbInterpreter
lldbTarget
lldbPluginPlatformPOSIX
)
370 changes: 370 additions & 0 deletions lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
//===-- 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"

// Use defined 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) {
#ifdef _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::ppc64}, 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"));
}

lldb::UnwindPlanSP
PlatformAIX::GetTrapHandlerUnwindPlan(const llvm::Triple &triple,
ConstString 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);

ast->CompleteTagDeclarationDefinition(union_type);
ast->AddFieldToRecordType(siginfo_type, "_sifields", union_type,
lldb::eAccessPublic, 0);

ast->CompleteTagDeclarationDefinition(siginfo_type);
return siginfo_type;
}
Loading
Loading