Skip to content

Commit 4236423

Browse files
authored
[LLDB] Add bit extraction to DIL (#141422)
1 parent 30725ef commit 4236423

File tree

11 files changed

+159
-7
lines changed

11 files changed

+159
-7
lines changed

lldb/include/lldb/ValueObject/DILAST.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace lldb_private::dil {
1919
/// The various types DIL AST nodes (used by the DIL parser).
2020
enum class NodeKind {
2121
eArraySubscriptNode,
22+
eBitExtractionNode,
2223
eErrorNode,
2324
eIdentifierNode,
2425
eMemberOfNode,
@@ -153,6 +154,30 @@ class ArraySubscriptNode : public ASTNode {
153154
int64_t m_index;
154155
};
155156

157+
class BitFieldExtractionNode : public ASTNode {
158+
public:
159+
BitFieldExtractionNode(uint32_t location, ASTNodeUP base, int64_t first_index,
160+
int64_t last_index)
161+
: ASTNode(location, NodeKind::eBitExtractionNode),
162+
m_base(std::move(base)), m_first_index(first_index),
163+
m_last_index(last_index) {}
164+
165+
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
166+
167+
ASTNode *GetBase() const { return m_base.get(); }
168+
int64_t GetFirstIndex() const { return m_first_index; }
169+
int64_t GetLastIndex() const { return m_last_index; }
170+
171+
static bool classof(const ASTNode *node) {
172+
return node->GetKind() == NodeKind::eBitExtractionNode;
173+
}
174+
175+
private:
176+
ASTNodeUP m_base;
177+
int64_t m_first_index;
178+
int64_t m_last_index;
179+
};
180+
156181
/// This class contains one Visit method for each specialized type of
157182
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
158183
/// the correct function in the DIL expression evaluator for evaluating that
@@ -168,6 +193,8 @@ class Visitor {
168193
Visit(const UnaryOpNode *node) = 0;
169194
virtual llvm::Expected<lldb::ValueObjectSP>
170195
Visit(const ArraySubscriptNode *node) = 0;
196+
virtual llvm::Expected<lldb::ValueObjectSP>
197+
Visit(const BitFieldExtractionNode *node) = 0;
171198
};
172199

173200
} // namespace lldb_private::dil

lldb/include/lldb/ValueObject/DILEval.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class Interpreter : Visitor {
5454
llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode *node) override;
5555
llvm::Expected<lldb::ValueObjectSP>
5656
Visit(const ArraySubscriptNode *node) override;
57+
llvm::Expected<lldb::ValueObjectSP>
58+
Visit(const BitFieldExtractionNode *node) override;
5759

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

lldb/include/lldb/ValueObject/DILLexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Token {
3131
identifier,
3232
l_paren,
3333
l_square,
34+
minus,
3435
numeric_constant,
3536
period,
3637
r_paren,

lldb/source/ValueObject/DILAST.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,9 @@ ArraySubscriptNode::Accept(Visitor *v) const {
3232
return v->Visit(this);
3333
}
3434

35+
llvm::Expected<lldb::ValueObjectSP>
36+
BitFieldExtractionNode::Accept(Visitor *v) const {
37+
return v->Visit(this);
38+
}
39+
3540
} // namespace lldb_private::dil

lldb/source/ValueObject/DILEval.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,4 +430,36 @@ Interpreter::Visit(const ArraySubscriptNode *node) {
430430
return base->GetSyntheticArrayMember(signed_child_idx, true);
431431
}
432432

433+
llvm::Expected<lldb::ValueObjectSP>
434+
Interpreter::Visit(const BitFieldExtractionNode *node) {
435+
auto lhs_or_err = Evaluate(node->GetBase());
436+
if (!lhs_or_err)
437+
return lhs_or_err;
438+
lldb::ValueObjectSP base = *lhs_or_err;
439+
int64_t first_index = node->GetFirstIndex();
440+
int64_t last_index = node->GetLastIndex();
441+
442+
// if the format given is [high-low], swap range
443+
if (first_index > last_index)
444+
std::swap(first_index, last_index);
445+
446+
Status error;
447+
if (base->GetCompilerType().IsReferenceType()) {
448+
base = base->Dereference(error);
449+
if (error.Fail())
450+
return error.ToError();
451+
}
452+
lldb::ValueObjectSP child_valobj_sp =
453+
base->GetSyntheticBitFieldChild(first_index, last_index, true);
454+
if (!child_valobj_sp) {
455+
std::string message = llvm::formatv(
456+
"bitfield range {0}-{1} is not valid for \"({2}) {3}\"", first_index,
457+
last_index, base->GetTypeName().AsCString("<invalid type>"),
458+
base->GetName().AsCString());
459+
return llvm::make_error<DILDiagnosticError>(m_expr, message,
460+
node->GetLocation());
461+
}
462+
return child_valobj_sp;
463+
}
464+
433465
} // namespace lldb_private::dil

lldb/source/ValueObject/DILLexer.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
3434
return "l_paren";
3535
case Kind::l_square:
3636
return "l_square";
37+
case Kind::minus:
38+
return "minus";
3739
case Kind::numeric_constant:
3840
return "numeric_constant";
3941
case Kind::period:
@@ -113,8 +115,9 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
113115

114116
constexpr std::pair<Token::Kind, const char *> operators[] = {
115117
{Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
116-
{Token::l_paren, "("}, {Token::l_square, "["}, {Token::period, "."},
117-
{Token::r_paren, ")"}, {Token::r_square, "]"}, {Token::star, "*"},
118+
{Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
119+
{Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
120+
{Token::star, "*"},
118121
};
119122
for (auto [kind, str] : operators) {
120123
if (remainder.consume_front(str))

lldb/source/ValueObject/DILParser.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
120120
// postfix_expression:
121121
// primary_expression
122122
// postfix_expression "[" integer_literal "]"
123+
// postfix_expression "[" integer_literal "-" integer_literal "]"
123124
// postfix_expression "." id_expression
124125
// postfix_expression "->" id_expression
125126
//
@@ -131,17 +132,30 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
131132
switch (token.GetKind()) {
132133
case Token::l_square: {
133134
m_dil_lexer.Advance();
134-
std::optional<int64_t> rhs = ParseIntegerConstant();
135-
if (!rhs) {
135+
std::optional<int64_t> index = ParseIntegerConstant();
136+
if (!index) {
136137
BailOut(
137138
llvm::formatv("failed to parse integer constant: {0}", CurToken()),
138139
CurToken().GetLocation(), CurToken().GetSpelling().length());
139140
return std::make_unique<ErrorNode>();
140141
}
142+
if (CurToken().GetKind() == Token::minus) {
143+
m_dil_lexer.Advance();
144+
std::optional<int64_t> last_index = ParseIntegerConstant();
145+
if (!last_index) {
146+
BailOut(llvm::formatv("failed to parse integer constant: {0}",
147+
CurToken()),
148+
CurToken().GetLocation(), CurToken().GetSpelling().length());
149+
return std::make_unique<ErrorNode>();
150+
}
151+
lhs = std::make_unique<BitFieldExtractionNode>(
152+
loc, std::move(lhs), std::move(*index), std::move(*last_index));
153+
} else {
154+
lhs = std::make_unique<ArraySubscriptNode>(loc, std::move(lhs),
155+
std::move(*index));
156+
}
141157
Expect(Token::r_square);
142158
m_dil_lexer.Advance();
143-
lhs = std::make_unique<ArraySubscriptNode>(loc, std::move(lhs),
144-
std::move(*rhs));
145159
break;
146160
}
147161
case Token::period:

lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_subscript(self):
6363
self.expect(
6464
"frame var 'int_arr[-1]'",
6565
error=True,
66-
substrs=["unrecognized token"],
66+
substrs=["failed to parse integer constant"],
6767
)
6868

6969
# Test for floating point index
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
3+
include Makefile.rules
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Test DIL BifField extraction.
3+
"""
4+
5+
import lldb
6+
from lldbsuite.test.lldbtest import *
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test import lldbutil
9+
10+
11+
class TestFrameVarDILBitFieldExtraction(TestBase):
12+
NO_DEBUG_INFO_TESTCASE = True
13+
14+
def expect_var_path(self, expr, compare_to_framevar=False, value=None, type=None):
15+
value_dil = super().expect_var_path(expr, value=value, type=type)
16+
if compare_to_framevar:
17+
self.runCmd("settings set target.experimental.use-DIL false")
18+
value_frv = super().expect_var_path(expr, value=value, type=type)
19+
self.runCmd("settings set target.experimental.use-DIL true")
20+
self.assertEqual(value_dil.GetValue(), value_frv.GetValue())
21+
22+
def test_bitfield_extraction(self):
23+
self.build()
24+
lldbutil.run_to_source_breakpoint(
25+
self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
26+
)
27+
28+
self.runCmd("settings set target.experimental.use-DIL true")
29+
30+
# Test ranges and type
31+
self.expect_var_path("value[0-1]", True, value="3", type="int:2")
32+
self.expect_var_path("value[4-7]", True, value="7", type="int:4")
33+
self.expect_var_path("value[7-0]", True, value="115", type="int:8")
34+
35+
# Test reference and dereferenced pointer
36+
self.expect_var_path("value_ref[0-1]", value="3", type="int:2")
37+
self.expect_var_path("(*value_ptr)[0-1]", value="3", type="int:2")
38+
39+
# Test array and pointer
40+
self.expect(
41+
"frame var 'int_arr[0-2]'",
42+
error=True,
43+
substrs=["bitfield range 0-2 is not valid"],
44+
)
45+
self.expect(
46+
"frame var 'value_ptr[0-1]'",
47+
error=True,
48+
substrs=["bitfield range 0-1 is not valid"],
49+
)
50+
51+
# Test invalid input
52+
self.expect(
53+
"frame var 'value[1-]'",
54+
error=True,
55+
substrs=["failed to parse integer constant"],
56+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
int main(int argc, char **argv) {
2+
int value = 0b01110011;
3+
int &value_ref = value;
4+
int *value_ptr = &value;
5+
6+
int int_arr[] = {7, 3, 1};
7+
8+
return 0; // Set a breakpoint here
9+
}

0 commit comments

Comments
 (0)