[Lldb-commits] [lldb] [llvm] [lldb] Add initial MicrosoftABIRuntime (PR #235090)

Charles Zablit via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 2 11:52:07 PST 2026


================
@@ -0,0 +1,426 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "MicrosoftABIRuntime.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "clang/AST/RecordLayout.h"
+
+#include <deque>
+#include <mutex>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const llvm::StringRef s_vtable_demangled_indicator = "::`vftable'";
+static const llvm::StringRef s_rtti_complete_object_locator_indicator =
+    "::`RTTI Complete Object Locator'";
+
+static llvm::StringRef StripDemangledVTableSuffix(llvm::StringRef demangled) {
+  llvm::StringRef name = demangled.split(s_vtable_demangled_indicator).first;
+  name.consume_front("const ");
+  return name;
+}
+
+static bool
+SplitVTableComponents(llvm::StringRef demangled,
+                      llvm::SmallVectorImpl<llvm::StringRef> &components) {
+  llvm::StringRef suffix = demangled.split(s_vtable_demangled_indicator).second;
+  if (suffix.empty())
+    return true; // e.g. MyClass::`vftable'
+
+  // Otherwise, suffix looks like "{for `MyBase2's `MyBase1'}" or
+  // "{for `MyBase'}".
+  if (!suffix.consume_front("{for `") || !suffix.consume_back("'}"))
+    return false;
+
+  suffix.split(components, "'s `");
+  return true;
+}
+
+MicrosoftABIRuntime::MicrosoftABIRuntime(Process *process)
+    : CommonABIRuntime(process) {}
+
+bool MicrosoftABIRuntime::GetDynamicTypeAndAddress(
+    ValueObject &in_value, lldb::DynamicValueType use_dynamic,
+    const LanguageRuntime::VTableInfo &vtable_info,
+    TypeAndOrName &class_type_or_name, Address &dynamic_address) {
+  std::optional<size_t> offset_to_top =
+      GetOffsetToTop(in_value, class_type_or_name, vtable_info);
+  if (!offset_to_top)
+    return false;
+
+  lldb::addr_t dynamic_addr =
+      in_value.GetPointerValue().address - *offset_to_top;
+  if (!m_process->GetTarget().ResolveLoadAddress(dynamic_addr, dynamic_address))
+    dynamic_address.SetRawAddress(dynamic_addr);
+
+  return true;
+}
+
+bool MicrosoftABIRuntime::IsVTableSymbol(Mangled &mangled) const {
+  return mangled.GetDemangledName().GetStringRef().contains(
+      s_vtable_demangled_indicator);
+}
+
+TypeAndOrName MicrosoftABIRuntime::GetTypeInfo(
+    ValueObject &in_value, const LanguageRuntime::VTableInfo &vtable_info,
+    llvm::SmallVectorImpl<llvm::StringRef> &vtable_components) {
+  if (!vtable_info.addr.IsSectionOffset() || !vtable_info.symbol)
+    return {};
+
+  // See if we have cached info for this type already
+  TypeAndOrName type_info = GetDynamicTypeInfo(vtable_info.addr);
+  if (type_info)
+    return type_info;
+
+  Log *log = GetLog(LLDBLog::Object);
+  llvm::StringRef symbol_name =
+      vtable_info.symbol->GetMangled().GetDemangledName().GetStringRef();
+  if (!SplitVTableComponents(symbol_name, vtable_components)) {
+    LLDB_LOG(log, "{0:x16}: '{1}' is not a valid vtable symbol",
+             in_value.GetPointerValue().address, symbol_name);
+    return {};
+  }
+
+  llvm::StringRef class_name = StripDemangledVTableSuffix(symbol_name);
+
+  type_info.SetName(class_name);
+  bool any_found = false;
+  TypeSP type_sp = LookupTypeByName(
+      class_name, vtable_info.symbol->CalculateSymbolContextModule(),
+      any_found);
+  if (!any_found)
+    return TypeAndOrName(); // Type is not dynamic.
+
+  if (type_sp) {
+    LLDB_LOG(log,
+             "static-type = '{0}' has dynamic type: uid={1:x}, type-name='{2}'",
+             in_value.GetTypeName(), type_sp->GetID(), type_sp->GetName());
+    type_info.SetTypeSP(std::move(type_sp));
+  }
+
+  if (type_info)
+    SetDynamicTypeInfo(vtable_info.addr, type_info);
+  return type_info;
+}
+
+std::optional<int64_t> MicrosoftABIRuntime::GetOffsetToTop(
+    ValueObject &in_value, TypeAndOrName &class_type_or_name,
+    const LanguageRuntime::VTableInfo &vtable_info) {
+  Log *log = GetLog(LLDBLog::Object);
+
+  llvm::SmallVector<llvm::StringRef, 2> vtable_components;
+  class_type_or_name = GetTypeInfo(in_value, vtable_info, vtable_components);
+  if (!class_type_or_name) {
+    LLDB_LOG(log, "{0:x16}: failed to get type info",
+             in_value.GetPointerValue().address);
+    return std::nullopt;
+  }
+
+  {
+    std::scoped_lock<std::mutex> g(m_mutex);
+    auto offset_to_top_it = m_offset_to_top_map.find(vtable_info.addr);
+    if (offset_to_top_it != m_offset_to_top_map.end())
+      return offset_to_top_it->second;
+  }
+
+  CompilerType type = class_type_or_name.GetCompilerType();
+  if (!type) {
+    LLDB_LOG(log, "{0:x16}: failed to get type info (no compiler type)",
+             in_value.GetPointerValue().address);
+    return std::nullopt;
+  }
+
+  CompilerType in_type = in_value.GetCompilerType();
+  if (in_type.IsPointerOrReferenceType())
+    in_type = in_type.GetPointeeType();
+  if (!in_type.GetCompleteType()) {
+    LLDB_LOG(log, "{0:x16}: {1} is not a complete type",
+             in_value.GetPointerValue().address, in_type.GetTypeName());
+    return std::nullopt;
+  }
+  if (!type.GetCompleteType()) {
+    LLDB_LOG(log, "{0:x16}: {1} is not a complete type",
+             in_value.GetPointerValue().address,
+             type.GetTypeName().GetCString());
+    return std::nullopt;
+  }
+
+  if (TypeSystemClang::AreTypesSame(in_type, type)) {
+    LLDB_LOG(log, "{0:x16}: in type is the same as the dynamic type",
+             in_value.GetPointerValue().address);
+
+    // The dynamic type we found was the same type, so we don't have a
+    // dynamic type here, but if a derived type encounters this vtable symbol,
+    // remember that it has offset 0.
+    std::scoped_lock<std::mutex> g(m_mutex);
+    m_offset_to_top_map[vtable_info.addr] = 0;
----------------
charles-zablit wrote:

Sounds good.

https://github.com/llvm/llvm-project/pull/235090


More information about the lldb-commits mailing list