1 //===-- DWARFLocationExpression.cpp ---------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "DWARFLocationExpression.h" 10 11 #include "lldb/Core/Module.h" 12 #include "lldb/Core/Section.h" 13 #include "lldb/Expression/DWARFExpression.h" 14 #include "lldb/Utility/ArchSpec.h" 15 #include "lldb/Utility/DataBufferHeap.h" 16 #include "lldb/Utility/StreamBuffer.h" 17 18 #include "llvm/BinaryFormat/Dwarf.h" 19 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 20 #include "llvm/DebugInfo/CodeView/TypeIndex.h" 21 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 22 #include "llvm/Support/Endian.h" 23 24 #include "PdbUtil.h" 25 #include "CodeViewRegisterMapping.h" 26 #include "PdbFPOProgramToDWARFExpression.h" 27 #include <optional> 28 29 using namespace lldb; 30 using namespace lldb_private; 31 using namespace lldb_private::npdb; 32 using namespace llvm::codeview; 33 using namespace llvm::pdb; 34 35 uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) { 36 if (register_id == llvm::codeview::RegisterId::VFRAME) 37 return LLDB_REGNUM_GENERIC_FP; 38 39 return LLDB_INVALID_REGNUM; 40 } 41 42 static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, 43 llvm::codeview::RegisterId register_id, 44 RegisterKind ®ister_kind) { 45 register_kind = eRegisterKindLLDB; 46 uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id); 47 if (reg_num != LLDB_INVALID_REGNUM) 48 return reg_num; 49 50 register_kind = eRegisterKindGeneric; 51 return GetGenericRegisterNumber(register_id); 52 } 53 54 static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) { 55 switch (kind) { 56 case SimpleTypeKind::Int128: 57 case SimpleTypeKind::Int64: 58 case SimpleTypeKind::Int64Quad: 59 case SimpleTypeKind::Int32: 60 case SimpleTypeKind::Int32Long: 61 case SimpleTypeKind::Int16: 62 case SimpleTypeKind::Int16Short: 63 case SimpleTypeKind::Float128: 64 case SimpleTypeKind::Float80: 65 case SimpleTypeKind::Float64: 66 case SimpleTypeKind::Float32: 67 case SimpleTypeKind::Float16: 68 case SimpleTypeKind::NarrowCharacter: 69 case SimpleTypeKind::SignedCharacter: 70 case SimpleTypeKind::SByte: 71 return true; 72 default: 73 return false; 74 } 75 } 76 77 static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti, 78 TpiStream &tpi) { 79 if (ti.isSimple()) { 80 SimpleTypeKind stk = ti.getSimpleKind(); 81 return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)}; 82 } 83 84 CVType cvt = tpi.getType(ti); 85 switch (cvt.kind()) { 86 case LF_MODIFIER: { 87 ModifierRecord mfr; 88 llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr)); 89 return GetIntegralTypeInfo(mfr.ModifiedType, tpi); 90 } 91 case LF_POINTER: { 92 PointerRecord pr; 93 llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr)); 94 return GetIntegralTypeInfo(pr.ReferentType, tpi); 95 } 96 case LF_ENUM: { 97 EnumRecord er; 98 llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); 99 return GetIntegralTypeInfo(er.UnderlyingType, tpi); 100 } 101 default: 102 assert(false && "Type is not integral!"); 103 return {0, false}; 104 } 105 } 106 107 template <typename StreamWriter> 108 static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module, 109 StreamWriter &&writer) { 110 const ArchSpec &architecture = module->GetArchitecture(); 111 ByteOrder byte_order = architecture.GetByteOrder(); 112 uint32_t address_size = architecture.GetAddressByteSize(); 113 uint32_t byte_size = architecture.GetDataByteSize(); 114 if (byte_order == eByteOrderInvalid || address_size == 0) 115 return DWARFExpression(); 116 117 RegisterKind register_kind = eRegisterKindDWARF; 118 StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order); 119 120 if (!writer(stream, register_kind)) 121 return DWARFExpression(); 122 123 DataBufferSP buffer = 124 std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize()); 125 DataExtractor extractor(buffer, byte_order, address_size, byte_size); 126 DWARFExpression result(extractor); 127 result.SetRegisterKind(register_kind); 128 129 return result; 130 } 131 132 static bool MakeRegisterBasedLocationExpressionInternal( 133 Stream &stream, llvm::codeview::RegisterId reg, RegisterKind ®ister_kind, 134 std::optional<int32_t> relative_offset, lldb::ModuleSP module) { 135 uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(), 136 reg, register_kind); 137 if (reg_num == LLDB_INVALID_REGNUM) 138 return false; 139 140 if (reg_num > 31) { 141 llvm::dwarf::LocationAtom base = 142 relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx; 143 stream.PutHex8(base); 144 stream.PutULEB128(reg_num); 145 } else { 146 llvm::dwarf::LocationAtom base = 147 relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0; 148 stream.PutHex8(base + reg_num); 149 } 150 151 if (relative_offset) 152 stream.PutSLEB128(*relative_offset); 153 154 return true; 155 } 156 157 static DWARFExpression MakeRegisterBasedLocationExpressionInternal( 158 llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset, 159 lldb::ModuleSP module) { 160 return MakeLocationExpressionInternal( 161 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 162 return MakeRegisterBasedLocationExpressionInternal( 163 stream, reg, register_kind, relative_offset, module); 164 }); 165 } 166 167 DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression( 168 llvm::codeview::RegisterId reg, lldb::ModuleSP module) { 169 return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module); 170 } 171 172 DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression( 173 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) { 174 return MakeRegisterBasedLocationExpressionInternal(reg, offset, module); 175 } 176 177 static bool EmitVFrameEvaluationDWARFExpression( 178 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) { 179 // VFrame value always stored in $TO pseudo-register 180 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type, 181 stream); 182 } 183 184 DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression( 185 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) { 186 return MakeLocationExpressionInternal( 187 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 188 const ArchSpec &architecture = module->GetArchitecture(); 189 190 if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(), 191 stream)) 192 return false; 193 194 stream.PutHex8(llvm::dwarf::DW_OP_consts); 195 stream.PutSLEB128(offset); 196 stream.PutHex8(llvm::dwarf::DW_OP_plus); 197 198 register_kind = eRegisterKindLLDB; 199 200 return true; 201 }); 202 } 203 204 DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression( 205 uint16_t section, uint32_t offset, ModuleSP module) { 206 assert(section > 0); 207 assert(module); 208 209 return MakeLocationExpressionInternal( 210 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 211 stream.PutHex8(llvm::dwarf::DW_OP_addr); 212 213 SectionList *section_list = module->GetSectionList(); 214 assert(section_list); 215 216 auto section_ptr = section_list->FindSectionByID(section); 217 if (!section_ptr) 218 return false; 219 220 stream.PutMaxHex64(section_ptr->GetFileAddress() + offset, 221 stream.GetAddressByteSize(), stream.GetByteOrder()); 222 223 return true; 224 }); 225 } 226 227 DWARFExpression lldb_private::npdb::MakeConstantLocationExpression( 228 TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant, 229 ModuleSP module) { 230 const ArchSpec &architecture = module->GetArchitecture(); 231 uint32_t address_size = architecture.GetAddressByteSize(); 232 233 size_t size = 0; 234 bool is_signed = false; 235 std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi); 236 237 union { 238 llvm::support::little64_t I; 239 llvm::support::ulittle64_t U; 240 } Value; 241 242 std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>(); 243 buffer->SetByteSize(size); 244 245 llvm::ArrayRef<uint8_t> bytes; 246 if (is_signed) { 247 Value.I = constant.getSExtValue(); 248 } else { 249 Value.U = constant.getZExtValue(); 250 } 251 252 bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8) 253 .take_front(size); 254 buffer->CopyData(bytes.data(), size); 255 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size); 256 DWARFExpression result(extractor); 257 return result; 258 } 259 260 DWARFExpression 261 lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite( 262 const std::map<uint64_t, MemberValLocation> &offset_to_location, 263 std::map<uint64_t, size_t> &offset_to_size, size_t total_size, 264 lldb::ModuleSP module) { 265 return MakeLocationExpressionInternal( 266 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 267 size_t cur_offset = 0; 268 bool is_simple_type = offset_to_size.empty(); 269 // Iterate through offset_to_location because offset_to_size might be 270 // empty if the variable is a simple type. 271 for (const auto &offset_loc : offset_to_location) { 272 if (cur_offset < offset_loc.first) { 273 stream.PutHex8(llvm::dwarf::DW_OP_piece); 274 stream.PutULEB128(offset_loc.first - cur_offset); 275 cur_offset = offset_loc.first; 276 } 277 MemberValLocation loc = offset_loc.second; 278 std::optional<int32_t> offset = 279 loc.is_at_reg ? std::nullopt 280 : std::optional<int32_t>(loc.reg_offset); 281 if (!MakeRegisterBasedLocationExpressionInternal( 282 stream, (RegisterId)loc.reg_id, register_kind, offset, 283 module)) 284 return false; 285 if (!is_simple_type) { 286 stream.PutHex8(llvm::dwarf::DW_OP_piece); 287 stream.PutULEB128(offset_to_size[offset_loc.first]); 288 cur_offset = offset_loc.first + offset_to_size[offset_loc.first]; 289 } 290 } 291 // For simple type, it specifies the byte size of the value described by 292 // the previous dwarf expr. For udt, it's the remaining byte size at end 293 // of a struct. 294 if (total_size > cur_offset) { 295 stream.PutHex8(llvm::dwarf::DW_OP_piece); 296 stream.PutULEB128(total_size - cur_offset); 297 } 298 return true; 299 }); 300 } 301