[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();
|
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(
|
llvm::Expected<Value> DWARFExpression::Evaluate(
|
||||||
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
|
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
|
||||||
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
|
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
|
// provides a way of describing how large a part of a variable a particular
|
||||||
// DWARF expression refers to.
|
// DWARF expression refers to.
|
||||||
case DW_OP_piece: {
|
case DW_OP_piece: {
|
||||||
LocationDescriptionKind piece_locdesc = dwarf4_location_description_kind;
|
if (llvm::Error err = Evaluate_DW_OP_piece(
|
||||||
// Reset for the next piece.
|
stack, pieces, op_piece_offset, dwarf4_location_description_kind,
|
||||||
dwarf4_location_description_kind = Memory;
|
dwarf_cu, module_sp, target, op->getRawOperand(0), log))
|
||||||
|
return err;
|
||||||
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;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
|
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
|
||||||
|
|||||||
Reference in New Issue
Block a user