[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Wed Jun 25 18:46:38 PDT 2025
================
@@ -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
More information about the lldb-commits
mailing list