Author: Ilia Kuklin Date: 2026-08-11T19:16:25+05:00 New Revision: eb7545872d4a480fdd6b0ce2144941e9dbbde8ce
URL: https://github.com/llvm/llvm-project/commit/eb7545872d4a480fdd6b0ce2144941e9dbbde8ce DIFF: https://github.com/llvm/llvm-project/commit/eb7545872d4a480fdd6b0ce2144941e9dbbde8ce.diff LOG: [lldb] Add operator `sizeof` to DIL (#211772) Added: lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp Modified: lldb/docs/dil-expr-lang.ebnf lldb/include/lldb/ValueObject/DILAST.h lldb/include/lldb/ValueObject/DILEval.h lldb/source/ValueObject/DILAST.cpp lldb/source/ValueObject/DILEval.cpp lldb/source/ValueObject/DILParser.cpp Removed: ################################################################################ diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf index 0dbfea6eeb637..9c610107da98a 100644 --- a/lldb/docs/dil-expr-lang.ebnf +++ b/lldb/docs/dil-expr-lang.ebnf @@ -45,7 +45,9 @@ postfix_expression = primary_expression primary_expression = numeric_literal | boolean_literal | id_expression - | "(" expression ")" ; + | "(" expression ")" + | "sizeof" "(" expression ")" + | "sizeof" "(" type_id ")" ; id_expression = unqualified_id | qualified_id diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h index a2b02bb4a9da8..b48fa33e5529c 100644 --- a/lldb/include/lldb/ValueObject/DILAST.h +++ b/lldb/include/lldb/ValueObject/DILAST.h @@ -29,6 +29,7 @@ enum class NodeKind { eIdentifierNode, eIntegerLiteralNode, eMemberOfNode, + eSizeOfNode, eUnaryOpNode, }; @@ -324,6 +325,29 @@ class CastNode : public ASTNode { CastKind m_cast_kind; }; +class SizeOfNode : public ASTNode { +public: + SizeOfNode(uint32_t location, ASTNodeUP node) + : ASTNode(location, NodeKind::eSizeOfNode), m_node_arg(std::move(node)) {} + + SizeOfNode(uint32_t location, CompilerType type) + : ASTNode(location, NodeKind::eSizeOfNode), m_type_arg(type) {} + + llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override; + + ASTNode &GetNodeArg() const { return *m_node_arg; } + CompilerType GetTypeArg() const { return m_type_arg; } + + static bool classof(const ASTNode &node) { + return node.GetKind() == NodeKind::eSizeOfNode; + } + +private: + std::string m_name; + ASTNodeUP m_node_arg; + CompilerType m_type_arg; +}; + /// 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 @@ -350,6 +374,7 @@ class Visitor { virtual llvm::Expected<lldb::ValueObjectSP> Visit(const BooleanLiteralNode &node) = 0; virtual llvm::Expected<lldb::ValueObjectSP> Visit(const CastNode &node) = 0; + virtual llvm::Expected<lldb::ValueObjectSP> Visit(const SizeOfNode &node) = 0; }; } // namespace lldb_private::dil diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h index 59fe465b2dd88..489dc801b20db 100644 --- a/lldb/include/lldb/ValueObject/DILEval.h +++ b/lldb/include/lldb/ValueObject/DILEval.h @@ -73,6 +73,7 @@ class Interpreter : Visitor { llvm::Expected<lldb::ValueObjectSP> Visit(const BooleanLiteralNode &node) override; llvm::Expected<lldb::ValueObjectSP> Visit(const CastNode &node) override; + llvm::Expected<lldb::ValueObjectSP> Visit(const SizeOfNode &node) override; /// Perform usual unary conversions on a value. At the moment this /// includes array-to-pointer and integral promotion for eligible types. diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp index bb018712a1ba4..275564916a840 100644 --- a/lldb/source/ValueObject/DILAST.cpp +++ b/lldb/source/ValueObject/DILAST.cpp @@ -93,4 +93,8 @@ llvm::Expected<lldb::ValueObjectSP> CastNode::Accept(Visitor *v) const { return v->Visit(*this); } +llvm::Expected<lldb::ValueObjectSP> SizeOfNode::Accept(Visitor *v) const { + return v->Visit(*this); +} + } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 867d6a74f87de..0ef4e244410a4 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -1682,4 +1682,44 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode &node) { node.GetLocation()); } +llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const SizeOfNode &node) { + CompilerType typearg = node.GetTypeArg(); + Scalar size; + if (typearg.IsValid()) { + if (typearg.IsReferenceType()) + typearg = typearg.GetNonReferenceType(); + llvm::Expected<uint64_t> byte_size = typearg.GetByteSize(m_target.get()); + if (!byte_size) + return byte_size.takeError(); + size = *byte_size; + } else { + auto arg_or_err = EvaluateAndDereference(node.GetNodeArg()); + if (!arg_or_err) + return arg_or_err; + lldb::ValueObjectSP arg = *arg_or_err; + + if (arg->IsBitfield()) + return llvm::make_error<DILDiagnosticError>( + m_expr, "invalid application of 'sizeof' to bit-field", + node.GetLocation()); + + llvm::Expected<uint64_t> byte_size = arg->GetByteSize(); + if (!byte_size) + return byte_size.takeError(); + size = *byte_size; + } + + llvm::Expected<lldb::TypeSystemSP> type_system = + GetTypeSystemFromCU(m_stack_frame); + if (!type_system) + return type_system.takeError(); + CompilerType size_type = type_system.get()->GetSizeType(); + if (!size_type) + return llvm::make_error<DILDiagnosticError>( + m_expr, "unable to determine size type", node.GetLocation()); + + return ValueObject::CreateValueObjectFromScalar(m_stack_frame, size, + size_type, "result"); +} + } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index 3af14d31c2e8b..389ce870539e4 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -472,8 +472,24 @@ ASTNodeUP DILParser::ParsePrimaryExpression() { uint32_t loc = CurToken().GetLocation(); std::string identifier = ParseIdExpression(); - if (!identifier.empty()) + if (!identifier.empty()) { + if (identifier == "sizeof" && CurToken().Is(Token::l_paren)) { + m_dil_lexer.Advance(); + uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx(); + auto type_id = ParseTypeId(); + if (type_id) { + Expect(Token::r_paren); + m_dil_lexer.Advance(); + return std::make_unique<SizeOfNode>(loc, *type_id); + } + TentativeParsingRollback(save_token_idx); + ASTNodeUP expr = ParseExpression(); + Expect(Token::r_paren); + m_dil_lexer.Advance(); + return std::make_unique<SizeOfNode>(loc, std::move(expr)); + } return std::make_unique<IdentifierNode>(loc, identifier); + } } if (CurToken().Is(Token::l_paren)) { diff --git a/lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py new file mode 100644 index 0000000000000..bf578e1c44887 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py @@ -0,0 +1,86 @@ +""" +Test DIL operator sizeof(). +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + + +class TestFrameVarDILExprSizeOf(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def test_sizeof(self): + self.build() + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") + ) + + self.runCmd("settings set target.experimental.use-DIL true") + + frame = thread.GetFrameAtIndex(0) + int_size = frame.GetValueForVariablePath("int_size").GetValue() + short_size = frame.GetValueForVariablePath("short_size").GetValue() + double_size = frame.GetValueForVariablePath("double_size").GetValue() + ptr_size = frame.GetValueForVariablePath("ptr_size").GetValue() + intref_size = frame.GetValueForVariablePath("intref_size").GetValue() + arr_size = frame.GetValueForVariablePath("arr_size").GetValue() + foo_size = frame.GetValueForVariablePath("foo_size").GetValue() + enum_size = frame.GetValueForVariablePath("enum_size").GetValue() + bitfield_size = frame.GetValueForVariablePath("bitfield_size").GetValue() + + # Check variables + self.expect_var_path("sizeof(i)", value=int_size, type="__size_t") + self.expect_var_path("sizeof(sh)", value=short_size) + self.expect_var_path("sizeof(d)", value=double_size) + self.expect_var_path("sizeof(ptr)", value=ptr_size) + self.expect_var_path("sizeof(iref)", value=intref_size) + self.expect_var_path("sizeof(arr)", value=arr_size) + self.expect_var_path("sizeof(arr + 1)", value=ptr_size) + self.expect_var_path("sizeof(arr[0])", value=int_size) + self.expect_var_path("sizeof(arr2d[1])", value=arr_size) + self.expect_var_path("sizeof(i + sh + d)", value=double_size) + + # Check types + self.expect_var_path("sizeof(int)", value=int_size) + self.expect_var_path("sizeof(int*)", value=ptr_size) + self.expect_var_path("sizeof(int***)", value=ptr_size) + self.expect_var_path("sizeof(short)", value=short_size) + self.expect_var_path("sizeof(double)", value=double_size) + self.expect_var_path("sizeof(int&)", value=intref_size) + self.expect_var_path("sizeof(short&)", value=short_size) + self.expect_var_path("sizeof(char&)", value="1") + self.expect_var_path("sizeof(short*&)", value=ptr_size) + + # Check struct + self.expect_var_path("sizeof(foo)", value=foo_size) + self.expect_var_path("sizeof(&foo)", value=ptr_size) + self.expect_var_path("sizeof(*foo_ptr)", value=foo_size) + self.expect_var_path("sizeof(SizeOfFoo)", value=foo_size) + self.expect_var_path("sizeof(SizeOfFoo&)", value=foo_size) + self.expect_var_path("sizeof(SizeOfFoo*)", value=ptr_size) + self.expect_var_path("sizeof(foo.d)", value=double_size) + + # Check enum + self.expect_var_path("sizeof(enum_one)", value=enum_size) + self.expect_var_path("sizeof(&enum_one)", value=ptr_size) + self.expect_var_path("sizeof(UnscopedEnum16::kOne16)", value=enum_size) + self.expect_var_path("sizeof(UnscopedEnum16)", value=enum_size) + self.expect_var_path("sizeof(UnscopedEnum16&)", value=enum_size) + self.expect_var_path("sizeof(UnscopedEnum16*)", value=ptr_size) + + # Check bitfield + self.expect_var_path("sizeof(bitfield)", value=bitfield_size) + self.expect_var_path("sizeof(BitFieldStruct)", value=bitfield_size) + self.expect( + "frame var -- 'sizeof(bitfield.a)'", + error=True, + substrs=["invalid application of 'sizeof' to bit-field"], + ) + + self.expect( + "frame var -- 'sizeof(bar)'", + error=True, + substrs=["use of undeclared identifier 'bar'"], + ) diff --git a/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp new file mode 100644 index 0000000000000..948e5e9271458 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp @@ -0,0 +1,46 @@ +#include <cstdint> + +void stop() {} + +struct SizeOfFoo { + int x, y; + double d; + static int z; + virtual void foo() {} +} foo; + +int main(int argc, char **argv) { + int i = 1; + short sh = 1; + double d = 1.0; + int *ptr = &i; + int &iref = i; + int arr[] = {1, 2, 3}; + int arr2d[2][3] = {{1, 2}, {3, 4, 5}}; + + SizeOfFoo *foo_ptr = &foo; + + enum UnscopedEnum16 : int16_t { kZero16, kOne16 }; + UnscopedEnum16 enum_one = kOne16; + + struct BitFieldStruct { + int8_t a : 4; + int32_t b : 20; + uint32_t c : 24; + uint64_t d : 48; + }; + BitFieldStruct bitfield = {1, 2, 3, 4}; + + auto int_size = sizeof(int); + auto short_size = sizeof(short); + auto double_size = sizeof(double); + auto ptr_size = sizeof(int *); + auto intref_size = sizeof(int &); + auto arr_size = sizeof(arr); + auto foo_size = sizeof(SizeOfFoo); + auto enum_size = sizeof(UnscopedEnum16); + auto bitfield_size = sizeof(BitFieldStruct); + + stop(); // Set a breakpoint here + return 0; +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
