File: ArchitectureAArch64.cpp

package info (click to toggle)
llvm-toolchain-18 1%3A18.1.8-18
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,908,340 kB
  • sloc: cpp: 6,667,937; ansic: 1,440,452; asm: 883,619; python: 230,549; objc: 76,880; f90: 74,238; lisp: 35,989; pascal: 16,571; sh: 10,229; perl: 7,459; ml: 5,047; awk: 3,523; makefile: 2,987; javascript: 2,149; xml: 892; fortran: 649; cs: 573
file content (124 lines) | stat: -rw-r--r-- 4,466 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//===-- 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"

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 (!vg_reg_value && !svg_reg_value)
    return false;

  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;
}