mirror of
https://github.com/intel/llvm.git
synced 2026-01-15 04:17:17 +08:00
This patch adds support for Linux on SystemZ: - A new ArchSpec value of eCore_s390x_generic - A new directory Plugins/ABI/SysV-s390x providing an ABI implementation - Register context support - Native Linux support including watchpoint support - ELF core file support - Misc. support throughout the code base (e.g. breakpoint opcodes) - Test case updates to support the platform This should provide complete support for debugging the SystemZ platform. Not yet supported are optional features like transaction support (zEC12) or SIMD vector support (z13). There is no instruction emulation, since our ABI requires that all code provide correct DWARF CFI at all PC locations in .eh_frame to support unwinding (i.e. -fasynchronous-unwind-tables is on by default). The implementation follows existing platforms in a mostly straightforward manner. A couple of things that are different: - We do not use PTRACE_PEEKUSER / PTRACE_POKEUSER to access single registers, since some registers (access register) reside at offsets in the user area that are multiples of 4, but the PTRACE_PEEKUSER interface only allows accessing aligned 8-byte blocks in the user area. Instead, we use a s390 specific ptrace interface PTRACE_PEEKUSR_AREA / PTRACE_POKEUSR_AREA that allows accessing a whole block of the user area in one go, so in effect allowing to treat parts of the user area as register sets. - SystemZ hardware does not provide any means to implement read watchpoints, only write watchpoints. In fact, we can only support a *single* write watchpoint (but this can span a range of arbitrary size). In LLDB this means we support only a single watchpoint. I've set all test cases that require read watchpoints (or multiple watchpoints) to expected failure on the platform. [ Note that there were two test cases that install a read/write watchpoint even though they nowhere rely on the "read" property. I've changed those to simply use plain write watchpoints. ] Differential Revision: http://reviews.llvm.org/D18978 llvm-svn: 266308
428 lines
15 KiB
C++
428 lines
15 KiB
C++
//===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Host/Config.h"
|
|
|
|
#include "lldb/Core/ArchSpec.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/Host.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Host/HostInfoBase.h"
|
|
|
|
#include "llvm/ADT/Triple.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/Host.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <thread>
|
|
#include <mutex> // std::once
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
namespace
|
|
{
|
|
//----------------------------------------------------------------------
|
|
// The HostInfoBaseFields is a work around for windows not supporting
|
|
// static variables correctly in a thread safe way. Really each of the
|
|
// variables in HostInfoBaseFields should live in the functions in which
|
|
// they are used and each one should be static, but the work around is
|
|
// in place to avoid this restriction. Ick.
|
|
//----------------------------------------------------------------------
|
|
|
|
struct HostInfoBaseFields
|
|
{
|
|
~HostInfoBaseFields()
|
|
{
|
|
if (m_lldb_process_tmp_dir.Exists())
|
|
{
|
|
// Remove the LLDB temporary directory if we have one. Set "recurse" to
|
|
// true to all files that were created for the LLDB process can be cleaned up.
|
|
FileSystem::DeleteDirectory(m_lldb_process_tmp_dir, true);
|
|
}
|
|
}
|
|
|
|
uint32_t m_number_cpus;
|
|
std::string m_vendor_string;
|
|
std::string m_os_string;
|
|
std::string m_host_triple;
|
|
|
|
ArchSpec m_host_arch_32;
|
|
ArchSpec m_host_arch_64;
|
|
|
|
FileSpec m_lldb_so_dir;
|
|
FileSpec m_lldb_support_exe_dir;
|
|
FileSpec m_lldb_headers_dir;
|
|
FileSpec m_lldb_python_dir;
|
|
FileSpec m_lldb_clang_resource_dir;
|
|
FileSpec m_lldb_system_plugin_dir;
|
|
FileSpec m_lldb_user_plugin_dir;
|
|
FileSpec m_lldb_process_tmp_dir;
|
|
FileSpec m_lldb_global_tmp_dir;
|
|
};
|
|
|
|
HostInfoBaseFields *g_fields = nullptr;
|
|
}
|
|
|
|
void
|
|
HostInfoBase::Initialize()
|
|
{
|
|
g_fields = new HostInfoBaseFields();
|
|
}
|
|
|
|
void
|
|
HostInfoBase::Terminate()
|
|
{
|
|
delete g_fields;
|
|
g_fields = nullptr;
|
|
}
|
|
|
|
uint32_t
|
|
HostInfoBase::GetNumberCPUS()
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
std::call_once(g_once_flag, []() {
|
|
g_fields->m_number_cpus = std::thread::hardware_concurrency();
|
|
});
|
|
return g_fields->m_number_cpus;
|
|
}
|
|
|
|
uint32_t
|
|
HostInfoBase::GetMaxThreadNameLength()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
llvm::StringRef
|
|
HostInfoBase::GetVendorString()
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
std::call_once(g_once_flag, []() {
|
|
g_fields->m_vendor_string = HostInfo::GetArchitecture().GetTriple().getVendorName().str();
|
|
});
|
|
return g_fields->m_vendor_string;
|
|
}
|
|
|
|
llvm::StringRef
|
|
HostInfoBase::GetOSString()
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
std::call_once(g_once_flag, []() {
|
|
g_fields->m_os_string = std::move(HostInfo::GetArchitecture().GetTriple().getOSName());
|
|
});
|
|
return g_fields->m_os_string;
|
|
}
|
|
|
|
llvm::StringRef
|
|
HostInfoBase::GetTargetTriple()
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
std::call_once(g_once_flag, []() {
|
|
g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple();
|
|
});
|
|
return g_fields->m_host_triple;
|
|
}
|
|
|
|
const ArchSpec &
|
|
HostInfoBase::GetArchitecture(ArchitectureKind arch_kind)
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
std::call_once(g_once_flag, []() {
|
|
HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64);
|
|
});
|
|
|
|
// If an explicit 32 or 64-bit architecture was requested, return that.
|
|
if (arch_kind == eArchKind32)
|
|
return g_fields->m_host_arch_32;
|
|
if (arch_kind == eArchKind64)
|
|
return g_fields->m_host_arch_64;
|
|
|
|
// Otherwise prefer the 64-bit architecture if it is valid.
|
|
return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
|
|
{
|
|
file_spec.Clear();
|
|
|
|
#if defined(LLDB_DISABLE_PYTHON)
|
|
if (type == lldb::ePathTypePythonDir)
|
|
return false;
|
|
#endif
|
|
|
|
FileSpec *result = nullptr;
|
|
switch (type)
|
|
{
|
|
case lldb::ePathTypeLLDBShlibDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_so_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeSupportExecutableDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
|
|
g_fields->m_lldb_support_exe_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_support_exe_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeHeaderDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_headers_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypePythonDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_python_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeClangDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_clang_resource_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeLLDBSystemPlugins:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
|
|
g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_system_plugin_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeLLDBUserPlugins:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
|
|
g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_user_plugin_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeLLDBTempSystemDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_process_tmp_dir;
|
|
}
|
|
break;
|
|
case lldb::ePathTypeGlobalLLDBTempSystemDir:
|
|
{
|
|
static std::once_flag g_once_flag;
|
|
static bool success = false;
|
|
std::call_once(g_once_flag, []() {
|
|
success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir);
|
|
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
|
|
if (log)
|
|
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
|
|
});
|
|
if (success)
|
|
result = &g_fields->m_lldb_global_tmp_dir;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!result)
|
|
return false;
|
|
file_spec = *result;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec)
|
|
{
|
|
// To get paths related to LLDB we get the path to the executable that
|
|
// contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
|
|
// on linux this is assumed to be the "lldb" main executable. If LLDB on
|
|
// linux is actually in a shared library (liblldb.so) then this function will
|
|
// need to be modified to "do the right thing".
|
|
|
|
FileSpec lldb_file_spec(
|
|
Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
|
|
|
|
// This is necessary because when running the testsuite the shlib might be a symbolic link inside the Python resource dir.
|
|
FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
|
|
|
|
// Remove the filename so that this FileSpec only represents the directory.
|
|
file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
|
|
|
|
return (bool)file_spec.GetDirectory();
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
|
|
{
|
|
return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec)
|
|
{
|
|
FileSpec temp_file_spec;
|
|
if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
|
|
return false;
|
|
|
|
std::string pid_str{std::to_string(Host::GetCurrentProcessID())};
|
|
temp_file_spec.AppendPathComponent(pid_str);
|
|
if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success())
|
|
return false;
|
|
|
|
file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec)
|
|
{
|
|
llvm::SmallVector<char, 16> tmpdir;
|
|
llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
|
|
file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec)
|
|
{
|
|
file_spec.Clear();
|
|
|
|
FileSpec temp_file_spec;
|
|
if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
|
|
return false;
|
|
|
|
temp_file_spec.AppendPathComponent("lldb");
|
|
if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success())
|
|
return false;
|
|
|
|
file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec)
|
|
{
|
|
// TODO(zturner): Figure out how to compute the header directory for all platforms.
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
|
|
{
|
|
// TODO(zturner): Figure out how to compute the system plugins directory for all platforms.
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeClangDirectory(FileSpec &file_spec)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
|
|
{
|
|
// TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
|
|
return false;
|
|
}
|
|
|
|
void
|
|
HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
|
|
{
|
|
llvm::Triple triple(llvm::sys::getProcessTriple());
|
|
|
|
arch_32.Clear();
|
|
arch_64.Clear();
|
|
|
|
switch (triple.getArch())
|
|
{
|
|
default:
|
|
arch_32.SetTriple(triple);
|
|
break;
|
|
|
|
case llvm::Triple::aarch64:
|
|
case llvm::Triple::ppc64:
|
|
case llvm::Triple::x86_64:
|
|
arch_64.SetTriple(triple);
|
|
arch_32.SetTriple(triple.get32BitArchVariant());
|
|
break;
|
|
|
|
case llvm::Triple::mips64:
|
|
case llvm::Triple::mips64el:
|
|
case llvm::Triple::sparcv9:
|
|
case llvm::Triple::systemz:
|
|
arch_64.SetTriple(triple);
|
|
break;
|
|
}
|
|
}
|