313 lines · cpp
1//===-- RegisterContextUnifiedCore.cpp ------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "RegisterContextUnifiedCore.h"10#include "lldb/Target/DynamicRegisterInfo.h"11#include "lldb/Target/Process.h"12#include "lldb/Utility/DataExtractor.h"13#include "lldb/Utility/RegisterValue.h"14#include "lldb/Utility/StructuredData.h"15 16using namespace lldb;17using namespace lldb_private;18 19RegisterContextUnifiedCore::RegisterContextUnifiedCore(20 Thread &thread, uint32_t concrete_frame_idx,21 RegisterContextSP core_thread_regctx_sp,22 StructuredData::ObjectSP metadata_thread_registers)23 : RegisterContext(thread, concrete_frame_idx) {24 25 ProcessSP process_sp(thread.GetProcess());26 Target &target = process_sp->GetTarget();27 StructuredData::Dictionary *metadata_registers_dict = nullptr;28 29 // If we have thread metadata, check if the keys for register30 // definitions are present; if not, clear the ObjectSP.31 if (metadata_thread_registers &&32 metadata_thread_registers->GetAsDictionary() &&33 metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) {34 metadata_registers_dict = metadata_thread_registers->GetAsDictionary()35 ->GetValueForKey("register_info")36 ->GetAsDictionary();37 if (metadata_registers_dict)38 if (!metadata_registers_dict->HasKey("sets") ||39 !metadata_registers_dict->HasKey("registers"))40 metadata_registers_dict = nullptr;41 }42 43 // When creating a register set list from the two sources,44 // the LC_THREAD aka core_thread_regctx_sp register sets45 // will be used at the same indexes.46 // Any additional sets named by the thread metadata registers47 // will be added after them. If the thread metadata48 // specify a set with the same name as LC_THREAD, the already-used49 // index from the core register context will be used in50 // the RegisterInfo.51 std::map<size_t, size_t> metadata_regset_to_combined_regset;52 53 // Calculate the total size of the register store buffer we need54 // for all registers. The corefile register definitions may include55 // RegisterInfo descriptions of registers that aren't actually56 // available. For simplicity, calculate the size of all registers57 // as if they are available, so we can maintain the same offsets into58 // the buffer.59 uint32_t core_buffer_end = 0;60 for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) {61 const RegisterInfo *reginfo =62 core_thread_regctx_sp->GetRegisterInfoAtIndex(idx);63 core_buffer_end =64 std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end);65 }66 67 // Add metadata register sizes to the total buffer size.68 uint32_t combined_buffer_end = core_buffer_end;69 if (metadata_registers_dict) {70 StructuredData::Array *registers = nullptr;71 if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers))72 registers->ForEach(73 [&combined_buffer_end](StructuredData::Object *ent) -> bool {74 uint32_t bitsize;75 if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize",76 bitsize))77 return false;78 combined_buffer_end += (bitsize / 8);79 return true;80 });81 }82 m_register_data.resize(combined_buffer_end, 0);83 84 // Copy the core register values into our combined data buffer,85 // skip registers that are contained within another (e.g. w0 vs. x0)86 // and registers that return as "unavailable".87 for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) {88 const RegisterInfo *reginfo =89 core_thread_regctx_sp->GetRegisterInfoAtIndex(idx);90 RegisterValue val;91 if (!reginfo->value_regs &&92 core_thread_regctx_sp->ReadRegister(reginfo, val))93 memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(),94 val.GetByteSize());95 }96 97 // Set 'offset' fields for each register definition into our combined98 // register data buffer. DynamicRegisterInfo needs this field set to99 // parse the JSON.100 // Also copy the values of the registers into our register data buffer.101 if (metadata_registers_dict) {102 size_t offset = core_buffer_end;103 ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder();104 StructuredData::Array *registers;105 if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers))106 registers->ForEach([this, &offset,107 byte_order](StructuredData::Object *ent) -> bool {108 uint64_t bitsize;109 uint64_t value;110 if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize",111 bitsize))112 return false;113 if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("value", value)) {114 // We had a bitsize but no value, so move the offset forward I guess.115 offset += (bitsize / 8);116 return false;117 }118 ent->GetAsDictionary()->AddIntegerItem("offset", offset);119 Status error;120 const int bytesize = bitsize / 8;121 switch (bytesize) {122 case 2: {123 Scalar value_scalar((uint16_t)value);124 value_scalar.GetAsMemoryData(m_register_data.data() + offset,125 bytesize, byte_order, error);126 offset += bytesize;127 } break;128 case 4: {129 Scalar value_scalar((uint32_t)value);130 value_scalar.GetAsMemoryData(m_register_data.data() + offset,131 bytesize, byte_order, error);132 offset += bytesize;133 } break;134 case 8: {135 Scalar value_scalar((uint64_t)value);136 value_scalar.GetAsMemoryData(m_register_data.data() + offset,137 bytesize, byte_order, error);138 offset += bytesize;139 } break;140 }141 return true;142 });143 }144 145 // Create a DynamicRegisterInfo from the metadata JSON.146 std::unique_ptr<DynamicRegisterInfo> additional_reginfo_up;147 if (metadata_registers_dict)148 additional_reginfo_up = DynamicRegisterInfo::Create(149 *metadata_registers_dict, target.GetArchitecture());150 151 // Put the RegisterSet names in the constant string pool,152 // to sidestep lifetime issues of char*'s.153 auto copy_regset_name = [](RegisterSet &dst, const RegisterSet &src) {154 dst.name = ConstString(src.name).AsCString();155 if (src.short_name)156 dst.short_name = ConstString(src.short_name).AsCString();157 else158 dst.short_name = nullptr;159 };160 161 // Copy the core thread register sets into our combined register set list.162 // RegisterSet indexes will be identical for the LC_THREAD RegisterContext.163 for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterSetCount();164 idx++) {165 RegisterSet new_set;166 const RegisterSet *old_set = core_thread_regctx_sp->GetRegisterSet(idx);167 copy_regset_name(new_set, *old_set);168 m_register_sets.push_back(new_set);169 }170 171 // Add any additional metadata RegisterSets to our combined RegisterSet array.172 if (additional_reginfo_up) {173 for (size_t idx = 0; idx < additional_reginfo_up->GetNumRegisterSets();174 idx++) {175 // See if this metadata RegisterSet name matches one already present176 // from the LC_THREAD RegisterContext.177 bool found_match = false;178 const RegisterSet *old_set = additional_reginfo_up->GetRegisterSet(idx);179 for (size_t jdx = 0; jdx < m_register_sets.size(); jdx++) {180 if (strcmp(m_register_sets[jdx].name, old_set->name) == 0) {181 metadata_regset_to_combined_regset[idx] = jdx;182 found_match = true;183 break;184 }185 }186 // This metadata RegisterSet is a new one.187 // Add it to the combined RegisterSet array.188 if (!found_match) {189 RegisterSet new_set;190 copy_regset_name(new_set, *old_set);191 metadata_regset_to_combined_regset[idx] = m_register_sets.size();192 m_register_sets.push_back(new_set);193 }194 }195 }196 197 // Set up our combined RegisterInfo array, one RegisterSet at a time.198 for (size_t combined_regset_idx = 0;199 combined_regset_idx < m_register_sets.size(); combined_regset_idx++) {200 uint32_t registers_this_regset = 0;201 202 // Copy all LC_THREAD RegisterInfos that have a value into our203 // combined RegisterInfo array. (the LC_THREAD RegisterContext204 // may describe registers that were not provided in this thread)205 //206 // LC_THREAD register set indexes are identical to the combined207 // register set indexes. The combined register set array may have208 // additional entries.209 if (combined_regset_idx < core_thread_regctx_sp->GetRegisterSetCount()) {210 const RegisterSet *regset =211 core_thread_regctx_sp->GetRegisterSet(combined_regset_idx);212 // Copy all the registers that have values in.213 for (size_t j = 0; j < regset->num_registers; j++) {214 uint32_t reg_idx = regset->registers[j];215 const RegisterInfo *reginfo =216 core_thread_regctx_sp->GetRegisterInfoAtIndex(reg_idx);217 RegisterValue val;218 if (!reginfo->value_regs &&219 core_thread_regctx_sp->ReadRegister(reginfo, val)) {220 m_regset_regnum_collection[combined_regset_idx].push_back(221 m_register_infos.size());222 m_register_infos.push_back(*reginfo);223 registers_this_regset++;224 }225 }226 }227 228 // Copy all the metadata RegisterInfos into our combined combined229 // RegisterInfo array.230 // The metadata may add registers to one of the LC_THREAD register sets,231 // or its own newly added register sets. metadata_regset_to_combined_regset232 // has the association of the RegisterSet indexes between the two.233 if (additional_reginfo_up) {234 // Find the register set in the metadata that matches this register235 // set, then copy all its RegisterInfos.236 for (size_t setidx = 0;237 setidx < additional_reginfo_up->GetNumRegisterSets(); setidx++) {238 if (metadata_regset_to_combined_regset[setidx] == combined_regset_idx) {239 const RegisterSet *regset =240 additional_reginfo_up->GetRegisterSet(setidx);241 for (size_t j = 0; j < regset->num_registers; j++) {242 uint32_t reg_idx = regset->registers[j];243 const RegisterInfo *reginfo =244 additional_reginfo_up->GetRegisterInfoAtIndex(reg_idx);245 m_regset_regnum_collection[combined_regset_idx].push_back(246 m_register_infos.size());247 m_register_infos.push_back(*reginfo);248 registers_this_regset++;249 }250 }251 }252 }253 m_register_sets[combined_regset_idx].num_registers = registers_this_regset;254 m_register_sets[combined_regset_idx].registers =255 m_regset_regnum_collection[combined_regset_idx].data();256 }257}258 259size_t RegisterContextUnifiedCore::GetRegisterCount() {260 return m_register_infos.size();261}262 263const RegisterInfo *264RegisterContextUnifiedCore::GetRegisterInfoAtIndex(size_t reg) {265 if (reg < m_register_infos.size())266 return &m_register_infos[reg];267 return nullptr;268}269 270size_t RegisterContextUnifiedCore::GetRegisterSetCount() {271 return m_register_sets.size();272}273 274const RegisterSet *RegisterContextUnifiedCore::GetRegisterSet(size_t set) {275 if (set < m_register_sets.size())276 return &m_register_sets[set];277 return nullptr;278}279 280bool RegisterContextUnifiedCore::ReadRegister(281 const lldb_private::RegisterInfo *reg_info,282 lldb_private::RegisterValue &value) {283 if (!reg_info)284 return false;285 if (ProcessSP process_sp = m_thread.GetProcess()) {286 DataExtractor regdata(m_register_data.data(), m_register_data.size(),287 process_sp->GetByteOrder(),288 process_sp->GetAddressByteSize());289 offset_t offset = reg_info->byte_offset;290 switch (reg_info->byte_size) {291 case 2:292 value.SetUInt16(regdata.GetU16(&offset));293 break;294 case 4:295 value.SetUInt32(regdata.GetU32(&offset));296 break;297 case 8:298 value.SetUInt64(regdata.GetU64(&offset));299 break;300 default:301 return false;302 }303 return true;304 }305 return false;306}307 308bool RegisterContextUnifiedCore::WriteRegister(309 const lldb_private::RegisterInfo *reg_info,310 const lldb_private::RegisterValue &value) {311 return false;312}313