Files
TheRock/compiler/amd-llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

166 lines
6.1 KiB
C++

//===-- ArchitectureAArch64.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 "Plugins/Architecture/AArch64/ArchitectureAArch64.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/DataExtractor.h"
#include "llvm/Support/Endian.h"
using namespace lldb_private;
using namespace lldb;
LLDB_PLUGIN_DEFINE(ArchitectureAArch64)
void ArchitectureAArch64::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
"AArch64-specific algorithms",
&ArchitectureAArch64::Create);
}
void ArchitectureAArch64::Terminate() {
PluginManager::UnregisterPlugin(&ArchitectureAArch64::Create);
}
std::unique_ptr<Architecture>
ArchitectureAArch64::Create(const ArchSpec &arch) {
auto machine = arch.GetMachine();
if (machine != llvm::Triple::aarch64 && machine != llvm::Triple::aarch64_be &&
machine != llvm::Triple::aarch64_32) {
return nullptr;
}
return std::unique_ptr<Architecture>(new ArchitectureAArch64());
}
static void
UpdateARM64SVERegistersInfos(DynamicRegisterInfo::reg_collection_range regs,
uint64_t vg) {
// SVE Z register size is vg x 8 bytes.
uint32_t z_reg_byte_size = vg * 8;
// SVE vector length has changed, accordingly set size of Z, P and FFR
// registers. Also invalidate register offsets it will be recalculated
// after SVE register size update.
for (auto &reg : regs) {
if (reg.value_regs == nullptr) {
if (reg.name[0] == 'z' && isdigit(reg.name[1]))
reg.byte_size = z_reg_byte_size;
else if (reg.name[0] == 'p' && isdigit(reg.name[1]))
reg.byte_size = vg;
else if (strcmp(reg.name, "ffr") == 0)
reg.byte_size = vg;
}
reg.byte_offset = LLDB_INVALID_INDEX32;
}
}
static void
UpdateARM64SMERegistersInfos(DynamicRegisterInfo::reg_collection_range regs,
uint64_t svg) {
for (auto &reg : regs) {
if (strcmp(reg.name, "za") == 0) {
// ZA is a register with size (svg*8) * (svg*8). A square essentially.
reg.byte_size = (svg * 8) * (svg * 8);
}
reg.byte_offset = LLDB_INVALID_INDEX32;
}
}
bool ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo &reg_info,
DataExtractor &reg_data,
RegisterContext &reg_context
) const {
// Once we start to reconfigure registers, we cannot read any of them.
// So we must read VG and SVG up front.
const uint64_t fail_value = LLDB_INVALID_ADDRESS;
std::optional<uint64_t> vg_reg_value;
const RegisterInfo *vg_reg_info = reg_info.GetRegisterInfo("vg");
if (vg_reg_info) {
uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB];
uint64_t reg_value =
reg_context.ReadRegisterAsUnsigned(vg_reg_num, fail_value);
if (reg_value != fail_value && reg_value <= 32)
vg_reg_value = reg_value;
}
std::optional<uint64_t> svg_reg_value;
const RegisterInfo *svg_reg_info = reg_info.GetRegisterInfo("svg");
if (svg_reg_info) {
uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB];
uint64_t reg_value =
reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value);
if (reg_value != fail_value && reg_value <= 32)
svg_reg_value = reg_value;
}
if (!svg_reg_value) {
const RegisterInfo *darwin_svg_reg_info = reg_info.GetRegisterInfo("svl");
if (darwin_svg_reg_info) {
uint32_t svg_reg_num = darwin_svg_reg_info->kinds[eRegisterKindLLDB];
uint64_t reg_value =
reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value);
// UpdateARM64SVERegistersInfos and UpdateARM64SMERegistersInfos
// expect the number of 8-byte granules; darwin provides number of
// bytes.
if (reg_value != fail_value && reg_value <= 256) {
svg_reg_value = reg_value / 8;
// Apple hardware only implements Streaming SVE mode, so
// the non-streaming Vector Length is not reported by the
// kernel. Set both svg and vg to this svl value.
if (!vg_reg_value)
vg_reg_value = reg_value / 8;
}
}
}
if (!vg_reg_value && !svg_reg_value)
return false;
if (!vg_reg_value) {
// This must be an SME only system, so VG == SVG.
vg_reg_value = svg_reg_value;
}
auto regs = reg_info.registers<DynamicRegisterInfo::reg_collection_range>();
if (vg_reg_value)
UpdateARM64SVERegistersInfos(regs, *vg_reg_value);
if (svg_reg_value)
UpdateARM64SMERegistersInfos(regs, *svg_reg_value);
// At this point if we have updated any registers, their offsets will all be
// invalid. If we did, we need to update them all.
reg_info.ConfigureOffsets();
// From here we are able to read registers again.
// Make a heap based buffer that is big enough to store all registers
reg_data.SetData(
std::make_shared<DataBufferHeap>(reg_info.GetRegisterDataByteSize(), 0));
reg_data.SetByteOrder(reg_context.GetByteOrder());
return true;
}
bool ArchitectureAArch64::IsValidTrapInstruction(
llvm::ArrayRef<uint8_t> reference, llvm::ArrayRef<uint8_t> observed) const {
if (reference.size() < 4 || observed.size() < 4)
return false;
auto ref_bytes = llvm::support::endian::read32le(reference.data());
auto bytes = llvm::support::endian::read32le(observed.data());
// Only the 11 highest bits define the breakpoint instruction, the others
// include an immediate value that we will explicitly check against.
uint32_t mask = 0xFFE00000;
// Check that the masked bytes match the reference, but also check that the
// immediate in the instruction is the default output by llvm.debugtrap.
// The reference has the immediate set as all-zero, so mask and check here.
return (ref_bytes == (bytes & mask)) && ((bytes & ~mask) >> 5 == 0xF000);
}