diff options
Diffstat (limited to 'lldb/source/ValueObject')
| -rw-r--r-- | lldb/source/ValueObject/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | lldb/source/ValueObject/DILAST.cpp | 4 | ||||
| -rw-r--r-- | lldb/source/ValueObject/DILEval.cpp | 208 | ||||
| -rw-r--r-- | lldb/source/ValueObject/DILParser.cpp | 181 | ||||
| -rw-r--r-- | lldb/source/ValueObject/ValueObject.cpp | 6 | ||||
| -rw-r--r-- | lldb/source/ValueObject/ValueObjectSynthetic.cpp | 15 |
6 files changed, 372 insertions, 46 deletions
diff --git a/lldb/source/ValueObject/CMakeLists.txt b/lldb/source/ValueObject/CMakeLists.txt index 2a61407..f0fe7f3 100644 --- a/lldb/source/ValueObject/CMakeLists.txt +++ b/lldb/source/ValueObject/CMakeLists.txt @@ -1,4 +1,4 @@ -add_lldb_library(lldbValueObject +add_lldb_library(lldbValueObject NO_PLUGIN_DEPENDENCIES DILAST.cpp DILEval.cpp DILLexer.cpp @@ -34,6 +34,4 @@ add_lldb_library(lldbValueObject lldbSymbol lldbTarget lldbUtility - lldbPluginCPlusPlusLanguage - lldbPluginObjCLanguage ) diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp index 7ed34db..0b9e1f4 100644 --- a/lldb/source/ValueObject/DILAST.cpp +++ b/lldb/source/ValueObject/DILAST.cpp @@ -51,4 +51,8 @@ BooleanLiteralNode::Accept(Visitor *v) const { return v->Visit(this); } +llvm::Expected<lldb::ValueObjectSP> CastNode::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 a9dbfad..dc0d93d 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -21,6 +21,101 @@ namespace lldb_private::dil { +static llvm::Expected<lldb::TypeSystemSP> +GetTypeSystemFromCU(std::shared_ptr<ExecutionContextScope> ctx) { + auto stack_frame = ctx->CalculateStackFrame(); + if (!stack_frame) + return llvm::createStringError("no stack frame in this context"); + SymbolContext symbol_context = + stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit); + lldb::LanguageType language = symbol_context.comp_unit->GetLanguage(); + + symbol_context = stack_frame->GetSymbolContext(lldb::eSymbolContextModule); + return symbol_context.module_sp->GetTypeSystemForLanguage(language); +} + +static CompilerType GetBasicType(lldb::TypeSystemSP type_system, + lldb::BasicType basic_type) { + if (type_system) + return type_system.get()->GetBasicTypeFromAST(basic_type); + + return CompilerType(); +} + +static lldb::ValueObjectSP +ArrayToPointerConversion(ValueObject &valobj, ExecutionContextScope &ctx) { + uint64_t addr = valobj.GetLoadAddress(); + ExecutionContext exe_ctx; + ctx.CalculateExecutionContext(exe_ctx); + return ValueObject::CreateValueObjectFromAddress( + "result", addr, exe_ctx, + valobj.GetCompilerType().GetArrayElementType(&ctx).GetPointerType(), + /* do_deref */ false); +} + +llvm::Expected<lldb::ValueObjectSP> +Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) { + if (!valobj) + return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object", + location); + llvm::Expected<lldb::TypeSystemSP> type_system = + GetTypeSystemFromCU(m_exe_ctx_scope); + if (!type_system) + return type_system.takeError(); + + CompilerType in_type = valobj->GetCompilerType(); + if (valobj->IsBitfield()) { + // Promote bitfields. If `int` can represent the bitfield value, it is + // converted to `int`. Otherwise, if `unsigned int` can represent it, it + // is converted to `unsigned int`. Otherwise, it is treated as its + // underlying type. + uint32_t bitfield_size = valobj->GetBitfieldBitSize(); + // Some bitfields have undefined size (e.g. result of ternary operation). + // The AST's `bitfield_size` of those is 0, and no promotion takes place. + if (bitfield_size > 0 && in_type.IsInteger()) { + CompilerType int_type = GetBasicType(*type_system, lldb::eBasicTypeInt); + CompilerType uint_type = + GetBasicType(*type_system, lldb::eBasicTypeUnsignedInt); + llvm::Expected<uint64_t> int_bit_size = + int_type.GetBitSize(m_exe_ctx_scope.get()); + if (!int_bit_size) + return int_bit_size.takeError(); + llvm::Expected<uint64_t> uint_bit_size = + uint_type.GetBitSize(m_exe_ctx_scope.get()); + if (!uint_bit_size) + return int_bit_size.takeError(); + if (bitfield_size < *int_bit_size || + (in_type.IsSigned() && bitfield_size == *int_bit_size)) + return valobj->CastToBasicType(int_type); + if (bitfield_size <= *uint_bit_size) + return valobj->CastToBasicType(uint_type); + // Re-create as a const value with the same underlying type + Scalar scalar; + bool resolved = valobj->ResolveValue(scalar); + if (!resolved) + return llvm::createStringError("invalid scalar value"); + return ValueObject::CreateValueObjectFromScalar(m_target, scalar, in_type, + "result"); + } + } + + if (in_type.IsArrayType()) + valobj = ArrayToPointerConversion(*valobj, *m_exe_ctx_scope); + + if (valobj->GetCompilerType().IsInteger() || + valobj->GetCompilerType().IsUnscopedEnumerationType()) { + llvm::Expected<CompilerType> promoted_type = + type_system.get()->DoIntegralPromotion(valobj->GetCompilerType(), + m_exe_ctx_scope.get()); + if (!promoted_type) + return promoted_type.takeError(); + if (!promoted_type->CompareTypes(valobj->GetCompilerType())) + return valobj->CastToBasicType(*promoted_type); + } + + return valobj; +} + static lldb::VariableSP DILFindVariable(ConstString name, VariableList &variable_list) { lldb::VariableSP exact_match; @@ -147,6 +242,10 @@ Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr, llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) { // Evaluate an AST. auto value_or_error = node->Accept(this); + // Convert SP with a nullptr to an error. + if (value_or_error && !*value_or_error) + return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object", + node->GetLocation()); // Return the computed value-or-error. The caller is responsible for // checking if an error occured during the evaluation. return value_or_error; @@ -175,21 +274,21 @@ Interpreter::Visit(const IdentifierNode *node) { llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const UnaryOpNode *node) { Status error; - auto rhs_or_err = Evaluate(node->GetOperand()); - if (!rhs_or_err) - return rhs_or_err; + auto op_or_err = Evaluate(node->GetOperand()); + if (!op_or_err) + return op_or_err; - lldb::ValueObjectSP rhs = *rhs_or_err; + lldb::ValueObjectSP operand = *op_or_err; switch (node->GetKind()) { case UnaryOpKind::Deref: { - lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_use_dynamic); - if (dynamic_rhs) - rhs = dynamic_rhs; + lldb::ValueObjectSP dynamic_op = operand->GetDynamicValue(m_use_dynamic); + if (dynamic_op) + operand = dynamic_op; - lldb::ValueObjectSP child_sp = rhs->Dereference(error); + lldb::ValueObjectSP child_sp = operand->Dereference(error); if (!child_sp && m_use_synthetic) { - if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) { + if (lldb::ValueObjectSP synth_obj_sp = operand->GetSyntheticValue()) { error.Clear(); child_sp = synth_obj_sp->Dereference(error); } @@ -202,18 +301,69 @@ Interpreter::Visit(const UnaryOpNode *node) { } case UnaryOpKind::AddrOf: { Status error; - lldb::ValueObjectSP value = rhs->AddressOf(error); + lldb::ValueObjectSP value = operand->AddressOf(error); if (error.Fail()) return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(), node->GetLocation()); return value; } + case UnaryOpKind::Minus: { + if (operand->GetCompilerType().IsReferenceType()) { + operand = operand->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + llvm::Expected<lldb::ValueObjectSP> conv_op = + UnaryConversion(operand, node->GetOperand()->GetLocation()); + if (!conv_op) + return conv_op; + operand = *conv_op; + CompilerType operand_type = operand->GetCompilerType(); + if (!operand_type.IsScalarType()) { + std::string errMsg = + llvm::formatv("invalid argument type '{0}' to unary expression", + operand_type.GetTypeName()); + return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, + node->GetLocation()); + } + Scalar scalar; + bool resolved = operand->ResolveValue(scalar); + if (!resolved) + break; + + bool negated = scalar.UnaryNegate(); + if (negated) + return ValueObject::CreateValueObjectFromScalar( + m_target, scalar, operand->GetCompilerType(), "result"); + break; } - - // Unsupported/invalid operation. - return llvm::make_error<DILDiagnosticError>( - m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); + case UnaryOpKind::Plus: { + if (operand->GetCompilerType().IsReferenceType()) { + operand = operand->Dereference(error); + if (error.Fail()) + return error.ToError(); + } + llvm::Expected<lldb::ValueObjectSP> conv_op = + UnaryConversion(operand, node->GetOperand()->GetLocation()); + if (!conv_op) + return conv_op; + operand = *conv_op; + CompilerType operand_type = operand->GetCompilerType(); + if (!operand_type.IsScalarType() && + // Unary plus is allowed for pointers. + !operand_type.IsPointerType()) { + std::string errMsg = + llvm::formatv("invalid argument type '{0}' to unary expression", + operand_type.GetTypeName()); + return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, + node->GetLocation()); + } + return operand; + } + } + return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary operation", + node->GetLocation()); } llvm::Expected<lldb::ValueObjectSP> @@ -499,24 +649,6 @@ Interpreter::Visit(const BitFieldExtractionNode *node) { return child_valobj_sp; } -static llvm::Expected<lldb::TypeSystemSP> -GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) { - SymbolContext symbol_context = - ctx->GetSymbolContext(lldb::eSymbolContextCompUnit); - lldb::LanguageType language = symbol_context.comp_unit->GetLanguage(); - - symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule); - return symbol_context.module_sp->GetTypeSystemForLanguage(language); -} - -static CompilerType GetBasicType(lldb::TypeSystemSP type_system, - lldb::BasicType basic_type) { - if (type_system) - return type_system.get()->GetBasicTypeFromAST(basic_type); - - return CompilerType(); -} - llvm::Expected<CompilerType> Interpreter::PickIntegerType(lldb::TypeSystemSP type_system, std::shared_ptr<ExecutionContextScope> ctx, @@ -608,4 +740,16 @@ Interpreter::Visit(const BooleanLiteralNode *node) { return ValueObject::CreateValueObjectFromBool(m_target, value, "result"); } +llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode *node) { + auto operand_or_err = Evaluate(node->GetOperand()); + if (!operand_or_err) + return operand_or_err; + + lldb::ValueObjectSP operand = *operand_or_err; + // Don't actually do the cast for now -- that code will be added later. + // For now just return an error message. + return llvm::make_error<DILDiagnosticError>( + m_expr, "Type casting is not supported here.", node->GetLocation()); +} + } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index 566bcaf..e94ce31 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "lldb/ValueObject/DILParser.h" +#include "lldb/Host/common/DiagnosticsRendering.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/ExecutionContextScope.h" -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Target/LanguageRuntime.h" #include "lldb/ValueObject/DILAST.h" #include "lldb/ValueObject/DILEval.h" #include "llvm/ADT/StringRef.h" @@ -80,26 +82,77 @@ ASTNodeUP DILParser::Run() { // Parse an expression. // // expression: -// unary_expression +// cast_expression // -ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); } +ASTNodeUP DILParser::ParseExpression() { return ParseCastExpression(); } + +// Parse a cast_expression. +// +// cast_expression: +// unary_expression +// "(" type_id ")" cast_expression + +ASTNodeUP DILParser::ParseCastExpression() { + if (!CurToken().Is(Token::l_paren)) + return ParseUnaryExpression(); + + // This could be a type cast, try parsing the contents as a type declaration. + Token token = CurToken(); + uint32_t loc = token.GetLocation(); + + // Enable lexer backtracking, so that we can rollback in case it's not + // actually a type declaration. + + // Start tentative parsing (save token location/idx, for possible rollback). + uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx(); + + // Consume the token only after enabling the backtracking. + m_dil_lexer.Advance(); + + // Try parsing the type declaration. If the returned value is not valid, + // then we should rollback and try parsing the expression. + auto type_id = ParseTypeId(); + if (type_id) { + // Successfully parsed the type declaration. Commit the backtracked + // tokens and parse the cast_expression. + + if (!type_id.value().IsValid()) + return std::make_unique<ErrorNode>(); + + Expect(Token::r_paren); + m_dil_lexer.Advance(); + auto rhs = ParseCastExpression(); + + return std::make_unique<CastNode>(loc, type_id.value(), std::move(rhs), + CastKind::eNone); + } + + // Failed to parse the contents of the parentheses as a type declaration. + // Rollback the lexer and try parsing it as unary_expression. + TentativeParsingRollback(save_token_idx); + + return ParseUnaryExpression(); +} // Parse an unary_expression. // // unary_expression: // postfix_expression -// unary_operator expression +// unary_operator cast_expression // // unary_operator: // "&" // "*" +// "+" +// "-" // ASTNodeUP DILParser::ParseUnaryExpression() { - if (CurToken().IsOneOf({Token::amp, Token::star})) { + if (CurToken().IsOneOf( + {Token::amp, Token::star, Token::minus, Token::plus})) { Token token = CurToken(); uint32_t loc = token.GetLocation(); m_dil_lexer.Advance(); - auto rhs = ParseExpression(); + auto rhs = ParseCastExpression(); switch (token.GetKind()) { case Token::star: return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Deref, @@ -107,7 +160,12 @@ ASTNodeUP DILParser::ParseUnaryExpression() { case Token::amp: return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::AddrOf, std::move(rhs)); - + case Token::minus: + return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Minus, + std::move(rhs)); + case Token::plus: + return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Plus, + std::move(rhs)); default: llvm_unreachable("invalid token kind"); } @@ -274,6 +332,81 @@ std::string DILParser::ParseNestedNameSpecifier() { } } +// Parse a type_id. +// +// type_id: +// type_specifier_seq [abstract_declarator] +// +// type_specifier_seq: +// type_specifier [type_specifier] +// +// type_specifier: +// ["::"] [nested_name_specifier] type_name // not handled for now! +// builtin_typename +// +std::optional<CompilerType> DILParser::ParseTypeId() { + CompilerType type; + // For now only allow builtin types -- will expand add to this later. + auto maybe_builtin_type = ParseBuiltinType(); + if (maybe_builtin_type) { + type = *maybe_builtin_type; + } else + return {}; + + // + // abstract_declarator: + // ptr_operator [abstract_declarator] + // + std::vector<Token> ptr_operators; + while (CurToken().IsOneOf({Token::star, Token::amp})) { + Token tok = CurToken(); + ptr_operators.push_back(std::move(tok)); + m_dil_lexer.Advance(); + } + type = ResolveTypeDeclarators(type, ptr_operators); + + return type; +} + +// Parse a built-in type +// +// builtin_typename: +// identifer_seq +// +// identifier_seq +// identifer [identifier_seq] +// +// A built-in type can be a single identifier or a space-separated +// list of identifiers (e.g. "short" or "long long"). +std::optional<CompilerType> DILParser::ParseBuiltinType() { + std::string type_name = ""; + uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx(); + bool first_word = true; + while (CurToken().GetKind() == Token::identifier) { + if (CurToken().GetSpelling() == "const" || + CurToken().GetSpelling() == "volatile") + continue; + if (!first_word) + type_name.push_back(' '); + else + first_word = false; + type_name.append(CurToken().GetSpelling()); + m_dil_lexer.Advance(); + } + + if (type_name.size() > 0) { + lldb::TargetSP target_sp = m_ctx_scope->CalculateTarget(); + ConstString const_type_name(type_name.c_str()); + for (auto type_system_sp : target_sp->GetScratchTypeSystems()) + if (auto compiler_type = + type_system_sp->GetBuiltinTypeByName(const_type_name)) + return compiler_type; + } + + TentativeParsingRollback(save_token_idx); + return {}; +} + // Parse an id_expression. // // id_expression: @@ -339,6 +472,40 @@ std::string DILParser::ParseUnqualifiedId() { return identifier; } +CompilerType +DILParser::ResolveTypeDeclarators(CompilerType type, + const std::vector<Token> &ptr_operators) { + // Resolve pointers/references. + for (Token tk : ptr_operators) { + uint32_t loc = tk.GetLocation(); + if (tk.GetKind() == Token::star) { + // Pointers to reference types are forbidden. + if (type.IsReferenceType()) { + BailOut(llvm::formatv("'type name' declared as a pointer to a " + "reference of type {0}", + type.TypeDescription()), + loc, CurToken().GetSpelling().length()); + return {}; + } + // Get pointer type for the base type: e.g. int* -> int**. + type = type.GetPointerType(); + + } else if (tk.GetKind() == Token::amp) { + // References to references are forbidden. + // FIXME: In future we may want to allow rvalue references (i.e. &&). + if (type.IsReferenceType()) { + BailOut("type name declared as a reference to a reference", loc, + CurToken().GetSpelling().length()); + return {}; + } + // Get reference type for the base type: e.g. int -> int&. + type = type.GetLValueReferenceType(); + } + } + + return type; +} + // Parse an boolean_literal. // // boolean_literal: diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 38b9f77..aeea32f 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -790,8 +790,7 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { return false; } - uint64_t count = 0; - const Encoding encoding = GetCompilerType().GetEncoding(count); + const Encoding encoding = GetCompilerType().GetEncoding(); const size_t byte_size = llvm::expectedToOptional(GetByteSize()).value_or(0); @@ -1669,8 +1668,7 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { return false; } - uint64_t count = 0; - const Encoding encoding = GetCompilerType().GetEncoding(count); + const Encoding encoding = GetCompilerType().GetEncoding(); const size_t byte_size = llvm::expectedToOptional(GetByteSize()).value_or(0); diff --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp b/lldb/source/ValueObject/ValueObjectSynthetic.cpp index f673c51..44e53bd 100644 --- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp +++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp @@ -443,3 +443,18 @@ void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) { else this->ValueObject::SetLanguageFlags(flags); } + +void ValueObjectSynthetic::GetExpressionPath(Stream &stream, + GetExpressionPathFormat epformat) { + // A synthetic ValueObject may wrap an underlying Register or RegisterSet + // ValueObject, which requires a different approach to generating the + // expression path. In such cases, delegate to the non-synthetic value object. + if (const lldb::ValueType obj_value_type = GetValueType(); + IsSynthetic() && (obj_value_type == lldb::eValueTypeRegister || + obj_value_type == lldb::eValueTypeRegisterSet)) { + + if (const lldb::ValueObjectSP raw_value = GetNonSyntheticValue()) + return raw_value->GetExpressionPath(stream, epformat); + } + return ValueObject::GetExpressionPath(stream, epformat); +} |
