[ABI] Implement Windows ABI for x86_64

Summary:
Implement the ABI for WIndows-x86_64 including register info and calling convention.
Handled nested struct returned in register (SysV doesn't have it supported)

Reviewers: xiaobai, compnerd

Reviewed By: compnerd

Subscribers: labath, jasonmolenda, fedor.sergeev, mgorny, teemperor, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D62213

llvm-svn: 364216
This commit is contained in:
Alex Langford 2019-06-24 18:21:05 +00:00
parent dbb6c03175
commit 09ede9d65f
9 changed files with 2118 additions and 11 deletions

View File

@ -26,7 +26,6 @@ class RegistersIteratorTestCase(TestBase):
'main.cpp', '// Set break point at this line.')
@add_test_categories(['pyapi'])
@expectedFailureAll(oslist=["windows"])
def test_iter_registers(self):
"""Test iterator works correctly for lldbutil.iter_registers()."""
self.build()

View File

@ -34,6 +34,7 @@
#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h"
#include "Plugins/ABI/SysV-s390x/ABISysV_s390x.h"
#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h"
#include "Plugins/ABI/Windows-x86_64/ABIWindows_x86_64.h"
#include "Plugins/Architecture/Arm/ArchitectureArm.h"
#include "Plugins/Architecture/Mips/ArchitectureMips.h"
#include "Plugins/Architecture/PPC64/ArchitecturePPC64.h"
@ -186,6 +187,7 @@ llvm::Error SystemInitializerFull::Initialize() {
ABISysV_mips::Initialize();
ABISysV_mips64::Initialize();
ABISysV_s390x::Initialize();
ABIWindows_x86_64::Initialize();
ArchitectureArm::Initialize();
ArchitectureMips::Initialize();
@ -299,6 +301,7 @@ void SystemInitializerFull::Terminate() {
ABISysV_mips::Terminate();
ABISysV_mips64::Terminate();
ABISysV_s390x::Terminate();
ABIWindows_x86_64::Terminate();
DisassemblerLLVMC::Terminate();
JITLoaderGDB::Terminate();

View File

@ -11,3 +11,4 @@ add_subdirectory(SysV-x86_64)
add_subdirectory(MacOSX-i386)
add_subdirectory(MacOSX-arm)
add_subdirectory(MacOSX-arm64)
add_subdirectory(Windows-x86_64)

View File

@ -220,8 +220,19 @@ size_t ABISysV_x86_64::GetRedZoneSize() const { return 128; }
ABISP
ABISysV_x86_64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
return ABISP(new ABISysV_x86_64(process_sp));
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
const llvm::Triple::OSType os_type = arch.GetTriple().getOS();
if (arch_type == llvm::Triple::x86_64) {
switch(os_type) {
case llvm::Triple::OSType::MacOSX:
case llvm::Triple::OSType::Linux:
case llvm::Triple::OSType::FreeBSD:
case llvm::Triple::OSType::Solaris:
case llvm::Triple::OSType::UnknownOS:
return ABISP(new ABISysV_x86_64(process_sp));
default:
return ABISP();
}
}
return ABISP();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
//===-- ABIWindows_x86_64.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_ABIWindows_x86_64_h_
#define liblldb_ABIWindows_x86_64_h_
#include "lldb/Target/ABI.h"
#include "lldb/lldb-private.h"
class ABIWindows_x86_64 : public lldb_private::ABI {
public:
~ABIWindows_x86_64() override = default;
size_t GetRedZoneSize() const override;
bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
llvm::ArrayRef<lldb::addr_t> args) const override;
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
lldb::ValueObjectSP
GetReturnValueObjectImpl(lldb_private::Thread &thread,
lldb_private::CompilerType &type) const override;
bool
CreateFunctionEntryUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override;
bool CreateDefaultUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override;
bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override;
// In Windows_x86_64 ABI, stack will always be maintained 16-byte aligned
bool CallFrameAddressIsValid(lldb::addr_t cfa) override {
if (cfa & (16ull - 1ull))
return false; // Not 16 byte aligned
if (cfa == 0)
return false; // Zero is not a valid stack address
return true;
}
bool CodeAddressIsValid(lldb::addr_t pc) override {
// We have a 64 bit address space, so anything is valid as opcodes
// aren't fixed width...
return true;
}
const lldb_private::RegisterInfo *
GetRegisterInfoArray(uint32_t &count) override;
bool GetPointerReturnRegister(const char *&name) override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static void Initialize();
static void Terminate();
static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
protected:
void CreateRegisterMapIfNeeded();
lldb::ValueObjectSP
GetReturnValueObjectSimple(lldb_private::Thread &thread,
lldb_private::CompilerType &ast_type) const;
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
ABIWindows_x86_64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
#endif // liblldb_ABISysV_x86_64_h_

View File

@ -0,0 +1,10 @@
add_lldb_library(lldbPluginABIWindows_x86_64 PLUGIN
ABIWindows_x86_64.cpp
LINK_LIBS
lldbCore
lldbSymbol
lldbTarget
LINK_COMPONENTS
Support
)

View File

@ -21,7 +21,7 @@
using namespace lldb;
using namespace lldb_private;
const DWORD kWinContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
const DWORD kWinContextFlags = CONTEXT_ALL;
// Constructors and Destructors
RegisterContextWindows::RegisterContextWindows(Thread &thread,
@ -114,8 +114,18 @@ bool RegisterContextWindows::CacheAllRegisterValues() {
return true;
TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
memset(&m_context, 0, sizeof(m_context));
m_context.ContextFlags = kWinContextFlags;
uint8_t buffer[2048];
memset(buffer, 0, sizeof(buffer));
PCONTEXT tmpContext = NULL;
DWORD contextLength = (DWORD)sizeof(buffer);
if (!::InitializeContext(buffer, kWinContextFlags, &tmpContext,
&contextLength)) {
return false;
}
memcpy(&m_context, tmpContext, sizeof(m_context));
if (!::SuspendThread(wthread.GetHostThread().GetNativeThread().GetSystemHandle())) {
return false;
}
if (!::GetThreadContext(
wthread.GetHostThread().GetNativeThread().GetSystemHandle(),
&m_context)) {
@ -125,6 +135,9 @@ bool RegisterContextWindows::CacheAllRegisterValues() {
::GetLastError());
return false;
}
if (!::ResumeThread(wthread.GetHostThread().GetNativeThread().GetSystemHandle())) {
return false;
}
LLDB_LOG(log, "successfully updated the register values.");
m_context_stale = false;
return true;

View File

@ -24,6 +24,11 @@ using namespace lldb_private;
#define DEFINE_GPR(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatHexUppercase
#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatBinary
#define DEFINE_FPU_XMM(reg) \
#reg, NULL, 16, 0, eEncodingUint, eFormatVectorOfUInt64, \
{dwarf_##reg##_x86_64, dwarf_##reg##_x86_64, LLDB_INVALID_REGNUM, \
LLDB_INVALID_REGNUM, lldb_##reg##_x86_64}, \
nullptr, nullptr, nullptr, 0
namespace {
@ -51,7 +56,24 @@ enum RegisterIndex {
eRegisterIndexR14,
eRegisterIndexR15,
eRegisterIndexRip,
eRegisterIndexRflags
eRegisterIndexRflags,
eRegisterIndexXmm0,
eRegisterIndexXmm1,
eRegisterIndexXmm2,
eRegisterIndexXmm3,
eRegisterIndexXmm4,
eRegisterIndexXmm5,
eRegisterIndexXmm6,
eRegisterIndexXmm7,
eRegisterIndexXmm8,
eRegisterIndexXmm9,
eRegisterIndexXmm10,
eRegisterIndexXmm11,
eRegisterIndexXmm12,
eRegisterIndexXmm13,
eRegisterIndexXmm14,
eRegisterIndexXmm15
};
// Array of all register information supported by Windows x86
@ -133,14 +155,14 @@ RegisterInfo g_register_infos[] = {
nullptr,
0},
{DEFINE_GPR(r10, nullptr),
{dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_REGNUM_GENERIC_ARG5,
{dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM, lldb_r10_x86_64},
nullptr,
nullptr,
nullptr,
0},
{DEFINE_GPR(r11, nullptr),
{dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_REGNUM_GENERIC_ARG6,
{dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM, lldb_r11_x86_64},
nullptr,
nullptr,
@ -188,6 +210,22 @@ RegisterInfo g_register_infos[] = {
nullptr,
nullptr,
0},
{DEFINE_FPU_XMM(xmm0)},
{DEFINE_FPU_XMM(xmm1)},
{DEFINE_FPU_XMM(xmm2)},
{DEFINE_FPU_XMM(xmm3)},
{DEFINE_FPU_XMM(xmm4)},
{DEFINE_FPU_XMM(xmm5)},
{DEFINE_FPU_XMM(xmm6)},
{DEFINE_FPU_XMM(xmm7)},
{DEFINE_FPU_XMM(xmm8)},
{DEFINE_FPU_XMM(xmm9)},
{DEFINE_FPU_XMM(xmm10)},
{DEFINE_FPU_XMM(xmm11)},
{DEFINE_FPU_XMM(xmm12)},
{DEFINE_FPU_XMM(xmm13)},
{DEFINE_FPU_XMM(xmm14)},
{DEFINE_FPU_XMM(xmm15)}
};
static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
@ -202,10 +240,20 @@ uint32_t g_gpr_reg_indices[] = {
eRegisterIndexR12, eRegisterIndexR13, eRegisterIndexR14,
eRegisterIndexR15, eRegisterIndexRip, eRegisterIndexRflags};
uint32_t g_fpu_reg_indices[] = {
eRegisterIndexXmm0, eRegisterIndexXmm1, eRegisterIndexXmm2,
eRegisterIndexXmm3, eRegisterIndexXmm4, eRegisterIndexXmm5,
eRegisterIndexXmm6, eRegisterIndexXmm7, eRegisterIndexXmm8,
eRegisterIndexXmm9, eRegisterIndexXmm10, eRegisterIndexXmm11,
eRegisterIndexXmm12, eRegisterIndexXmm13, eRegisterIndexXmm14,
eRegisterIndexXmm15
};
RegisterSet g_register_sets[] = {
{"General Purpose Registers", "gpr",
llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices},
};
{"Floating Point Registers", "fpu",
llvm::array_lengthof(g_fpu_reg_indices), g_fpu_reg_indices}};
}
// Constructors and Destructors
@ -242,7 +290,9 @@ bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info,
if (reg_info == nullptr)
return false;
switch (reg_info->kinds[eRegisterKindLLDB]) {
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
switch (reg) {
case lldb_rax_x86_64:
reg_value.SetUInt64(m_context.Rax);
break;
@ -297,6 +347,70 @@ bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info,
case lldb_rflags_x86_64:
reg_value.SetUInt64(m_context.EFlags);
break;
case lldb_xmm0_x86_64:
reg_value.SetBytes(&m_context.Xmm0,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm1_x86_64:
reg_value.SetBytes(&m_context.Xmm1,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm2_x86_64:
reg_value.SetBytes(&m_context.Xmm2,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm3_x86_64:
reg_value.SetBytes(&m_context.Xmm3,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm4_x86_64:
reg_value.SetBytes(&m_context.Xmm4,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm5_x86_64:
reg_value.SetBytes(&m_context.Xmm5,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm6_x86_64:
reg_value.SetBytes(&m_context.Xmm6,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm7_x86_64:
reg_value.SetBytes(&m_context.Xmm7,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm8_x86_64:
reg_value.SetBytes(&m_context.Xmm8,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm9_x86_64:
reg_value.SetBytes(&m_context.Xmm9,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm10_x86_64:
reg_value.SetBytes(&m_context.Xmm10,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm11_x86_64:
reg_value.SetBytes(&m_context.Xmm11,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm12_x86_64:
reg_value.SetBytes(&m_context.Xmm12,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm13_x86_64:
reg_value.SetBytes(&m_context.Xmm13,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm14_x86_64:
reg_value.SetBytes(&m_context.Xmm14,
reg_info->byte_size, endian::InlHostByteOrder());
break;
case lldb_xmm15_x86_64:
reg_value.SetBytes(&m_context.Xmm15,
reg_info->byte_size, endian::InlHostByteOrder());
break;
}
return true;
}
@ -365,6 +479,54 @@ bool RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info,
case lldb_rflags_x86_64:
m_context.EFlags = reg_value.GetAsUInt64();
break;
case lldb_xmm0_x86_64:
memcpy(&m_context.Xmm0, reg_value.GetBytes(), 16);
break;
case lldb_xmm1_x86_64:
memcpy(&m_context.Xmm1, reg_value.GetBytes(), 16);
break;
case lldb_xmm2_x86_64:
memcpy(&m_context.Xmm2, reg_value.GetBytes(), 16);
break;
case lldb_xmm3_x86_64:
memcpy(&m_context.Xmm3, reg_value.GetBytes(), 16);
break;
case lldb_xmm4_x86_64:
memcpy(&m_context.Xmm4, reg_value.GetBytes(), 16);
break;
case lldb_xmm5_x86_64:
memcpy(&m_context.Xmm5, reg_value.GetBytes(), 16);
break;
case lldb_xmm6_x86_64:
memcpy(&m_context.Xmm6, reg_value.GetBytes(), 16);
break;
case lldb_xmm7_x86_64:
memcpy(&m_context.Xmm7, reg_value.GetBytes(), 16);
break;
case lldb_xmm8_x86_64:
memcpy(&m_context.Xmm8, reg_value.GetBytes(), 16);
break;
case lldb_xmm9_x86_64:
memcpy(&m_context.Xmm9, reg_value.GetBytes(), 16);
break;
case lldb_xmm10_x86_64:
memcpy(&m_context.Xmm10, reg_value.GetBytes(), 16);
break;
case lldb_xmm11_x86_64:
memcpy(&m_context.Xmm11, reg_value.GetBytes(), 16);
break;
case lldb_xmm12_x86_64:
memcpy(&m_context.Xmm12, reg_value.GetBytes(), 16);
break;
case lldb_xmm13_x86_64:
memcpy(&m_context.Xmm13, reg_value.GetBytes(), 16);
break;
case lldb_xmm14_x86_64:
memcpy(&m_context.Xmm14, reg_value.GetBytes(), 16);
break;
case lldb_xmm15_x86_64:
memcpy(&m_context.Xmm15, reg_value.GetBytes(), 16);
break;
}
// Physically update the registers in the target process.