[Lldb-commits] [lldb] [LLDB] Add AST node classes, functions, etc. for Data Inspection Lang… (PR #95738)

via lldb-commits lldb-commits at lists.llvm.org
Sat Jul 27 21:56:09 PDT 2024


================
@@ -0,0 +1,468 @@
+//===-- DILAST.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 "lldb/Core/DILAST.h"
+#include "lldb/API/SBType.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/RegisterContext.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <vector>
+
+namespace lldb_private {
+
+lldb::ValueObjectSP DILGetSPWithLock(lldb::ValueObjectSP in_valobj_sp,
+                                     lldb::DynamicValueType use_dynamic,
+                                     bool use_synthetic) {
+  Process::StopLocker stop_locker;
+  std::unique_lock<std::recursive_mutex> lock;
+  Status error;
+
+  if (!in_valobj_sp) {
+    error.SetErrorString("invalid value object");
+    return in_valobj_sp;
+  }
+
+  lldb::ValueObjectSP value_sp = in_valobj_sp;
+
+  Target *target = value_sp->GetTargetSP().get();
+  // If this ValueObject holds an error, then it is valuable for that.
+  if (value_sp->GetError().Fail())
+    return value_sp;
+
+  if (!target)
+    return lldb::ValueObjectSP();
+
+  lock = std::unique_lock<std::recursive_mutex>(target->GetAPIMutex());
+
+  lldb::ProcessSP process_sp(value_sp->GetProcessSP());
+  if (process_sp && !stop_locker.TryLock(&process_sp->GetRunLock())) {
+    // We don't allow people to play around with ValueObject if the process
+    // is running. If you want to look at values, pause the process, then
+    // look.
+    error.SetErrorString("process must be stopped.");
+    return lldb::ValueObjectSP();
+  }
+
+  if (use_dynamic != lldb::eNoDynamicValues) {
+    lldb::ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(use_dynamic);
+    if (dynamic_sp)
+      value_sp = dynamic_sp;
+  }
+
+  if (use_synthetic) {
+    lldb::ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue();
+    if (synthetic_sp)
+      value_sp = synthetic_sp;
+  }
+
+  if (!value_sp)
+    error.SetErrorString("invalid value object");
+
+  return value_sp;
+}
+
+CompilerType DILASTNode::result_type_deref() const {
+  auto type = result_type();
+  return type.IsReferenceType() ? type.GetNonReferenceType() : type;
+}
+
+static std::unordered_map<std::string, CompilerType> context_args;
+
+bool IsContextVar(const std::string &name) {
+  return context_args.find(name) != context_args.end();
+}
+
+static lldb::ValueObjectSP
+LookupStaticIdentifier(lldb::TargetSP target_sp,
+                       const llvm::StringRef &name_ref,
+                       ConstString unqualified_name) {
+  // List global variable with the same "basename". There can be many matches
+  // from other scopes (namespaces, classes), so we do additional filtering
+  // later.
+  std::vector<lldb::ValueObjectSP> values;
+  VariableList variable_list;
+  ConstString name(name_ref);
+  target_sp->GetImages().FindGlobalVariables(
+      name, (size_t)std::numeric_limits<uint32_t>::max, variable_list);
+  if (!variable_list.Empty()) {
+    ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get();
+    if (exe_scope == nullptr)
+      exe_scope = target_sp.get();
+    for (const lldb::VariableSP &var_sp : variable_list) {
+      lldb::ValueObjectSP valobj_sp(
+          ValueObjectVariable::Create(exe_scope, var_sp));
+      if (valobj_sp)
+        values.push_back(valobj_sp);
+    }
+  }
+
+  // Find the corrent variable by matching the name. lldb::SBValue::GetName()
+  // can return strings like "::globarVar", "ns::i" or "int const ns::foo"
+  // depending on the version and the platform.
+  for (uint32_t i = 0; i < values.size(); ++i) {
+    lldb::ValueObjectSP val = values[i];
+    llvm::StringRef val_name_sstr = val->GetName().GetStringRef();
+    llvm::StringRef name_sstr = name.GetStringRef();
+
+    if (val->GetVariable() && val->GetVariable()->NameMatches(unqualified_name))
+      return val;
+
+    if (val_name_sstr == name_sstr ||
+        val_name_sstr == llvm::formatv("::{0}", name_sstr).str() ||
+        val_name_sstr.ends_with(llvm::formatv(" {0}", name_sstr).str()) ||
+        val_name_sstr.ends_with(llvm::formatv("*{0}", name_sstr).str()) ||
+        val_name_sstr.ends_with(llvm::formatv("&{0}", name_sstr).str()))
+      return val;
+  }
+  lldb::ValueObjectSP empty_obj_sp;
+  return empty_obj_sp;
+}
+
+struct EnumMember {
+  CompilerType type;
+  ConstString name;
+  llvm::APSInt value;
+};
+
+static std::vector<EnumMember> GetEnumMembers(CompilerType type) {
+  std::vector<EnumMember> enum_member_list;
+  if (type.IsValid()) {
+    type.ForEachEnumerator(
+        [&enum_member_list](const CompilerType &integer_type, ConstString name,
+                            const llvm::APSInt &value) -> bool {
+          EnumMember enum_member = {integer_type, name, value};
+          enum_member_list.push_back(enum_member);
+          return true; // Keep iterating
+        });
+  }
+  return enum_member_list;
+}
+
+CompilerType
+ResolveTypeByName(const std::string &name,
+                  std::shared_ptr<ExecutionContextScope> ctx_scope) {
+  // Internally types don't have global scope qualifier in their names and
+  // LLDB doesn't support queries with it too.
+  llvm::StringRef name_ref(name);
+  bool global_scope = false;
+
+  if (name_ref.starts_with("::")) {
+    name_ref = name_ref.drop_front(2);
+    global_scope = true;
+  }
+
+  std::vector<CompilerType> result_type_list;
+  lldb::TargetSP target_sp = ctx_scope->CalculateTarget();
+  const char *type_name = name_ref.data();
+  if (type_name && type_name[0] && target_sp) {
+    ModuleList &images = target_sp->GetImages();
+    ConstString const_type_name(type_name);
+    TypeQuery query(type_name);
+    TypeResults results;
+    images.FindTypes(nullptr, query, results);
+    for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types())
+      if (type_sp)
+        result_type_list.push_back(type_sp->GetFullCompilerType());
+
+    if (auto process_sp = target_sp->GetProcessSP()) {
+      for (auto *runtime : process_sp->GetLanguageRuntimes()) {
+        if (auto *vendor = runtime->GetDeclVendor()) {
+          auto types = vendor->FindTypes(const_type_name, UINT32_MAX);
+          for (auto type : types)
+            result_type_list.push_back(type);
+        }
+      }
+    }
+
+    if (result_type_list.size() == 0) {
+      for (auto type_system_sp : target_sp->GetScratchTypeSystems())
+        if (auto compiler_type =
+                type_system_sp->GetBuiltinTypeByName(const_type_name))
+          result_type_list.push_back(compiler_type);
+    }
+  }
+
+  // We've found multiple types, try finding the "correct" one.
+  CompilerType full_match;
+  std::vector<CompilerType> partial_matches;
+
+  for (uint32_t i = 0; i < result_type_list.size(); ++i) {
+    CompilerType type = result_type_list[i];
+    llvm::StringRef type_name_ref = type.GetTypeName().GetStringRef();
+    ;
+
+    if (type_name_ref == name_ref)
+      full_match = type;
+    else if (type_name_ref.ends_with(name_ref))
+      partial_matches.push_back(type);
+  }
+
+  if (global_scope) {
+    // Look only for full matches when looking for a globally qualified type.
+    if (full_match.IsValid())
+      return full_match;
+  } else {
+    // We're looking for type, but there may be multiple candidates and which
+    // one is correct may depend on the currect scope. For now just pick the
+    // most "probable" type.
+
+    // Full match is always correct if we're currently in the global scope.
+    if (full_match.IsValid())
+      return full_match;
+
+    // If we have partial matches, pick a "random" one.
+    if (partial_matches.size() > 0)
+      return partial_matches.back();
+  }
+
+  CompilerType empty_type;
+  return empty_type;
+}
+
+static lldb::VariableSP DILFindVariable(ConstString name,
+                                        VariableList *variable_list) {
+  lldb::VariableSP exact_match;
+  std::vector<lldb::VariableSP> possible_matches;
+
+  typedef std::vector<lldb::VariableSP> collection;
+  typedef collection::iterator iterator;
+
+  iterator pos, end = variable_list->end();
+  for (pos = variable_list->begin(); pos != end; ++pos) {
+    llvm::StringRef str_ref_name = pos->get()->GetName().GetStringRef();
+    // Check for global vars, which might start with '::'.
+    if (str_ref_name.size() > 2 && str_ref_name[0] == ':' &&
+        str_ref_name[1] == ':')
+      str_ref_name = str_ref_name.drop_front(2);
+
+    ConstString tmp_name(str_ref_name);
+    if (tmp_name == name)
+      possible_matches.push_back(*pos);
+    else if (pos->get()->NameMatches(name))
+      possible_matches.push_back(*pos);
+  }
+
+  // Look for exact matches (favors local vars over global vars)
+  for (auto var_sp : possible_matches)
+    if (var_sp->GetName() == name) {
+      exact_match = var_sp;
+      break;
+    }
+
+  if (!exact_match)
+    // Look for a global var exact match.
+    for (auto var_sp : possible_matches) {
+      llvm::StringRef str_ref_name = var_sp->GetName().GetStringRef();
+      if (str_ref_name.size() > 2 && str_ref_name[0] == ':' &&
+          str_ref_name[1] == ':')
+        str_ref_name = str_ref_name.drop_front(2);
+      ConstString tmp_name(str_ref_name);
+      if (tmp_name == name) {
+        exact_match = var_sp;
+        break;
+      }
+    }
+
+  // Take any match at this point.
+  if (!exact_match && possible_matches.size() > 0)
+    exact_match = possible_matches[0];
+
+  return exact_match;
+}
+
+std::unique_ptr<IdentifierInfo>
+LookupIdentifier(const std::string &name,
+                 std::shared_ptr<ExecutionContextScope> ctx_scope,
+                 lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr) {
+  auto context_arg = context_args.find(name);
+  if (context_arg != context_args.end())
+    return IdentifierInfo::FromContextArg(context_arg->second);
+
+  ConstString name_str(name);
+  llvm::StringRef name_ref = name_str.GetStringRef();
+
+  // Support $rax as a special syntax for accessing registers.
+  // Will return an invalid value in case the requested register doesn't exist.
+  if (name_ref.starts_with("$")) {
+    lldb::ValueObjectSP value_sp;
+    const char *reg_name = name_ref.drop_front(1).data();
+    Target *target = ctx_scope->CalculateTarget().get();
+    Process *process = ctx_scope->CalculateProcess().get();
+    if (target && process) {
+      Process::StopLocker stop_locker;
----------------
cmtice wrote:

Turns out it's not actually needed here. Have removed it.

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


More information about the lldb-commits mailing list