[lldb][RISCV] Add RegisterContextPOSIXCore for RISC-V 64 (#93297)

The PR adds the support of CoreDump debugging for RISC-V 64. It
implements new `RegisterContextCorePOSIX_riscv64` class.

Also, the contribution fixes `GetRegisterCount()` ->
`GetRegisterSetCount()` misprint in
`RegisterContextPOSIX_riscv64::GetRegisterSetCount()` method, which
leaded to `set && "Register set should be valid."` assertion during
`register info aX` command call.

The patch was tested (on coredumps generated for simple Integer/FP
calculation code) for _cross x86_64 -> RISCV_ and _native RISCV_ LLDB
builds. There were performed basic LLDB functionality tests, such as:

 - CoreDump file load
 - Backtrace / frames
 - GP/FP registers read/info/list
 - Basic switch between threads
 - Disassembler code
 - Memory regions read / display
This commit is contained in:
Alexey Merzlyakov
2024-06-05 12:14:48 +03:00
committed by GitHub
parent 8ab578a126
commit d3a9043ec2
8 changed files with 251 additions and 2 deletions

View File

@@ -58,7 +58,7 @@ RegisterContextPOSIX_riscv64::GetRegisterInfoAtIndex(size_t reg) {
}
size_t RegisterContextPOSIX_riscv64::GetRegisterSetCount() {
return m_register_info_up->GetRegisterCount();
return m_register_info_up->GetRegisterSetCount();
}
const lldb_private::RegisterSet *

View File

@@ -9,6 +9,7 @@ add_lldb_library(lldbPluginProcessElfCore PLUGIN
RegisterContextPOSIXCore_ppc64le.cpp
RegisterContextPOSIXCore_s390x.cpp
RegisterContextPOSIXCore_x86_64.cpp
RegisterContextPOSIXCore_riscv64.cpp
RegisterUtilities.cpp
LINK_LIBS

View File

@@ -0,0 +1,82 @@
//===-- RegisterContextPOSIXCore_riscv64.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 "RegisterContextPOSIXCore_riscv64.h"
#include "lldb/Utility/DataBufferHeap.h"
using namespace lldb_private;
std::unique_ptr<RegisterContextCorePOSIX_riscv64>
RegisterContextCorePOSIX_riscv64::Create(Thread &thread, const ArchSpec &arch,
const DataExtractor &gpregset,
llvm::ArrayRef<CoreNote> notes) {
return std::unique_ptr<RegisterContextCorePOSIX_riscv64>(
new RegisterContextCorePOSIX_riscv64(
thread, std::make_unique<RegisterInfoPOSIX_riscv64>(arch, Flags()),
gpregset, notes));
}
RegisterContextCorePOSIX_riscv64::RegisterContextCorePOSIX_riscv64(
Thread &thread, std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info,
const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
: RegisterContextPOSIX_riscv64(thread, std::move(register_info)) {
m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
gpregset.GetByteSize());
m_gpr.SetData(m_gpr_buffer);
m_gpr.SetByteOrder(gpregset.GetByteOrder());
ArchSpec arch = m_register_info_up->GetTargetArchitecture();
DataExtractor fpregset = getRegset(notes, arch.GetTriple(), FPR_Desc);
m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(),
fpregset.GetByteSize());
m_fpr.SetData(m_fpr_buffer);
m_fpr.SetByteOrder(fpregset.GetByteOrder());
}
RegisterContextCorePOSIX_riscv64::~RegisterContextCorePOSIX_riscv64() = default;
bool RegisterContextCorePOSIX_riscv64::ReadGPR() { return true; }
bool RegisterContextCorePOSIX_riscv64::ReadFPR() { return true; }
bool RegisterContextCorePOSIX_riscv64::WriteGPR() {
assert(false && "Writing registers is not allowed for core dumps");
return false;
}
bool RegisterContextCorePOSIX_riscv64::WriteFPR() {
assert(false && "Writing registers is not allowed for core dumps");
return false;
}
bool RegisterContextCorePOSIX_riscv64::ReadRegister(
const RegisterInfo *reg_info, RegisterValue &value) {
const uint8_t *src = nullptr;
lldb::offset_t offset = reg_info->byte_offset;
if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
src = m_gpr.GetDataStart();
} else if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
src = m_fpr.GetDataStart();
offset -= GetGPRSize();
} else {
return false;
}
Status error;
value.SetFromMemoryData(*reg_info, src + offset, reg_info->byte_size,
lldb::eByteOrderLittle, error);
return error.Success();
}
bool RegisterContextCorePOSIX_riscv64::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &value) {
return false;
}

View File

@@ -0,0 +1,60 @@
//===-- RegisterContextPOSIXCore_riscv64.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_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H
#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H
#include "Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"
#include "Plugins/Process/elf-core/RegisterUtilities.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/RegisterValue.h"
#include <memory>
class RegisterContextCorePOSIX_riscv64 : public RegisterContextPOSIX_riscv64 {
public:
static std::unique_ptr<RegisterContextCorePOSIX_riscv64>
Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch,
const lldb_private::DataExtractor &gpregset,
llvm::ArrayRef<lldb_private::CoreNote> notes);
~RegisterContextCorePOSIX_riscv64() override;
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value) override;
protected:
RegisterContextCorePOSIX_riscv64(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info,
const lldb_private::DataExtractor &gpregset,
llvm::ArrayRef<lldb_private::CoreNote> notes);
bool ReadGPR() override;
bool ReadFPR() override;
bool WriteGPR() override;
bool WriteFPR() override;
private:
lldb::DataBufferSP m_gpr_buffer;
lldb::DataBufferSP m_fpr_buffer;
lldb_private::DataExtractor m_gpr;
lldb_private::DataExtractor m_fpr;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H

View File

@@ -35,6 +35,7 @@
#include "RegisterContextPOSIXCore_mips64.h"
#include "RegisterContextPOSIXCore_powerpc.h"
#include "RegisterContextPOSIXCore_ppc64le.h"
#include "RegisterContextPOSIXCore_riscv64.h"
#include "RegisterContextPOSIXCore_s390x.h"
#include "RegisterContextPOSIXCore_x86_64.h"
#include "ThreadElfCore.h"
@@ -168,7 +169,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
}
if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 &&
arch.GetMachine() != llvm::Triple::arm) {
arch.GetMachine() != llvm::Triple::arm &&
arch.GetMachine() != llvm::Triple::riscv64) {
LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported",
__FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS());
assert(false && "Architecture or OS not supported");
@@ -184,6 +186,10 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
*this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data,
m_notes);
break;
case llvm::Triple::riscv64:
m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv64::Create(
*this, arch, m_gpregset_data, m_notes);
break;
case llvm::Triple::mipsel:
case llvm::Triple::mips:
m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(

View File

@@ -21,12 +21,14 @@ class LinuxCoreTestCase(TestBase):
_x86_64_pid = 32259
_s390x_pid = 1045
_ppc64le_pid = 28147
_riscv64_pid = 89328
_aarch64_regions = 4
_i386_regions = 4
_x86_64_regions = 5
_s390x_regions = 2
_ppc64le_regions = 2
_riscv64_regions = 4
@skipIfLLVMTargetMissing("AArch64")
def test_aarch64(self):
@@ -58,6 +60,11 @@ class LinuxCoreTestCase(TestBase):
"""Test that lldb can read the process information from an s390x linux core file."""
self.do_test("linux-s390x", self._s390x_pid, self._s390x_regions, "a.out")
@skipIfLLVMTargetMissing("RISCV")
def test_riscv64(self):
"""Test that lldb can read the process information from an riscv64 linux core file."""
self.do_test("linux-riscv64", self._riscv64_pid, self._riscv64_regions, "a.out")
@skipIfLLVMTargetMissing("X86")
def test_same_pid_running(self):
"""Test that we read the information from the core correctly even if we have a running
@@ -629,6 +636,99 @@ class LinuxCoreTestCase(TestBase):
self.expect("register read --all")
@skipIfLLVMTargetMissing("RISCV")
def test_riscv64_regs(self):
# check basic registers using 64 bit RISC-V core file
target = self.dbg.CreateTarget(None)
self.assertTrue(target, VALID_TARGET)
process = target.LoadCore("linux-riscv64.core")
values = {}
values["pc"] = "0x000000000001015e"
values["ra"] = "0x000000000001018c"
values["sp"] = "0x0000003fffd132a0"
values["gp"] = "0x0000002ae919af50"
values["tp"] = "0x0000003fdceae3e0"
values["t0"] = "0x0"
values["t1"] = "0x0000002ae9187b1c"
values["t2"] = "0x0000000000000021"
values["fp"] = "0x0000003fffd132d0"
values["s1"] = "0x0000002ae919cd98"
values["a0"] = "0x0"
values["a1"] = "0x0000000000010144"
values["a2"] = "0x0000002ae919cdb0"
values["a3"] = "0x000000000000002f"
values["a4"] = "0x000000000000002f"
values["a5"] = "0x0"
values["a6"] = "0x7efefefefefefeff"
values["a7"] = "0x00000000000000dd"
values["s2"] = "0x0000002ae9196860"
values["s3"] = "0x0000002ae919cdb0"
values["s4"] = "0x0000003fffc63be8"
values["s5"] = "0x0000002ae919cb78"
values["s6"] = "0x0000002ae9196860"
values["s7"] = "0x0000002ae9196860"
values["s8"] = "0x0"
values["s9"] = "0x000000000000000f"
values["s10"] = "0x0000002ae919a8d0"
values["s11"] = "0x0000000000000008"
values["t3"] = "0x0000003fdce07df4"
values["t4"] = "0x0"
values["t5"] = "0x0000000000000020"
values["t6"] = "0x0000002ae919f1b0"
values["zero"] = "0x0"
values["fcsr"] = "0x00000000"
fpr_names = {
"ft0",
"ft1",
"ft2",
"ft3",
"ft4",
"ft5",
"ft6",
"ft7",
"ft8",
"ft9",
"ft10",
"ft11",
"fa0",
"fa1",
"fa2",
"fa3",
"fa4",
"fa5",
"fa6",
"fa7",
"fs0",
"fs1",
"fs2",
"fs3",
"fs4",
"fs5",
"fs6",
"fs7",
"fs8",
"fs9",
"fs10",
"fs11",
}
fpr_value = "0x0000000000000000"
for regname, value in values.items():
self.expect(
"register read {}".format(regname),
substrs=["{} = {}".format(regname, value)],
)
for regname in fpr_names:
self.expect(
"register read {}".format(regname),
substrs=["{} = {}".format(regname, fpr_value)],
)
self.expect("register read --all")
def test_get_core_file_api(self):
"""
Test SBProcess::GetCoreFile() API can successfully get the core file.