Skip to content

Commit 2c6710a

Browse files
committed
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
1 parent 5fac87d commit 2c6710a

File tree

2 files changed

+127
-34
lines changed

2 files changed

+127
-34
lines changed

lldb/source/Expression/DWARFExpression.cpp

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,52 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx,
904904
object_address_ptr, result, error_ptr);
905905
}
906906

907+
namespace {
908+
/// The location description kinds described by the DWARF v5
909+
/// specification. Composite locations are handled out-of-band and
910+
/// thus aren't part of the enum.
911+
enum LocationDescriptionKind {
912+
Empty,
913+
Memory,
914+
Register,
915+
Implicit
916+
/* Composite*/
917+
};
918+
/// Adjust value's ValueType according to the kind of location description.
919+
void UpdateValueTypeFromLocationDescription(Log *log, const DWARFUnit *dwarf_cu,
920+
LocationDescriptionKind kind,
921+
Value *value = nullptr) {
922+
// Note that this function is conflating DWARF expressions with
923+
// DWARF location descriptions. Perhaps it would be better to define
924+
// a wrapper for DWARFExpresssion::Eval() that deals with DWARF
925+
// location descriptions (which consist of one or more DWARF
926+
// expressions). But doing this would mean we'd also need factor the
927+
// handling of DW_OP_(bit_)piece out of this function.
928+
if (dwarf_cu && dwarf_cu->GetVersion() >= 4) {
929+
const char *log_msg = "DWARF location description kind: %s";
930+
switch (kind) {
931+
case Empty:
932+
LLDB_LOGF(log, log_msg, "Empty");
933+
break;
934+
case Memory:
935+
LLDB_LOGF(log, log_msg, "Memory");
936+
if (value->GetValueType() == Value::ValueType::Scalar)
937+
value->SetValueType(Value::ValueType::LoadAddress);
938+
break;
939+
case Register:
940+
LLDB_LOGF(log, log_msg, "Register");
941+
value->SetValueType(Value::ValueType::Scalar);
942+
break;
943+
case Implicit:
944+
LLDB_LOGF(log, log_msg, "Implicit");
945+
if (value->GetValueType() == Value::ValueType::LoadAddress)
946+
value->SetValueType(Value::ValueType::Scalar);
947+
break;
948+
}
949+
}
950+
}
951+
} // namespace
952+
907953
bool DWARFExpression::Evaluate(
908954
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
909955
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
@@ -952,6 +998,11 @@ bool DWARFExpression::Evaluate(
952998
!is_signed));
953999
};
9541000

1001+
// The default kind is a memory location. This is updated by any
1002+
// operation that changes this, such as DW_OP_stack_value, and reset
1003+
// by composition operations like DW_OP_piece.
1004+
LocationDescriptionKind dwarf4_location_description_kind = Memory;
1005+
9551006
while (opcodes.ValidOffset(offset)) {
9561007
const lldb::offset_t op_offset = offset;
9571008
const uint8_t op = opcodes.GetU8(&offset);
@@ -1950,6 +2001,7 @@ bool DWARFExpression::Evaluate(
19502001
case DW_OP_reg29:
19512002
case DW_OP_reg30:
19522003
case DW_OP_reg31: {
2004+
dwarf4_location_description_kind = Register;
19532005
reg_num = op - DW_OP_reg0;
19542006

19552007
if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
@@ -1962,6 +2014,7 @@ bool DWARFExpression::Evaluate(
19622014
// ULEB128 literal operand that encodes the register.
19632015
// DESCRIPTION: Push the value in register on the top of the stack.
19642016
case DW_OP_regx: {
2017+
dwarf4_location_description_kind = Register;
19652018
reg_num = opcodes.GetULEB128(&offset);
19662019
if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
19672020
stack.push_back(tmp);
@@ -2085,12 +2138,18 @@ bool DWARFExpression::Evaluate(
20852138
// provides a way of describing how large a part of a variable a particular
20862139
// DWARF expression refers to.
20872140
case DW_OP_piece: {
2141+
LocationDescriptionKind piece_locdesc = dwarf4_location_description_kind;
2142+
// Reset for the next piece.
2143+
dwarf4_location_description_kind = Memory;
2144+
20882145
const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
20892146

20902147
if (piece_byte_size > 0) {
20912148
Value curr_piece;
20922149

20932150
if (stack.empty()) {
2151+
UpdateValueTypeFromLocationDescription(
2152+
log, dwarf_cu, LocationDescriptionKind::Empty);
20942153
// In a multi-piece expression, this means that the current piece is
20952154
// not available. Fill with zeros for now by resizing the data and
20962155
// appending it
@@ -2106,6 +2165,8 @@ bool DWARFExpression::Evaluate(
21062165
// Extract the current piece into "curr_piece"
21072166
Value curr_piece_source_value(stack.back());
21082167
stack.pop_back();
2168+
UpdateValueTypeFromLocationDescription(log, dwarf_cu, piece_locdesc,
2169+
&curr_piece_source_value);
21092170

21102171
const Value::ValueType curr_piece_source_value_type =
21112172
curr_piece_source_value.GetValueType();
@@ -2216,11 +2277,19 @@ bool DWARFExpression::Evaluate(
22162277

22172278
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
22182279
if (stack.size() < 1) {
2280+
UpdateValueTypeFromLocationDescription(log, dwarf_cu,
2281+
LocationDescriptionKind::Empty);
2282+
// Reset for the next piece.
2283+
dwarf4_location_description_kind = Memory;
22192284
if (error_ptr)
22202285
error_ptr->SetErrorString(
22212286
"Expression stack needs at least 1 item for DW_OP_bit_piece.");
22222287
return false;
22232288
} else {
2289+
UpdateValueTypeFromLocationDescription(
2290+
log, dwarf_cu, dwarf4_location_description_kind, &stack.back());
2291+
// Reset for the next piece.
2292+
dwarf4_location_description_kind = Memory;
22242293
const uint64_t piece_bit_size = opcodes.GetULEB128(&offset);
22252294
const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset);
22262295
switch (stack.back().GetValueType()) {
@@ -2261,6 +2330,8 @@ bool DWARFExpression::Evaluate(
22612330
// DESCRIPTION: Value is immediately stored in block in the debug info with
22622331
// the memory representation of the target.
22632332
case DW_OP_implicit_value: {
2333+
dwarf4_location_description_kind = Implicit;
2334+
22642335
const uint32_t len = opcodes.GetULEB128(&offset);
22652336
const void *data = opcodes.GetData(&offset, len);
22662337

@@ -2276,6 +2347,12 @@ bool DWARFExpression::Evaluate(
22762347
break;
22772348
}
22782349

2350+
case DW_OP_implicit_pointer: {
2351+
dwarf4_location_description_kind = Implicit;
2352+
LLDB_ERRORF(error_ptr, "Could not evaluate %s.", DW_OP_value_to_name(op));
2353+
return false;
2354+
}
2355+
22792356
// OPCODE: DW_OP_push_object_address
22802357
// OPERANDS: none
22812358
// DESCRIPTION: Pushes the address of the object currently being
@@ -2347,6 +2424,7 @@ bool DWARFExpression::Evaluate(
23472424
// rather is a constant value. The value from the top of the stack is the
23482425
// value to be used. This is the actual object value and not the location.
23492426
case DW_OP_stack_value:
2427+
dwarf4_location_description_kind = Implicit;
23502428
if (stack.empty()) {
23512429
if (error_ptr)
23522430
error_ptr->SetErrorString(
@@ -2567,25 +2645,28 @@ bool DWARFExpression::Evaluate(
25672645
// or DW_OP_bit_piece opcodes
25682646
if (pieces.GetBuffer().GetByteSize()) {
25692647
result = pieces;
2570-
} else {
2571-
if (error_ptr)
2572-
error_ptr->SetErrorString("Stack empty after evaluation.");
2573-
return false;
2648+
return true;
25742649
}
2575-
} else {
2576-
if (log && log->GetVerbose()) {
2577-
size_t count = stack.size();
2578-
LLDB_LOGF(log, "Stack after operation has %" PRIu64 " values:",
2579-
(uint64_t)count);
2580-
for (size_t i = 0; i < count; ++i) {
2581-
StreamString new_value;
2582-
new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
2583-
stack[i].Dump(&new_value);
2584-
LLDB_LOGF(log, " %s", new_value.GetData());
2585-
}
2650+
if (error_ptr)
2651+
error_ptr->SetErrorString("Stack empty after evaluation.");
2652+
return false;
2653+
}
2654+
2655+
UpdateValueTypeFromLocationDescription(
2656+
log, dwarf_cu, dwarf4_location_description_kind, &stack.back());
2657+
2658+
if (log && log->GetVerbose()) {
2659+
size_t count = stack.size();
2660+
LLDB_LOGF(log,
2661+
"Stack after operation has %" PRIu64 " values:", (uint64_t)count);
2662+
for (size_t i = 0; i < count; ++i) {
2663+
StreamString new_value;
2664+
new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
2665+
stack[i].Dump(&new_value);
2666+
LLDB_LOGF(log, " %s", new_value.GetData());
25862667
}
2587-
result = stack.back();
25882668
}
2669+
result = stack.back();
25892670
return true; // Return true on success
25902671
}
25912672

lldb/unittests/Expression/DWARFExpressionTest.cpp

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -213,42 +213,45 @@ TEST(DWARFExpression, DW_OP_convert) {
213213
//
214214

215215
// Leave as is.
216-
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
217-
DW_OP_convert, offs_uint32_t}),
218-
llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
216+
EXPECT_THAT_EXPECTED(
217+
t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
218+
DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
219+
llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
219220

220221
// Zero-extend to 64 bits.
221-
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
222-
DW_OP_convert, offs_uint64_t}),
223-
llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
222+
EXPECT_THAT_EXPECTED(
223+
t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
224+
DW_OP_convert, offs_uint64_t, DW_OP_stack_value}),
225+
llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
224226

225227
// Sign-extend to 64 bits.
226228
EXPECT_THAT_EXPECTED(
227229
t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
228-
DW_OP_convert, offs_sint64_t}),
230+
DW_OP_convert, offs_sint64_t, DW_OP_stack_value}),
229231
llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed)));
230232

231233
// Sign-extend, then truncate.
232-
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
233-
DW_OP_convert, offs_sint64_t, //
234-
DW_OP_convert, offs_uint32_t}),
235-
llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
234+
EXPECT_THAT_EXPECTED(
235+
t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
236+
DW_OP_convert, offs_sint64_t, //
237+
DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
238+
llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
236239

237240
// Truncate to default unspecified (pointer-sized) type.
238241
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
239242
DW_OP_convert, offs_sint64_t, //
240-
DW_OP_convert, 0x00}),
243+
DW_OP_convert, 0x00, DW_OP_stack_value}),
241244
llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
242245

243246
// Truncate to 8 bits.
244-
EXPECT_THAT_EXPECTED(
245-
t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, offs_uchar}),
246-
llvm::HasValue(GetScalar(8, 'A', not_signed)));
247+
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
248+
offs_uchar, DW_OP_stack_value}),
249+
llvm::HasValue(GetScalar(8, 'A', not_signed)));
247250

248251
// Also truncate to 8 bits.
249-
EXPECT_THAT_EXPECTED(
250-
t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, offs_schar}),
251-
llvm::HasValue(GetScalar(8, 'A', is_signed)));
252+
EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
253+
offs_schar, DW_OP_stack_value}),
254+
llvm::HasValue(GetScalar(8, 'A', is_signed)));
252255

253256
//
254257
// Errors.
@@ -354,4 +357,13 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
354357
// Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
355358
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),
356359
llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS)));
360+
// Memory location: *0x4.
361+
// Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
362+
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx),
363+
llvm::HasValue(Scalar(4)));
364+
// Implicit location: *0x4.
365+
// Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
366+
EXPECT_THAT_EXPECTED(
367+
Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx),
368+
llvm::HasValue(GetScalar(32, 0x07060504, false)));
357369
}

0 commit comments

Comments
 (0)