Skip to content

Commit da9e8d5

Browse files
authored
[lldb] Unify DW_OP_deref and DW_OP_deref_size implementations (#169587)
This commit unifies the code in the dwarf expression evaluator that handles these two deref operations. Previously we had similar, but not identical code for handling them. The implementation was taken from the DW_OP_deref_size code path since that handles the general case. We put that code into an Evaluate_DW_OP_deref_size function and call it with the address size when evaluating DW_OP_deref. There were initially two test failures when I made the change. The `DW_op_deref_no_ptr_fixing` unittest failed because we were not correctly setting the address size when we created the DataExtractor. The `DW_OP_deref test` failed because previously the expression `DW_OP_lit4, DW_OP_deref` would evaluate to a LoadAddress, but the code for deref_size was evaluating it to a scalar. The difference was in how it handled a deref of a scalar value type. In the deref code path we convert a scalar to a load address, but this was not done in the deref_size code path. ``` case Value::ValueType::Scalar: stack.back().SetValueType(Value::ValueType::LoadAddress); ``` I decided to modify the deref_size code to also convert the value to a load address to keep the test passing. There is no functional change intended here. The motivation is to reduce the number of code paths that implement the deref operation.
1 parent 5d4c441 commit da9e8d5

File tree

2 files changed

+114
-171
lines changed

2 files changed

+114
-171
lines changed

lldb/source/Expression/DWARFExpression.cpp

Lines changed: 111 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -861,84 +861,146 @@ ResolveLoadAddress(ExecutionContext *exe_ctx, lldb::ModuleSP &module_sp,
861861
return load_addr;
862862
}
863863

864-
static llvm::Error Evaluate_DW_OP_deref(DWARFExpression::Stack &stack,
865-
ExecutionContext *exe_ctx,
866-
lldb::ModuleSP module_sp,
867-
Process *process) {
864+
/// @brief Helper function to load sized data from a uint8_t buffer.
865+
///
866+
/// @param addr_bytes The buffer containing raw data.
867+
/// @param size_addr_bytes How large is the underlying raw data.
868+
/// @param byte_order What is the byte order of the underlying data.
869+
/// @param size How much of the underlying data we want to use.
870+
/// @return The underlying data converted into a Scalar.
871+
static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes,
872+
size_t size_addr_bytes,
873+
ByteOrder byte_order, size_t size) {
874+
DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size);
875+
876+
lldb::offset_t addr_data_offset = 0;
877+
if (size <= 8)
878+
return addr_data.GetMaxU64(&addr_data_offset, size);
879+
return addr_data.GetAddress(&addr_data_offset);
880+
}
881+
882+
static llvm::Error Evaluate_DW_OP_deref_size(DWARFExpression::Stack &stack,
883+
ExecutionContext *exe_ctx,
884+
lldb::ModuleSP module_sp,
885+
Process *process, Target *target,
886+
uint8_t size) {
868887
if (stack.empty())
869-
return llvm::createStringError("expression stack empty for DW_OP_deref");
888+
return llvm::createStringError(
889+
"expression stack empty for DW_OP_deref_size");
870890

871-
const Value::ValueType value_type = stack.back().GetValueType();
891+
if (size > 8)
892+
return llvm::createStringError(
893+
"Invalid address size for DW_OP_deref_size: %d\n", size);
894+
895+
Value::ValueType value_type = stack.back().GetValueType();
872896
switch (value_type) {
873897
case Value::ValueType::HostAddress: {
874898
void *src = (void *)stack.back().GetScalar().ULongLong();
875899
intptr_t ptr;
876900
::memcpy(&ptr, src, sizeof(void *));
901+
// I can't decide whether the size operand should apply to the bytes in
902+
// their lldb-host endianness or the target endianness.. I doubt this'll
903+
// ever come up but I'll opt for assuming big endian regardless.
904+
switch (size) {
905+
case 1:
906+
ptr = ptr & 0xff;
907+
break;
908+
case 2:
909+
ptr = ptr & 0xffff;
910+
break;
911+
case 3:
912+
ptr = ptr & 0xffffff;
913+
break;
914+
case 4:
915+
ptr = ptr & 0xffffffff;
916+
break;
917+
// The casts are added to work around the case where intptr_t is a 32-bit
918+
// quantity. Presumably we won't hit the 5..7 cases if (void*) is 32-bits in
919+
// this program.
920+
case 5:
921+
ptr = (intptr_t)ptr & 0xffffffffffULL;
922+
break;
923+
case 6:
924+
ptr = (intptr_t)ptr & 0xffffffffffffULL;
925+
break;
926+
case 7:
927+
ptr = (intptr_t)ptr & 0xffffffffffffffULL;
928+
break;
929+
default:
930+
break;
931+
}
877932
stack.back().GetScalar() = ptr;
878933
stack.back().ClearContext();
879934
} break;
880935
case Value::ValueType::FileAddress: {
881936
auto file_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
882937
Address so_addr;
883-
auto maybe_load_addr = ResolveLoadAddress(exe_ctx, module_sp, "DW_OP_deref",
884-
file_addr, so_addr);
938+
auto maybe_load_addr = ResolveLoadAddress(
939+
exe_ctx, module_sp, "DW_OP_deref_size", file_addr, so_addr,
940+
/*check_sectionoffset=*/true);
941+
885942
if (!maybe_load_addr)
886943
return maybe_load_addr.takeError();
887-
stack.back().GetScalar() = *maybe_load_addr;
944+
945+
addr_t load_addr = *maybe_load_addr;
946+
947+
if (load_addr == LLDB_INVALID_ADDRESS && so_addr.IsSectionOffset()) {
948+
uint8_t addr_bytes[8];
949+
Status error;
950+
951+
if (!target || target->ReadMemory(so_addr, &addr_bytes, size, error,
952+
/*force_live_memory=*/false) != size)
953+
return llvm::createStringError(
954+
"failed to dereference pointer for DW_OP_deref_size: "
955+
"%s\n",
956+
error.AsCString());
957+
958+
ObjectFile *objfile = module_sp->GetObjectFile();
959+
960+
stack.back().GetScalar() = DerefSizeExtractDataHelper(
961+
addr_bytes, size, objfile->GetByteOrder(), size);
962+
stack.back().ClearContext();
963+
break;
964+
}
965+
stack.back().GetScalar() = load_addr;
888966
// Fall through to load address promotion code below.
889967
}
968+
890969
[[fallthrough]];
891970
case Value::ValueType::Scalar:
892971
// Promote Scalar to LoadAddress and fall through.
893972
stack.back().SetValueType(Value::ValueType::LoadAddress);
894973
[[fallthrough]];
895974
case Value::ValueType::LoadAddress: {
896975
if (!exe_ctx)
897-
return llvm::createStringError("NULL execution context for DW_OP_deref");
976+
return llvm::createStringError(
977+
"no execution context for DW_OP_deref_size");
898978
if (!process)
899-
return llvm::createStringError("NULL process for DW_OP_deref");
979+
return llvm::createStringError("no process for DW_OP_deref_size");
980+
900981
lldb::addr_t pointer_addr =
901982
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
983+
uint8_t addr_bytes[sizeof(lldb::addr_t)];
902984
Status error;
903-
lldb::addr_t pointer_value =
904-
process->ReadPointerFromMemory(pointer_addr, error);
905-
if (pointer_value == LLDB_INVALID_ADDRESS)
906-
return llvm::joinErrors(
907-
llvm::createStringError(
908-
"Failed to dereference pointer from 0x%" PRIx64
909-
" for DW_OP_deref",
910-
pointer_addr),
911-
error.takeError());
912-
stack.back().GetScalar() = pointer_value;
985+
986+
if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) != size)
987+
return llvm::createStringError(
988+
"failed to dereference pointer from 0x%" PRIx64
989+
" for DW_OP_deref_size: %s\n",
990+
pointer_addr, error.AsCString());
991+
992+
stack.back().GetScalar() = DerefSizeExtractDataHelper(
993+
addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), size);
913994
stack.back().ClearContext();
914995
} break;
996+
915997
case Value::ValueType::Invalid:
916-
return llvm::createStringError("invalid value type for DW_OP_deref");
998+
return llvm::createStringError("invalid value for DW_OP_deref_size");
917999
}
9181000

9191001
return llvm::Error::success();
9201002
}
9211003

922-
/// Helper function to move common code used to load sized data from a uint8_t
923-
/// buffer.
924-
///
925-
/// \param addr_bytes uint8_t buffer containg raw data
926-
/// \param size_addr_bytes how large is the underlying raw data
927-
/// \param byte_order what is the byter order of the underlyig data
928-
/// \param size How much of the underlying data we want to use
929-
/// \return The underlying data converted into a Scalar
930-
static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes,
931-
size_t size_addr_bytes,
932-
ByteOrder byte_order, size_t size) {
933-
DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size);
934-
935-
lldb::offset_t addr_data_offset = 0;
936-
if (size <= 8)
937-
return addr_data.GetMaxU64(&addr_data_offset, size);
938-
else
939-
return addr_data.GetAddress(&addr_data_offset);
940-
}
941-
9421004
llvm::Expected<Value> DWARFExpression::Evaluate(
9431005
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
9441006
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
@@ -1079,8 +1141,9 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
10791141
// retrieved from the dereferenced address is the size of an address on the
10801142
// target machine.
10811143
case DW_OP_deref: {
1082-
if (llvm::Error err =
1083-
Evaluate_DW_OP_deref(stack, exe_ctx, module_sp, process))
1144+
size_t size = opcodes.GetAddressByteSize();
1145+
if (llvm::Error err = Evaluate_DW_OP_deref_size(stack, exe_ctx, module_sp,
1146+
process, target, size))
10841147
return err;
10851148
} break;
10861149

@@ -1097,131 +1160,10 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
10971160
// the size of an address on the target machine before being pushed on the
10981161
// expression stack.
10991162
case DW_OP_deref_size: {
1100-
if (stack.empty()) {
1101-
return llvm::createStringError(
1102-
"expression stack empty for DW_OP_deref_size");
1103-
}
1104-
uint8_t size = opcodes.GetU8(&offset);
1105-
if (size > 8) {
1106-
return llvm::createStringError(
1107-
"Invalid address size for DW_OP_deref_size: %d\n", size);
1108-
}
1109-
Value::ValueType value_type = stack.back().GetValueType();
1110-
switch (value_type) {
1111-
case Value::ValueType::HostAddress: {
1112-
void *src = (void *)stack.back().GetScalar().ULongLong();
1113-
intptr_t ptr;
1114-
::memcpy(&ptr, src, sizeof(void *));
1115-
// I can't decide whether the size operand should apply to the bytes in
1116-
// their
1117-
// lldb-host endianness or the target endianness.. I doubt this'll ever
1118-
// come up but I'll opt for assuming big endian regardless.
1119-
switch (size) {
1120-
case 1:
1121-
ptr = ptr & 0xff;
1122-
break;
1123-
case 2:
1124-
ptr = ptr & 0xffff;
1125-
break;
1126-
case 3:
1127-
ptr = ptr & 0xffffff;
1128-
break;
1129-
case 4:
1130-
ptr = ptr & 0xffffffff;
1131-
break;
1132-
// the casts are added to work around the case where intptr_t is a 32
1133-
// bit quantity;
1134-
// presumably we won't hit the 5..7 cases if (void*) is 32-bits in this
1135-
// program.
1136-
case 5:
1137-
ptr = (intptr_t)ptr & 0xffffffffffULL;
1138-
break;
1139-
case 6:
1140-
ptr = (intptr_t)ptr & 0xffffffffffffULL;
1141-
break;
1142-
case 7:
1143-
ptr = (intptr_t)ptr & 0xffffffffffffffULL;
1144-
break;
1145-
default:
1146-
break;
1147-
}
1148-
stack.back().GetScalar() = ptr;
1149-
stack.back().ClearContext();
1150-
} break;
1151-
case Value::ValueType::FileAddress: {
1152-
auto file_addr =
1153-
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1154-
Address so_addr;
1155-
auto maybe_load_addr = ResolveLoadAddress(
1156-
exe_ctx, module_sp, "DW_OP_deref_size", file_addr, so_addr,
1157-
/*check_sectionoffset=*/true);
1158-
1159-
if (!maybe_load_addr)
1160-
return maybe_load_addr.takeError();
1161-
1162-
addr_t load_addr = *maybe_load_addr;
1163-
1164-
if (load_addr == LLDB_INVALID_ADDRESS && so_addr.IsSectionOffset()) {
1165-
uint8_t addr_bytes[8];
1166-
Status error;
1167-
1168-
if (target &&
1169-
target->ReadMemory(so_addr, &addr_bytes, size, error,
1170-
/*force_live_memory=*/false) == size) {
1171-
ObjectFile *objfile = module_sp->GetObjectFile();
1172-
1173-
stack.back().GetScalar() = DerefSizeExtractDataHelper(
1174-
addr_bytes, size, objfile->GetByteOrder(), size);
1175-
stack.back().ClearContext();
1176-
break;
1177-
} else {
1178-
return llvm::createStringError(
1179-
"Failed to dereference pointer for DW_OP_deref_size: "
1180-
"%s\n",
1181-
error.AsCString());
1182-
}
1183-
}
1184-
stack.back().GetScalar() = load_addr;
1185-
// Fall through to load address promotion code below.
1186-
}
1187-
1188-
[[fallthrough]];
1189-
case Value::ValueType::Scalar:
1190-
case Value::ValueType::LoadAddress:
1191-
if (exe_ctx) {
1192-
if (process) {
1193-
lldb::addr_t pointer_addr =
1194-
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1195-
uint8_t addr_bytes[sizeof(lldb::addr_t)];
1196-
Status error;
1197-
if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) ==
1198-
size) {
1199-
1200-
stack.back().GetScalar() =
1201-
DerefSizeExtractDataHelper(addr_bytes, sizeof(addr_bytes),
1202-
process->GetByteOrder(), size);
1203-
stack.back().ClearContext();
1204-
} else {
1205-
return llvm::createStringError(
1206-
"Failed to dereference pointer from 0x%" PRIx64
1207-
" for DW_OP_deref: %s\n",
1208-
pointer_addr, error.AsCString());
1209-
}
1210-
} else {
1211-
1212-
return llvm::createStringError("NULL process for DW_OP_deref_size");
1213-
}
1214-
} else {
1215-
return llvm::createStringError(
1216-
"NULL execution context for DW_OP_deref_size");
1217-
}
1218-
break;
1219-
1220-
case Value::ValueType::Invalid:
1221-
1222-
return llvm::createStringError("invalid value for DW_OP_deref_size");
1223-
}
1224-
1163+
size_t size = opcodes.GetU8(&offset);
1164+
if (llvm::Error err = Evaluate_DW_OP_deref_size(stack, exe_ctx, module_sp,
1165+
process, target, size))
1166+
return err;
12251167
} break;
12261168

12271169
// OPCODE: DW_OP_xderef_size

lldb/unittests/Expression/DWARFExpressionTest.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,9 @@ static llvm::Expected<Value> Evaluate(llvm::ArrayRef<uint8_t> expr,
237237
DWARFExpression::Delegate *unit = nullptr,
238238
ExecutionContext *exe_ctx = nullptr,
239239
RegisterContext *reg_ctx = nullptr) {
240-
DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
241-
/*addr_size*/ 4);
240+
DataExtractor extractor(
241+
expr.data(), expr.size(), lldb::eByteOrderLittle,
242+
/*addr_size*/ exe_ctx ? exe_ctx->GetAddressByteSize() : 4);
242243

243244
return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, extractor, unit,
244245
lldb::eRegisterKindLLDB,

0 commit comments

Comments
 (0)