aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/ValueObject
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/ValueObject')
-rw-r--r--lldb/source/ValueObject/CMakeLists.txt4
-rw-r--r--lldb/source/ValueObject/DILAST.cpp4
-rw-r--r--lldb/source/ValueObject/DILEval.cpp208
-rw-r--r--lldb/source/ValueObject/DILParser.cpp181
-rw-r--r--lldb/source/ValueObject/ValueObject.cpp6
-rw-r--r--lldb/source/ValueObject/ValueObjectSynthetic.cpp15
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);
+}