15ffd83dbSDimitry Andric //===-- DWARFLocationExpression.cpp ---------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "DWARFLocationExpression.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Core/Module.h"
120b57cec5SDimitry Andric #include "lldb/Core/Section.h"
130b57cec5SDimitry Andric #include "lldb/Expression/DWARFExpression.h"
140b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h"
150b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
165f757f3fSDimitry Andric #include "lldb/Utility/StreamBuffer.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
190b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndex.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
220b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #include "PdbUtil.h"
250b57cec5SDimitry Andric #include "CodeViewRegisterMapping.h"
260b57cec5SDimitry Andric #include "PdbFPOProgramToDWARFExpression.h"
27bdd1243dSDimitry Andric #include <optional>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace lldb;
300b57cec5SDimitry Andric using namespace lldb_private;
310b57cec5SDimitry Andric using namespace lldb_private::npdb;
320b57cec5SDimitry Andric using namespace llvm::codeview;
330b57cec5SDimitry Andric using namespace llvm::pdb;
340b57cec5SDimitry Andric 
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)350b57cec5SDimitry Andric uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
360b57cec5SDimitry Andric   if (register_id == llvm::codeview::RegisterId::VFRAME)
370b57cec5SDimitry Andric     return LLDB_REGNUM_GENERIC_FP;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   return LLDB_INVALID_REGNUM;
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)420b57cec5SDimitry Andric static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
430b57cec5SDimitry Andric                                   llvm::codeview::RegisterId register_id,
440b57cec5SDimitry Andric                                   RegisterKind &register_kind) {
450b57cec5SDimitry Andric   register_kind = eRegisterKindLLDB;
460b57cec5SDimitry Andric   uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
470b57cec5SDimitry Andric   if (reg_num != LLDB_INVALID_REGNUM)
480b57cec5SDimitry Andric     return reg_num;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   register_kind = eRegisterKindGeneric;
510b57cec5SDimitry Andric   return GetGenericRegisterNumber(register_id);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
IsSimpleTypeSignedInteger(SimpleTypeKind kind)540b57cec5SDimitry Andric static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
550b57cec5SDimitry Andric   switch (kind) {
560b57cec5SDimitry Andric   case SimpleTypeKind::Int128:
570b57cec5SDimitry Andric   case SimpleTypeKind::Int64:
580b57cec5SDimitry Andric   case SimpleTypeKind::Int64Quad:
590b57cec5SDimitry Andric   case SimpleTypeKind::Int32:
600b57cec5SDimitry Andric   case SimpleTypeKind::Int32Long:
610b57cec5SDimitry Andric   case SimpleTypeKind::Int16:
620b57cec5SDimitry Andric   case SimpleTypeKind::Int16Short:
630b57cec5SDimitry Andric   case SimpleTypeKind::Float128:
640b57cec5SDimitry Andric   case SimpleTypeKind::Float80:
650b57cec5SDimitry Andric   case SimpleTypeKind::Float64:
660b57cec5SDimitry Andric   case SimpleTypeKind::Float32:
670b57cec5SDimitry Andric   case SimpleTypeKind::Float16:
680b57cec5SDimitry Andric   case SimpleTypeKind::NarrowCharacter:
690b57cec5SDimitry Andric   case SimpleTypeKind::SignedCharacter:
700b57cec5SDimitry Andric   case SimpleTypeKind::SByte:
710b57cec5SDimitry Andric     return true;
720b57cec5SDimitry Andric   default:
730b57cec5SDimitry Andric     return false;
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)770b57cec5SDimitry Andric static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
780b57cec5SDimitry Andric                                                    TpiStream &tpi) {
790b57cec5SDimitry Andric   if (ti.isSimple()) {
800b57cec5SDimitry Andric     SimpleTypeKind stk = ti.getSimpleKind();
810b57cec5SDimitry Andric     return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   CVType cvt = tpi.getType(ti);
850b57cec5SDimitry Andric   switch (cvt.kind()) {
860b57cec5SDimitry Andric   case LF_MODIFIER: {
870b57cec5SDimitry Andric     ModifierRecord mfr;
880b57cec5SDimitry Andric     llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
890b57cec5SDimitry Andric     return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric   case LF_POINTER: {
920b57cec5SDimitry Andric     PointerRecord pr;
930b57cec5SDimitry Andric     llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
940b57cec5SDimitry Andric     return GetIntegralTypeInfo(pr.ReferentType, tpi);
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric   case LF_ENUM: {
970b57cec5SDimitry Andric     EnumRecord er;
980b57cec5SDimitry Andric     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
990b57cec5SDimitry Andric     return GetIntegralTypeInfo(er.UnderlyingType, tpi);
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric   default:
1020b57cec5SDimitry Andric     assert(false && "Type is not integral!");
1030b57cec5SDimitry Andric     return {0, false};
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)1080b57cec5SDimitry Andric static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
1090b57cec5SDimitry Andric                                                       StreamWriter &&writer) {
1100b57cec5SDimitry Andric   const ArchSpec &architecture = module->GetArchitecture();
1110b57cec5SDimitry Andric   ByteOrder byte_order = architecture.GetByteOrder();
1120b57cec5SDimitry Andric   uint32_t address_size = architecture.GetAddressByteSize();
1130b57cec5SDimitry Andric   uint32_t byte_size = architecture.GetDataByteSize();
1140b57cec5SDimitry Andric   if (byte_order == eByteOrderInvalid || address_size == 0)
1150b57cec5SDimitry Andric     return DWARFExpression();
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   RegisterKind register_kind = eRegisterKindDWARF;
1180b57cec5SDimitry Andric   StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   if (!writer(stream, register_kind))
1210b57cec5SDimitry Andric     return DWARFExpression();
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   DataBufferSP buffer =
1240b57cec5SDimitry Andric       std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
1250b57cec5SDimitry Andric   DataExtractor extractor(buffer, byte_order, address_size, byte_size);
126753f127fSDimitry Andric   DWARFExpression result(extractor);
1270b57cec5SDimitry Andric   result.SetRegisterKind(register_kind);
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   return result;
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
MakeRegisterBasedLocationExpressionInternal(Stream & stream,llvm::codeview::RegisterId reg,RegisterKind & register_kind,std::optional<int32_t> relative_offset,lldb::ModuleSP module)132bdd1243dSDimitry Andric static bool MakeRegisterBasedLocationExpressionInternal(
133bdd1243dSDimitry Andric     Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
134bdd1243dSDimitry Andric     std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
135bdd1243dSDimitry Andric   uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
136bdd1243dSDimitry Andric                                        reg, register_kind);
1370b57cec5SDimitry Andric   if (reg_num == LLDB_INVALID_REGNUM)
1380b57cec5SDimitry Andric     return false;
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (reg_num > 31) {
141bdd1243dSDimitry Andric     llvm::dwarf::LocationAtom base =
142bdd1243dSDimitry Andric         relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
1430b57cec5SDimitry Andric     stream.PutHex8(base);
1440b57cec5SDimitry Andric     stream.PutULEB128(reg_num);
1450b57cec5SDimitry Andric   } else {
146bdd1243dSDimitry Andric     llvm::dwarf::LocationAtom base =
147bdd1243dSDimitry Andric         relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
1480b57cec5SDimitry Andric     stream.PutHex8(base + reg_num);
1490b57cec5SDimitry Andric   }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   if (relative_offset)
1520b57cec5SDimitry Andric     stream.PutSLEB128(*relative_offset);
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   return true;
155bdd1243dSDimitry Andric }
156bdd1243dSDimitry Andric 
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,std::optional<int32_t> relative_offset,lldb::ModuleSP module)157bdd1243dSDimitry Andric static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158bdd1243dSDimitry Andric     llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159bdd1243dSDimitry Andric     lldb::ModuleSP module) {
160bdd1243dSDimitry Andric   return MakeLocationExpressionInternal(
161bdd1243dSDimitry Andric       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
162bdd1243dSDimitry Andric         return MakeRegisterBasedLocationExpressionInternal(
163bdd1243dSDimitry Andric             stream, reg, register_kind, relative_offset, module);
1640b57cec5SDimitry Andric       });
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)1670b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
1680b57cec5SDimitry Andric     llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169bdd1243dSDimitry Andric   return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)1720b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
1730b57cec5SDimitry Andric     llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
1740b57cec5SDimitry Andric   return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)1770b57cec5SDimitry Andric static bool EmitVFrameEvaluationDWARFExpression(
1780b57cec5SDimitry Andric     llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
1790b57cec5SDimitry Andric   // VFrame value always stored in $TO pseudo-register
1800b57cec5SDimitry Andric   return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
1810b57cec5SDimitry Andric                                               stream);
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric 
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)1840b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
1850b57cec5SDimitry Andric     llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
1860b57cec5SDimitry Andric   return MakeLocationExpressionInternal(
1870b57cec5SDimitry Andric       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
1880b57cec5SDimitry Andric         const ArchSpec &architecture = module->GetArchitecture();
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric         if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
1910b57cec5SDimitry Andric                                                  stream))
1920b57cec5SDimitry Andric           return false;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric         stream.PutHex8(llvm::dwarf::DW_OP_consts);
1950b57cec5SDimitry Andric         stream.PutSLEB128(offset);
1960b57cec5SDimitry Andric         stream.PutHex8(llvm::dwarf::DW_OP_plus);
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric         register_kind = eRegisterKindLLDB;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric         return true;
2010b57cec5SDimitry Andric       });
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)2040b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
2050b57cec5SDimitry Andric     uint16_t section, uint32_t offset, ModuleSP module) {
2060b57cec5SDimitry Andric   assert(section > 0);
2070b57cec5SDimitry Andric   assert(module);
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   return MakeLocationExpressionInternal(
2100b57cec5SDimitry Andric       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
2110b57cec5SDimitry Andric         stream.PutHex8(llvm::dwarf::DW_OP_addr);
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric         SectionList *section_list = module->GetSectionList();
2140b57cec5SDimitry Andric         assert(section_list);
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric         auto section_ptr = section_list->FindSectionByID(section);
2170b57cec5SDimitry Andric         if (!section_ptr)
2180b57cec5SDimitry Andric           return false;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric         stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
2210b57cec5SDimitry Andric                            stream.GetAddressByteSize(), stream.GetByteOrder());
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric         return true;
2240b57cec5SDimitry Andric       });
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)2270b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
2280b57cec5SDimitry Andric     TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
2290b57cec5SDimitry Andric     ModuleSP module) {
2300b57cec5SDimitry Andric   const ArchSpec &architecture = module->GetArchitecture();
2310b57cec5SDimitry Andric   uint32_t address_size = architecture.GetAddressByteSize();
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   size_t size = 0;
2340b57cec5SDimitry Andric   bool is_signed = false;
2350b57cec5SDimitry Andric   std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   union {
2380b57cec5SDimitry Andric     llvm::support::little64_t I;
2390b57cec5SDimitry Andric     llvm::support::ulittle64_t U;
2400b57cec5SDimitry Andric   } Value;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
2430b57cec5SDimitry Andric   buffer->SetByteSize(size);
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   llvm::ArrayRef<uint8_t> bytes;
2460b57cec5SDimitry Andric   if (is_signed) {
2470b57cec5SDimitry Andric     Value.I = constant.getSExtValue();
2480b57cec5SDimitry Andric   } else {
2490b57cec5SDimitry Andric     Value.U = constant.getZExtValue();
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric 
252bdd1243dSDimitry Andric   bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
2530b57cec5SDimitry Andric               .take_front(size);
2540b57cec5SDimitry Andric   buffer->CopyData(bytes.data(), size);
2550b57cec5SDimitry Andric   DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
256753f127fSDimitry Andric   DWARFExpression result(extractor);
2570b57cec5SDimitry Andric   return result;
2580b57cec5SDimitry Andric }
25981ad6265SDimitry Andric 
260bdd1243dSDimitry Andric DWARFExpression
MakeEnregisteredLocationExpressionForComposite(const std::map<uint64_t,MemberValLocation> & offset_to_location,std::map<uint64_t,size_t> & offset_to_size,size_t total_size,lldb::ModuleSP module)261bdd1243dSDimitry Andric lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
262bdd1243dSDimitry Andric     const std::map<uint64_t, MemberValLocation> &offset_to_location,
263bdd1243dSDimitry Andric     std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
26481ad6265SDimitry Andric     lldb::ModuleSP module) {
26581ad6265SDimitry Andric   return MakeLocationExpressionInternal(
26681ad6265SDimitry Andric       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
267bdd1243dSDimitry Andric         size_t cur_offset = 0;
268bdd1243dSDimitry Andric         bool is_simple_type = offset_to_size.empty();
269bdd1243dSDimitry Andric         // Iterate through offset_to_location because offset_to_size might be
270bdd1243dSDimitry Andric         // empty if the variable is a simple type.
271bdd1243dSDimitry Andric         for (const auto &offset_loc : offset_to_location) {
272bdd1243dSDimitry Andric           if (cur_offset < offset_loc.first) {
27381ad6265SDimitry Andric             stream.PutHex8(llvm::dwarf::DW_OP_piece);
274bdd1243dSDimitry Andric             stream.PutULEB128(offset_loc.first - cur_offset);
275bdd1243dSDimitry Andric             cur_offset = offset_loc.first;
276bdd1243dSDimitry Andric           }
277bdd1243dSDimitry Andric           MemberValLocation loc = offset_loc.second;
278bdd1243dSDimitry Andric           std::optional<int32_t> offset =
279bdd1243dSDimitry Andric               loc.is_at_reg ? std::nullopt
280bdd1243dSDimitry Andric                             : std::optional<int32_t>(loc.reg_offset);
281bdd1243dSDimitry Andric           if (!MakeRegisterBasedLocationExpressionInternal(
282bdd1243dSDimitry Andric                   stream, (RegisterId)loc.reg_id, register_kind, offset,
283bdd1243dSDimitry Andric                   module))
284bdd1243dSDimitry Andric             return false;
285bdd1243dSDimitry Andric           if (!is_simple_type) {
286bdd1243dSDimitry Andric             stream.PutHex8(llvm::dwarf::DW_OP_piece);
287bdd1243dSDimitry Andric             stream.PutULEB128(offset_to_size[offset_loc.first]);
288bdd1243dSDimitry Andric             cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
289bdd1243dSDimitry Andric           }
290bdd1243dSDimitry Andric         }
291bdd1243dSDimitry Andric         // For simple type, it specifies the byte size of the value described by
292bdd1243dSDimitry Andric         // the previous dwarf expr. For udt, it's the remaining byte size at end
293bdd1243dSDimitry Andric         // of a struct.
294bdd1243dSDimitry Andric         if (total_size > cur_offset) {
295bdd1243dSDimitry Andric           stream.PutHex8(llvm::dwarf::DW_OP_piece);
296bdd1243dSDimitry Andric           stream.PutULEB128(total_size - cur_offset);
29781ad6265SDimitry Andric         }
29881ad6265SDimitry Andric         return true;
29981ad6265SDimitry Andric       });
30081ad6265SDimitry Andric }
301