Skip to content

Commit ad204cd

Browse files
committed
[LLDB] Add array subscription and integer parsing to DIL
1 parent 8696d16 commit ad204cd

File tree

13 files changed

+506
-11
lines changed

13 files changed

+506
-11
lines changed

lldb/docs/dil-expr-lang.ebnf

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66
expression = unary_expression ;
77
88
unary_expression = unary_operator expression
9-
| primary_expression ;
9+
| postfix_expression ;
1010
1111
unary_operator = "*" | "&" ;
1212
13-
primary_expression = id_expression
13+
postfix_expression = primary_expression
14+
| postfix_expression "[" expression "]";
15+
16+
primary_expression = numeric_literal
17+
| id_expression
1418
| "(" expression ")";
1519
1620
id_expression = unqualified_id
1721
| qualified_id
18-
| register ;
22+
| register ;
1923
2024
unqualified_id = identifier ;
2125
@@ -24,6 +28,8 @@ qualified_id = ["::"] [nested_name_specifier] unqualified_id
2428
2529
identifier = ? C99 Identifier ? ;
2630
31+
numeric_literal = ? C99 Integer constant ? ;
32+
2733
register = "$" ? Register name ? ;
2834
2935
nested_name_specifier = type_name "::"

lldb/include/lldb/ValueObject/DILAST.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ namespace lldb_private::dil {
1818

1919
/// The various types DIL AST nodes (used by the DIL parser).
2020
enum class NodeKind {
21+
eArraySubscriptNode,
2122
eErrorNode,
2223
eIdentifierNode,
24+
eScalarLiteralNode,
2325
eUnaryOpNode,
2426
};
2527

@@ -71,6 +73,26 @@ class ErrorNode : public ASTNode {
7173
}
7274
};
7375

76+
class ScalarLiteralNode : public ASTNode {
77+
public:
78+
ScalarLiteralNode(uint32_t location, lldb::BasicType type, Scalar value)
79+
: ASTNode(location, NodeKind::eScalarLiteralNode), m_type(type),
80+
m_value(value) {}
81+
82+
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
83+
84+
lldb::BasicType GetType() const { return m_type; }
85+
Scalar GetValue() const & { return m_value; }
86+
87+
static bool classof(const ASTNode *node) {
88+
return node->GetKind() == NodeKind::eScalarLiteralNode;
89+
}
90+
91+
private:
92+
lldb::BasicType m_type;
93+
Scalar m_value;
94+
};
95+
7496
class IdentifierNode : public ASTNode {
7597
public:
7698
IdentifierNode(uint32_t location, std::string name)
@@ -108,6 +130,26 @@ class UnaryOpNode : public ASTNode {
108130
ASTNodeUP m_operand;
109131
};
110132

133+
class ArraySubscriptNode : public ASTNode {
134+
public:
135+
ArraySubscriptNode(uint32_t location, ASTNodeUP lhs, ASTNodeUP rhs)
136+
: ASTNode(location, NodeKind::eArraySubscriptNode), m_lhs(std::move(lhs)),
137+
m_rhs(std::move(rhs)) {}
138+
139+
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
140+
141+
ASTNode *lhs() const { return m_lhs.get(); }
142+
ASTNode *rhs() const { return m_rhs.get(); }
143+
144+
static bool classof(const ASTNode *node) {
145+
return node->GetKind() == NodeKind::eArraySubscriptNode;
146+
}
147+
148+
private:
149+
ASTNodeUP m_lhs;
150+
ASTNodeUP m_rhs;
151+
};
152+
111153
/// This class contains one Visit method for each specialized type of
112154
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
113155
/// the correct function in the DIL expression evaluator for evaluating that
@@ -116,9 +158,13 @@ class Visitor {
116158
public:
117159
virtual ~Visitor() = default;
118160
virtual llvm::Expected<lldb::ValueObjectSP>
161+
Visit(const ScalarLiteralNode *node) = 0;
162+
virtual llvm::Expected<lldb::ValueObjectSP>
119163
Visit(const IdentifierNode *node) = 0;
120164
virtual llvm::Expected<lldb::ValueObjectSP>
121165
Visit(const UnaryOpNode *node) = 0;
166+
virtual llvm::Expected<lldb::ValueObjectSP>
167+
Visit(const ArraySubscriptNode *node) = 0;
122168
};
123169

124170
} // namespace lldb_private::dil

lldb/include/lldb/ValueObject/DILEval.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,15 @@ class Interpreter : Visitor {
4747
llvm::Expected<lldb::ValueObjectSP> Evaluate(const ASTNode *node);
4848

4949
private:
50+
llvm::Expected<lldb::ValueObjectSP>
51+
Visit(const ScalarLiteralNode *node) override;
5052
llvm::Expected<lldb::ValueObjectSP>
5153
Visit(const IdentifierNode *node) override;
5254
llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode *node) override;
55+
llvm::Expected<lldb::ValueObjectSP>
56+
Visit(const ArraySubscriptNode *node) override;
57+
58+
lldb::ValueObjectSP PointerAdd(lldb::ValueObjectSP lhs, int64_t offset);
5359

5460
// Used by the interpreter to create objects, perform casts, etc.
5561
lldb::TargetSP m_target;

lldb/include/lldb/ValueObject/DILLexer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ class Token {
2929
eof,
3030
identifier,
3131
l_paren,
32+
l_square,
33+
numeric_constant,
3234
r_paren,
35+
r_square,
3336
star,
3437
};
3538

lldb/include/lldb/ValueObject/DILParser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,15 @@ class DILParser {
8484

8585
ASTNodeUP ParseExpression();
8686
ASTNodeUP ParseUnaryExpression();
87+
ASTNodeUP ParsePostfixExpression();
8788
ASTNodeUP ParsePrimaryExpression();
8889

8990
std::string ParseNestedNameSpecifier();
9091

9192
std::string ParseIdExpression();
9293
std::string ParseUnqualifiedId();
94+
ASTNodeUP ParseNumericLiteral();
95+
ASTNodeUP ParseNumericConstant();
9396

9497
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
9598

lldb/source/ValueObject/DILAST.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ llvm::Expected<lldb::ValueObjectSP> ErrorNode::Accept(Visitor *v) const {
1515
llvm_unreachable("Attempting to Visit a DIL ErrorNode.");
1616
}
1717

18+
llvm::Expected<lldb::ValueObjectSP>
19+
ScalarLiteralNode::Accept(Visitor *v) const {
20+
return v->Visit(this);
21+
}
22+
1823
llvm::Expected<lldb::ValueObjectSP> IdentifierNode::Accept(Visitor *v) const {
1924
return v->Visit(this);
2025
}
@@ -23,4 +28,9 @@ llvm::Expected<lldb::ValueObjectSP> UnaryOpNode::Accept(Visitor *v) const {
2328
return v->Visit(this);
2429
}
2530

31+
llvm::Expected<lldb::ValueObjectSP>
32+
ArraySubscriptNode::Accept(Visitor *v) const {
33+
return v->Visit(this);
34+
}
35+
2636
} // namespace lldb_private::dil

lldb/source/ValueObject/DILEval.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,22 @@
1818

1919
namespace lldb_private::dil {
2020

21+
static lldb::ValueObjectSP
22+
ArrayToPointerConversion(lldb::ValueObjectSP valobj,
23+
std::shared_ptr<ExecutionContextScope> ctx) {
24+
assert(valobj->IsArrayType() &&
25+
"an argument to array-to-pointer conversion must be an array");
26+
27+
uint64_t addr = valobj->GetLoadAddress();
28+
llvm::StringRef name = "result";
29+
ExecutionContext exe_ctx;
30+
ctx->CalculateExecutionContext(exe_ctx);
31+
return ValueObject::CreateValueObjectFromAddress(
32+
name, addr, exe_ctx,
33+
valobj->GetCompilerType().GetArrayElementType(ctx.get()).GetPointerType(),
34+
/* do_deref */ false);
35+
}
36+
2137
static lldb::ValueObjectSP LookupStaticIdentifier(
2238
VariableList &variable_list, std::shared_ptr<StackFrame> exe_scope,
2339
llvm::StringRef name_ref, llvm::StringRef unqualified_name) {
@@ -214,6 +230,45 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) {
214230
return value_or_error;
215231
}
216232

233+
static CompilerType GetBasicType(std::shared_ptr<ExecutionContextScope> ctx,
234+
lldb::BasicType basic_type) {
235+
static std::unordered_map<lldb::BasicType, CompilerType> basic_types;
236+
auto type = basic_types.find(basic_type);
237+
if (type != basic_types.end()) {
238+
std::string type_name((type->second).GetTypeName().AsCString());
239+
// Only return the found type if it's valid.
240+
if (type_name != "<invalid>")
241+
return type->second;
242+
}
243+
244+
lldb::TargetSP target_sp = ctx->CalculateTarget();
245+
if (target_sp) {
246+
for (auto type_system_sp : target_sp->GetScratchTypeSystems())
247+
if (auto compiler_type =
248+
type_system_sp->GetBasicTypeFromAST(basic_type)) {
249+
basic_types.insert({basic_type, compiler_type});
250+
return compiler_type;
251+
}
252+
}
253+
CompilerType empty_type;
254+
return empty_type;
255+
}
256+
257+
llvm::Expected<lldb::ValueObjectSP>
258+
Interpreter::Visit(const ScalarLiteralNode *node) {
259+
CompilerType result_type = GetBasicType(m_exe_ctx_scope, node->GetType());
260+
Scalar value = node->GetValue();
261+
262+
if (result_type.IsInteger() || result_type.IsNullPtrType() ||
263+
result_type.IsPointerType()) {
264+
llvm::APInt val = value.GetAPSInt();
265+
return ValueObject::CreateValueObjectFromAPInt(m_target, val, result_type,
266+
"result");
267+
}
268+
269+
return lldb::ValueObjectSP();
270+
}
271+
217272
llvm::Expected<lldb::ValueObjectSP>
218273
Interpreter::Visit(const IdentifierNode *node) {
219274
lldb::DynamicValueType use_dynamic = m_default_dynamic;
@@ -272,4 +327,108 @@ Interpreter::Visit(const UnaryOpNode *node) {
272327
m_expr, "invalid ast: unexpected binary operator", node->GetLocation());
273328
}
274329

330+
lldb::ValueObjectSP Interpreter::PointerAdd(lldb::ValueObjectSP lhs,
331+
int64_t offset) {
332+
uint64_t byte_size = 0;
333+
if (auto temp = lhs->GetCompilerType().GetPointeeType().GetByteSize(
334+
lhs->GetTargetSP().get()))
335+
byte_size = *temp;
336+
uintptr_t addr = lhs->GetValueAsUnsigned(0) + offset * byte_size;
337+
338+
llvm::StringRef name = "result";
339+
ExecutionContext exe_ctx(m_target.get(), false);
340+
return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx,
341+
lhs->GetCompilerType(),
342+
/* do_deref */ false);
343+
}
344+
345+
llvm::Expected<lldb::ValueObjectSP>
346+
Interpreter::Visit(const ArraySubscriptNode *node) {
347+
auto lhs_or_err = Evaluate(node->lhs());
348+
if (!lhs_or_err) {
349+
return lhs_or_err;
350+
}
351+
lldb::ValueObjectSP base = *lhs_or_err;
352+
auto rhs_or_err = Evaluate(node->rhs());
353+
if (!rhs_or_err) {
354+
return rhs_or_err;
355+
}
356+
lldb::ValueObjectSP index = *rhs_or_err;
357+
358+
Status error;
359+
if (base->GetCompilerType().IsReferenceType()) {
360+
base = base->Dereference(error);
361+
if (error.Fail())
362+
return error.ToError();
363+
}
364+
if (index->GetCompilerType().IsReferenceType()) {
365+
index = index->Dereference(error);
366+
if (error.Fail())
367+
return error.ToError();
368+
}
369+
370+
auto index_type = index->GetCompilerType();
371+
if (!index_type.IsIntegerOrUnscopedEnumerationType())
372+
return llvm::make_error<DILDiagnosticError>(
373+
m_expr, "array subscript is not an integer", node->GetLocation());
374+
375+
// Check to see if 'base' has a synthetic value; if so, try using that.
376+
if (base->HasSyntheticValue()) {
377+
lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
378+
if (synthetic && synthetic != base) {
379+
uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors();
380+
// Verify that the 'index' is not out-of-range for the declared type.
381+
if (index->GetValueAsSigned(0) >= num_children) {
382+
auto message =
383+
llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
384+
index->GetValueAsSigned(0),
385+
base->GetTypeName().AsCString("<invalid type>"),
386+
base->GetName().AsCString());
387+
return llvm::make_error<DILDiagnosticError>(m_expr, message,
388+
node->GetLocation());
389+
}
390+
391+
uint64_t child_idx = index->GetValueAsUnsigned(0);
392+
if (static_cast<uint32_t>(child_idx) <
393+
synthetic->GetNumChildrenIgnoringErrors()) {
394+
lldb::ValueObjectSP child_valobj_sp =
395+
synthetic->GetChildAtIndex(child_idx);
396+
if (child_valobj_sp) {
397+
return child_valobj_sp;
398+
}
399+
}
400+
}
401+
}
402+
403+
auto base_type = base->GetCompilerType();
404+
if (!base_type.IsPointerType() && !base_type.IsArrayType())
405+
return llvm::make_error<DILDiagnosticError>(
406+
m_expr, "subscripted value is not an array or pointer",
407+
node->GetLocation());
408+
if (base_type.IsPointerToVoid())
409+
return llvm::make_error<DILDiagnosticError>(
410+
m_expr, "subscript of pointer to incomplete type 'void'",
411+
node->GetLocation());
412+
413+
if (base_type.IsArrayType())
414+
base = ArrayToPointerConversion(base, m_exe_ctx_scope);
415+
416+
CompilerType item_type = base->GetCompilerType().GetPointeeType();
417+
lldb::addr_t base_addr = base->GetValueAsUnsigned(0);
418+
419+
llvm::StringRef name = "result";
420+
ExecutionContext exe_ctx(m_target.get(), false);
421+
// Create a pointer and add the index, i.e. "base + index".
422+
lldb::ValueObjectSP value =
423+
PointerAdd(ValueObject::CreateValueObjectFromAddress(
424+
name, base_addr, exe_ctx, item_type.GetPointerType(),
425+
/*do_deref=*/false),
426+
index->GetValueAsSigned(0));
427+
428+
lldb::ValueObjectSP val2 = value->Dereference(error);
429+
if (error.Fail())
430+
return error.ToError();
431+
return val2;
432+
}
433+
275434
} // namespace lldb_private::dil

0 commit comments

Comments
 (0)