Skip to content

Commit 8ec4d87

Browse files
authored
[lldb][elf-core][ARM] Add support for VFP registers (#155956)
This patch loads values of the VFP registers from the NT_ARM_VFP note. Note that a CORE/NT_FPREGSET note is typically present in core dump files and is used to store the FPA registers. The FPA unit is rare and obsolete; however, Linux creates the note even if the unit is absent.
1 parent 1e17113 commit 8ec4d87

File tree

6 files changed

+88
-6
lines changed

6 files changed

+88
-6
lines changed

lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(
2323
gpregset.GetByteSize());
2424
m_gpr.SetData(m_gpr_buffer);
2525
m_gpr.SetByteOrder(gpregset.GetByteOrder());
26+
27+
const llvm::Triple &target_triple =
28+
m_register_info_up->GetTargetArchitecture().GetTriple();
29+
m_fpr = getRegset(notes, target_triple, ARM_VFP_Desc);
2630
}
2731

2832
RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() = default;
@@ -43,14 +47,25 @@ bool RegisterContextCorePOSIX_arm::WriteFPR() {
4347

4448
bool RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info,
4549
RegisterValue &value) {
46-
lldb::offset_t offset = reg_info->byte_offset;
47-
if (offset + reg_info->byte_size <= GetGPRSize()) {
48-
uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
49-
if (offset == reg_info->byte_offset + reg_info->byte_size) {
50-
value = v;
51-
return true;
50+
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
51+
if (reg == LLDB_INVALID_REGNUM)
52+
return false;
53+
54+
if (IsGPR(reg)) {
55+
lldb::offset_t offset = reg_info->byte_offset;
56+
if (m_gpr.ValidOffsetForDataOfSize(offset, reg_info->byte_size)) {
57+
value = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
58+
return offset == reg_info->byte_offset + reg_info->byte_size;
5259
}
60+
} else if (IsFPR(reg)) {
61+
assert(reg_info->byte_offset >= GetGPRSize());
62+
lldb::offset_t offset = reg_info->byte_offset - GetGPRSize();
63+
if (m_fpr.ValidOffsetForDataOfSize(offset, reg_info->byte_size))
64+
return value
65+
.SetValueFromData(*reg_info, m_fpr, offset, /*partial_data_ok=*/false)
66+
.Success();
5367
}
68+
5469
return false;
5570
}
5671

lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class RegisterContextCorePOSIX_arm : public RegisterContextPOSIX_arm {
4848
private:
4949
lldb::DataBufferSP m_gpr_buffer;
5050
lldb_private::DataExtractor m_gpr;
51+
lldb_private::DataExtractor m_fpr;
5152
};
5253

5354
#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H

lldb/source/Plugins/Process/elf-core/RegisterUtilities.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ constexpr RegsetDesc AARCH64_GCS_Desc[] = {
152152
{llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_GCS},
153153
};
154154

155+
constexpr RegsetDesc ARM_VFP_Desc[] = {
156+
{llvm::Triple::FreeBSD, llvm::Triple::arm, llvm::ELF::NT_ARM_VFP},
157+
{llvm::Triple::Linux, llvm::Triple::arm, llvm::ELF::NT_ARM_VFP},
158+
};
159+
155160
constexpr RegsetDesc PPC_VMX_Desc[] = {
156161
{llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
157162
{llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},

lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,43 @@ def test_arm_core(self):
696696

697697
self.expect("register read --all")
698698

699+
@skipIfLLVMTargetMissing("ARM")
700+
def test_arm_core_vfp(self):
701+
# check reading VFP registers
702+
target = self.dbg.CreateTarget(None)
703+
self.assertTrue(target, VALID_TARGET)
704+
process = target.LoadCore("linux-arm-vfp.core")
705+
706+
values = {
707+
"d0": "0.5",
708+
"d1": "1.5",
709+
"d14": "14.5",
710+
"d15": "15.5",
711+
"s4": "4.5",
712+
"s5": "5.5",
713+
"s6": "6.5",
714+
"s7": "7.5",
715+
"fpscr": "0x20000000",
716+
# s0 and s1 overlap d0, s2 and s3 overlap d1 and so on. Therefore,
717+
# the following values are not as neat as those in the explicitly
718+
# set registers.
719+
"s0": "0",
720+
"s1": "1.75",
721+
"s2": "0",
722+
"s3": "1.9375",
723+
"s28": "0",
724+
"s29": "2.703125",
725+
"s30": "0",
726+
"s31": "2.734375",
727+
}
728+
for regname, value in values.items():
729+
self.expect(
730+
"register read {}".format(regname),
731+
substrs=["{} = {}".format(regname, value)],
732+
)
733+
734+
self.expect("register read --all")
735+
699736
@skipIfLLVMTargetMissing("RISCV")
700737
def test_riscv64_regs_gpr_fpr(self):
701738
# check basic registers using 64 bit RISC-V core file
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// linux-arm-vfp.core was generated with:
2+
// > gcc-12 -march=armv7+fp -nostdlib -static -Wl,--build-id=none \
3+
// linux-arm-vfp.c -o linux-arm-vfp.out
4+
// > ulimit -c 1000
5+
// > ulimit -s 8
6+
// > env -i ./linux-arm-vfp.out
7+
8+
static void foo(char *boom) {
9+
asm volatile(R"(
10+
vmov.f64 d0, #0.5
11+
vmov.f64 d1, #1.5
12+
vmov.f64 d14, #14.5
13+
vmov.f64 d15, #15.5
14+
vmov.f32 s4, #4.5
15+
vmov.f32 s5, #5.5
16+
vmov.f32 s6, #6.5
17+
vmov.f32 s7, #7.5
18+
vcmp.f32 s7, s6
19+
)");
20+
21+
*boom = 47;
22+
}
23+
24+
void _start(void) { foo(0); }
24 KB
Binary file not shown.

0 commit comments

Comments
 (0)