File: ArchitectureAArch64.cpp

package info (click to toggle)
llvm-toolchain-20 1%3A20.1.8-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,111,696 kB
  • sloc: cpp: 7,438,781; ansic: 1,393,871; asm: 1,012,926; python: 241,771; f90: 86,635; objc: 75,411; lisp: 42,144; pascal: 17,286; sh: 8,596; ml: 5,082; perl: 4,730; makefile: 3,591; awk: 3,523; javascript: 2,251; xml: 892; fortran: 672
file content (143 lines) | stat: -rw-r--r-- 5,304 bytes parent folder | download | duplicates (8)
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//===-- 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 (!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;

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