[lldb] Extract DW_OP_piece evaluation into a helper (NFC) (#195142)
The DW_OP_piece case was the deepest-nested body in DWARFExpression::Evaluate, with a switch inside a switch. Move it to a static Evaluate_DW_OP_piece helper, following the pattern already used for Evaluate_DW_OP_deref_size and Evaluate_DW_OP_entry_value.
This commit is contained in:
committed by
GitHub
parent
16cef47f1c
commit
def34823cd
@@ -1014,6 +1014,137 @@ static llvm::Error Evaluate_DW_OP_deref_size(
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
static llvm::Error Evaluate_DW_OP_piece(
|
||||
DWARFExpression::Stack &stack, Value &pieces, uint64_t &op_piece_offset,
|
||||
LocationDescriptionKind &dwarf4_location_description_kind,
|
||||
const DWARFExpression::Delegate *dwarf_cu, lldb::ModuleSP module_sp,
|
||||
Target *target, uint64_t piece_byte_size, Log *log) {
|
||||
LocationDescriptionKind piece_locdesc = dwarf4_location_description_kind;
|
||||
// Reset for the next piece.
|
||||
dwarf4_location_description_kind = Memory;
|
||||
|
||||
if (piece_byte_size == 0)
|
||||
return llvm::Error::success();
|
||||
|
||||
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
|
||||
curr_piece.ResizeData(piece_byte_size);
|
||||
// Note that "0" is not a correct value for the unknown bits.
|
||||
// It would be better to also return a mask of valid bits together
|
||||
// with the expression result, so the debugger can print missing
|
||||
// members as "<optimized out>" or something.
|
||||
::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
|
||||
pieces.AppendDataToHostBuffer(curr_piece);
|
||||
} else {
|
||||
Status error;
|
||||
// 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();
|
||||
Scalar &scalar = curr_piece_source_value.GetScalar();
|
||||
lldb::addr_t addr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
|
||||
switch (curr_piece_source_value_type) {
|
||||
case Value::ValueType::Invalid:
|
||||
return llvm::createStringError("invalid value type");
|
||||
case Value::ValueType::FileAddress:
|
||||
if (target) {
|
||||
curr_piece_source_value.ConvertToLoadAddress(module_sp.get(), target);
|
||||
addr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
|
||||
} else {
|
||||
return llvm::createStringError(
|
||||
"unable to convert file address 0x%" PRIx64 " to load address "
|
||||
"for DW_OP_piece(%" PRIu64 "): "
|
||||
"no target available",
|
||||
addr, piece_byte_size);
|
||||
}
|
||||
[[fallthrough]];
|
||||
case Value::ValueType::LoadAddress: {
|
||||
if (target) {
|
||||
if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) {
|
||||
if (target->ReadMemory(
|
||||
Address(addr), curr_piece.GetBuffer().GetBytes(),
|
||||
piece_byte_size, error,
|
||||
/*force_live_memory=*/false) != piece_byte_size) {
|
||||
const char *addr_type =
|
||||
(curr_piece_source_value_type == Value::ValueType::LoadAddress)
|
||||
? "load"
|
||||
: "file";
|
||||
return llvm::createStringError(
|
||||
"failed to read memory DW_OP_piece(%" PRIu64
|
||||
") from %s address 0x%" PRIx64,
|
||||
piece_byte_size, addr_type, addr);
|
||||
}
|
||||
} else {
|
||||
return llvm::createStringError(
|
||||
"failed to resize the piece memory buffer for "
|
||||
"DW_OP_piece(%" PRIu64 ")",
|
||||
piece_byte_size);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Value::ValueType::HostAddress: {
|
||||
return llvm::createStringError(
|
||||
"failed to read memory DW_OP_piece(%" PRIu64
|
||||
") from host address 0x%" PRIx64,
|
||||
piece_byte_size, addr);
|
||||
} break;
|
||||
|
||||
case Value::ValueType::Scalar: {
|
||||
uint32_t bit_size = piece_byte_size * 8;
|
||||
uint32_t bit_offset = 0;
|
||||
if (!scalar.ExtractBitfield(bit_size, bit_offset)) {
|
||||
return llvm::createStringError(
|
||||
"unable to extract %" PRIu64 " bytes from a %" PRIu64
|
||||
" byte scalar value.",
|
||||
piece_byte_size,
|
||||
(uint64_t)curr_piece_source_value.GetScalar().GetByteSize());
|
||||
}
|
||||
|
||||
// We have seen a case where we have expression like:
|
||||
// DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x28
|
||||
// here we are assuming the compiler was trying to zero
|
||||
// extend the value that we should append to the buffer.
|
||||
scalar.TruncOrExtendTo(bit_size, /*sign=*/false);
|
||||
curr_piece.GetScalar() = scalar;
|
||||
} break;
|
||||
}
|
||||
|
||||
// Check if this is the first piece?
|
||||
if (op_piece_offset == 0) {
|
||||
// This is the first piece, we should push it back onto the stack
|
||||
// so subsequent pieces will be able to access this piece and add
|
||||
// to it.
|
||||
if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
|
||||
return llvm::createStringError("failed to append piece data");
|
||||
}
|
||||
} else {
|
||||
// If this is the second or later piece there should be a value on
|
||||
// the stack.
|
||||
if (pieces.GetBuffer().GetByteSize() != op_piece_offset) {
|
||||
return llvm::createStringError("DW_OP_piece for offset %" PRIu64
|
||||
" but top of stack is of size %" PRIu64,
|
||||
op_piece_offset,
|
||||
pieces.GetBuffer().GetByteSize());
|
||||
}
|
||||
|
||||
if (pieces.AppendDataToHostBuffer(curr_piece) == 0)
|
||||
return llvm::createStringError("failed to append piece data");
|
||||
}
|
||||
}
|
||||
op_piece_offset += piece_byte_size;
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Expected<Value> DWARFExpression::Evaluate(
|
||||
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
|
||||
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
|
||||
@@ -1790,132 +1921,10 @@ llvm::Expected<Value> 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 = op->getRawOperand(0);
|
||||
|
||||
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
|
||||
curr_piece.ResizeData(piece_byte_size);
|
||||
// Note that "0" is not a correct value for the unknown bits.
|
||||
// It would be better to also return a mask of valid bits together
|
||||
// with the expression result, so the debugger can print missing
|
||||
// members as "<optimized out>" or something.
|
||||
::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
|
||||
pieces.AppendDataToHostBuffer(curr_piece);
|
||||
} else {
|
||||
Status error;
|
||||
// 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();
|
||||
Scalar &scalar = curr_piece_source_value.GetScalar();
|
||||
lldb::addr_t addr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
|
||||
switch (curr_piece_source_value_type) {
|
||||
case Value::ValueType::Invalid:
|
||||
return llvm::createStringError("invalid value type");
|
||||
case Value::ValueType::FileAddress:
|
||||
if (target) {
|
||||
curr_piece_source_value.ConvertToLoadAddress(module_sp.get(),
|
||||
target);
|
||||
addr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
|
||||
} else {
|
||||
return llvm::createStringError(
|
||||
"unable to convert file address 0x%" PRIx64
|
||||
" to load address "
|
||||
"for DW_OP_piece(%" PRIu64 "): "
|
||||
"no target available",
|
||||
addr, piece_byte_size);
|
||||
}
|
||||
[[fallthrough]];
|
||||
case Value::ValueType::LoadAddress: {
|
||||
if (target) {
|
||||
if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) {
|
||||
if (target->ReadMemory(
|
||||
Address(addr), curr_piece.GetBuffer().GetBytes(),
|
||||
piece_byte_size, error,
|
||||
/*force_live_memory=*/false) != piece_byte_size) {
|
||||
const char *addr_type = (curr_piece_source_value_type ==
|
||||
Value::ValueType::LoadAddress)
|
||||
? "load"
|
||||
: "file";
|
||||
return llvm::createStringError(
|
||||
"failed to read memory DW_OP_piece(%" PRIu64
|
||||
") from %s address 0x%" PRIx64,
|
||||
piece_byte_size, addr_type, addr);
|
||||
}
|
||||
} else {
|
||||
return llvm::createStringError(
|
||||
"failed to resize the piece memory buffer for "
|
||||
"DW_OP_piece(%" PRIu64 ")",
|
||||
piece_byte_size);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Value::ValueType::HostAddress: {
|
||||
return llvm::createStringError(
|
||||
"failed to read memory DW_OP_piece(%" PRIu64
|
||||
") from host address 0x%" PRIx64,
|
||||
piece_byte_size, addr);
|
||||
} break;
|
||||
|
||||
case Value::ValueType::Scalar: {
|
||||
uint32_t bit_size = piece_byte_size * 8;
|
||||
uint32_t bit_offset = 0;
|
||||
if (!scalar.ExtractBitfield(bit_size, bit_offset)) {
|
||||
return llvm::createStringError(
|
||||
"unable to extract %" PRIu64 " bytes from a %" PRIu64
|
||||
" byte scalar value.",
|
||||
piece_byte_size,
|
||||
(uint64_t)curr_piece_source_value.GetScalar().GetByteSize());
|
||||
}
|
||||
|
||||
// We have seen a case where we have expression like:
|
||||
// DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x28
|
||||
// here we are assuming the compiler was trying to zero
|
||||
// extend the value that we should append to the buffer.
|
||||
scalar.TruncOrExtendTo(bit_size, /*sign=*/false);
|
||||
curr_piece.GetScalar() = scalar;
|
||||
} break;
|
||||
}
|
||||
|
||||
// Check if this is the first piece?
|
||||
if (op_piece_offset == 0) {
|
||||
// This is the first piece, we should push it back onto the stack
|
||||
// so subsequent pieces will be able to access this piece and add
|
||||
// to it.
|
||||
if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
|
||||
return llvm::createStringError("failed to append piece data");
|
||||
}
|
||||
} else {
|
||||
// If this is the second or later piece there should be a value on
|
||||
// the stack.
|
||||
if (pieces.GetBuffer().GetByteSize() != op_piece_offset) {
|
||||
return llvm::createStringError(
|
||||
"DW_OP_piece for offset %" PRIu64
|
||||
" but top of stack is of size %" PRIu64,
|
||||
op_piece_offset, pieces.GetBuffer().GetByteSize());
|
||||
}
|
||||
|
||||
if (pieces.AppendDataToHostBuffer(curr_piece) == 0)
|
||||
return llvm::createStringError("failed to append piece data");
|
||||
}
|
||||
}
|
||||
op_piece_offset += piece_byte_size;
|
||||
}
|
||||
if (llvm::Error err = Evaluate_DW_OP_piece(
|
||||
stack, pieces, op_piece_offset, dwarf4_location_description_kind,
|
||||
dwarf_cu, module_sp, target, op->getRawOperand(0), log))
|
||||
return err;
|
||||
} break;
|
||||
|
||||
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
|
||||
|
||||
Reference in New Issue
Block a user