-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[LLDB] Add unary operators Dereference and AddressOf to DIL #134428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
58c4f08
36d4f95
d7fdf3f
336d59f
8b63dfd
b183a3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,13 @@ namespace lldb_private::dil { | |
| enum class NodeKind { | ||
| eErrorNode, | ||
| eIdentifierNode, | ||
| eUnaryOpNode, | ||
| }; | ||
|
|
||
| /// The Unary operators recognized by DIL. | ||
| enum class UnaryOpKind { | ||
| AddrOf, // "&" | ||
| Deref, // "*" | ||
| }; | ||
|
|
||
| /// Forward declaration, for use in DIL AST nodes. Definition is at the very | ||
|
|
@@ -44,6 +51,8 @@ class ASTNode { | |
|
|
||
| virtual llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const = 0; | ||
|
|
||
| virtual bool is_rvalue() const { return false; } | ||
|
|
||
| uint32_t GetLocation() const { return m_location; } | ||
| NodeKind GetKind() const { return m_kind; } | ||
|
|
||
|
|
@@ -81,6 +90,27 @@ class IdentifierNode : public ASTNode { | |
| std::string m_name; | ||
| }; | ||
|
|
||
| class UnaryOpNode : public ASTNode { | ||
| public: | ||
| UnaryOpNode(uint32_t location, UnaryOpKind kind, ASTNodeUP rhs) | ||
| : ASTNode(location, NodeKind::eUnaryOpNode), m_kind(kind), | ||
| m_rhs(std::move(rhs)) {} | ||
|
|
||
| llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override; | ||
| bool is_rvalue() const override { return m_kind != UnaryOpKind::Deref; } | ||
|
|
||
| UnaryOpKind kind() const { return m_kind; } | ||
| ASTNode *rhs() const { return m_rhs.get(); } | ||
|
|
||
| static bool classof(const ASTNode *node) { | ||
| return node->GetKind() == NodeKind::eUnaryOpNode; | ||
| } | ||
|
|
||
| private: | ||
| UnaryOpKind m_kind; | ||
| ASTNodeUP 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 | ||
|
|
@@ -90,6 +120,8 @@ class Visitor { | |
| virtual ~Visitor() = default; | ||
| virtual llvm::Expected<lldb::ValueObjectSP> | ||
| Visit(const IdentifierNode *node) = 0; | ||
| virtual llvm::Expected<lldb::ValueObjectSP> | ||
| Visit(const UnaryOpNode *node) = 0; | ||
| }; | ||
|
|
||
| } // namespace lldb_private::dil | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,22 @@ | |||||
|
|
||||||
| namespace lldb_private::dil { | ||||||
|
|
||||||
| static lldb::ValueObjectSP | ||||||
| ArrayToPointerConversion(lldb::ValueObjectSP valobj, | ||||||
| std::shared_ptr<ExecutionContextScope> ctx) { | ||||||
| assert(valobj->IsArrayType() && | ||||||
| "an argument to array-to-pointer conversion must be an array"); | ||||||
|
|
||||||
| uint64_t addr = valobj->GetLoadAddress(); | ||||||
| llvm::StringRef name = "result"; | ||||||
| ExecutionContext exe_ctx; | ||||||
| ctx->CalculateExecutionContext(exe_ctx); | ||||||
| return ValueObject::CreateValueObjectFromAddress( | ||||||
| name, addr, exe_ctx, | ||||||
| valobj->GetCompilerType().GetArrayElementType(ctx.get()).GetPointerType(), | ||||||
| /* do_deref */ false); | ||||||
| } | ||||||
|
|
||||||
|
||||||
| static lldb::ValueObjectSP LookupStaticIdentifier( | ||||||
| VariableList &variable_list, std::shared_ptr<StackFrame> exe_scope, | ||||||
| llvm::StringRef name_ref, llvm::StringRef unqualified_name) { | ||||||
|
|
@@ -206,10 +222,25 @@ Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr, | |||||
| : m_target(std::move(target)), m_expr(expr), m_default_dynamic(use_dynamic), | ||||||
| m_exe_ctx_scope(frame_sp) {} | ||||||
|
|
||||||
| llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) { | ||||||
| llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *tree) { | ||||||
| // Evaluate an AST. | ||||||
| auto value_or_error = EvaluateNode(tree); | ||||||
|
|
||||||
| // Return the computed result-or-error. | ||||||
| return value_or_error; | ||||||
| } | ||||||
|
|
||||||
| llvm::Expected<lldb::ValueObjectSP> | ||||||
| Interpreter::EvaluateNode(const ASTNode *node, FlowAnalysis *flow) { | ||||||
| // Set up the evaluation context for the current node. | ||||||
| m_flow_analysis_chain.push_back(flow); | ||||||
| // Traverse an AST pointed by the `node`. | ||||||
| return node->Accept(this); | ||||||
| auto value_or_error = node->Accept(this); | ||||||
| // Cleanup the context. | ||||||
| m_flow_analysis_chain.pop_back(); | ||||||
| // Return the computed value-or-error. The caller is responsible for | ||||||
| // checking if an error occured during the evaluation. | ||||||
| return value_or_error; | ||||||
| } | ||||||
|
|
||||||
| llvm::Expected<lldb::ValueObjectSP> | ||||||
|
|
@@ -232,4 +263,105 @@ Interpreter::Visit(const IdentifierNode *node) { | |||||
| return identifier; | ||||||
| } | ||||||
|
|
||||||
| } // namespace lldb_private::dil | ||||||
| llvm::Expected<lldb::ValueObjectSP> | ||||||
| Interpreter::Visit(const UnaryOpNode *node) { | ||||||
| FlowAnalysis rhs_flow( | ||||||
| /* address_of_is_pending */ node->kind() == UnaryOpKind::AddrOf); | ||||||
|
|
||||||
| Status error; | ||||||
| auto rhs_or_err = EvaluateNode(node->rhs(), &rhs_flow); | ||||||
| if (!rhs_or_err) { | ||||||
| return rhs_or_err; | ||||||
| } | ||||||
| lldb::ValueObjectSP rhs = *rhs_or_err; | ||||||
|
|
||||||
| CompilerType rhs_type = rhs->GetCompilerType(); | ||||||
| switch (node->kind()) { | ||||||
| case UnaryOpKind::Deref: { | ||||||
| if (rhs_type.IsArrayType()) | ||||||
| rhs = ArrayToPointerConversion(rhs, m_exe_ctx_scope); | ||||||
|
|
||||||
| lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_default_dynamic); | ||||||
| if (dynamic_rhs) | ||||||
| rhs = dynamic_rhs; | ||||||
|
|
||||||
| if (rhs->GetCompilerType().IsPointerType()) { | ||||||
| if (rhs->GetCompilerType().IsPointerToVoid()) { | ||||||
| return llvm::make_error<DILDiagnosticError>( | ||||||
| m_expr, "indirection not permitted on operand of type 'void *'", | ||||||
| node->GetLocation(), 1); | ||||||
| } | ||||||
| return EvaluateDereference(rhs); | ||||||
| } | ||||||
| lldb::ValueObjectSP child_sp = rhs->Dereference(error); | ||||||
| if (error.Success()) | ||||||
| rhs = child_sp; | ||||||
|
|
||||||
| return rhs; | ||||||
| } | ||||||
| case UnaryOpKind::AddrOf: { | ||||||
| if (node->rhs()->is_rvalue()) { | ||||||
|
||||||
| std::string errMsg = | ||||||
| llvm::formatv("cannot take the address of an rvalue of type {0}", | ||||||
| rhs_type.TypeDescription()); | ||||||
| return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, | ||||||
| node->GetLocation()); | ||||||
| } | ||||||
| if (rhs->IsBitfield()) { | ||||||
| return llvm::make_error<DILDiagnosticError>( | ||||||
| m_expr, "address of bit-field requested", node->GetLocation()); | ||||||
| } | ||||||
|
||||||
| // If the address-of operation wasn't cancelled during the evaluation of | ||||||
| // RHS (e.g. because of the address-of-a-dereference elision), apply it | ||||||
| // here. | ||||||
| if (rhs_flow.AddressOfIsPending()) { | ||||||
| Status error; | ||||||
| lldb::ValueObjectSP value = rhs->AddressOf(error); | ||||||
| if (error.Fail()) { | ||||||
| return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(), | ||||||
| node->GetLocation()); | ||||||
| } | ||||||
| return value; | ||||||
| } | ||||||
| return rhs; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Unsupported/invalid operation. | ||||||
| return llvm::make_error<DILDiagnosticError>( | ||||||
| m_expr, "invalid ast: unexpected binary operator", node->GetLocation(), | ||||||
| 1); | ||||||
| } | ||||||
|
|
||||||
| lldb::ValueObjectSP Interpreter::EvaluateDereference(lldb::ValueObjectSP rhs) { | ||||||
| // If rhs is a reference, dereference it first. | ||||||
| Status error; | ||||||
| if (rhs->GetCompilerType().IsReferenceType()) | ||||||
| rhs = rhs->Dereference(error); | ||||||
|
|
||||||
| assert(rhs->GetCompilerType().IsPointerType() && | ||||||
| "invalid ast: must be a pointer type"); | ||||||
|
|
||||||
| if (rhs->GetDerefValobj()) | ||||||
|
||||||
| return rhs->GetDerefValobj()->GetSP(); | ||||||
|
|
||||||
| CompilerType pointer_type = rhs->GetCompilerType(); | ||||||
| lldb::addr_t base_addr = rhs->GetValueAsUnsigned(0); | ||||||
|
|
||||||
| llvm::StringRef name = "result"; | ||||||
| ExecutionContext exe_ctx(m_target.get(), false); | ||||||
| lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress( | ||||||
| name, base_addr, exe_ctx, pointer_type, | ||||||
| /* do_deref */ false); | ||||||
|
||||||
| /* do_deref */ false); | |
| /*do_deref=*/false); |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing newline
Uh oh!
There was an error while loading. Please reload this page.