Skip to content

Commit 8f6d74a

Browse files
committed
[lldb] Unify DW_OP_deref and DW_OP_deref_size implementations
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 89206de commit 8f6d74a

File tree

2 files changed

+136
-180
lines changed

2 files changed

+136
-180
lines changed

lldb/source/Expression/DWARFExpression.cpp

Lines changed: 133 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -861,84 +861,159 @@ 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) {
868-
if (stack.empty())
869-
return llvm::createStringError("expression stack empty for DW_OP_deref");
870-
871-
const Value::ValueType value_type = stack.back().GetValueType();
864+
/// Helper function to move common code used to load sized data from a uint8_t
865+
/// buffer.
866+
///
867+
/// \param addr_bytes uint8_t buffer containg raw data
868+
/// \param size_addr_bytes how large is the underlying raw data
869+
/// \param byte_order what is the byter order of the underlyig data
870+
/// \param size How much of the underlying data we want to use
871+
/// \return The underlying data converted into a Scalar
872+
static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes,
873+
size_t size_addr_bytes,
874+
ByteOrder byte_order, size_t size) {
875+
DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size);
876+
877+
lldb::offset_t addr_data_offset = 0;
878+
if (size <= 8)
879+
return addr_data.GetMaxU64(&addr_data_offset, size);
880+
else
881+
return addr_data.GetAddress(&addr_data_offset);
882+
}
883+
884+
static llvm::Error Evaluate_DW_OP_deref_size(DWARFExpression::Stack &stack,
885+
ExecutionContext *exe_ctx,
886+
lldb::ModuleSP module_sp,
887+
Process *process, Target *target,
888+
uint8_t size) {
889+
if (stack.empty()) {
890+
return llvm::createStringError(
891+
"expression stack empty for DW_OP_deref_size");
892+
}
893+
894+
if (size > 8) {
895+
return llvm::createStringError(
896+
"Invalid address size for DW_OP_deref_size: %d\n", size);
897+
}
898+
Value::ValueType value_type = stack.back().GetValueType();
872899
switch (value_type) {
873900
case Value::ValueType::HostAddress: {
874901
void *src = (void *)stack.back().GetScalar().ULongLong();
875902
intptr_t ptr;
876903
::memcpy(&ptr, src, sizeof(void *));
904+
// I can't decide whether the size operand should apply to the bytes in
905+
// their
906+
// lldb-host endianness or the target endianness.. I doubt this'll ever
907+
// come up but I'll opt for assuming big endian regardless.
908+
switch (size) {
909+
case 1:
910+
ptr = ptr & 0xff;
911+
break;
912+
case 2:
913+
ptr = ptr & 0xffff;
914+
break;
915+
case 3:
916+
ptr = ptr & 0xffffff;
917+
break;
918+
case 4:
919+
ptr = ptr & 0xffffffff;
920+
break;
921+
// the casts are added to work around the case where intptr_t is a 32
922+
// bit quantity;
923+
// presumably we won't hit the 5..7 cases if (void*) is 32-bits in this
924+
// program.
925+
case 5:
926+
ptr = (intptr_t)ptr & 0xffffffffffULL;
927+
break;
928+
case 6:
929+
ptr = (intptr_t)ptr & 0xffffffffffffULL;
930+
break;
931+
case 7:
932+
ptr = (intptr_t)ptr & 0xffffffffffffffULL;
933+
break;
934+
default:
935+
break;
936+
}
877937
stack.back().GetScalar() = ptr;
878938
stack.back().ClearContext();
879939
} break;
880940
case Value::ValueType::FileAddress: {
881941
auto file_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
882942
Address so_addr;
883-
auto maybe_load_addr = ResolveLoadAddress(exe_ctx, module_sp, "DW_OP_deref",
884-
file_addr, so_addr);
943+
auto maybe_load_addr = ResolveLoadAddress(
944+
exe_ctx, module_sp, "DW_OP_deref_size", file_addr, so_addr,
945+
/*check_sectionoffset=*/true);
946+
885947
if (!maybe_load_addr)
886948
return maybe_load_addr.takeError();
887-
stack.back().GetScalar() = *maybe_load_addr;
949+
950+
addr_t load_addr = *maybe_load_addr;
951+
952+
if (load_addr == LLDB_INVALID_ADDRESS && so_addr.IsSectionOffset()) {
953+
uint8_t addr_bytes[8];
954+
Status error;
955+
956+
if (target && target->ReadMemory(so_addr, &addr_bytes, size, error,
957+
/*force_live_memory=*/false) == size) {
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+
} else {
965+
return llvm::createStringError(
966+
"Failed to dereference pointer for DW_OP_deref_size: "
967+
"%s\n",
968+
error.AsCString());
969+
}
970+
}
971+
stack.back().GetScalar() = load_addr;
888972
// Fall through to load address promotion code below.
889973
}
974+
890975
[[fallthrough]];
891976
case Value::ValueType::Scalar:
892977
// Promote Scalar to LoadAddress and fall through.
893978
stack.back().SetValueType(Value::ValueType::LoadAddress);
894979
[[fallthrough]];
895-
case Value::ValueType::LoadAddress: {
896-
if (!exe_ctx)
897-
return llvm::createStringError("NULL execution context for DW_OP_deref");
898-
if (!process)
899-
return llvm::createStringError("NULL process for DW_OP_deref");
900-
lldb::addr_t pointer_addr =
901-
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
902-
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(
980+
case Value::ValueType::LoadAddress:
981+
if (exe_ctx) {
982+
if (process) {
983+
lldb::addr_t pointer_addr =
984+
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
985+
uint8_t addr_bytes[sizeof(lldb::addr_t)];
986+
Status error;
987+
if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) ==
988+
size) {
989+
990+
stack.back().GetScalar() = DerefSizeExtractDataHelper(
991+
addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), size);
992+
stack.back().ClearContext();
993+
} else {
994+
return llvm::createStringError(
908995
"Failed to dereference pointer from 0x%" PRIx64
909-
" for DW_OP_deref",
910-
pointer_addr),
911-
error.takeError());
912-
stack.back().GetScalar() = pointer_value;
913-
stack.back().ClearContext();
914-
} break;
996+
" for DW_OP_deref: %s\n",
997+
pointer_addr, error.AsCString());
998+
}
999+
} else {
1000+
1001+
return llvm::createStringError("NULL process for DW_OP_deref_size");
1002+
}
1003+
} else {
1004+
return llvm::createStringError(
1005+
"NULL execution context for DW_OP_deref_size");
1006+
}
1007+
break;
1008+
9151009
case Value::ValueType::Invalid:
916-
return llvm::createStringError("invalid value type for DW_OP_deref");
1010+
1011+
return llvm::createStringError("invalid value for DW_OP_deref_size");
9171012
}
9181013

9191014
return llvm::Error::success();
9201015
}
9211016

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-
9421017
llvm::Expected<Value> DWARFExpression::Evaluate(
9431018
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
9441019
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
@@ -1079,8 +1154,9 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
10791154
// retrieved from the dereferenced address is the size of an address on the
10801155
// target machine.
10811156
case DW_OP_deref: {
1082-
if (llvm::Error err =
1083-
Evaluate_DW_OP_deref(stack, exe_ctx, module_sp, process))
1157+
size_t size = opcodes.GetAddressByteSize();
1158+
if (llvm::Error err = Evaluate_DW_OP_deref_size(stack, exe_ctx, module_sp,
1159+
process, target, size))
10841160
return err;
10851161
} break;
10861162

@@ -1097,131 +1173,10 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
10971173
// the size of an address on the target machine before being pushed on the
10981174
// expression stack.
10991175
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-
1176+
size_t size = opcodes.GetU8(&offset);
1177+
if (llvm::Error err = Evaluate_DW_OP_deref_size(stack, exe_ctx, module_sp,
1178+
process, target, size))
1179+
return err;
12251180
} break;
12261181

12271182
// 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)