================ @@ -0,0 +1,293 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( + Thread &thread, uint32_t concrete_frame_idx, + RegisterContextSP core_thread_regctx_sp, + StructuredData::ObjectSP metadata_thread_registers) + : RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { + metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); + if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) + metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added. If the thread metadata registers specify + // a set with the same name, the already-used index from the + // core register context will be used. + std::map<size_t, size_t> metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { + const RegisterInfo *reginfo = + core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); + core_buffer_end = + std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { + StructuredData::Array *registers = nullptr; + if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { + uint32_t bitsize; + if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; + combined_buffer_end += (bitsize / 8); + return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { + const RegisterInfo *reginfo = + core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); + RegisterValue val; + if (!reginfo->value_regs && + core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { + size_t offset = core_buffer_end; + ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); + StructuredData::Array *registers; + if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { + uint64_t bitsize; + uint64_t value; + if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; + if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("value", value)) { + // we had a bitsize but no value, so move the offset forward I guess. + offset += (bitsize / 8); + return false; + } + ent->GetAsDictionary()->AddIntegerItem("offset", offset); + Status error; + switch (bitsize / 8) { + case 2: { + Scalar value_scalar((uint16_t)value); + value_scalar.GetAsMemoryData(m_register_data.data() + offset, 2, + byte_order, error); + offset += 2; + } break; + case 4: { + Scalar value_scalar((uint32_t)value); + value_scalar.GetAsMemoryData(m_register_data.data() + offset, 4, + byte_order, error); + offset += 4; + } break; + case 8: { + Scalar value_scalar((uint64_t)value); + value_scalar.GetAsMemoryData(m_register_data.data() + offset, 8, + byte_order, error); + offset += 8; + } break; + } + return true; + }); + } + + // Create a DynamicRegisterInfo from the metadata JSON. + std::unique_ptr<DynamicRegisterInfo> additional_reginfo_up; + if (metadata_registers_dict) + additional_reginfo_up = DynamicRegisterInfo::Create( + *metadata_registers_dict, target.GetArchitecture()); + ---------------- jasonmolenda wrote:
I don't prefer larger, multi-line ternary operators like this, just a personal preference. In this case the original code is fewer lines than using the ternary operator. https://github.com/llvm/llvm-project/pull/144627 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits