Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions lldb/include/lldb/ValueObject/DILAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace lldb_private::dil {
/// The various types DIL AST nodes (used by the DIL parser).
enum class NodeKind {
eArraySubscriptNode,
eBitExtractionNode,
eErrorNode,
eIdentifierNode,
eMemberOfNode,
Expand Down Expand Up @@ -153,6 +154,30 @@ class ArraySubscriptNode : public ASTNode {
int64_t m_index;
};

class BitFieldExtractionNode : public ASTNode {
public:
BitFieldExtractionNode(uint32_t location, ASTNodeUP base, int64_t first_index,
int64_t last_index)
: ASTNode(location, NodeKind::eBitExtractionNode),
m_base(std::move(base)), m_first_index(first_index),
m_last_index(last_index) {}

llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;

ASTNode *GetBase() const { return m_base.get(); }
int64_t GetFirstIndex() const { return m_first_index; }
int64_t GetLastIndex() const { return m_last_index; }

static bool classof(const ASTNode *node) {
return node->GetKind() == NodeKind::eBitExtractionNode;
}

private:
ASTNodeUP m_base;
int64_t m_first_index;
int64_t m_last_index;
};

/// 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
Expand All @@ -168,6 +193,8 @@ class Visitor {
Visit(const UnaryOpNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const ArraySubscriptNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode *node) = 0;
};

} // namespace lldb_private::dil
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/ValueObject/DILEval.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class Interpreter : Visitor {
llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const ArraySubscriptNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode *node) override;

// Used by the interpreter to create objects, perform casts, etc.
lldb::TargetSP m_target;
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/ValueObject/DILLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Token {
identifier,
l_paren,
l_square,
minus,
numeric_constant,
period,
r_paren,
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/ValueObject/DILAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ ArraySubscriptNode::Accept(Visitor *v) const {
return v->Visit(this);
}

llvm::Expected<lldb::ValueObjectSP>
BitFieldExtractionNode::Accept(Visitor *v) const {
return v->Visit(this);
}

} // namespace lldb_private::dil
32 changes: 32 additions & 0 deletions lldb/source/ValueObject/DILEval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,36 @@ Interpreter::Visit(const ArraySubscriptNode *node) {
return base->GetSyntheticArrayMember(signed_child_idx, true);
}

llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const BitFieldExtractionNode *node) {
auto lhs_or_err = Evaluate(node->GetBase());
if (!lhs_or_err)
return lhs_or_err;
lldb::ValueObjectSP base = *lhs_or_err;
int64_t first_index = node->GetFirstIndex();
int64_t last_index = node->GetLastIndex();

// if the format given is [high-low], swap range
if (first_index > last_index)
std::swap(first_index, last_index);

Status error;
if (base->GetCompilerType().IsReferenceType()) {
base = base->Dereference(error);
if (error.Fail())
return error.ToError();
}
lldb::ValueObjectSP child_valobj_sp =
base->GetSyntheticBitFieldChild(first_index, last_index, true);
if (!child_valobj_sp) {
std::string message = llvm::formatv(
"bitfield range {0}-{1} is not valid for \"({2}) {3}\"", first_index,
last_index, base->GetTypeName().AsCString("<invalid type>"),
base->GetName().AsCString());
return llvm::make_error<DILDiagnosticError>(m_expr, message,
node->GetLocation());
}
return child_valobj_sp;
}

} // namespace lldb_private::dil
7 changes: 5 additions & 2 deletions lldb/source/ValueObject/DILLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "l_paren";
case Kind::l_square:
return "l_square";
case Kind::minus:
return "minus";
case Kind::numeric_constant:
return "numeric_constant";
case Kind::period:
Expand Down Expand Up @@ -113,8 +115,9 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,

constexpr std::pair<Token::Kind, const char *> operators[] = {
{Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
{Token::l_paren, "("}, {Token::l_square, "["}, {Token::period, "."},
{Token::r_paren, ")"}, {Token::r_square, "]"}, {Token::star, "*"},
{Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
{Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
{Token::star, "*"},
};
for (auto [kind, str] : operators) {
if (remainder.consume_front(str))
Expand Down
22 changes: 18 additions & 4 deletions lldb/source/ValueObject/DILParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
// postfix_expression:
// primary_expression
// postfix_expression "[" integer_literal "]"
// postfix_expression "[" integer_literal "-" integer_literal "]"
// postfix_expression "." id_expression
// postfix_expression "->" id_expression
//
Expand All @@ -131,17 +132,30 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
switch (token.GetKind()) {
case Token::l_square: {
m_dil_lexer.Advance();
std::optional<int64_t> rhs = ParseIntegerConstant();
if (!rhs) {
std::optional<int64_t> index = ParseIntegerConstant();
if (!index) {
BailOut(
llvm::formatv("failed to parse integer constant: {0}", CurToken()),
CurToken().GetLocation(), CurToken().GetSpelling().length());
return std::make_unique<ErrorNode>();
}
if (CurToken().GetKind() == Token::minus) {
m_dil_lexer.Advance();
std::optional<int64_t> last_index = ParseIntegerConstant();
if (!last_index) {
BailOut(llvm::formatv("failed to parse integer constant: {0}",
CurToken()),
CurToken().GetLocation(), CurToken().GetSpelling().length());
return std::make_unique<ErrorNode>();
}
lhs = std::make_unique<BitFieldExtractionNode>(
loc, std::move(lhs), std::move(*index), std::move(*last_index));
} else {
lhs = std::make_unique<ArraySubscriptNode>(loc, std::move(lhs),
std::move(*index));
}
Expect(Token::r_square);
m_dil_lexer.Advance();
lhs = std::make_unique<ArraySubscriptNode>(loc, std::move(lhs),
std::move(*rhs));
break;
}
case Token::period:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_subscript(self):
self.expect(
"frame var 'int_arr[-1]'",
error=True,
substrs=["unrecognized token"],
substrs=["failed to parse integer constant"],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of the previous PR, but I think this should actually work. Current "frame var" will happily access a pointer/array with negative indexes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I make a separate PR to fix this?

)

# Test for floating point index
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""
Test DIL BifField extraction.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil


class TestFrameVarDILBitFieldExtraction(TestBase):
NO_DEBUG_INFO_TESTCASE = True

def expect_var_path(self, expr, compare_to_framevar=False, value=None, type=None):
value_dil = super().expect_var_path(expr, value=value, type=type)
if compare_to_framevar:
self.runCmd("settings set target.experimental.use-DIL false")
value_frv = super().expect_var_path(expr, value=value, type=type)
self.runCmd("settings set target.experimental.use-DIL true")
self.assertEqual(value_dil.GetValue(), value_frv.GetValue())

def test_bitfield_extraction(self):
self.build()
lldbutil.run_to_source_breakpoint(
self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
)

self.runCmd("settings set target.experimental.use-DIL true")

# Test ranges and type
self.expect_var_path("value[0-1]", True, value="3", type="int:2")
self.expect_var_path("value[4-7]", True, value="7", type="int:4")
self.expect_var_path("value[7-0]", True, value="115", type="int:8")

# Test reference and dereferenced pointer
self.expect_var_path("value_ref[0-1]", value="3", type="int:2")
self.expect_var_path("(*value_ptr)[0-1]", value="3", type="int:2")

# Test array and pointer
self.expect(
"frame var 'int_arr[0-2]'",
error=True,
substrs=["bitfield range 0-2 is not valid"],
)
self.expect(
"frame var 'value_ptr[0-1]'",
error=True,
substrs=["bitfield range 0-1 is not valid"],
)

# Test invalid input
self.expect(
"frame var 'value[1-]'",
error=True,
substrs=["failed to parse integer constant"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
int main(int argc, char **argv) {
int value = 0b01110011;
int &value_ref = value;
int *value_ptr = &value;

int int_arr[] = {7, 3, 1};

return 0; // Set a breakpoint here
}
Loading