[Lldb-commits] [lldb] 2c6710a - Teach DWARFExpression about DWARF 4+ Location Descriptions
Adrian Prantl via lldb-commits
lldb-commits at lists.llvm.org
Tue Mar 23 10:30:23 PDT 2021
Author: Adrian Prantl
Date: 2021-03-23T10:29:51-07:00
New Revision: 2c6710a5e10021387e47cf133a9929209c8e0415
URL: https://github.com/llvm/llvm-project/commit/2c6710a5e10021387e47cf133a9929209c8e0415
DIFF: https://github.com/llvm/llvm-project/commit/2c6710a5e10021387e47cf133a9929209c8e0415.diff
LOG: Teach DWARFExpression about DWARF 4+ Location Descriptions
DWARFExpression implements the DWARF2 expression model that left
ambiguity on whether the result of an expression was a value or an
address. This patch implements the DWARF location description model
introduces in DWARF 4 and sets the result Value's kind accordingly, if
the expression comes from a DWARF v4+ compile unit. The nomenclature
is taken from DWARF 5, chapter 2.6 "Location Descriptions".
Differential Revision: https://reviews.llvm.org/D98996
Added:
Modified:
lldb/source/Expression/DWARFExpression.cpp
lldb/unittests/Expression/DWARFExpressionTest.cpp
Removed:
################################################################################
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index a8843ca0543b..12fe76ee95d2 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -904,6 +904,52 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx,
object_address_ptr, result, error_ptr);
}
+namespace {
+/// The location description kinds described by the DWARF v5
+/// specification. Composite locations are handled out-of-band and
+/// thus aren't part of the enum.
+enum LocationDescriptionKind {
+ Empty,
+ Memory,
+ Register,
+ Implicit
+ /* Composite*/
+};
+/// Adjust value's ValueType according to the kind of location description.
+void UpdateValueTypeFromLocationDescription(Log *log, const DWARFUnit *dwarf_cu,
+ LocationDescriptionKind kind,
+ Value *value = nullptr) {
+ // Note that this function is conflating DWARF expressions with
+ // DWARF location descriptions. Perhaps it would be better to define
+ // a wrapper for DWARFExpresssion::Eval() that deals with DWARF
+ // location descriptions (which consist of one or more DWARF
+ // expressions). But doing this would mean we'd also need factor the
+ // handling of DW_OP_(bit_)piece out of this function.
+ if (dwarf_cu && dwarf_cu->GetVersion() >= 4) {
+ const char *log_msg = "DWARF location description kind: %s";
+ switch (kind) {
+ case Empty:
+ LLDB_LOGF(log, log_msg, "Empty");
+ break;
+ case Memory:
+ LLDB_LOGF(log, log_msg, "Memory");
+ if (value->GetValueType() == Value::ValueType::Scalar)
+ value->SetValueType(Value::ValueType::LoadAddress);
+ break;
+ case Register:
+ LLDB_LOGF(log, log_msg, "Register");
+ value->SetValueType(Value::ValueType::Scalar);
+ break;
+ case Implicit:
+ LLDB_LOGF(log, log_msg, "Implicit");
+ if (value->GetValueType() == Value::ValueType::LoadAddress)
+ value->SetValueType(Value::ValueType::Scalar);
+ break;
+ }
+ }
+}
+} // namespace
+
bool DWARFExpression::Evaluate(
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
@@ -952,6 +998,11 @@ bool DWARFExpression::Evaluate(
!is_signed));
};
+ // The default kind is a memory location. This is updated by any
+ // operation that changes this, such as DW_OP_stack_value, and reset
+ // by composition operations like DW_OP_piece.
+ LocationDescriptionKind dwarf4_location_description_kind = Memory;
+
while (opcodes.ValidOffset(offset)) {
const lldb::offset_t op_offset = offset;
const uint8_t op = opcodes.GetU8(&offset);
@@ -1950,6 +2001,7 @@ bool DWARFExpression::Evaluate(
case DW_OP_reg29:
case DW_OP_reg30:
case DW_OP_reg31: {
+ dwarf4_location_description_kind = Register;
reg_num = op - DW_OP_reg0;
if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
@@ -1962,6 +2014,7 @@ bool DWARFExpression::Evaluate(
// ULEB128 literal operand that encodes the register.
// DESCRIPTION: Push the value in register on the top of the stack.
case DW_OP_regx: {
+ dwarf4_location_description_kind = Register;
reg_num = opcodes.GetULEB128(&offset);
if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
stack.push_back(tmp);
@@ -2085,12 +2138,18 @@ bool DWARFExpression::Evaluate(
// provides a way of describing how large a part of a variable a particular
// DWARF expression refers to.
case DW_OP_piece: {
+ LocationDescriptionKind piece_locdesc = dwarf4_location_description_kind;
+ // Reset for the next piece.
+ dwarf4_location_description_kind = Memory;
+
const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
if (piece_byte_size > 0) {
Value curr_piece;
if (stack.empty()) {
+ UpdateValueTypeFromLocationDescription(
+ log, dwarf_cu, LocationDescriptionKind::Empty);
// In a multi-piece expression, this means that the current piece is
// not available. Fill with zeros for now by resizing the data and
// appending it
@@ -2106,6 +2165,8 @@ bool DWARFExpression::Evaluate(
// Extract the current piece into "curr_piece"
Value curr_piece_source_value(stack.back());
stack.pop_back();
+ UpdateValueTypeFromLocationDescription(log, dwarf_cu, piece_locdesc,
+ &curr_piece_source_value);
const Value::ValueType curr_piece_source_value_type =
curr_piece_source_value.GetValueType();
@@ -2216,11 +2277,19 @@ bool DWARFExpression::Evaluate(
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
if (stack.size() < 1) {
+ UpdateValueTypeFromLocationDescription(log, dwarf_cu,
+ LocationDescriptionKind::Empty);
+ // Reset for the next piece.
+ dwarf4_location_description_kind = Memory;
if (error_ptr)
error_ptr->SetErrorString(
"Expression stack needs at least 1 item for DW_OP_bit_piece.");
return false;
} else {
+ UpdateValueTypeFromLocationDescription(
+ log, dwarf_cu, dwarf4_location_description_kind, &stack.back());
+ // Reset for the next piece.
+ dwarf4_location_description_kind = Memory;
const uint64_t piece_bit_size = opcodes.GetULEB128(&offset);
const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset);
switch (stack.back().GetValueType()) {
@@ -2261,6 +2330,8 @@ bool DWARFExpression::Evaluate(
// DESCRIPTION: Value is immediately stored in block in the debug info with
// the memory representation of the target.
case DW_OP_implicit_value: {
+ dwarf4_location_description_kind = Implicit;
+
const uint32_t len = opcodes.GetULEB128(&offset);
const void *data = opcodes.GetData(&offset, len);
@@ -2276,6 +2347,12 @@ bool DWARFExpression::Evaluate(
break;
}
+ case DW_OP_implicit_pointer: {
+ dwarf4_location_description_kind = Implicit;
+ LLDB_ERRORF(error_ptr, "Could not evaluate %s.", DW_OP_value_to_name(op));
+ return false;
+ }
+
// OPCODE: DW_OP_push_object_address
// OPERANDS: none
// DESCRIPTION: Pushes the address of the object currently being
@@ -2347,6 +2424,7 @@ bool DWARFExpression::Evaluate(
// rather is a constant value. The value from the top of the stack is the
// value to be used. This is the actual object value and not the location.
case DW_OP_stack_value:
+ dwarf4_location_description_kind = Implicit;
if (stack.empty()) {
if (error_ptr)
error_ptr->SetErrorString(
@@ -2567,25 +2645,28 @@ bool DWARFExpression::Evaluate(
// or DW_OP_bit_piece opcodes
if (pieces.GetBuffer().GetByteSize()) {
result = pieces;
- } else {
- if (error_ptr)
- error_ptr->SetErrorString("Stack empty after evaluation.");
- return false;
+ return true;
}
- } else {
- if (log && log->GetVerbose()) {
- size_t count = stack.size();
- LLDB_LOGF(log, "Stack after operation has %" PRIu64 " values:",
- (uint64_t)count);
- for (size_t i = 0; i < count; ++i) {
- StreamString new_value;
- new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
- stack[i].Dump(&new_value);
- LLDB_LOGF(log, " %s", new_value.GetData());
- }
+ if (error_ptr)
+ error_ptr->SetErrorString("Stack empty after evaluation.");
+ return false;
+ }
+
+ UpdateValueTypeFromLocationDescription(
+ log, dwarf_cu, dwarf4_location_description_kind, &stack.back());
+
+ if (log && log->GetVerbose()) {
+ size_t count = stack.size();
+ LLDB_LOGF(log,
+ "Stack after operation has %" PRIu64 " values:", (uint64_t)count);
+ for (size_t i = 0; i < count; ++i) {
+ StreamString new_value;
+ new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+ stack[i].Dump(&new_value);
+ LLDB_LOGF(log, " %s", new_value.GetData());
}
- result = stack.back();
}
+ result = stack.back();
return true; // Return true on success
}
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 7fcd967990ce..92101e913c22 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -213,42 +213,45 @@ TEST(DWARFExpression, DW_OP_convert) {
//
// Leave as is.
- EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
- DW_OP_convert, offs_uint32_t}),
- llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
+ EXPECT_THAT_EXPECTED(
+ t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
+ DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
+ llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
// Zero-extend to 64 bits.
- EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
- DW_OP_convert, offs_uint64_t}),
- llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
+ EXPECT_THAT_EXPECTED(
+ t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
+ DW_OP_convert, offs_uint64_t, DW_OP_stack_value}),
+ llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
// Sign-extend to 64 bits.
EXPECT_THAT_EXPECTED(
t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
- DW_OP_convert, offs_sint64_t}),
+ DW_OP_convert, offs_sint64_t, DW_OP_stack_value}),
llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed)));
// Sign-extend, then truncate.
- EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
- DW_OP_convert, offs_sint64_t, //
- DW_OP_convert, offs_uint32_t}),
- llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
+ EXPECT_THAT_EXPECTED(
+ t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
+ DW_OP_convert, offs_sint64_t, //
+ DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
+ llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
// Truncate to default unspecified (pointer-sized) type.
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
DW_OP_convert, offs_sint64_t, //
- DW_OP_convert, 0x00}),
+ DW_OP_convert, 0x00, DW_OP_stack_value}),
llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
// Truncate to 8 bits.
- EXPECT_THAT_EXPECTED(
- t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, offs_uchar}),
- llvm::HasValue(GetScalar(8, 'A', not_signed)));
+ EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
+ offs_uchar, DW_OP_stack_value}),
+ llvm::HasValue(GetScalar(8, 'A', not_signed)));
// Also truncate to 8 bits.
- EXPECT_THAT_EXPECTED(
- t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, offs_schar}),
- llvm::HasValue(GetScalar(8, 'A', is_signed)));
+ EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
+ offs_schar, DW_OP_stack_value}),
+ llvm::HasValue(GetScalar(8, 'A', is_signed)));
//
// Errors.
@@ -354,4 +357,13 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
// Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),
llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS)));
+ // Memory location: *0x4.
+ // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
+ EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx),
+ llvm::HasValue(Scalar(4)));
+ // Implicit location: *0x4.
+ // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
+ EXPECT_THAT_EXPECTED(
+ Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx),
+ llvm::HasValue(GetScalar(32, 0x07060504, false)));
}
More information about the lldb-commits
mailing list