[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
Fri Sep 6 22:05:56 PDT 2024
https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/95738
>From c703c473147e3e554a98014319294668a0ec790d Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 16 Jun 2024 16:32:47 -0700
Subject: [PATCH 1/8] [LLDB] Add AST node classes, functions, etc. for Data
Inspection Language (DIL).
The Data Inspection Language (DIL), described in
https://discourse.llvm.org/t/rfc-data-inspection-language/69893 includes
its own parser and expression evaluator.
This change defines the AST nodes, classes and functions which are used by the
DIL parser and expression evaluator. It also adds the .ebnf file documenting
the (current) expression language handled by the DIL parser and expression
evaluator.
---
lldb/docs/dil-expr-lang.ebnf | 165 ++++++++
lldb/include/lldb/Core/DILAST.h | 690 ++++++++++++++++++++++++++++++++
lldb/source/Core/CMakeLists.txt | 1 +
lldb/source/Core/DILAST.cpp | 568 ++++++++++++++++++++++++++
4 files changed, 1424 insertions(+)
create mode 100644 lldb/docs/dil-expr-lang.ebnf
create mode 100644 lldb/include/lldb/Core/DILAST.h
create mode 100644 lldb/source/Core/DILAST.cpp
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
new file mode 100644
index 00000000000000..40c678c25cda5e
--- /dev/null
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -0,0 +1,165 @@
+(* LLDB Debug Expressions, a subset of C++ *)
+(* Insired by https://www.nongnu.org/hcb *)
+
+expression = assignment_expression ;
+
+assignment_expression = conditional_expression
+ logical_or_expression assignment_operator assignment_expression ;
+
+assignment_operator = "="
+ | "*="
+ | "/="
+ | "%="
+ | "+="
+ | "-="
+ | ">>="
+ | "<<="
+ | "&="
+ | "^="
+ | "|=" ;
+
+conditional_expression = logical_or_expression
+ | logical_or_expression "?" expression ":" assignment_expression ;
+
+logical_or_expression = logical_and_expression {"||" logical_and_expression} ;
+
+logical_and_expression = inclusive_or_expression {"&&" inclusive_or_expression} ;
+
+inclusive_or_expression = exclusive_or_expression {"|" exclusive_or_expression} ;
+
+exclusive_or_expression = and_expression {"^" and_expression} ;
+
+and_expression = equality_expression {"&" equality_expression} ;
+
+equality_expression = relational_expression {"==" relational_expression}
+ | relational_expression {"!=" relational_expression} ;
+
+relational_expression = shift_expression {"<" shift_expression}
+ | shift_expression {">" shift_expression}
+ | shift_expression {"<=" shift_expression}
+ | shift_expression {">=" shift_expression} ;
+
+shift_expression = additive_expression {"<<" additive_expression}
+ | additive_expression {">>" additive_expression} ;
+
+additive_expression = multiplicative_expression {"+" multiplicative_expression}
+ | multiplicative_expression {"-" multiplicative_expression} ;
+
+multiplicative_expression = cast_expression {"*" cast_expression}
+ | cast_expression {"/" cast_expression}
+ | cast_expression {"%" cast_expression} ;
+
+cast_expression = unary_expression
+ | "(" type_id ")" cast_expression ;
+
+unary_expression = postfix_expression
+ | "++" cast_expression
+ | "--" cast_expression
+ | unary_operator cast_expression
+ | "sizeof" unary_expression
+ | "sizeof" "(" type_id ")" ;
+
+unary_operator = "*" | "&" | "+" | "-" | "!" | "~" ;
+
+postfix_expression = primary_expression
+ | postfix_expression "[" expression "]"
+ | postfix_expression "." id_expression
+ | postfix_expression "->" id_expression
+ | postfix_expression "++"
+ | postfix_expression "--"
+ | static_cast "<" type_id ">" "(" expression ")" ;
+ | dynamic_cast "<" type_id ">" "(" expression ")" ;
+ | reinterpret_cast "<" type_id ">" "(" expression ")" ;
+
+primary_expression = numeric_literal
+ | boolean_literal
+ | pointer_literal
+ | id_expression
+ | "this"
+ | "(" expression ")"
+ | builtin_func ;
+
+type_id = type_specifier_seq [abstract_declarator] ;
+
+type_specifier_seq = type_specifier [type_specifier_seq] ;
+
+type_specifier = simple_type_specifier
+ | cv_qualifier ;
+
+simple_type_specifier = ["::"] [nested_name_specifier] type_name
+ | "char"
+ | "char16_t"
+ | "char32_t"
+ | "wchar_t"
+ | "bool"
+ | "short"
+ | "int"
+ | "long"
+ | "signed"
+ | "unsigned"
+ | "float"
+ | "double"
+ | "void" ;
+
+nested_name_specifier = type_name "::"
+ | namespace_name '::'
+ | nested_name_specifier identifier "::"
+ | nested_name_specifier simple_template_id "::"
+
+type_name = class_name
+ | enum_name
+ | typedef_name
+ | simple_template_id ;
+
+class_name = identifier ;
+
+enum_name = identifier ;
+
+typedef_name = identifier ;
+
+simple_template_id = template_name "<" [template_argument_list] ">" ;
+
+template_name = identifier ;
+
+template_argument_list = template_argument
+ | template_argument_list "," template_argument ;
+
+template_argument = type_id
+ | numeric_literal
+ | id_expression ;
+
+namespace_name = identifier ;
+
+cv_qualifier = "const" | "volatile" ;
+
+cv_qualifier_seq = cv_qualifier [cv_qualifier_seq] ;
+
+abstract_declarator = ptr_operator [abstract_declarator] ;
+
+ptr_operator = "*" [cv_qualifier_seq]
+ | "&" ;
+
+id_expression = unqualified_id
+ | qualified_id ;
+
+unqualified_id = identifier ;
+
+qualified_id = ["::"] [nested_name_specifier] unqualified_id
+ | ["::"] identifier ;
+
+identifier = ? clang::tok::identifier ? ;
+
+numeric_literal = ? clang::tok::numeric_constant ? ;
+
+boolean_literal = "true" | "false" ;
+
+pointer_literal = "nullptr" ;
+
+builtin_func = builtin_func_name "(" [builtin_func_argument_list] ")" ;
+
+builtin_func_name = "__log2" ;
+
+builtin_func_argument_list = builtin_func_argument
+ | builtin_func_argument_list "," builtin_func_argument
+
+builtin_func_argument = expression ;
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
new file mode 100644
index 00000000000000..acb9da088eda87
--- /dev/null
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -0,0 +1,690 @@
+//===-- DILAST.h ------------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_DIL_AST_H_
+#define LLDB_DIL_AST_H_
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <variant>
+#include <vector>
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Utility/ConstString.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+
+namespace lldb_private {
+
+/// Struct to hold information about member fields. Used by the parser for the
+/// Data Inspection Language (DIL).
+struct DILMemberInfo {
+ std::optional<std::string> name;
+ CompilerType type;
+ bool is_bitfield;
+ uint32_t bitfield_size_in_bits;
+ bool is_synthetic;
+ bool is_dynamic;
+ lldb::ValueObjectSP val_obj_sp;
+
+ explicit operator bool() const { return type.IsValid(); }
+};
+
+/// This determines if the type is a shared, unique or weak pointer, either
+/// from stdlibc++ or libc+++.
+bool IsSmartPtrType(CompilerType type);
+
+/// Finds the member field with the given name and type, stores the child index
+/// corresponding to the field in the idx vector and returns a DILMemberInfo
+/// struct with appropriate information about the field.
+DILMemberInfo GetFieldWithNameIndexPath(lldb::ValueObjectSP lhs_val_sp,
+ CompilerType type,
+ const std::string &name,
+ std::vector<uint32_t> *idx,
+ CompilerType empty_type,
+ bool use_synthetic, bool is_dynamic);
+
+std::tuple<DILMemberInfo, std::vector<uint32_t>>
+GetMemberInfo(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
+ const std::string &name, bool use_synthetic);
+
+/// Get the appropriate ValueObjectSP, consulting the use_dynamic and
+/// use_synthetic options passed, acquiring the process & target locks if
+/// appropriate.
+lldb::ValueObjectSP
+DILGetSPWithLock(lldb::ValueObjectSP valobj_sp,
+ lldb::DynamicValueType use_dynamic = lldb::eNoDynamicValues,
+ bool use_synthetic = false);
+
+/// The various types DIL AST nodes (used by the DIL parser).
+enum class DILNodeKind {
+ kDILErrorNode,
+ kLiteralNode,
+ kIdentifierNode,
+ kSizeOfNode,
+ kBuiltinFunctionCallNode,
+ kCStyleCastNode,
+ kCxxStaticCastNode,
+ kCxxReinterpretCastNode,
+ kMemberOfNode,
+ kArraySubscriptNode,
+ kBinaryOpNode,
+ kUnaryOpNode,
+ kTernaryOpNode,
+ kSmartPtrToPtrDecay
+};
+
+/// The C-Style casts allowed by DIL.
+enum class CStyleCastKind {
+ kArithmetic,
+ kEnumeration,
+ kPointer,
+ kNullptr,
+ kReference,
+};
+
+/// The Cxx static casts allowed by DIL.
+enum class CxxStaticCastKind {
+ kNoOp,
+ kArithmetic,
+ kEnumeration,
+ kPointer,
+ kNullptr,
+ kBaseToDerived,
+ kDerivedToBase,
+};
+
+/// The binary operators recognized by DIL.
+enum class BinaryOpKind {
+ Mul, // "*"
+ Div, // "/"
+ Rem, // "%"
+ Add, // "+"
+ Sub, // "-"
+ Shl, // "<<"
+ Shr, // ">>"
+ LT, // "<"
+ GT, // ">"
+ LE, // "<="
+ GE, // ">="
+ EQ, // "=="
+ NE, // "!="
+ And, // "&"
+ Xor, // "^"
+ Or, // "|"
+ LAnd, // "&&"
+ LOr, // "||"
+ Assign, // "="
+ MulAssign, // "*="
+ DivAssign, // "/="
+ RemAssign, // "%="
+ AddAssign, // "+="
+ SubAssign, // "-="
+ ShlAssign, // "<<="
+ ShrAssign, // ">>="
+ AndAssign, // "&="
+ XorAssign, // "^="
+ OrAssign, // "|="
+};
+
+/// The Unary operators recognized by DIL.
+enum class UnaryOpKind {
+ PostInc, // "++"
+ PostDec, // "--"
+ PreInc, // "++"
+ PreDec, // "--"
+ AddrOf, // "&"
+ Deref, // "*"
+ Plus, // "+"
+ Minus, // "-"
+ Not, // "~"
+ LNot, // "!"
+};
+
+/// Helper functions for DIL AST node parsing.
+
+/// Translates clang tokens to BinaryOpKind.
+BinaryOpKind
+clang_token_kind_to_binary_op_kind(clang::tok::TokenKind token_kind);
+
+/// Returns bool indicating whether or not the input kind is an assignment.
+bool binary_op_kind_is_comp_assign(BinaryOpKind kind);
+
+/// Given a string representing a type, returns the CompilerType corresponding
+/// to the named type, if it exists.
+CompilerType
+ResolveTypeByName(const std::string &name,
+ std::shared_ptr<ExecutionContextScope> ctx_scope);
+
+/// Quick lookup to check if a type name already exists in a
+/// name-to-CompilerType map the DIL parser keeps of previously found
+/// name/type pairs.
+bool IsContextVar(const std::string &name);
+
+/// Checks to see if the CompilerType is a Smart Pointer (shared, unique, weak)
+/// or not. Only applicable for C++, which is why this is here and not part of
+/// the CompilerType class.
+bool IsSmartPtrType(CompilerType type);
+
+/// Class used to store & manipulate information about identifiers.
+class IdentifierInfo {
+private:
+ using MemberPath = std::vector<uint32_t>;
+ using IdentifierInfoPtr = std::unique_ptr<IdentifierInfo>;
+
+public:
+ enum class Kind {
+ kValue,
+ kContextArg,
+ kMemberPath,
+ kThisKeyword,
+ };
+
+ static IdentifierInfoPtr FromValue(lldb::ValueObjectSP value_sp) {
+ CompilerType type;
+ lldb::ValueObjectSP value = DILGetSPWithLock(value_sp);
+ if (value)
+ type = value->GetCompilerType();
+ return IdentifierInfoPtr(new IdentifierInfo(Kind::kValue, type, value, {}));
+ }
+
+ static IdentifierInfoPtr FromContextArg(CompilerType type) {
+ lldb::ValueObjectSP empty_value;
+ return IdentifierInfoPtr(
+ new IdentifierInfo(Kind::kContextArg, type, empty_value, {}));
+ }
+
+ static IdentifierInfoPtr FromMemberPath(CompilerType type, MemberPath path) {
+ lldb::ValueObjectSP empty_value;
+ return IdentifierInfoPtr(new IdentifierInfo(Kind::kMemberPath, type,
+ empty_value, std::move(path)));
+ }
+
+ static IdentifierInfoPtr FromThisKeyword(CompilerType type) {
+ lldb::ValueObjectSP empty_value;
+ return IdentifierInfoPtr(
+ new IdentifierInfo(Kind::kThisKeyword, type, empty_value, {}));
+ }
+
+ Kind kind() const { return m_kind; }
+ lldb::ValueObjectSP value() const { return m_value; }
+ const MemberPath &path() const { return m_path; }
+
+ CompilerType GetType() { return m_type; }
+ bool IsValid() const { return m_type.IsValid(); }
+
+ IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
+ MemberPath path)
+ : m_kind(kind), m_type(type), m_value(std::move(value)),
+ m_path(std::move(path)) {}
+
+private:
+ Kind m_kind;
+ CompilerType m_type;
+ lldb::ValueObjectSP m_value;
+ MemberPath m_path;
+};
+
+/// Given the name of an identifier (variable name, member name, type name,
+/// etc.), find the ValueObject for that name (if it exists) and create and
+/// return an IdentifierInfo object containing all the relevant information
+/// about that object (for DIL parsing and evaluating).
+std::unique_ptr<IdentifierInfo> LookupIdentifier(
+ const std::string &name, std::shared_ptr<ExecutionContextScope> ctx_scope,
+ lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr = nullptr);
+
+/// Forward declaration, for use in DIL AST nodes. Definition is at the very
+/// end of this file.
+class DILVisitor;
+
+/// The rest of the classes in this file, except for the DILVisitor class at the
+/// very end, define all the types of AST nodes used by the DIL parser and
+/// expression evaluator. The DIL parser parses the input string and creates the
+/// AST parse tree from the AST nodes. The resulting AST node tree gets passed
+/// to the DIL expression evaluator, which evaluates the DIL AST nodes and
+/// creates/returns a ValueObjectSP containing the result.
+
+/// Base class for AST nodes used by the Data Inspection Language (DIL) parser.
+/// All of the specialized types of AST nodes inherit from this (virtual) base
+/// class.
+class DILASTNode {
+public:
+ DILASTNode(clang::SourceLocation location) : location_(location) {}
+ virtual ~DILASTNode() {}
+
+ virtual void Accept(DILVisitor *v) const = 0;
+
+ virtual bool is_error() const { return false; };
+ virtual bool is_rvalue() const = 0;
+ virtual bool is_bitfield() const { return false; };
+ virtual bool is_context_var() const { return false; };
+ virtual bool is_literal_zero() const { return false; }
+ virtual uint32_t bitfield_size() const { return 0; }
+ virtual CompilerType result_type() const = 0;
+
+ virtual DILNodeKind what_am_i() const = 0;
+
+ clang::SourceLocation location() const { return location_; }
+
+ // The expression result type, but dereferenced in case it's a reference. This
+ // is for convenience, since for the purposes of the semantic analysis only
+ // the dereferenced type matters.
+ CompilerType result_type_deref() const;
+
+private:
+ clang::SourceLocation location_;
+};
+
+using ParseResult = std::unique_ptr<DILASTNode>;
+
+class DILErrorNode : public DILASTNode {
+public:
+ DILErrorNode(CompilerType empty_type)
+ : DILASTNode(clang::SourceLocation()), m_empty_type(empty_type) {}
+ void Accept(DILVisitor *v) const override;
+ bool is_error() const override { return true; }
+ bool is_rvalue() const override { return false; }
+ CompilerType result_type() const override { return m_empty_type; }
+ CompilerType result_type_real() const { return m_empty_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kDILErrorNode; }
+
+private:
+ CompilerType m_empty_type;
+};
+
+class LiteralNode : public DILASTNode {
+public:
+ template <typename ValueT>
+ LiteralNode(clang::SourceLocation location, CompilerType type, ValueT &&value,
+ bool is_literal_zero)
+ : DILASTNode(location), m_type(type),
+ m_value(std::forward<ValueT>(value)),
+ m_is_literal_zero(is_literal_zero) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return true; }
+ bool is_literal_zero() const override { return m_is_literal_zero; }
+ CompilerType result_type() const override { return m_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kLiteralNode; }
+
+ template <typename ValueT> ValueT value() const {
+ return std::get<ValueT>(m_value);
+ }
+
+ auto value() const { return m_value; }
+
+private:
+ CompilerType m_type;
+ std::variant<llvm::APInt, llvm::APFloat, bool, std::vector<char>> m_value;
+ bool m_is_literal_zero;
+};
+
+class IdentifierNode : public DILASTNode {
+public:
+ IdentifierNode(clang::SourceLocation location, std::string name,
+ std::unique_ptr<IdentifierInfo> identifier, bool is_rvalue,
+ bool is_context_var)
+ : DILASTNode(location), m_is_rvalue(is_rvalue),
+ m_is_context_var(is_context_var), m_name(std::move(name)),
+ m_identifier(std::move(identifier)) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return m_is_rvalue; }
+ bool is_context_var() const override { return m_is_context_var; };
+ CompilerType result_type() const override { return m_identifier->GetType(); }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kIdentifierNode;
+ }
+
+ std::string name() const { return m_name; }
+ const IdentifierInfo &info() const { return *m_identifier; }
+
+private:
+ bool m_is_rvalue;
+ bool m_is_context_var;
+ std::string m_name;
+ std::unique_ptr<IdentifierInfo> m_identifier;
+};
+
+class SizeOfNode : public DILASTNode {
+public:
+ SizeOfNode(clang::SourceLocation location, CompilerType type,
+ CompilerType operand)
+ : DILASTNode(location), m_type(type), m_operand(operand) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return true; }
+ CompilerType result_type() const override { return m_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kSizeOfNode; }
+
+ CompilerType operand() const { return m_operand; }
+
+private:
+ CompilerType m_type;
+ CompilerType m_operand;
+};
+
+class BuiltinFunctionCallNode : public DILASTNode {
+public:
+ BuiltinFunctionCallNode(clang::SourceLocation location,
+ CompilerType result_type, std::string name,
+ std::vector<ParseResult> arguments)
+ : DILASTNode(location), m_result_type(result_type),
+ m_name(std::move(name)), m_arguments(std::move(arguments)) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return true; }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kBuiltinFunctionCallNode;
+ }
+
+ std::string name() const { return m_name; }
+ const std::vector<ParseResult> &arguments() const { return m_arguments; };
+
+private:
+ CompilerType m_result_type;
+ std::string m_name;
+ std::vector<ParseResult> m_arguments;
+};
+
+class CStyleCastNode : public DILASTNode {
+public:
+ CStyleCastNode(clang::SourceLocation location, CompilerType type,
+ ParseResult rhs, CStyleCastKind kind)
+ : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
+ m_kind(kind) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override {
+ return m_kind != CStyleCastKind::kReference;
+ }
+ CompilerType result_type() const override { return m_type; }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kCStyleCastNode;
+ }
+
+ CompilerType type() const { return m_type; }
+ DILASTNode *rhs() const { return m_rhs.get(); }
+ CStyleCastKind kind() const { return m_kind; }
+
+private:
+ CompilerType m_type;
+ ParseResult m_rhs;
+ CStyleCastKind m_kind;
+};
+
+class CxxStaticCastNode : public DILASTNode {
+public:
+ CxxStaticCastNode(clang::SourceLocation location, CompilerType type,
+ ParseResult rhs, CxxStaticCastKind kind, bool is_rvalue)
+ : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)), m_kind(kind),
+ m_is_rvalue(is_rvalue) {
+ assert(kind != CxxStaticCastKind::kBaseToDerived &&
+ kind != CxxStaticCastKind::kDerivedToBase &&
+ "invalid constructor for base-to-derived and derived-to-base casts");
+ }
+
+ CxxStaticCastNode(clang::SourceLocation location, CompilerType type,
+ ParseResult rhs, std::vector<uint32_t> idx, bool is_rvalue)
+ : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
+ m_idx(std::move(idx)), m_kind(CxxStaticCastKind::kDerivedToBase),
+ m_is_rvalue(is_rvalue) {}
+
+ CxxStaticCastNode(clang::SourceLocation location, CompilerType type,
+ ParseResult rhs, uint64_t offset, bool is_rvalue)
+ : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
+ m_offset(offset), m_kind(CxxStaticCastKind::kBaseToDerived),
+ m_is_rvalue(is_rvalue) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return m_is_rvalue; }
+ CompilerType result_type() const override { return m_type; }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kCxxStaticCastNode;
+ }
+
+ CompilerType type() const { return m_type; }
+ DILASTNode *rhs() const { return m_rhs.get(); }
+ const std::vector<uint32_t> &idx() const { return m_idx; }
+ uint64_t offset() const { return m_offset; }
+ CxxStaticCastKind kind() const { return m_kind; }
+
+private:
+ CompilerType m_type;
+ ParseResult m_rhs;
+ std::vector<uint32_t> m_idx;
+ uint64_t m_offset = 0;
+ CxxStaticCastKind m_kind;
+ bool m_is_rvalue;
+};
+
+class CxxReinterpretCastNode : public DILASTNode {
+public:
+ CxxReinterpretCastNode(clang::SourceLocation location, CompilerType type,
+ ParseResult rhs, bool is_rvalue)
+ : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
+ m_is_rvalue(is_rvalue) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return m_is_rvalue; }
+ CompilerType result_type() const override { return m_type; }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kCxxReinterpretCastNode;
+ }
+
+ CompilerType type() const { return m_type; }
+ DILASTNode *rhs() const { return m_rhs.get(); }
+
+private:
+ CompilerType m_type;
+ ParseResult m_rhs;
+ bool m_is_rvalue;
+};
+
+class MemberOfNode : public DILASTNode {
+public:
+ MemberOfNode(clang::SourceLocation location, CompilerType result_type,
+ ParseResult lhs, bool is_bitfield, uint32_t bitfield_size,
+ std::vector<uint32_t> member_index, bool is_arrow,
+ bool is_synthetic, bool is_dynamic, ConstString name,
+ lldb::ValueObjectSP valobj_sp)
+ : DILASTNode(location), m_result_type(result_type), m_lhs(std::move(lhs)),
+ m_is_bitfield(is_bitfield), m_bitfield_size(bitfield_size),
+ m_member_index(std::move(member_index)), m_is_arrow(is_arrow),
+ m_is_synthetic(is_synthetic), m_is_dynamic(is_dynamic),
+ m_field_name(name), m_valobj_sp(valobj_sp) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return false; }
+ bool is_bitfield() const override { return m_is_bitfield; }
+ uint32_t bitfield_size() const override { return m_bitfield_size; }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kMemberOfNode; }
+
+ DILASTNode *lhs() const { return m_lhs.get(); }
+ const std::vector<uint32_t> &member_index() const { return m_member_index; }
+ bool is_arrow() const { return m_is_arrow; }
+ bool is_synthetic() const { return m_is_synthetic; }
+ bool is_dynamic() const { return m_is_dynamic; }
+ ConstString field_name() const { return m_field_name; }
+ lldb::ValueObjectSP valobj_sp() const { return m_valobj_sp; }
+
+private:
+ CompilerType m_result_type;
+ ParseResult m_lhs;
+ bool m_is_bitfield;
+ uint32_t m_bitfield_size;
+ std::vector<uint32_t> m_member_index;
+ bool m_is_arrow;
+ bool m_is_synthetic;
+ bool m_is_dynamic;
+ ConstString m_field_name;
+ lldb::ValueObjectSP m_valobj_sp;
+};
+
+class ArraySubscriptNode : public DILASTNode {
+public:
+ ArraySubscriptNode(clang::SourceLocation location, CompilerType result_type,
+ ParseResult base, ParseResult index)
+ : DILASTNode(location), m_result_type(result_type),
+ m_base(std::move(base)), m_index(std::move(index)) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return false; }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kArraySubscriptNode;
+ }
+
+ DILASTNode *base() const { return m_base.get(); }
+ DILASTNode *index() const { return m_index.get(); }
+
+private:
+ CompilerType m_result_type;
+ ParseResult m_base;
+ ParseResult m_index;
+};
+
+class BinaryOpNode : public DILASTNode {
+public:
+ BinaryOpNode(clang::SourceLocation location, CompilerType result_type,
+ BinaryOpKind kind, ParseResult lhs, ParseResult rhs,
+ CompilerType comp_assign_type,
+ ValueObject *val_obj_ptr = nullptr)
+ : DILASTNode(location), m_result_type(result_type), m_kind(kind),
+ m_lhs(std::move(lhs)), m_rhs(std::move(rhs)),
+ m_comp_assign_type(comp_assign_type) {
+ if (val_obj_ptr)
+ m_val_obj_sp = val_obj_ptr->GetSP();
+ }
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override {
+ return !binary_op_kind_is_comp_assign(m_kind);
+ }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kBinaryOpNode; }
+
+ BinaryOpKind kind() const { return m_kind; }
+ DILASTNode *lhs() const { return m_lhs.get(); }
+ DILASTNode *rhs() const { return m_rhs.get(); }
+ CompilerType comp_assign_type() const { return m_comp_assign_type; }
+ lldb::ValueObjectSP get_valobj_sp() const { return m_val_obj_sp; }
+
+private:
+ CompilerType m_result_type;
+ BinaryOpKind m_kind;
+ ParseResult m_lhs;
+ ParseResult m_rhs;
+ CompilerType m_comp_assign_type;
+ lldb::ValueObjectSP m_val_obj_sp;
+};
+
+class UnaryOpNode : public DILASTNode {
+public:
+ UnaryOpNode(clang::SourceLocation location, CompilerType result_type,
+ UnaryOpKind kind, ParseResult rhs)
+ : DILASTNode(location), m_result_type(result_type), m_kind(kind),
+ m_rhs(std::move(rhs)) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return m_kind != UnaryOpKind::Deref; }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kUnaryOpNode; }
+
+ UnaryOpKind kind() const { return m_kind; }
+ DILASTNode *rhs() const { return m_rhs.get(); }
+
+private:
+ CompilerType m_result_type;
+ UnaryOpKind m_kind;
+ ParseResult m_rhs;
+};
+
+class TernaryOpNode : public DILASTNode {
+public:
+ TernaryOpNode(clang::SourceLocation location, CompilerType result_type,
+ ParseResult cond, ParseResult lhs, ParseResult rhs)
+ : DILASTNode(location), m_result_type(result_type),
+ m_cond(std::move(cond)), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override {
+ return m_lhs->is_rvalue() || m_rhs->is_rvalue();
+ }
+ bool is_bitfield() const override {
+ return m_lhs->is_bitfield() || m_rhs->is_bitfield();
+ }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override { return DILNodeKind::kTernaryOpNode; }
+
+ DILASTNode *cond() const { return m_cond.get(); }
+ DILASTNode *lhs() const { return m_lhs.get(); }
+ DILASTNode *rhs() const { return m_rhs.get(); }
+
+private:
+ CompilerType m_result_type;
+ ParseResult m_cond;
+ ParseResult m_lhs;
+ ParseResult m_rhs;
+};
+
+class SmartPtrToPtrDecay : public DILASTNode {
+public:
+ SmartPtrToPtrDecay(clang::SourceLocation location, CompilerType result_type,
+ ParseResult ptr)
+ : DILASTNode(location), m_result_type(result_type),
+ m_ptr(std::move(ptr)) {}
+
+ void Accept(DILVisitor *v) const override;
+ bool is_rvalue() const override { return false; }
+ CompilerType result_type() const override { return m_result_type; }
+ DILNodeKind what_am_i() const override {
+ return DILNodeKind::kSmartPtrToPtrDecay;
+ }
+
+ DILASTNode *ptr() const { return m_ptr.get(); }
+
+private:
+ CompilerType m_result_type;
+ ParseResult m_ptr;
+};
+
+/// This class contains one Visit method for each specialized type of
+/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
+/// the correct function in the DIL expression evaluator for evaluating that
+/// type of AST node.
+class DILVisitor {
+public:
+ virtual ~DILVisitor() {}
+ virtual void Visit(const DILErrorNode *node) = 0;
+ virtual void Visit(const LiteralNode *node) = 0;
+ virtual void Visit(const IdentifierNode *node) = 0;
+ virtual void Visit(const SizeOfNode *node) = 0;
+ virtual void Visit(const BuiltinFunctionCallNode *node) = 0;
+ virtual void Visit(const CStyleCastNode *node) = 0;
+ virtual void Visit(const CxxStaticCastNode *node) = 0;
+ virtual void Visit(const CxxReinterpretCastNode *node) = 0;
+ virtual void Visit(const MemberOfNode *node) = 0;
+ virtual void Visit(const ArraySubscriptNode *node) = 0;
+ virtual void Visit(const BinaryOpNode *node) = 0;
+ virtual void Visit(const UnaryOpNode *node) = 0;
+ virtual void Visit(const TernaryOpNode *node) = 0;
+ virtual void Visit(const SmartPtrToPtrDecay *node) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_DIL_AST_H_
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index dbc620b91b1ed1..794895134db53a 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -29,6 +29,7 @@ add_lldb_library(lldbCore
DebuggerEvents.cpp
Declaration.cpp
Disassembler.cpp
+ DILAST.cpp
DumpDataExtractor.cpp
DumpRegisterValue.cpp
DumpRegisterInfo.cpp
diff --git a/lldb/source/Core/DILAST.cpp b/lldb/source/Core/DILAST.cpp
new file mode 100644
index 00000000000000..909c94064c4663
--- /dev/null
+++ b/lldb/source/Core/DILAST.cpp
@@ -0,0 +1,568 @@
+//===-- 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;
+}
+
+BinaryOpKind
+clang_token_kind_to_binary_op_kind(clang::tok::TokenKind token_kind) {
+ switch (token_kind) {
+ case clang::tok::star:
+ return BinaryOpKind::Mul;
+ case clang::tok::slash:
+ return BinaryOpKind::Div;
+ case clang::tok::percent:
+ return BinaryOpKind::Rem;
+ case clang::tok::plus:
+ return BinaryOpKind::Add;
+ case clang::tok::minus:
+ return BinaryOpKind::Sub;
+ case clang::tok::lessless:
+ return BinaryOpKind::Shl;
+ case clang::tok::greatergreater:
+ return BinaryOpKind::Shr;
+ case clang::tok::less:
+ return BinaryOpKind::LT;
+ case clang::tok::greater:
+ return BinaryOpKind::GT;
+ case clang::tok::lessequal:
+ return BinaryOpKind::LE;
+ case clang::tok::greaterequal:
+ return BinaryOpKind::GE;
+ case clang::tok::equalequal:
+ return BinaryOpKind::EQ;
+ case clang::tok::exclaimequal:
+ return BinaryOpKind::NE;
+ case clang::tok::amp:
+ return BinaryOpKind::And;
+ case clang::tok::caret:
+ return BinaryOpKind::Xor;
+ case clang::tok::pipe:
+ return BinaryOpKind::Or;
+ case clang::tok::ampamp:
+ return BinaryOpKind::LAnd;
+ case clang::tok::pipepipe:
+ return BinaryOpKind::LOr;
+ case clang::tok::equal:
+ return BinaryOpKind::Assign;
+ case clang::tok::starequal:
+ return BinaryOpKind::MulAssign;
+ case clang::tok::slashequal:
+ return BinaryOpKind::DivAssign;
+ case clang::tok::percentequal:
+ return BinaryOpKind::RemAssign;
+ case clang::tok::plusequal:
+ return BinaryOpKind::AddAssign;
+ case clang::tok::minusequal:
+ return BinaryOpKind::SubAssign;
+ case clang::tok::lesslessequal:
+ return BinaryOpKind::ShlAssign;
+ case clang::tok::greatergreaterequal:
+ return BinaryOpKind::ShrAssign;
+ case clang::tok::ampequal:
+ return BinaryOpKind::AndAssign;
+ case clang::tok::caretequal:
+ return BinaryOpKind::XorAssign;
+ case clang::tok::pipeequal:
+ return BinaryOpKind::OrAssign;
+
+ default:
+ break;
+ }
+ llvm_unreachable("did you add an element to BinaryOpKind?");
+}
+
+bool binary_op_kind_is_comp_assign(BinaryOpKind kind) {
+ switch (kind) {
+ case BinaryOpKind::Assign:
+ case BinaryOpKind::MulAssign:
+ case BinaryOpKind::DivAssign:
+ case BinaryOpKind::RemAssign:
+ case BinaryOpKind::AddAssign:
+ case BinaryOpKind::SubAssign:
+ case BinaryOpKind::ShlAssign:
+ case BinaryOpKind::ShrAssign:
+ case BinaryOpKind::AndAssign:
+ case BinaryOpKind::XorAssign:
+ case BinaryOpKind::OrAssign:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+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;
+ if (stop_locker.TryLock(&process->GetRunLock())) {
+ StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+ if (stack_frame) {
+ lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+ if (reg_ctx) {
+ if (const RegisterInfo *reg_info =
+ reg_ctx->GetRegisterInfoByName(reg_name))
+ value_sp =
+ ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
+ }
+ }
+ }
+ }
+ return IdentifierInfo::FromValue(value_sp);
+ }
+
+ // Internally values don't have global scope qualifier in their names and
+ // LLDB doesn't support queries with it too.
+ bool global_scope = false;
+ if (name_ref.starts_with("::")) {
+ name_ref = name_ref.drop_front(2);
+ global_scope = true;
+ }
+
+ // If the identifier doesn't refer to the global scope and doesn't have any
+ // other scope qualifiers, try looking among the local and instance variables.
+ if (!global_scope && !name_ref.contains("::")) {
+ if (!scope_ptr || !scope_ptr->IsValid()) {
+ // Lookup in the current frame.
+ lldb::StackFrameSP frame = ctx_scope->CalculateStackFrame();
+ // Try looking for a local variable in current scope.
+ lldb::ValueObjectSP value_sp;
+ lldb::VariableListSP var_list_sp(frame->GetInScopeVariableList(true));
+ VariableList *variable_list = var_list_sp.get();
+ if (variable_list) {
+ lldb::VariableSP var_sp =
+ DILFindVariable(ConstString(name_ref), variable_list);
+ if (var_sp)
+ value_sp = frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);
+ }
+ if (!value_sp)
+ value_sp = frame->FindVariable(ConstString(name_ref));
+
+ bool use_synthetic = false;
+ lldb::ValueObjectSP value(
+ DILGetSPWithLock(value_sp, use_dynamic, use_synthetic));
+ if (value)
+ // Force static value, otherwise we can end up with the "real" type.
+ return IdentifierInfo::FromValue(value);
+
+ // Try looking for an instance variable (class member).
+ ConstString this_string("this");
+ value = frame->FindVariable(this_string);
+ if (value)
+ value = value->GetChildMemberWithName(name_ref.data());
+
+ if (value)
+ // Force static value, otherwise we can end up with the "real" type.
+ return IdentifierInfo::FromValue(value->GetStaticValue());
+
+ } else {
+ // In a "value" scope `this` refers to the scope object itself.
+ if (name_ref == "this")
+ return IdentifierInfo::FromThisKeyword(scope_ptr->GetPointerType());
+
+ // Lookup the variable as a member of the current scope value.
+ lldb::ValueObjectSP empty_sp;
+ bool use_synthetic = false;
+ auto [member, path] =
+ GetMemberInfo(empty_sp, *scope_ptr, name_ref.data(), use_synthetic);
+ if (member)
+ return IdentifierInfo::FromMemberPath(member.type, std::move(path));
+ }
+ }
+
+ // Try looking for a global or static variable.
+
+ lldb::ValueObjectSP value;
+ if (!global_scope) {
+ // Try looking for static member of the current scope value, e.g.
+ // `ScopeType::NAME`. NAME can include nested struct (`Nested::SUBNAME`),
+ // but it cannot be part of the global scope (start with "::").
+ const char *type_name = "";
+ if (scope_ptr)
+ type_name = scope_ptr->GetCanonicalType().GetTypeName().AsCString();
+ std::string name_with_type_prefix =
+ llvm::formatv("{0}::{1}", type_name, name_ref).str();
+ value = LookupStaticIdentifier(ctx_scope->CalculateTarget(),
+ name_with_type_prefix, name_str);
+ }
+
+ // Lookup a regular global variable.
+ if (!value)
+ value = LookupStaticIdentifier(ctx_scope->CalculateTarget(), name_ref,
+ name_str);
+
+ // Try looking up enum value.
+ if (!value && name_ref.contains("::")) {
+ auto [enum_typename, enumerator_name] = name_ref.rsplit("::");
+
+ auto type = ResolveTypeByName(enum_typename.str(), ctx_scope);
+ std::vector<EnumMember> enum_members = GetEnumMembers(type);
+
+ for (size_t i = 0; i < enum_members.size(); i++) {
+ EnumMember enum_member = enum_members[i];
+ if (enum_member.name == enumerator_name) {
+ uint64_t bytes = enum_member.value.getZExtValue();
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(ctx_scope.get()))
+ byte_size = temp.value();
+ lldb::TargetSP target_sp = ctx_scope->CalculateTarget();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ &bytes, byte_size, target_sp->GetArchitecture().GetByteOrder(),
+ static_cast<uint8_t>(
+ target_sp->GetArchitecture().GetAddressByteSize()));
+ ExecutionContext exe_ctx(
+ ExecutionContextRef(ExecutionContext(target_sp.get(), false)));
+ value = ValueObject::CreateValueObjectFromData("result", *data_sp,
+ exe_ctx, type);
+ break;
+ }
+ }
+ }
+
+ // Last resort, lookup as a register (e.g. `rax` or `rip`).
+ if (!value) {
+ Target *target = ctx_scope->CalculateTarget().get();
+ Process *process = ctx_scope->CalculateProcess().get();
+ if (target && process) {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock())) {
+ StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+ if (stack_frame) {
+ lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+ if (reg_ctx) {
+ if (const RegisterInfo *reg_info =
+ reg_ctx->GetRegisterInfoByName(name_ref.data()))
+ value =
+ ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
+ }
+ }
+ }
+ }
+ }
+
+ // Force static value, otherwise we can end up with the "real" type.
+ return IdentifierInfo::FromValue(value);
+}
+
+void DILErrorNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void LiteralNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void IdentifierNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void SizeOfNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void BuiltinFunctionCallNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void CStyleCastNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void CxxStaticCastNode::Accept(DILVisitor *v) const { return v->Visit(this); }
+
+void CxxReinterpretCastNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void MemberOfNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void ArraySubscriptNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void BinaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void UnaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void TernaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
+
+void SmartPtrToPtrDecay::Accept(DILVisitor *v) const { v->Visit(this); }
+
+} // namespace lldb_private
>From d38cdf05f5bcbb0ad34abe67caa09bf137ca0259 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 18 Jun 2024 12:39:26 -0700
Subject: [PATCH 2/8] [LLDB] Add AST node classes, functions, etc. for Data
Inspection Language
Fix semicolons in the .ebnf file.
---
lldb/docs/dil-expr-lang.ebnf | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 40c678c25cda5e..37eb870162abf9 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -67,8 +67,8 @@ postfix_expression = primary_expression
| postfix_expression "->" id_expression
| postfix_expression "++"
| postfix_expression "--"
- | static_cast "<" type_id ">" "(" expression ")" ;
- | dynamic_cast "<" type_id ">" "(" expression ")" ;
+ | static_cast "<" type_id ">" "(" expression ")"
+ | dynamic_cast "<" type_id ">" "(" expression ")"
| reinterpret_cast "<" type_id ">" "(" expression ")" ;
primary_expression = numeric_literal
@@ -104,7 +104,7 @@ simple_type_specifier = ["::"] [nested_name_specifier] type_name
nested_name_specifier = type_name "::"
| namespace_name '::'
| nested_name_specifier identifier "::"
- | nested_name_specifier simple_template_id "::"
+ | nested_name_specifier simple_template_id "::";
type_name = class_name
| enum_name
@@ -160,6 +160,6 @@ builtin_func = builtin_func_name "(" [builtin_func_argument_list] ")" ;
builtin_func_name = "__log2" ;
builtin_func_argument_list = builtin_func_argument
- | builtin_func_argument_list "," builtin_func_argument
+ | builtin_func_argument_list "," builtin_func_argument;
builtin_func_argument = expression ;
>From c230c2844814b0edcf90c0b62dd8030cd6a5a0a8 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 1 Jul 2024 22:01:58 -0700
Subject: [PATCH 3/8] [LLDB] Add AST node classes, functions, etc. for Data
Inspection Language
Remove all the pieces for adding functionality beyond what the current
default "frame variable" implementation does. Update the .ebnf file to
reflect the current simplified version of DIL.
---
lldb/docs/dil-expr-lang.ebnf | 140 ++----------------
lldb/include/lldb/Core/DILAST.h | 244 --------------------------------
lldb/source/Core/DILAST.cpp | 100 -------------
3 files changed, 9 insertions(+), 475 deletions(-)
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 37eb870162abf9..a3cef16c841340 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -1,151 +1,38 @@
(* LLDB Debug Expressions, a subset of C++ *)
(* Insired by https://www.nongnu.org/hcb *)
-expression = assignment_expression ;
+expression = cast_expression;
-assignment_expression = conditional_expression
- logical_or_expression assignment_operator assignment_expression ;
-
-assignment_operator = "="
- | "*="
- | "/="
- | "%="
- | "+="
- | "-="
- | ">>="
- | "<<="
- | "&="
- | "^="
- | "|=" ;
-
-conditional_expression = logical_or_expression
- | logical_or_expression "?" expression ":" assignment_expression ;
-
-logical_or_expression = logical_and_expression {"||" logical_and_expression} ;
-
-logical_and_expression = inclusive_or_expression {"&&" inclusive_or_expression} ;
-
-inclusive_or_expression = exclusive_or_expression {"|" exclusive_or_expression} ;
-
-exclusive_or_expression = and_expression {"^" and_expression} ;
-
-and_expression = equality_expression {"&" equality_expression} ;
-
-equality_expression = relational_expression {"==" relational_expression}
- | relational_expression {"!=" relational_expression} ;
-
-relational_expression = shift_expression {"<" shift_expression}
- | shift_expression {">" shift_expression}
- | shift_expression {"<=" shift_expression}
- | shift_expression {">=" shift_expression} ;
-
-shift_expression = additive_expression {"<<" additive_expression}
- | additive_expression {">>" additive_expression} ;
-
-additive_expression = multiplicative_expression {"+" multiplicative_expression}
- | multiplicative_expression {"-" multiplicative_expression} ;
-
-multiplicative_expression = cast_expression {"*" cast_expression}
- | cast_expression {"/" cast_expression}
- | cast_expression {"%" cast_expression} ;
-
-cast_expression = unary_expression
- | "(" type_id ")" cast_expression ;
+cast_expression = unary_expression;
unary_expression = postfix_expression
- | "++" cast_expression
- | "--" cast_expression
- | unary_operator cast_expression
- | "sizeof" unary_expression
- | "sizeof" "(" type_id ")" ;
+ | unary_operator cast_expression;
-unary_operator = "*" | "&" | "+" | "-" | "!" | "~" ;
+unary_operator = "*" | "&" | "-" ;
postfix_expression = primary_expression
| postfix_expression "[" expression "]"
| postfix_expression "." id_expression
| postfix_expression "->" id_expression
- | postfix_expression "++"
- | postfix_expression "--"
- | static_cast "<" type_id ">" "(" expression ")"
- | dynamic_cast "<" type_id ">" "(" expression ")"
- | reinterpret_cast "<" type_id ">" "(" expression ")" ;
primary_expression = numeric_literal
| boolean_literal
| pointer_literal
| id_expression
- | "this"
- | "(" expression ")"
- | builtin_func ;
-
-type_id = type_specifier_seq [abstract_declarator] ;
-
-type_specifier_seq = type_specifier [type_specifier_seq] ;
-
-type_specifier = simple_type_specifier
- | cv_qualifier ;
-
-simple_type_specifier = ["::"] [nested_name_specifier] type_name
- | "char"
- | "char16_t"
- | "char32_t"
- | "wchar_t"
- | "bool"
- | "short"
- | "int"
- | "long"
- | "signed"
- | "unsigned"
- | "float"
- | "double"
- | "void" ;
+ | "this" ;
-nested_name_specifier = type_name "::"
- | namespace_name '::'
- | nested_name_specifier identifier "::"
- | nested_name_specifier simple_template_id "::";
-
-type_name = class_name
- | enum_name
- | typedef_name
- | simple_template_id ;
-
-class_name = identifier ;
-
-enum_name = identifier ;
-
-typedef_name = identifier ;
-
-simple_template_id = template_name "<" [template_argument_list] ">" ;
-
-template_name = identifier ;
-
-template_argument_list = template_argument
- | template_argument_list "," template_argument ;
-
-template_argument = type_id
- | numeric_literal
- | id_expression ;
+nested_name_specifier = namespace_name '::'
+ | nested_name_specifier identifier "::";
namespace_name = identifier ;
-cv_qualifier = "const" | "volatile" ;
-
-cv_qualifier_seq = cv_qualifier [cv_qualifier_seq] ;
-
-abstract_declarator = ptr_operator [abstract_declarator] ;
-
-ptr_operator = "*" [cv_qualifier_seq]
- | "&" ;
-
id_expression = unqualified_id
| qualified_id ;
unqualified_id = identifier ;
-qualified_id = ["::"] [nested_name_specifier] unqualified_id
- | ["::"] identifier ;
+qualified_id = [nested_name_specifier] unqualified_id
+ | identifier ;
identifier = ? clang::tok::identifier ? ;
@@ -154,12 +41,3 @@ numeric_literal = ? clang::tok::numeric_constant ? ;
boolean_literal = "true" | "false" ;
pointer_literal = "nullptr" ;
-
-builtin_func = builtin_func_name "(" [builtin_func_argument_list] ")" ;
-
-builtin_func_name = "__log2" ;
-
-builtin_func_argument_list = builtin_func_argument
- | builtin_func_argument_list "," builtin_func_argument;
-
-builtin_func_argument = expression ;
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
index acb9da088eda87..6b61157201c543 100644
--- a/lldb/include/lldb/Core/DILAST.h
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -72,16 +72,11 @@ enum class DILNodeKind {
kDILErrorNode,
kLiteralNode,
kIdentifierNode,
- kSizeOfNode,
kBuiltinFunctionCallNode,
kCStyleCastNode,
- kCxxStaticCastNode,
- kCxxReinterpretCastNode,
kMemberOfNode,
kArraySubscriptNode,
- kBinaryOpNode,
kUnaryOpNode,
- kTernaryOpNode,
kSmartPtrToPtrDecay
};
@@ -94,73 +89,13 @@ enum class CStyleCastKind {
kReference,
};
-/// The Cxx static casts allowed by DIL.
-enum class CxxStaticCastKind {
- kNoOp,
- kArithmetic,
- kEnumeration,
- kPointer,
- kNullptr,
- kBaseToDerived,
- kDerivedToBase,
-};
-
-/// The binary operators recognized by DIL.
-enum class BinaryOpKind {
- Mul, // "*"
- Div, // "/"
- Rem, // "%"
- Add, // "+"
- Sub, // "-"
- Shl, // "<<"
- Shr, // ">>"
- LT, // "<"
- GT, // ">"
- LE, // "<="
- GE, // ">="
- EQ, // "=="
- NE, // "!="
- And, // "&"
- Xor, // "^"
- Or, // "|"
- LAnd, // "&&"
- LOr, // "||"
- Assign, // "="
- MulAssign, // "*="
- DivAssign, // "/="
- RemAssign, // "%="
- AddAssign, // "+="
- SubAssign, // "-="
- ShlAssign, // "<<="
- ShrAssign, // ">>="
- AndAssign, // "&="
- XorAssign, // "^="
- OrAssign, // "|="
-};
-
/// The Unary operators recognized by DIL.
enum class UnaryOpKind {
- PostInc, // "++"
- PostDec, // "--"
- PreInc, // "++"
- PreDec, // "--"
AddrOf, // "&"
Deref, // "*"
- Plus, // "+"
Minus, // "-"
- Not, // "~"
- LNot, // "!"
};
-/// Helper functions for DIL AST node parsing.
-
-/// Translates clang tokens to BinaryOpKind.
-BinaryOpKind
-clang_token_kind_to_binary_op_kind(clang::tok::TokenKind token_kind);
-
-/// Returns bool indicating whether or not the input kind is an assignment.
-bool binary_op_kind_is_comp_assign(BinaryOpKind kind);
-
/// Given a string representing a type, returns the CompilerType corresponding
/// to the named type, if it exists.
CompilerType
@@ -357,48 +292,6 @@ class IdentifierNode : public DILASTNode {
std::unique_ptr<IdentifierInfo> m_identifier;
};
-class SizeOfNode : public DILASTNode {
-public:
- SizeOfNode(clang::SourceLocation location, CompilerType type,
- CompilerType operand)
- : DILASTNode(location), m_type(type), m_operand(operand) {}
-
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override { return true; }
- CompilerType result_type() const override { return m_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kSizeOfNode; }
-
- CompilerType operand() const { return m_operand; }
-
-private:
- CompilerType m_type;
- CompilerType m_operand;
-};
-
-class BuiltinFunctionCallNode : public DILASTNode {
-public:
- BuiltinFunctionCallNode(clang::SourceLocation location,
- CompilerType result_type, std::string name,
- std::vector<ParseResult> arguments)
- : DILASTNode(location), m_result_type(result_type),
- m_name(std::move(name)), m_arguments(std::move(arguments)) {}
-
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override { return true; }
- CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kBuiltinFunctionCallNode;
- }
-
- std::string name() const { return m_name; }
- const std::vector<ParseResult> &arguments() const { return m_arguments; };
-
-private:
- CompilerType m_result_type;
- std::string m_name;
- std::vector<ParseResult> m_arguments;
-};
-
class CStyleCastNode : public DILASTNode {
public:
CStyleCastNode(clang::SourceLocation location, CompilerType type,
@@ -425,74 +318,6 @@ class CStyleCastNode : public DILASTNode {
CStyleCastKind m_kind;
};
-class CxxStaticCastNode : public DILASTNode {
-public:
- CxxStaticCastNode(clang::SourceLocation location, CompilerType type,
- ParseResult rhs, CxxStaticCastKind kind, bool is_rvalue)
- : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)), m_kind(kind),
- m_is_rvalue(is_rvalue) {
- assert(kind != CxxStaticCastKind::kBaseToDerived &&
- kind != CxxStaticCastKind::kDerivedToBase &&
- "invalid constructor for base-to-derived and derived-to-base casts");
- }
-
- CxxStaticCastNode(clang::SourceLocation location, CompilerType type,
- ParseResult rhs, std::vector<uint32_t> idx, bool is_rvalue)
- : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
- m_idx(std::move(idx)), m_kind(CxxStaticCastKind::kDerivedToBase),
- m_is_rvalue(is_rvalue) {}
-
- CxxStaticCastNode(clang::SourceLocation location, CompilerType type,
- ParseResult rhs, uint64_t offset, bool is_rvalue)
- : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
- m_offset(offset), m_kind(CxxStaticCastKind::kBaseToDerived),
- m_is_rvalue(is_rvalue) {}
-
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override { return m_is_rvalue; }
- CompilerType result_type() const override { return m_type; }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kCxxStaticCastNode;
- }
-
- CompilerType type() const { return m_type; }
- DILASTNode *rhs() const { return m_rhs.get(); }
- const std::vector<uint32_t> &idx() const { return m_idx; }
- uint64_t offset() const { return m_offset; }
- CxxStaticCastKind kind() const { return m_kind; }
-
-private:
- CompilerType m_type;
- ParseResult m_rhs;
- std::vector<uint32_t> m_idx;
- uint64_t m_offset = 0;
- CxxStaticCastKind m_kind;
- bool m_is_rvalue;
-};
-
-class CxxReinterpretCastNode : public DILASTNode {
-public:
- CxxReinterpretCastNode(clang::SourceLocation location, CompilerType type,
- ParseResult rhs, bool is_rvalue)
- : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
- m_is_rvalue(is_rvalue) {}
-
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override { return m_is_rvalue; }
- CompilerType result_type() const override { return m_type; }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kCxxReinterpretCastNode;
- }
-
- CompilerType type() const { return m_type; }
- DILASTNode *rhs() const { return m_rhs.get(); }
-
-private:
- CompilerType m_type;
- ParseResult m_rhs;
- bool m_is_rvalue;
-};
-
class MemberOfNode : public DILASTNode {
public:
MemberOfNode(clang::SourceLocation location, CompilerType result_type,
@@ -557,41 +382,6 @@ class ArraySubscriptNode : public DILASTNode {
ParseResult m_index;
};
-class BinaryOpNode : public DILASTNode {
-public:
- BinaryOpNode(clang::SourceLocation location, CompilerType result_type,
- BinaryOpKind kind, ParseResult lhs, ParseResult rhs,
- CompilerType comp_assign_type,
- ValueObject *val_obj_ptr = nullptr)
- : DILASTNode(location), m_result_type(result_type), m_kind(kind),
- m_lhs(std::move(lhs)), m_rhs(std::move(rhs)),
- m_comp_assign_type(comp_assign_type) {
- if (val_obj_ptr)
- m_val_obj_sp = val_obj_ptr->GetSP();
- }
-
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override {
- return !binary_op_kind_is_comp_assign(m_kind);
- }
- CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kBinaryOpNode; }
-
- BinaryOpKind kind() const { return m_kind; }
- DILASTNode *lhs() const { return m_lhs.get(); }
- DILASTNode *rhs() const { return m_rhs.get(); }
- CompilerType comp_assign_type() const { return m_comp_assign_type; }
- lldb::ValueObjectSP get_valobj_sp() const { return m_val_obj_sp; }
-
-private:
- CompilerType m_result_type;
- BinaryOpKind m_kind;
- ParseResult m_lhs;
- ParseResult m_rhs;
- CompilerType m_comp_assign_type;
- lldb::ValueObjectSP m_val_obj_sp;
-};
-
class UnaryOpNode : public DILASTNode {
public:
UnaryOpNode(clang::SourceLocation location, CompilerType result_type,
@@ -613,34 +403,6 @@ class UnaryOpNode : public DILASTNode {
ParseResult m_rhs;
};
-class TernaryOpNode : public DILASTNode {
-public:
- TernaryOpNode(clang::SourceLocation location, CompilerType result_type,
- ParseResult cond, ParseResult lhs, ParseResult rhs)
- : DILASTNode(location), m_result_type(result_type),
- m_cond(std::move(cond)), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
-
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override {
- return m_lhs->is_rvalue() || m_rhs->is_rvalue();
- }
- bool is_bitfield() const override {
- return m_lhs->is_bitfield() || m_rhs->is_bitfield();
- }
- CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kTernaryOpNode; }
-
- DILASTNode *cond() const { return m_cond.get(); }
- DILASTNode *lhs() const { return m_lhs.get(); }
- DILASTNode *rhs() const { return m_rhs.get(); }
-
-private:
- CompilerType m_result_type;
- ParseResult m_cond;
- ParseResult m_lhs;
- ParseResult m_rhs;
-};
-
class SmartPtrToPtrDecay : public DILASTNode {
public:
SmartPtrToPtrDecay(clang::SourceLocation location, CompilerType result_type,
@@ -672,16 +434,10 @@ class DILVisitor {
virtual void Visit(const DILErrorNode *node) = 0;
virtual void Visit(const LiteralNode *node) = 0;
virtual void Visit(const IdentifierNode *node) = 0;
- virtual void Visit(const SizeOfNode *node) = 0;
- virtual void Visit(const BuiltinFunctionCallNode *node) = 0;
virtual void Visit(const CStyleCastNode *node) = 0;
- virtual void Visit(const CxxStaticCastNode *node) = 0;
- virtual void Visit(const CxxReinterpretCastNode *node) = 0;
virtual void Visit(const MemberOfNode *node) = 0;
virtual void Visit(const ArraySubscriptNode *node) = 0;
- virtual void Visit(const BinaryOpNode *node) = 0;
virtual void Visit(const UnaryOpNode *node) = 0;
- virtual void Visit(const TernaryOpNode *node) = 0;
virtual void Visit(const SmartPtrToPtrDecay *node) = 0;
};
diff --git a/lldb/source/Core/DILAST.cpp b/lldb/source/Core/DILAST.cpp
index 909c94064c4663..5a299714c299ff 100644
--- a/lldb/source/Core/DILAST.cpp
+++ b/lldb/source/Core/DILAST.cpp
@@ -71,94 +71,6 @@ lldb::ValueObjectSP DILGetSPWithLock(lldb::ValueObjectSP in_valobj_sp,
return value_sp;
}
-BinaryOpKind
-clang_token_kind_to_binary_op_kind(clang::tok::TokenKind token_kind) {
- switch (token_kind) {
- case clang::tok::star:
- return BinaryOpKind::Mul;
- case clang::tok::slash:
- return BinaryOpKind::Div;
- case clang::tok::percent:
- return BinaryOpKind::Rem;
- case clang::tok::plus:
- return BinaryOpKind::Add;
- case clang::tok::minus:
- return BinaryOpKind::Sub;
- case clang::tok::lessless:
- return BinaryOpKind::Shl;
- case clang::tok::greatergreater:
- return BinaryOpKind::Shr;
- case clang::tok::less:
- return BinaryOpKind::LT;
- case clang::tok::greater:
- return BinaryOpKind::GT;
- case clang::tok::lessequal:
- return BinaryOpKind::LE;
- case clang::tok::greaterequal:
- return BinaryOpKind::GE;
- case clang::tok::equalequal:
- return BinaryOpKind::EQ;
- case clang::tok::exclaimequal:
- return BinaryOpKind::NE;
- case clang::tok::amp:
- return BinaryOpKind::And;
- case clang::tok::caret:
- return BinaryOpKind::Xor;
- case clang::tok::pipe:
- return BinaryOpKind::Or;
- case clang::tok::ampamp:
- return BinaryOpKind::LAnd;
- case clang::tok::pipepipe:
- return BinaryOpKind::LOr;
- case clang::tok::equal:
- return BinaryOpKind::Assign;
- case clang::tok::starequal:
- return BinaryOpKind::MulAssign;
- case clang::tok::slashequal:
- return BinaryOpKind::DivAssign;
- case clang::tok::percentequal:
- return BinaryOpKind::RemAssign;
- case clang::tok::plusequal:
- return BinaryOpKind::AddAssign;
- case clang::tok::minusequal:
- return BinaryOpKind::SubAssign;
- case clang::tok::lesslessequal:
- return BinaryOpKind::ShlAssign;
- case clang::tok::greatergreaterequal:
- return BinaryOpKind::ShrAssign;
- case clang::tok::ampequal:
- return BinaryOpKind::AndAssign;
- case clang::tok::caretequal:
- return BinaryOpKind::XorAssign;
- case clang::tok::pipeequal:
- return BinaryOpKind::OrAssign;
-
- default:
- break;
- }
- llvm_unreachable("did you add an element to BinaryOpKind?");
-}
-
-bool binary_op_kind_is_comp_assign(BinaryOpKind kind) {
- switch (kind) {
- case BinaryOpKind::Assign:
- case BinaryOpKind::MulAssign:
- case BinaryOpKind::DivAssign:
- case BinaryOpKind::RemAssign:
- case BinaryOpKind::AddAssign:
- case BinaryOpKind::SubAssign:
- case BinaryOpKind::ShlAssign:
- case BinaryOpKind::ShrAssign:
- case BinaryOpKind::AndAssign:
- case BinaryOpKind::XorAssign:
- case BinaryOpKind::OrAssign:
- return true;
-
- default:
- return false;
- }
-}
-
CompilerType DILASTNode::result_type_deref() const {
auto type = result_type();
return type.IsReferenceType() ? type.GetNonReferenceType() : type;
@@ -543,26 +455,14 @@ void LiteralNode::Accept(DILVisitor *v) const { v->Visit(this); }
void IdentifierNode::Accept(DILVisitor *v) const { v->Visit(this); }
-void SizeOfNode::Accept(DILVisitor *v) const { v->Visit(this); }
-
-void BuiltinFunctionCallNode::Accept(DILVisitor *v) const { v->Visit(this); }
-
void CStyleCastNode::Accept(DILVisitor *v) const { v->Visit(this); }
-void CxxStaticCastNode::Accept(DILVisitor *v) const { return v->Visit(this); }
-
-void CxxReinterpretCastNode::Accept(DILVisitor *v) const { v->Visit(this); }
-
void MemberOfNode::Accept(DILVisitor *v) const { v->Visit(this); }
void ArraySubscriptNode::Accept(DILVisitor *v) const { v->Visit(this); }
-void BinaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
-
void UnaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
-void TernaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
-
void SmartPtrToPtrDecay::Accept(DILVisitor *v) const { v->Visit(this); }
} // namespace lldb_private
>From 17a593402dde818cb0dadfd8d8888180ee04c56c Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 2 Jul 2024 08:55:34 -0700
Subject: [PATCH 4/8] Fix clang format issue.
---
lldb/include/lldb/Core/DILAST.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
index 6b61157201c543..0bc43098262753 100644
--- a/lldb/include/lldb/Core/DILAST.h
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -91,9 +91,9 @@ enum class CStyleCastKind {
/// The Unary operators recognized by DIL.
enum class UnaryOpKind {
- AddrOf, // "&"
- Deref, // "*"
- Minus, // "-"
+ AddrOf, // "&"
+ Deref, // "*"
+ Minus, // "-"
};
/// Given a string representing a type, returns the CompilerType corresponding
>From d5f7e773079f396f068aebdff46781992a69088f Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sat, 27 Jul 2024 21:38:22 -0700
Subject: [PATCH 5/8] [LLDB] Add AST node classes & functions for Data
Inspection Language
Address review comments:
Remove decls for functions not defined or used in AST files; add
DIL namespace, code cleanups, etc.
---
lldb/docs/dil-expr-lang.ebnf | 13 +-
lldb/include/lldb/Core/DILAST.h | 331 ++++++++++++++++---------------
lldb/source/Core/DILAST.cpp | 302 ++++++++++++++++++----------
lldb/source/Core/ValueObject.cpp | 9 +-
4 files changed, 376 insertions(+), 279 deletions(-)
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index a3cef16c841340..a0244ee65cdebc 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -1,12 +1,10 @@
(* LLDB Debug Expressions, a subset of C++ *)
(* Insired by https://www.nongnu.org/hcb *)
-expression = cast_expression;
-
-cast_expression = unary_expression;
+expression = unary_expression;
unary_expression = postfix_expression
- | unary_operator cast_expression;
+ | unary_operator unary_expression;
unary_operator = "*" | "&" | "-" ;
@@ -18,8 +16,7 @@ postfix_expression = primary_expression
primary_expression = numeric_literal
| boolean_literal
| pointer_literal
- | id_expression
- | "this" ;
+ | id_expression;
nested_name_specifier = namespace_name '::'
| nested_name_specifier identifier "::";
@@ -37,7 +34,3 @@ qualified_id = [nested_name_specifier] unqualified_id
identifier = ? clang::tok::identifier ? ;
numeric_literal = ? clang::tok::numeric_constant ? ;
-
-boolean_literal = "true" | "false" ;
-
-pointer_literal = "nullptr" ;
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
index 0bc43098262753..67d273bf154933 100644
--- a/lldb/include/lldb/Core/DILAST.h
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLDB_DIL_AST_H_
-#define LLDB_DIL_AST_H_
+#ifndef LLDB_CORE_DILAST_H
+#define LLDB_CORE_DILAST_H
#include <memory>
#include <optional>
@@ -24,69 +24,48 @@
#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/Support/Casting.h"
namespace lldb_private {
+namespace DIL {
+
/// Struct to hold information about member fields. Used by the parser for the
/// Data Inspection Language (DIL).
-struct DILMemberInfo {
+struct MemberInfo {
std::optional<std::string> name;
CompilerType type;
- bool is_bitfield;
- uint32_t bitfield_size_in_bits;
+ std::optional<uint32_t> bitfield_size_in_bits;
bool is_synthetic;
bool is_dynamic;
lldb::ValueObjectSP val_obj_sp;
-
- explicit operator bool() const { return type.IsValid(); }
};
-/// This determines if the type is a shared, unique or weak pointer, either
-/// from stdlibc++ or libc+++.
-bool IsSmartPtrType(CompilerType type);
-
-/// Finds the member field with the given name and type, stores the child index
-/// corresponding to the field in the idx vector and returns a DILMemberInfo
-/// struct with appropriate information about the field.
-DILMemberInfo GetFieldWithNameIndexPath(lldb::ValueObjectSP lhs_val_sp,
- CompilerType type,
- const std::string &name,
- std::vector<uint32_t> *idx,
- CompilerType empty_type,
- bool use_synthetic, bool is_dynamic);
-
-std::tuple<DILMemberInfo, std::vector<uint32_t>>
-GetMemberInfo(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
- const std::string &name, bool use_synthetic);
-
/// Get the appropriate ValueObjectSP, consulting the use_dynamic and
/// use_synthetic options passed, acquiring the process & target locks if
/// appropriate.
-lldb::ValueObjectSP
-DILGetSPWithLock(lldb::ValueObjectSP valobj_sp,
- lldb::DynamicValueType use_dynamic = lldb::eNoDynamicValues,
- bool use_synthetic = false);
+lldb::ValueObjectSP GetDynamicOrSyntheticValue(
+ lldb::ValueObjectSP valobj_sp,
+ lldb::DynamicValueType use_dynamic = lldb::eNoDynamicValues,
+ bool use_synthetic = false);
/// The various types DIL AST nodes (used by the DIL parser).
-enum class DILNodeKind {
- kDILErrorNode,
- kLiteralNode,
- kIdentifierNode,
- kBuiltinFunctionCallNode,
- kCStyleCastNode,
- kMemberOfNode,
- kArraySubscriptNode,
- kUnaryOpNode,
- kSmartPtrToPtrDecay
+enum class NodeKind {
+ eErrorNode,
+ eScalarLiteralNode,
+ eStringLiteralNode,
+ eIdentifierNode,
+ eCStyleCastNode,
+ eMemberOfNode,
+ eArraySubscriptNode,
+ eUnaryOpNode,
+ eSmartPtrToPtrDecayNode
};
-/// The C-Style casts allowed by DIL.
-enum class CStyleCastKind {
- kArithmetic,
- kEnumeration,
- kPointer,
- kNullptr,
- kReference,
+/// The C-Style casts for type promotion allowed by DIL.
+enum class TypePromotionCastKind {
+ eArithmetic,
+ ePointer,
};
/// The Unary operators recognized by DIL.
@@ -102,54 +81,44 @@ CompilerType
ResolveTypeByName(const std::string &name,
std::shared_ptr<ExecutionContextScope> ctx_scope);
-/// Quick lookup to check if a type name already exists in a
-/// name-to-CompilerType map the DIL parser keeps of previously found
-/// name/type pairs.
-bool IsContextVar(const std::string &name);
-
-/// Checks to see if the CompilerType is a Smart Pointer (shared, unique, weak)
-/// or not. Only applicable for C++, which is why this is here and not part of
-/// the CompilerType class.
-bool IsSmartPtrType(CompilerType type);
-
/// Class used to store & manipulate information about identifiers.
class IdentifierInfo {
private:
using MemberPath = std::vector<uint32_t>;
- using IdentifierInfoPtr = std::unique_ptr<IdentifierInfo>;
+ using IdentifierInfoUP = std::unique_ptr<IdentifierInfo>;
public:
enum class Kind {
- kValue,
- kContextArg,
- kMemberPath,
- kThisKeyword,
+ eValue,
+ eContextArg,
+ eMemberPath,
+ eThisKeyword,
};
- static IdentifierInfoPtr FromValue(lldb::ValueObjectSP value_sp) {
+ static IdentifierInfoUP FromValue(lldb::ValueObjectSP value_sp) {
CompilerType type;
- lldb::ValueObjectSP value = DILGetSPWithLock(value_sp);
- if (value)
- type = value->GetCompilerType();
- return IdentifierInfoPtr(new IdentifierInfo(Kind::kValue, type, value, {}));
+ if (value_sp)
+ type = value_sp->GetCompilerType();
+ return IdentifierInfoUP(
+ new IdentifierInfo(Kind::eValue, type, value_sp, {}));
}
- static IdentifierInfoPtr FromContextArg(CompilerType type) {
+ static IdentifierInfoUP FromContextArg(CompilerType type) {
lldb::ValueObjectSP empty_value;
- return IdentifierInfoPtr(
- new IdentifierInfo(Kind::kContextArg, type, empty_value, {}));
+ return IdentifierInfoUP(
+ new IdentifierInfo(Kind::eContextArg, type, empty_value, {}));
}
- static IdentifierInfoPtr FromMemberPath(CompilerType type, MemberPath path) {
+ static IdentifierInfoUP FromMemberPath(CompilerType type, MemberPath path) {
lldb::ValueObjectSP empty_value;
- return IdentifierInfoPtr(new IdentifierInfo(Kind::kMemberPath, type,
- empty_value, std::move(path)));
+ return IdentifierInfoUP(new IdentifierInfo(Kind::eMemberPath, type,
+ empty_value, std::move(path)));
}
- static IdentifierInfoPtr FromThisKeyword(CompilerType type) {
+ static IdentifierInfoUP FromThisKeyword(CompilerType type) {
lldb::ValueObjectSP empty_value;
- return IdentifierInfoPtr(
- new IdentifierInfo(Kind::kThisKeyword, type, empty_value, {}));
+ return IdentifierInfoUP(
+ new IdentifierInfo(Kind::eThisKeyword, type, empty_value, {}));
}
Kind kind() const { return m_kind; }
@@ -181,9 +150,9 @@ std::unique_ptr<IdentifierInfo> LookupIdentifier(
/// Forward declaration, for use in DIL AST nodes. Definition is at the very
/// end of this file.
-class DILVisitor;
+class Visitor;
-/// The rest of the classes in this file, except for the DILVisitor class at the
+/// The rest of the classes in this file, except for the Visitor class at the
/// very end, define all the types of AST nodes used by the DIL parser and
/// expression evaluator. The DIL parser parses the input string and creates the
/// AST parse tree from the AST nodes. The resulting AST node tree gets passed
@@ -195,12 +164,12 @@ class DILVisitor;
/// class.
class DILASTNode {
public:
- DILASTNode(clang::SourceLocation location) : location_(location) {}
- virtual ~DILASTNode() {}
+ DILASTNode(clang::SourceLocation location, NodeKind kind)
+ : m_location(location), m_kind(kind) {}
+ virtual ~DILASTNode() = default;
- virtual void Accept(DILVisitor *v) const = 0;
+ virtual void Accept(Visitor *v) const = 0;
- virtual bool is_error() const { return false; };
virtual bool is_rvalue() const = 0;
virtual bool is_bitfield() const { return false; };
virtual bool is_context_var() const { return false; };
@@ -208,60 +177,84 @@ class DILASTNode {
virtual uint32_t bitfield_size() const { return 0; }
virtual CompilerType result_type() const = 0;
- virtual DILNodeKind what_am_i() const = 0;
-
- clang::SourceLocation location() const { return location_; }
+ clang::SourceLocation GetLocation() const { return m_location; }
+ NodeKind getKind() const { return m_kind; }
// The expression result type, but dereferenced in case it's a reference. This
// is for convenience, since for the purposes of the semantic analysis only
// the dereferenced type matters.
- CompilerType result_type_deref() const;
+ CompilerType GetDereferencedResultType() const;
private:
- clang::SourceLocation location_;
+ clang::SourceLocation m_location;
+ const NodeKind m_kind;
};
-using ParseResult = std::unique_ptr<DILASTNode>;
+using DILASTNodeUP = std::unique_ptr<DILASTNode>;
-class DILErrorNode : public DILASTNode {
+class ErrorNode : public DILASTNode {
public:
- DILErrorNode(CompilerType empty_type)
- : DILASTNode(clang::SourceLocation()), m_empty_type(empty_type) {}
- void Accept(DILVisitor *v) const override;
- bool is_error() const override { return true; }
+ ErrorNode(CompilerType empty_type)
+ : DILASTNode(clang::SourceLocation(), NodeKind::eErrorNode),
+ m_empty_type(empty_type) {}
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_empty_type; }
CompilerType result_type_real() const { return m_empty_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kDILErrorNode; }
+
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eErrorNode;
+ }
private:
CompilerType m_empty_type;
};
-class LiteralNode : public DILASTNode {
+class ScalarLiteralNode : public DILASTNode {
public:
- template <typename ValueT>
- LiteralNode(clang::SourceLocation location, CompilerType type, ValueT &&value,
- bool is_literal_zero)
- : DILASTNode(location), m_type(type),
- m_value(std::forward<ValueT>(value)),
- m_is_literal_zero(is_literal_zero) {}
-
- void Accept(DILVisitor *v) const override;
+ ScalarLiteralNode(clang::SourceLocation location, CompilerType type,
+ Scalar value, bool is_literal_zero)
+ : DILASTNode(location, NodeKind::eScalarLiteralNode), m_type(type),
+ m_value(value), m_is_literal_zero(is_literal_zero) {}
+
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return true; }
bool is_literal_zero() const override { return m_is_literal_zero; }
CompilerType result_type() const override { return m_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kLiteralNode; }
- template <typename ValueT> ValueT value() const {
- return std::get<ValueT>(m_value);
+ auto value() const { return m_value; }
+
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eScalarLiteralNode;
}
+private:
+ CompilerType m_type;
+ Scalar m_value;
+ bool m_is_literal_zero;
+};
+
+class StringLiteralNode : public DILASTNode {
+public:
+ StringLiteralNode(clang::SourceLocation location, CompilerType type,
+ std::vector<char> value, bool is_literal_zero)
+ : DILASTNode(location, NodeKind::eStringLiteralNode), m_type(type),
+ m_value(value), m_is_literal_zero(is_literal_zero) {}
+
+ void Accept(Visitor *v) const override;
+ bool is_rvalue() const override { return true; }
+ bool is_literal_zero() const override { return m_is_literal_zero; }
+ CompilerType result_type() const override { return m_type; }
+
auto value() const { return m_value; }
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eStringLiteralNode;
+ }
+
private:
CompilerType m_type;
- std::variant<llvm::APInt, llvm::APFloat, bool, std::vector<char>> m_value;
+ std::vector<char> m_value;
bool m_is_literal_zero;
};
@@ -270,21 +263,22 @@ class IdentifierNode : public DILASTNode {
IdentifierNode(clang::SourceLocation location, std::string name,
std::unique_ptr<IdentifierInfo> identifier, bool is_rvalue,
bool is_context_var)
- : DILASTNode(location), m_is_rvalue(is_rvalue),
+ : DILASTNode(location, NodeKind::eIdentifierNode), m_is_rvalue(is_rvalue),
m_is_context_var(is_context_var), m_name(std::move(name)),
m_identifier(std::move(identifier)) {}
- void Accept(DILVisitor *v) const override;
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return m_is_rvalue; }
bool is_context_var() const override { return m_is_context_var; };
CompilerType result_type() const override { return m_identifier->GetType(); }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kIdentifierNode;
- }
std::string name() const { return m_name; }
const IdentifierInfo &info() const { return *m_identifier; }
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eIdentifierNode;
+ }
+
private:
bool m_is_rvalue;
bool m_is_context_var;
@@ -295,48 +289,54 @@ class IdentifierNode : public DILASTNode {
class CStyleCastNode : public DILASTNode {
public:
CStyleCastNode(clang::SourceLocation location, CompilerType type,
- ParseResult rhs, CStyleCastKind kind)
- : DILASTNode(location), m_type(type), m_rhs(std::move(rhs)),
- m_kind(kind) {}
+ DILASTNodeUP rhs, TypePromotionCastKind kind)
+ : DILASTNode(location, NodeKind::eCStyleCastNode), m_type(type),
+ m_rhs(std::move(rhs)), m_promo_kind(kind) {}
- void Accept(DILVisitor *v) const override;
- bool is_rvalue() const override {
- return m_kind != CStyleCastKind::kReference;
- }
+ void Accept(Visitor *v) const override;
+ bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_type; }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kCStyleCastNode;
- }
CompilerType type() const { return m_type; }
DILASTNode *rhs() const { return m_rhs.get(); }
- CStyleCastKind kind() const { return m_kind; }
+ TypePromotionCastKind promo_kind() const { return m_promo_kind; }
+
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eCStyleCastNode;
+ }
private:
CompilerType m_type;
- ParseResult m_rhs;
- CStyleCastKind m_kind;
+ DILASTNodeUP m_rhs;
+ TypePromotionCastKind m_promo_kind;
};
class MemberOfNode : public DILASTNode {
public:
MemberOfNode(clang::SourceLocation location, CompilerType result_type,
- ParseResult lhs, bool is_bitfield, uint32_t bitfield_size,
+ DILASTNodeUP lhs, std::optional<uint32_t> bitfield_size,
std::vector<uint32_t> member_index, bool is_arrow,
bool is_synthetic, bool is_dynamic, ConstString name,
lldb::ValueObjectSP valobj_sp)
- : DILASTNode(location), m_result_type(result_type), m_lhs(std::move(lhs)),
- m_is_bitfield(is_bitfield), m_bitfield_size(bitfield_size),
+ : DILASTNode(location, NodeKind::eMemberOfNode),
+ m_result_type(result_type), m_lhs(std::move(lhs)),
m_member_index(std::move(member_index)), m_is_arrow(is_arrow),
m_is_synthetic(is_synthetic), m_is_dynamic(is_dynamic),
- m_field_name(name), m_valobj_sp(valobj_sp) {}
+ m_field_name(name), m_valobj_sp(valobj_sp) {
+ if (bitfield_size) {
+ m_is_bitfield = true;
+ m_bitfield_size = bitfield_size.value();
+ } else {
+ m_is_bitfield = false;
+ m_bitfield_size = 0;
+ }
+ }
- void Accept(DILVisitor *v) const override;
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
bool is_bitfield() const override { return m_is_bitfield; }
uint32_t bitfield_size() const override { return m_bitfield_size; }
CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kMemberOfNode; }
DILASTNode *lhs() const { return m_lhs.get(); }
const std::vector<uint32_t> &member_index() const { return m_member_index; }
@@ -346,9 +346,13 @@ class MemberOfNode : public DILASTNode {
ConstString field_name() const { return m_field_name; }
lldb::ValueObjectSP valobj_sp() const { return m_valobj_sp; }
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eMemberOfNode;
+ }
+
private:
CompilerType m_result_type;
- ParseResult m_lhs;
+ DILASTNodeUP m_lhs;
bool m_is_bitfield;
uint32_t m_bitfield_size;
std::vector<uint32_t> m_member_index;
@@ -362,77 +366,84 @@ class MemberOfNode : public DILASTNode {
class ArraySubscriptNode : public DILASTNode {
public:
ArraySubscriptNode(clang::SourceLocation location, CompilerType result_type,
- ParseResult base, ParseResult index)
- : DILASTNode(location), m_result_type(result_type),
- m_base(std::move(base)), m_index(std::move(index)) {}
+ DILASTNodeUP base, DILASTNodeUP index)
+ : DILASTNode(location, NodeKind::eArraySubscriptNode),
+ m_result_type(result_type), m_base(std::move(base)),
+ m_index(std::move(index)) {}
- void Accept(DILVisitor *v) const override;
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kArraySubscriptNode;
- }
DILASTNode *base() const { return m_base.get(); }
DILASTNode *index() const { return m_index.get(); }
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eArraySubscriptNode;
+ }
+
private:
CompilerType m_result_type;
- ParseResult m_base;
- ParseResult m_index;
+ DILASTNodeUP m_base;
+ DILASTNodeUP m_index;
};
class UnaryOpNode : public DILASTNode {
public:
UnaryOpNode(clang::SourceLocation location, CompilerType result_type,
- UnaryOpKind kind, ParseResult rhs)
- : DILASTNode(location), m_result_type(result_type), m_kind(kind),
- m_rhs(std::move(rhs)) {}
+ UnaryOpKind kind, DILASTNodeUP rhs)
+ : DILASTNode(location, NodeKind::eUnaryOpNode),
+ m_result_type(result_type), m_kind(kind), m_rhs(std::move(rhs)) {}
- void Accept(DILVisitor *v) const override;
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return m_kind != UnaryOpKind::Deref; }
CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override { return DILNodeKind::kUnaryOpNode; }
UnaryOpKind kind() const { return m_kind; }
DILASTNode *rhs() const { return m_rhs.get(); }
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eUnaryOpNode;
+ }
+
private:
CompilerType m_result_type;
UnaryOpKind m_kind;
- ParseResult m_rhs;
+ DILASTNodeUP m_rhs;
};
class SmartPtrToPtrDecay : public DILASTNode {
public:
SmartPtrToPtrDecay(clang::SourceLocation location, CompilerType result_type,
- ParseResult ptr)
- : DILASTNode(location), m_result_type(result_type),
- m_ptr(std::move(ptr)) {}
+ DILASTNodeUP ptr)
+ : DILASTNode(location, NodeKind::eSmartPtrToPtrDecayNode),
+ m_result_type(result_type), m_ptr(std::move(ptr)) {}
- void Accept(DILVisitor *v) const override;
+ void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_result_type; }
- DILNodeKind what_am_i() const override {
- return DILNodeKind::kSmartPtrToPtrDecay;
- }
DILASTNode *ptr() const { return m_ptr.get(); }
+ static bool classof(const DILASTNode *node) {
+ return node->getKind() == NodeKind::eSmartPtrToPtrDecayNode;
+ }
+
private:
CompilerType m_result_type;
- ParseResult m_ptr;
+ DILASTNodeUP m_ptr;
};
/// This class contains one Visit method for each specialized type of
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
/// the correct function in the DIL expression evaluator for evaluating that
/// type of AST node.
-class DILVisitor {
+class Visitor {
public:
- virtual ~DILVisitor() {}
- virtual void Visit(const DILErrorNode *node) = 0;
- virtual void Visit(const LiteralNode *node) = 0;
+ virtual ~Visitor() = default;
+ virtual void Visit(const ErrorNode *node) = 0;
+ virtual void Visit(const ScalarLiteralNode *node) = 0;
+ virtual void Visit(const StringLiteralNode *node) = 0;
virtual void Visit(const IdentifierNode *node) = 0;
virtual void Visit(const CStyleCastNode *node) = 0;
virtual void Visit(const MemberOfNode *node) = 0;
@@ -441,6 +452,8 @@ class DILVisitor {
virtual void Visit(const SmartPtrToPtrDecay *node) = 0;
};
+} // namespace DIL
+
} // namespace lldb_private
-#endif // LLDB_DIL_AST_H_
+#endif // LLDB_CORE_DILAST_H
diff --git a/lldb/source/Core/DILAST.cpp b/lldb/source/Core/DILAST.cpp
index 5a299714c299ff..05fadeb4ec8c53 100644
--- a/lldb/source/Core/DILAST.cpp
+++ b/lldb/source/Core/DILAST.cpp
@@ -20,11 +20,12 @@
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;
+namespace DIL {
+
+lldb::ValueObjectSP
+GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp,
+ lldb::DynamicValueType use_dynamic,
+ bool use_synthetic) {
Status error;
if (!in_valobj_sp) {
@@ -42,17 +43,6 @@ lldb::ValueObjectSP DILGetSPWithLock(lldb::ValueObjectSP in_valobj_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)
@@ -71,15 +61,144 @@ lldb::ValueObjectSP DILGetSPWithLock(lldb::ValueObjectSP in_valobj_sp,
return value_sp;
}
-CompilerType DILASTNode::result_type_deref() const {
+CompilerType DILASTNode::GetDereferencedResultType() const {
auto type = result_type();
return type.IsReferenceType() ? type.GetNonReferenceType() : type;
}
-static std::unordered_map<std::string, CompilerType> context_args;
+std::optional<MemberInfo>
+GetFieldWithNameIndexPath(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
+ const std::string &name, std::vector<uint32_t> *idx,
+ CompilerType empty_type, bool use_synthetic,
+ bool is_dynamic) {
+ bool is_synthetic = false;
+ // Go through the fields first.
+ uint32_t num_fields = type.GetNumFields();
+ lldb::ValueObjectSP empty_valobj_sp;
+ for (uint32_t i = 0; i < num_fields; ++i) {
+ uint64_t bit_offset = 0;
+ uint32_t bitfield_bit_size = 0;
+ bool is_bitfield = false;
+ std::string name_sstr;
+ CompilerType field_type(type.GetFieldAtIndex(
+ i, name_sstr, &bit_offset, &bitfield_bit_size, &is_bitfield));
+ auto field_name =
+ name_sstr.length() == 0 ? std::optional<std::string>() : name_sstr;
+ if (field_type.IsValid()) {
+ std::optional<uint32_t> size_in_bits;
+ if (is_bitfield)
+ size_in_bits = bitfield_bit_size;
+ struct MemberInfo field = {field_name, field_type, size_in_bits,
+ is_synthetic, is_dynamic, empty_valobj_sp};
+
+ // Name can be null if this is a padding field.
+ if (field.name == name) {
+ if (lhs_val_sp) {
+ lldb::ValueObjectSP child_valobj_sp =
+ lhs_val_sp->GetChildMemberWithName(name);
+ if (child_valobj_sp)
+ field.val_obj_sp = child_valobj_sp;
+ }
+
+ if (idx) {
+ assert(idx->empty());
+ // Direct base classes are located before fields, so field members
+ // needs to be offset by the number of base classes.
+ idx->push_back(i + type.GetNumberOfNonEmptyBaseClasses());
+ }
+ return field;
+ } else if (field.type.IsAnonymousType()) {
+ // Every member of an anonymous struct is considered to be a member of
+ // the enclosing struct or union. This applies recursively if the
+ // enclosing struct or union is also anonymous.
+
+ assert(!field.name && "Field should be unnamed.");
+
+ std::optional<MemberInfo> field_in_anon_type =
+ GetFieldWithNameIndexPath(lhs_val_sp, field.type, name, idx,
+ empty_type, use_synthetic, is_dynamic);
+ if (field_in_anon_type) {
+ if (idx) {
+ idx->push_back(i + type.GetNumberOfNonEmptyBaseClasses());
+ }
+ return field_in_anon_type.value();
+ }
+ }
+ }
+ }
+
+ // LLDB can't access inherited fields of anonymous struct members.
+ if (type.IsAnonymousType()) {
+ return {};
+ }
+
+ // Go through the base classes and look for the field there.
+ uint32_t num_non_empty_bases = 0;
+ uint32_t num_direct_bases = type.GetNumDirectBaseClasses();
+ for (uint32_t i = 0; i < num_direct_bases; ++i) {
+ uint32_t bit_offset;
+ auto base = type.GetDirectBaseClassAtIndex(i, &bit_offset);
+ auto field = GetFieldWithNameIndexPath(
+ lhs_val_sp, base, name, idx, empty_type, use_synthetic, is_dynamic);
+ if (field) {
+ if (idx) {
+ idx->push_back(num_non_empty_bases);
+ }
+ return field.value();
+ }
+ if (base.GetNumFields() > 0) {
+ num_non_empty_bases += 1;
+ }
+ }
+
+ // Check for synthetic member
+ if (lhs_val_sp && use_synthetic) {
+ lldb::ValueObjectSP child_valobj_sp = lhs_val_sp->GetSyntheticValue();
+ if (child_valobj_sp) {
+ is_synthetic = true;
+ uint32_t child_idx = child_valobj_sp->GetIndexOfChildWithName(name);
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(name);
+ if (child_valobj_sp) {
+ CompilerType field_type = child_valobj_sp->GetCompilerType();
+ if (field_type.IsValid()) {
+ struct MemberInfo field = {name, field_type, {},
+ is_synthetic, is_dynamic, child_valobj_sp};
+ if (idx) {
+ assert(idx->empty());
+ idx->push_back(child_idx);
+ }
+ return field;
+ }
+ }
+ }
+ }
+
+ if (lhs_val_sp) {
+ lldb::ValueObjectSP dynamic_val_sp =
+ lhs_val_sp->GetDynamicValue(lldb::eDynamicDontRunTarget);
+ if (dynamic_val_sp) {
+ CompilerType lhs_type = dynamic_val_sp->GetCompilerType();
+ if (lhs_type.IsPointerType())
+ lhs_type = lhs_type.GetPointeeType();
+ is_dynamic = true;
+ return GetFieldWithNameIndexPath(dynamic_val_sp, lhs_type, name, idx,
+ empty_type, use_synthetic, is_dynamic);
+ }
+ }
+
+ return {};
+}
-bool IsContextVar(const std::string &name) {
- return context_args.find(name) != context_args.end();
+std::tuple<std::optional<MemberInfo>, std::vector<uint32_t>>
+GetMemberInfo(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
+ const std::string &name, bool use_synthetic) {
+ std::vector<uint32_t> idx;
+ CompilerType empty_type;
+ bool is_dynamic = false;
+ std::optional<MemberInfo> member = GetFieldWithNameIndexPath(
+ lhs_val_sp, type, name, &idx, empty_type, use_synthetic, is_dynamic);
+ std::reverse(idx.begin(), idx.end());
+ return {member, std::move(idx)};
}
static lldb::ValueObjectSP
@@ -106,22 +225,12 @@ LookupStaticIdentifier(lldb::TargetSP target_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.
+ // Find the corrent variable by matching the name.
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()))
+ if (val->GetVariable() &&
+ (val->GetVariable()->NameMatches(unqualified_name) ||
+ val->GetVariable()->NameMatches(ConstString(name_ref))))
return val;
}
lldb::ValueObjectSP empty_obj_sp;
@@ -184,7 +293,7 @@ ResolveTypeByName(const std::string &name,
}
}
- if (result_type_list.size() == 0) {
+ if (result_type_list.empty()) {
for (auto type_system_sp : target_sp->GetScratchTypeSystems())
if (auto compiler_type =
type_system_sp->GetBuiltinTypeByName(const_type_name))
@@ -207,26 +316,20 @@ ResolveTypeByName(const std::string &name,
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 {
+ // Full match is always correct.
+ if (full_match.IsValid())
+ return full_match;
+
+ if (!global_scope) {
// 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.
+ // most "probable" type (pick a random one). TODO: Try to find a better way
+ // to do this.
if (partial_matches.size() > 0)
return partial_matches.back();
}
- CompilerType empty_type;
- return empty_type;
+ return {};
}
static lldb::VariableSP DILFindVariable(ConstString name,
@@ -241,23 +344,21 @@ static lldb::VariableSP DILFindVariable(ConstString name,
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);
+ str_ref_name.consume_front("::");
- ConstString tmp_name(str_ref_name);
- if (tmp_name == name)
+ if (str_ref_name == name.GetStringRef())
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;
- }
+ auto exact_match_it =
+ llvm::find_if(possible_matches, [&](lldb::VariableSP var_sp) {
+ return var_sp->GetName() == name;
+ });
+
+ if (exact_match_it != llvm::adl_end(possible_matches))
+ exact_match = *exact_match_it;
if (!exact_match)
// Look for a global var exact match.
@@ -284,10 +385,6 @@ 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();
@@ -299,17 +396,14 @@ LookupIdentifier(const std::string &name,
Target *target = ctx_scope->CalculateTarget().get();
Process *process = ctx_scope->CalculateProcess().get();
if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
- if (stack_frame) {
- lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
- if (reg_ctx) {
- if (const RegisterInfo *reg_info =
- reg_ctx->GetRegisterInfoByName(reg_name))
- value_sp =
- ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
- }
+ StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+ if (stack_frame) {
+ lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+ if (reg_ctx) {
+ if (const RegisterInfo *reg_info =
+ reg_ctx->GetRegisterInfoByName(reg_name))
+ value_sp =
+ ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
}
}
}
@@ -343,22 +437,19 @@ LookupIdentifier(const std::string &name,
if (!value_sp)
value_sp = frame->FindVariable(ConstString(name_ref));
- bool use_synthetic = false;
- lldb::ValueObjectSP value(
- DILGetSPWithLock(value_sp, use_dynamic, use_synthetic));
- if (value)
+ if (value_sp)
// Force static value, otherwise we can end up with the "real" type.
- return IdentifierInfo::FromValue(value);
+ return IdentifierInfo::FromValue(value_sp);
// Try looking for an instance variable (class member).
ConstString this_string("this");
- value = frame->FindVariable(this_string);
- if (value)
- value = value->GetChildMemberWithName(name_ref.data());
+ value_sp = frame->FindVariable(this_string);
+ if (value_sp)
+ value_sp = value_sp->GetChildMemberWithName(name_ref.data());
- if (value)
+ if (value_sp)
// Force static value, otherwise we can end up with the "real" type.
- return IdentifierInfo::FromValue(value->GetStaticValue());
+ return IdentifierInfo::FromValue(value_sp->GetStaticValue());
} else {
// In a "value" scope `this` refers to the scope object itself.
@@ -371,7 +462,8 @@ LookupIdentifier(const std::string &name,
auto [member, path] =
GetMemberInfo(empty_sp, *scope_ptr, name_ref.data(), use_synthetic);
if (member)
- return IdentifierInfo::FromMemberPath(member.type, std::move(path));
+ return IdentifierInfo::FromMemberPath(member.value().type,
+ std::move(path));
}
}
@@ -429,17 +521,13 @@ LookupIdentifier(const std::string &name,
Target *target = ctx_scope->CalculateTarget().get();
Process *process = ctx_scope->CalculateProcess().get();
if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
- if (stack_frame) {
- lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
- if (reg_ctx) {
- if (const RegisterInfo *reg_info =
- reg_ctx->GetRegisterInfoByName(name_ref.data()))
- value =
- ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
- }
+ StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+ if (stack_frame) {
+ lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+ if (reg_ctx) {
+ if (const RegisterInfo *reg_info =
+ reg_ctx->GetRegisterInfoByName(name_ref.data()))
+ value = ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
}
}
}
@@ -449,20 +537,24 @@ LookupIdentifier(const std::string &name,
return IdentifierInfo::FromValue(value);
}
-void DILErrorNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void ErrorNode::Accept(Visitor *v) const { v->Visit(this); }
+
+void ScalarLiteralNode::Accept(Visitor *v) const { v->Visit(this); }
+
+void StringLiteralNode::Accept(Visitor *v) const { v->Visit(this); }
-void LiteralNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void IdentifierNode::Accept(Visitor *v) const { v->Visit(this); }
-void IdentifierNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void CStyleCastNode::Accept(Visitor *v) const { v->Visit(this); }
-void CStyleCastNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void MemberOfNode::Accept(Visitor *v) const { v->Visit(this); }
-void MemberOfNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void ArraySubscriptNode::Accept(Visitor *v) const { v->Visit(this); }
-void ArraySubscriptNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void UnaryOpNode::Accept(Visitor *v) const { v->Visit(this); }
-void UnaryOpNode::Accept(DILVisitor *v) const { v->Visit(this); }
+void SmartPtrToPtrDecay::Accept(Visitor *v) const { v->Visit(this); }
-void SmartPtrToPtrDecay::Accept(DILVisitor *v) const { v->Visit(this); }
+} // namespace DIL
} // namespace lldb_private
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 8f72efc2299b4f..4927dac55d9114 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1198,6 +1198,7 @@ void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) {
// Verify the proposed new value is the right size.
lldb::TargetSP target = GetTargetSP();
+ ExecutionContext exe_ctx(target.get(), false);
uint64_t byte_size = 0;
if (auto temp = GetCompilerType().GetByteSize(target.get()))
byte_size = temp.value();
@@ -1207,11 +1208,9 @@ void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) {
return;
}
- lldb::DataExtractorSP data_sp;
- data_sp->SetData(value.getRawData(), byte_size,
- target->GetArchitecture().GetByteOrder());
- data_sp->SetAddressByteSize(
- static_cast<uint8_t>(target->GetArchitecture().GetAddressByteSize()));
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ value.getRawData(), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
SetData(*data_sp, error);
}
>From 33d134560564310f83295ce69eab2e86ef8fcad8 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 9 Aug 2024 22:19:36 -0700
Subject: [PATCH 6/8] [LLDB] Add AST node classes, functions, etc. for Data
Inspection Language
Address latest round of review comments.
---
lldb/include/lldb/Core/DILAST.h | 161 +++++++++++++-------------------
lldb/source/Core/DILAST.cpp | 65 +++++--------
2 files changed, 87 insertions(+), 139 deletions(-)
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
index 67d273bf154933..ee86c0a4a3fee7 100644
--- a/lldb/include/lldb/Core/DILAST.h
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -28,7 +28,7 @@
namespace lldb_private {
-namespace DIL {
+namespace dil {
/// Struct to hold information about member fields. Used by the parser for the
/// Data Inspection Language (DIL).
@@ -42,8 +42,7 @@ struct MemberInfo {
};
/// Get the appropriate ValueObjectSP, consulting the use_dynamic and
-/// use_synthetic options passed, acquiring the process & target locks if
-/// appropriate.
+/// use_synthetic options passed.
lldb::ValueObjectSP GetDynamicOrSyntheticValue(
lldb::ValueObjectSP valobj_sp,
lldb::DynamicValueType use_dynamic = lldb::eNoDynamicValues,
@@ -59,7 +58,6 @@ enum class NodeKind {
eMemberOfNode,
eArraySubscriptNode,
eUnaryOpNode,
- eSmartPtrToPtrDecayNode
};
/// The C-Style casts for type promotion allowed by DIL.
@@ -84,52 +82,43 @@ ResolveTypeByName(const std::string &name,
/// Class used to store & manipulate information about identifiers.
class IdentifierInfo {
private:
- using MemberPath = std::vector<uint32_t>;
- using IdentifierInfoUP = std::unique_ptr<IdentifierInfo>;
public:
enum class Kind {
eValue,
eContextArg,
eMemberPath,
- eThisKeyword,
};
- static IdentifierInfoUP FromValue(lldb::ValueObjectSP value_sp) {
+ static std::unique_ptr<IdentifierInfo> FromValue(ValueObject &valobj) {
CompilerType type;
- if (value_sp)
- type = value_sp->GetCompilerType();
- return IdentifierInfoUP(
- new IdentifierInfo(Kind::eValue, type, value_sp, {}));
+ type = valobj.GetCompilerType();
+ return std::unique_ptr<IdentifierInfo>(
+ new IdentifierInfo(Kind::eValue, type, valobj.GetSP(), {}));
}
- static IdentifierInfoUP FromContextArg(CompilerType type) {
+ static std::unique_ptr<IdentifierInfo> FromContextArg(CompilerType type) {
lldb::ValueObjectSP empty_value;
- return IdentifierInfoUP(
+ return std::unique_ptr<IdentifierInfo>(
new IdentifierInfo(Kind::eContextArg, type, empty_value, {}));
}
- static IdentifierInfoUP FromMemberPath(CompilerType type, MemberPath path) {
+ static std::unique_ptr<IdentifierInfo>
+ FromMemberPath(CompilerType type, std::vector<uint32_t> path) {
lldb::ValueObjectSP empty_value;
- return IdentifierInfoUP(new IdentifierInfo(Kind::eMemberPath, type,
- empty_value, std::move(path)));
+ return std::unique_ptr<IdentifierInfo>(new IdentifierInfo(
+ Kind::eMemberPath, type, empty_value, std::move(path)));
}
- static IdentifierInfoUP FromThisKeyword(CompilerType type) {
- lldb::ValueObjectSP empty_value;
- return IdentifierInfoUP(
- new IdentifierInfo(Kind::eThisKeyword, type, empty_value, {}));
- }
-
- Kind kind() const { return m_kind; }
- lldb::ValueObjectSP value() const { return m_value; }
- const MemberPath &path() const { return m_path; }
+ Kind GetKind() const { return m_kind; }
+ lldb::ValueObjectSP GetValue() const { return m_value; }
+ const std::vector<uint32_t> &GetPath() const { return m_path; }
CompilerType GetType() { return m_type; }
bool IsValid() const { return m_type.IsValid(); }
IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
- MemberPath path)
+ std::vector<uint32_t> path)
: m_kind(kind), m_type(type), m_value(std::move(value)),
m_path(std::move(path)) {}
@@ -137,7 +126,7 @@ class IdentifierInfo {
Kind m_kind;
CompilerType m_type;
lldb::ValueObjectSP m_value;
- MemberPath m_path;
+ std::vector<uint32_t> m_path;
};
/// Given the name of an identifier (variable name, member name, type name,
@@ -176,9 +165,10 @@ class DILASTNode {
virtual bool is_literal_zero() const { return false; }
virtual uint32_t bitfield_size() const { return 0; }
virtual CompilerType result_type() const = 0;
+ virtual ValueObject *valobj() const { return nullptr; }
clang::SourceLocation GetLocation() const { return m_location; }
- NodeKind getKind() const { return m_kind; }
+ NodeKind GetKind() const { return m_kind; }
// The expression result type, but dereferenced in case it's a reference. This
// is for convenience, since for the purposes of the semantic analysis only
@@ -203,7 +193,7 @@ class ErrorNode : public DILASTNode {
CompilerType result_type_real() const { return m_empty_type; }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eErrorNode;
+ return node->GetKind() == NodeKind::eErrorNode;
}
private:
@@ -213,49 +203,48 @@ class ErrorNode : public DILASTNode {
class ScalarLiteralNode : public DILASTNode {
public:
ScalarLiteralNode(clang::SourceLocation location, CompilerType type,
- Scalar value, bool is_literal_zero)
+ Scalar value)
: DILASTNode(location, NodeKind::eScalarLiteralNode), m_type(type),
- m_value(value), m_is_literal_zero(is_literal_zero) {}
+ m_value(value) {}
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return true; }
- bool is_literal_zero() const override { return m_is_literal_zero; }
+ bool is_literal_zero() const override {
+ return m_value.IsZero() && !m_type.IsBoolean();
+ }
CompilerType result_type() const override { return m_type; }
- auto value() const { return m_value; }
+ Scalar GetValue() const & { return m_value; }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eScalarLiteralNode;
+ return node->GetKind() == NodeKind::eScalarLiteralNode;
}
private:
CompilerType m_type;
Scalar m_value;
- bool m_is_literal_zero;
};
class StringLiteralNode : public DILASTNode {
public:
StringLiteralNode(clang::SourceLocation location, CompilerType type,
- std::vector<char> value, bool is_literal_zero)
+ std::string value)
: DILASTNode(location, NodeKind::eStringLiteralNode), m_type(type),
- m_value(value), m_is_literal_zero(is_literal_zero) {}
+ m_value(value) {}
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return true; }
- bool is_literal_zero() const override { return m_is_literal_zero; }
CompilerType result_type() const override { return m_type; }
- auto value() const { return m_value; }
+ std::string GetValue() const & { return m_value; }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eStringLiteralNode;
+ return node->GetKind() == NodeKind::eStringLiteralNode;
}
private:
CompilerType m_type;
- std::vector<char> m_value;
- bool m_is_literal_zero;
+ std::string m_value;
};
class IdentifierNode : public DILASTNode {
@@ -271,12 +260,15 @@ class IdentifierNode : public DILASTNode {
bool is_rvalue() const override { return m_is_rvalue; }
bool is_context_var() const override { return m_is_context_var; };
CompilerType result_type() const override { return m_identifier->GetType(); }
+ ValueObject *valobj() const override {
+ return m_identifier->GetValue().get();
+ }
std::string name() const { return m_name; }
const IdentifierInfo &info() const { return *m_identifier; }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eIdentifierNode;
+ return node->GetKind() == NodeKind::eIdentifierNode;
}
private:
@@ -289,78 +281,73 @@ class IdentifierNode : public DILASTNode {
class CStyleCastNode : public DILASTNode {
public:
CStyleCastNode(clang::SourceLocation location, CompilerType type,
- DILASTNodeUP rhs, TypePromotionCastKind kind)
+ DILASTNodeUP operand, TypePromotionCastKind kind)
: DILASTNode(location, NodeKind::eCStyleCastNode), m_type(type),
- m_rhs(std::move(rhs)), m_promo_kind(kind) {}
+ m_operand(std::move(operand)), m_promo_kind(kind) {}
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_type; }
+ ValueObject *valobj() const override { return m_operand->valobj(); }
CompilerType type() const { return m_type; }
- DILASTNode *rhs() const { return m_rhs.get(); }
+ DILASTNode *operand() const { return m_operand.get(); }
TypePromotionCastKind promo_kind() const { return m_promo_kind; }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eCStyleCastNode;
+ return node->GetKind() == NodeKind::eCStyleCastNode;
}
private:
CompilerType m_type;
- DILASTNodeUP m_rhs;
+ DILASTNodeUP m_operand;
TypePromotionCastKind m_promo_kind;
};
class MemberOfNode : public DILASTNode {
public:
MemberOfNode(clang::SourceLocation location, CompilerType result_type,
- DILASTNodeUP lhs, std::optional<uint32_t> bitfield_size,
+ DILASTNodeUP base, std::optional<uint32_t> bitfield_size,
std::vector<uint32_t> member_index, bool is_arrow,
bool is_synthetic, bool is_dynamic, ConstString name,
- lldb::ValueObjectSP valobj_sp)
+ lldb::ValueObjectSP field_valobj_sp)
: DILASTNode(location, NodeKind::eMemberOfNode),
- m_result_type(result_type), m_lhs(std::move(lhs)),
- m_member_index(std::move(member_index)), m_is_arrow(is_arrow),
- m_is_synthetic(is_synthetic), m_is_dynamic(is_dynamic),
- m_field_name(name), m_valobj_sp(valobj_sp) {
- if (bitfield_size) {
- m_is_bitfield = true;
- m_bitfield_size = bitfield_size.value();
- } else {
- m_is_bitfield = false;
- m_bitfield_size = 0;
- }
- }
+ m_result_type(result_type), m_base(std::move(base)),
+ m_bitfield_size(bitfield_size), m_member_index(std::move(member_index)),
+ m_is_arrow(is_arrow), m_is_synthetic(is_synthetic),
+ m_is_dynamic(is_dynamic), m_field_name(name),
+ m_field_valobj_sp(field_valobj_sp) {}
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
- bool is_bitfield() const override { return m_is_bitfield; }
- uint32_t bitfield_size() const override { return m_bitfield_size; }
+ bool is_bitfield() const override { return m_bitfield_size ? true : false; }
+ uint32_t bitfield_size() const override {
+ return m_bitfield_size ? m_bitfield_size.value() : 0;
+ }
CompilerType result_type() const override { return m_result_type; }
+ ValueObject *valobj() const override { return m_field_valobj_sp.get(); }
- DILASTNode *lhs() const { return m_lhs.get(); }
+ DILASTNode *base() const { return m_base.get(); }
const std::vector<uint32_t> &member_index() const { return m_member_index; }
bool is_arrow() const { return m_is_arrow; }
bool is_synthetic() const { return m_is_synthetic; }
bool is_dynamic() const { return m_is_dynamic; }
ConstString field_name() const { return m_field_name; }
- lldb::ValueObjectSP valobj_sp() const { return m_valobj_sp; }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eMemberOfNode;
+ return node->GetKind() == NodeKind::eMemberOfNode;
}
private:
CompilerType m_result_type;
- DILASTNodeUP m_lhs;
- bool m_is_bitfield;
- uint32_t m_bitfield_size;
+ DILASTNodeUP m_base;
+ std::optional<uint32_t> m_bitfield_size;
std::vector<uint32_t> m_member_index;
bool m_is_arrow;
bool m_is_synthetic;
bool m_is_dynamic;
ConstString m_field_name;
- lldb::ValueObjectSP m_valobj_sp;
+ lldb::ValueObjectSP m_field_valobj_sp;
};
class ArraySubscriptNode : public DILASTNode {
@@ -374,12 +361,13 @@ class ArraySubscriptNode : public DILASTNode {
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_result_type; }
+ ValueObject *valobj() const override { return m_base->valobj(); }
DILASTNode *base() const { return m_base.get(); }
DILASTNode *index() const { return m_index.get(); }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eArraySubscriptNode;
+ return node->GetKind() == NodeKind::eArraySubscriptNode;
}
private:
@@ -398,12 +386,13 @@ class UnaryOpNode : public DILASTNode {
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return m_kind != UnaryOpKind::Deref; }
CompilerType result_type() const override { return m_result_type; }
+ ValueObject *valobj() const override { return m_rhs->valobj(); }
UnaryOpKind kind() const { return m_kind; }
DILASTNode *rhs() const { return m_rhs.get(); }
static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eUnaryOpNode;
+ return node->GetKind() == NodeKind::eUnaryOpNode;
}
private:
@@ -412,27 +401,6 @@ class UnaryOpNode : public DILASTNode {
DILASTNodeUP m_rhs;
};
-class SmartPtrToPtrDecay : public DILASTNode {
-public:
- SmartPtrToPtrDecay(clang::SourceLocation location, CompilerType result_type,
- DILASTNodeUP ptr)
- : DILASTNode(location, NodeKind::eSmartPtrToPtrDecayNode),
- m_result_type(result_type), m_ptr(std::move(ptr)) {}
-
- void Accept(Visitor *v) const override;
- bool is_rvalue() const override { return false; }
- CompilerType result_type() const override { return m_result_type; }
-
- DILASTNode *ptr() const { return m_ptr.get(); }
-
- static bool classof(const DILASTNode *node) {
- return node->getKind() == NodeKind::eSmartPtrToPtrDecayNode;
- }
-
-private:
- CompilerType m_result_type;
- DILASTNodeUP m_ptr;
-};
/// This class contains one Visit method for each specialized type of
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
@@ -449,10 +417,9 @@ class Visitor {
virtual void Visit(const MemberOfNode *node) = 0;
virtual void Visit(const ArraySubscriptNode *node) = 0;
virtual void Visit(const UnaryOpNode *node) = 0;
- virtual void Visit(const SmartPtrToPtrDecay *node) = 0;
};
-} // namespace DIL
+} // namespace dil
} // namespace lldb_private
diff --git a/lldb/source/Core/DILAST.cpp b/lldb/source/Core/DILAST.cpp
index 05fadeb4ec8c53..44b4837fdbf6f4 100644
--- a/lldb/source/Core/DILAST.cpp
+++ b/lldb/source/Core/DILAST.cpp
@@ -20,7 +20,7 @@
namespace lldb_private {
-namespace DIL {
+namespace dil {
lldb::ValueObjectSP
GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp,
@@ -96,7 +96,8 @@ GetFieldWithNameIndexPath(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
if (lhs_val_sp) {
lldb::ValueObjectSP child_valobj_sp =
lhs_val_sp->GetChildMemberWithName(name);
- if (child_valobj_sp)
+ if (child_valobj_sp &&
+ child_valobj_sp->GetName() == ConstString(name))
field.val_obj_sp = child_valobj_sp;
}
@@ -208,11 +209,9 @@ LookupStaticIdentifier(lldb::TargetSP target_sp,
// 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);
+ target_sp->GetImages().FindGlobalVariables(name, 1, variable_list);
if (!variable_list.Empty()) {
ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get();
if (exe_scope == nullptr)
@@ -220,21 +219,13 @@ LookupStaticIdentifier(lldb::TargetSP target_sp,
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);
+ if (valobj_sp && valobj_sp->GetVariable() &&
+ (valobj_sp->GetVariable()->NameMatches(unqualified_name) ||
+ valobj_sp->GetVariable()->NameMatches(ConstString(name_ref))))
+ return valobj_sp;
}
}
-
- // Find the corrent variable by matching the name.
- for (uint32_t i = 0; i < values.size(); ++i) {
- lldb::ValueObjectSP val = values[i];
- if (val->GetVariable() &&
- (val->GetVariable()->NameMatches(unqualified_name) ||
- val->GetVariable()->NameMatches(ConstString(name_ref))))
- return val;
- }
- lldb::ValueObjectSP empty_obj_sp;
- return empty_obj_sp;
+ return nullptr;
}
struct EnumMember {
@@ -263,12 +254,9 @@ ResolveTypeByName(const std::string &name,
// 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("::")) {
+ 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();
@@ -320,15 +308,6 @@ ResolveTypeByName(const std::string &name,
if (full_match.IsValid())
return full_match;
- if (!global_scope) {
- // 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 (pick a random one). TODO: Try to find a better way
- // to do this.
- if (partial_matches.size() > 0)
- return partial_matches.back();
- }
-
return {};
}
@@ -407,7 +386,11 @@ LookupIdentifier(const std::string &name,
}
}
}
- return IdentifierInfo::FromValue(value_sp);
+ if (value_sp)
+ return IdentifierInfo::FromValue(*value_sp);
+ else
+ return std::unique_ptr<IdentifierInfo>(
+ new IdentifierInfo(IdentifierInfo::Kind::eValue, {}, nullptr, {}));
}
// Internally values don't have global scope qualifier in their names and
@@ -439,7 +422,7 @@ LookupIdentifier(const std::string &name,
if (value_sp)
// Force static value, otherwise we can end up with the "real" type.
- return IdentifierInfo::FromValue(value_sp);
+ return IdentifierInfo::FromValue(*value_sp);
// Try looking for an instance variable (class member).
ConstString this_string("this");
@@ -449,13 +432,9 @@ LookupIdentifier(const std::string &name,
if (value_sp)
// Force static value, otherwise we can end up with the "real" type.
- return IdentifierInfo::FromValue(value_sp->GetStaticValue());
+ return IdentifierInfo::FromValue(*(value_sp->GetStaticValue()));
} else {
- // In a "value" scope `this` refers to the scope object itself.
- if (name_ref == "this")
- return IdentifierInfo::FromThisKeyword(scope_ptr->GetPointerType());
-
// Lookup the variable as a member of the current scope value.
lldb::ValueObjectSP empty_sp;
bool use_synthetic = false;
@@ -534,7 +513,11 @@ LookupIdentifier(const std::string &name,
}
// Force static value, otherwise we can end up with the "real" type.
- return IdentifierInfo::FromValue(value);
+ if (value)
+ return IdentifierInfo::FromValue(*value);
+ else
+ return std::unique_ptr<IdentifierInfo>(
+ new IdentifierInfo(IdentifierInfo::Kind::eValue, {}, nullptr, {}));
}
void ErrorNode::Accept(Visitor *v) const { v->Visit(this); }
@@ -553,8 +536,6 @@ void ArraySubscriptNode::Accept(Visitor *v) const { v->Visit(this); }
void UnaryOpNode::Accept(Visitor *v) const { v->Visit(this); }
-void SmartPtrToPtrDecay::Accept(Visitor *v) const { v->Visit(this); }
-
-} // namespace DIL
+} // namespace dil
} // namespace lldb_private
>From 41ced65c88a8727152d39d22a942ab927cf0b079 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 6 Sep 2024 21:55:31 -0700
Subject: [PATCH 7/8] [LLDB] Add AST node clases, functions, etc. for Data
Inspection Language
Address review comments.
---
lldb/include/lldb/Core/DILAST.h | 30 ++-----
lldb/source/Core/DILAST.cpp | 155 +-------------------------------
2 files changed, 12 insertions(+), 173 deletions(-)
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
index ee86c0a4a3fee7..3a671816a74759 100644
--- a/lldb/include/lldb/Core/DILAST.h
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -34,8 +34,6 @@ namespace dil {
/// Data Inspection Language (DIL).
struct MemberInfo {
std::optional<std::string> name;
- CompilerType type;
- std::optional<uint32_t> bitfield_size_in_bits;
bool is_synthetic;
bool is_dynamic;
lldb::ValueObjectSP val_obj_sp;
@@ -64,6 +62,7 @@ enum class NodeKind {
enum class TypePromotionCastKind {
eArithmetic,
ePointer,
+ eNone,
};
/// The Unary operators recognized by DIL.
@@ -81,8 +80,6 @@ ResolveTypeByName(const std::string &name,
/// Class used to store & manipulate information about identifiers.
class IdentifierInfo {
-private:
-
public:
enum class Kind {
eValue,
@@ -115,7 +112,6 @@ class IdentifierInfo {
const std::vector<uint32_t> &GetPath() const { return m_path; }
CompilerType GetType() { return m_type; }
- bool IsValid() const { return m_type.IsValid(); }
IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
std::vector<uint32_t> path)
@@ -165,7 +161,6 @@ class DILASTNode {
virtual bool is_literal_zero() const { return false; }
virtual uint32_t bitfield_size() const { return 0; }
virtual CompilerType result_type() const = 0;
- virtual ValueObject *valobj() const { return nullptr; }
clang::SourceLocation GetLocation() const { return m_location; }
NodeKind GetKind() const { return m_kind; }
@@ -260,9 +255,6 @@ class IdentifierNode : public DILASTNode {
bool is_rvalue() const override { return m_is_rvalue; }
bool is_context_var() const override { return m_is_context_var; };
CompilerType result_type() const override { return m_identifier->GetType(); }
- ValueObject *valobj() const override {
- return m_identifier->GetValue().get();
- }
std::string name() const { return m_name; }
const IdentifierInfo &info() const { return *m_identifier; }
@@ -288,7 +280,6 @@ class CStyleCastNode : public DILASTNode {
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_type; }
- ValueObject *valobj() const override { return m_operand->valobj(); }
CompilerType type() const { return m_type; }
DILASTNode *operand() const { return m_operand.get(); }
@@ -307,28 +298,27 @@ class CStyleCastNode : public DILASTNode {
class MemberOfNode : public DILASTNode {
public:
MemberOfNode(clang::SourceLocation location, CompilerType result_type,
- DILASTNodeUP base, std::optional<uint32_t> bitfield_size,
- std::vector<uint32_t> member_index, bool is_arrow,
- bool is_synthetic, bool is_dynamic, ConstString name,
+ DILASTNodeUP base, bool is_arrow, bool is_synthetic,
+ bool is_dynamic, ConstString name,
lldb::ValueObjectSP field_valobj_sp)
: DILASTNode(location, NodeKind::eMemberOfNode),
m_result_type(result_type), m_base(std::move(base)),
- m_bitfield_size(bitfield_size), m_member_index(std::move(member_index)),
m_is_arrow(is_arrow), m_is_synthetic(is_synthetic),
m_is_dynamic(is_dynamic), m_field_name(name),
m_field_valobj_sp(field_valobj_sp) {}
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
- bool is_bitfield() const override { return m_bitfield_size ? true : false; }
+ bool is_bitfield() const override { return m_field_valobj_sp->IsBitfield(); }
uint32_t bitfield_size() const override {
- return m_bitfield_size ? m_bitfield_size.value() : 0;
+ if (m_field_valobj_sp->IsBitfield())
+ return m_field_valobj_sp->GetBitfieldBitSize();
+ return 0;
}
CompilerType result_type() const override { return m_result_type; }
- ValueObject *valobj() const override { return m_field_valobj_sp.get(); }
DILASTNode *base() const { return m_base.get(); }
- const std::vector<uint32_t> &member_index() const { return m_member_index; }
+ ValueObject *valobj() const { return m_field_valobj_sp.get(); }
bool is_arrow() const { return m_is_arrow; }
bool is_synthetic() const { return m_is_synthetic; }
bool is_dynamic() const { return m_is_dynamic; }
@@ -341,8 +331,6 @@ class MemberOfNode : public DILASTNode {
private:
CompilerType m_result_type;
DILASTNodeUP m_base;
- std::optional<uint32_t> m_bitfield_size;
- std::vector<uint32_t> m_member_index;
bool m_is_arrow;
bool m_is_synthetic;
bool m_is_dynamic;
@@ -361,7 +349,6 @@ class ArraySubscriptNode : public DILASTNode {
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return false; }
CompilerType result_type() const override { return m_result_type; }
- ValueObject *valobj() const override { return m_base->valobj(); }
DILASTNode *base() const { return m_base.get(); }
DILASTNode *index() const { return m_index.get(); }
@@ -386,7 +373,6 @@ class UnaryOpNode : public DILASTNode {
void Accept(Visitor *v) const override;
bool is_rvalue() const override { return m_kind != UnaryOpKind::Deref; }
CompilerType result_type() const override { return m_result_type; }
- ValueObject *valobj() const override { return m_rhs->valobj(); }
UnaryOpKind kind() const { return m_kind; }
DILASTNode *rhs() const { return m_rhs.get(); }
diff --git a/lldb/source/Core/DILAST.cpp b/lldb/source/Core/DILAST.cpp
index 44b4837fdbf6f4..15b1062aab54ac 100644
--- a/lldb/source/Core/DILAST.cpp
+++ b/lldb/source/Core/DILAST.cpp
@@ -29,7 +29,7 @@ GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp,
Status error;
if (!in_valobj_sp) {
- error.SetErrorString("invalid value object");
+ error = Status("invalid value object");
return in_valobj_sp;
}
@@ -56,7 +56,7 @@ GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp,
}
if (!value_sp)
- error.SetErrorString("invalid value object");
+ error = Status("invalid value object");
return value_sp;
}
@@ -66,142 +66,6 @@ CompilerType DILASTNode::GetDereferencedResultType() const {
return type.IsReferenceType() ? type.GetNonReferenceType() : type;
}
-std::optional<MemberInfo>
-GetFieldWithNameIndexPath(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
- const std::string &name, std::vector<uint32_t> *idx,
- CompilerType empty_type, bool use_synthetic,
- bool is_dynamic) {
- bool is_synthetic = false;
- // Go through the fields first.
- uint32_t num_fields = type.GetNumFields();
- lldb::ValueObjectSP empty_valobj_sp;
- for (uint32_t i = 0; i < num_fields; ++i) {
- uint64_t bit_offset = 0;
- uint32_t bitfield_bit_size = 0;
- bool is_bitfield = false;
- std::string name_sstr;
- CompilerType field_type(type.GetFieldAtIndex(
- i, name_sstr, &bit_offset, &bitfield_bit_size, &is_bitfield));
- auto field_name =
- name_sstr.length() == 0 ? std::optional<std::string>() : name_sstr;
- if (field_type.IsValid()) {
- std::optional<uint32_t> size_in_bits;
- if (is_bitfield)
- size_in_bits = bitfield_bit_size;
- struct MemberInfo field = {field_name, field_type, size_in_bits,
- is_synthetic, is_dynamic, empty_valobj_sp};
-
- // Name can be null if this is a padding field.
- if (field.name == name) {
- if (lhs_val_sp) {
- lldb::ValueObjectSP child_valobj_sp =
- lhs_val_sp->GetChildMemberWithName(name);
- if (child_valobj_sp &&
- child_valobj_sp->GetName() == ConstString(name))
- field.val_obj_sp = child_valobj_sp;
- }
-
- if (idx) {
- assert(idx->empty());
- // Direct base classes are located before fields, so field members
- // needs to be offset by the number of base classes.
- idx->push_back(i + type.GetNumberOfNonEmptyBaseClasses());
- }
- return field;
- } else if (field.type.IsAnonymousType()) {
- // Every member of an anonymous struct is considered to be a member of
- // the enclosing struct or union. This applies recursively if the
- // enclosing struct or union is also anonymous.
-
- assert(!field.name && "Field should be unnamed.");
-
- std::optional<MemberInfo> field_in_anon_type =
- GetFieldWithNameIndexPath(lhs_val_sp, field.type, name, idx,
- empty_type, use_synthetic, is_dynamic);
- if (field_in_anon_type) {
- if (idx) {
- idx->push_back(i + type.GetNumberOfNonEmptyBaseClasses());
- }
- return field_in_anon_type.value();
- }
- }
- }
- }
-
- // LLDB can't access inherited fields of anonymous struct members.
- if (type.IsAnonymousType()) {
- return {};
- }
-
- // Go through the base classes and look for the field there.
- uint32_t num_non_empty_bases = 0;
- uint32_t num_direct_bases = type.GetNumDirectBaseClasses();
- for (uint32_t i = 0; i < num_direct_bases; ++i) {
- uint32_t bit_offset;
- auto base = type.GetDirectBaseClassAtIndex(i, &bit_offset);
- auto field = GetFieldWithNameIndexPath(
- lhs_val_sp, base, name, idx, empty_type, use_synthetic, is_dynamic);
- if (field) {
- if (idx) {
- idx->push_back(num_non_empty_bases);
- }
- return field.value();
- }
- if (base.GetNumFields() > 0) {
- num_non_empty_bases += 1;
- }
- }
-
- // Check for synthetic member
- if (lhs_val_sp && use_synthetic) {
- lldb::ValueObjectSP child_valobj_sp = lhs_val_sp->GetSyntheticValue();
- if (child_valobj_sp) {
- is_synthetic = true;
- uint32_t child_idx = child_valobj_sp->GetIndexOfChildWithName(name);
- child_valobj_sp = child_valobj_sp->GetChildMemberWithName(name);
- if (child_valobj_sp) {
- CompilerType field_type = child_valobj_sp->GetCompilerType();
- if (field_type.IsValid()) {
- struct MemberInfo field = {name, field_type, {},
- is_synthetic, is_dynamic, child_valobj_sp};
- if (idx) {
- assert(idx->empty());
- idx->push_back(child_idx);
- }
- return field;
- }
- }
- }
- }
-
- if (lhs_val_sp) {
- lldb::ValueObjectSP dynamic_val_sp =
- lhs_val_sp->GetDynamicValue(lldb::eDynamicDontRunTarget);
- if (dynamic_val_sp) {
- CompilerType lhs_type = dynamic_val_sp->GetCompilerType();
- if (lhs_type.IsPointerType())
- lhs_type = lhs_type.GetPointeeType();
- is_dynamic = true;
- return GetFieldWithNameIndexPath(dynamic_val_sp, lhs_type, name, idx,
- empty_type, use_synthetic, is_dynamic);
- }
- }
-
- return {};
-}
-
-std::tuple<std::optional<MemberInfo>, std::vector<uint32_t>>
-GetMemberInfo(lldb::ValueObjectSP lhs_val_sp, CompilerType type,
- const std::string &name, bool use_synthetic) {
- std::vector<uint32_t> idx;
- CompilerType empty_type;
- bool is_dynamic = false;
- std::optional<MemberInfo> member = GetFieldWithNameIndexPath(
- lhs_val_sp, type, name, &idx, empty_type, use_synthetic, is_dynamic);
- std::reverse(idx.begin(), idx.end());
- return {member, std::move(idx)};
-}
-
static lldb::ValueObjectSP
LookupStaticIdentifier(lldb::TargetSP target_sp,
const llvm::StringRef &name_ref,
@@ -389,8 +253,7 @@ LookupIdentifier(const std::string &name,
if (value_sp)
return IdentifierInfo::FromValue(*value_sp);
else
- return std::unique_ptr<IdentifierInfo>(
- new IdentifierInfo(IdentifierInfo::Kind::eValue, {}, nullptr, {}));
+ return nullptr;
}
// Internally values don't have global scope qualifier in their names and
@@ -434,15 +297,6 @@ LookupIdentifier(const std::string &name,
// Force static value, otherwise we can end up with the "real" type.
return IdentifierInfo::FromValue(*(value_sp->GetStaticValue()));
- } else {
- // Lookup the variable as a member of the current scope value.
- lldb::ValueObjectSP empty_sp;
- bool use_synthetic = false;
- auto [member, path] =
- GetMemberInfo(empty_sp, *scope_ptr, name_ref.data(), use_synthetic);
- if (member)
- return IdentifierInfo::FromMemberPath(member.value().type,
- std::move(path));
}
}
@@ -516,8 +370,7 @@ LookupIdentifier(const std::string &name,
if (value)
return IdentifierInfo::FromValue(*value);
else
- return std::unique_ptr<IdentifierInfo>(
- new IdentifierInfo(IdentifierInfo::Kind::eValue, {}, nullptr, {}));
+ return nullptr;
}
void ErrorNode::Accept(Visitor *v) const { v->Visit(this); }
>From 4ff808aa8fbbc76c66d79de381254f4f7d3540d6 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 6 Sep 2024 22:05:16 -0700
Subject: [PATCH 8/8] Fix clang format issues.
---
lldb/include/lldb/Core/DILAST.h | 1 -
lldb/source/Core/DILAST.cpp | 1 -
2 files changed, 2 deletions(-)
diff --git a/lldb/include/lldb/Core/DILAST.h b/lldb/include/lldb/Core/DILAST.h
index 3a671816a74759..fc72a827ba58a0 100644
--- a/lldb/include/lldb/Core/DILAST.h
+++ b/lldb/include/lldb/Core/DILAST.h
@@ -387,7 +387,6 @@ class UnaryOpNode : public DILASTNode {
DILASTNodeUP m_rhs;
};
-
/// This class contains one Visit method for each specialized type of
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
/// the correct function in the DIL expression evaluator for evaluating that
diff --git a/lldb/source/Core/DILAST.cpp b/lldb/source/Core/DILAST.cpp
index 15b1062aab54ac..81e3584c4bf85e 100644
--- a/lldb/source/Core/DILAST.cpp
+++ b/lldb/source/Core/DILAST.cpp
@@ -296,7 +296,6 @@ LookupIdentifier(const std::string &name,
if (value_sp)
// Force static value, otherwise we can end up with the "real" type.
return IdentifierInfo::FromValue(*(value_sp->GetStaticValue()));
-
}
}
More information about the lldb-commits
mailing list