1 //===-- DWARFLocationExpression.cpp -----------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "DWARFLocationExpression.h"
11 
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Section.h"
14 #include "lldb/Core/StreamBuffer.h"
15 #include "lldb/Expression/DWARFExpression.h"
16 #include "lldb/Utility/ArchSpec.h"
17 #include "lldb/Utility/DataBufferHeap.h"
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 
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::npdb;
29 using namespace llvm::codeview;
30 using namespace llvm::pdb;
31 
32 static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
33   switch (kind) {
34   case SimpleTypeKind::Int128:
35   case SimpleTypeKind::Int64:
36   case SimpleTypeKind::Int64Quad:
37   case SimpleTypeKind::Int32:
38   case SimpleTypeKind::Int32Long:
39   case SimpleTypeKind::Int16:
40   case SimpleTypeKind::Int16Short:
41   case SimpleTypeKind::Float128:
42   case SimpleTypeKind::Float80:
43   case SimpleTypeKind::Float64:
44   case SimpleTypeKind::Float32:
45   case SimpleTypeKind::Float16:
46   case SimpleTypeKind::NarrowCharacter:
47   case SimpleTypeKind::SignedCharacter:
48   case SimpleTypeKind::SByte:
49     return true;
50   default:
51     return false;
52   }
53 }
54 
55 static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
56                                                    TpiStream &tpi) {
57   if (ti.isSimple()) {
58     SimpleTypeKind stk = ti.getSimpleKind();
59     return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
60   }
61 
62   CVType cvt = tpi.getType(ti);
63   switch (cvt.kind()) {
64   case LF_MODIFIER: {
65     ModifierRecord mfr;
66     llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
67     return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
68   }
69   case LF_POINTER: {
70     PointerRecord pr;
71     llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
72     return GetIntegralTypeInfo(pr.ReferentType, tpi);
73   }
74   case LF_ENUM: {
75     EnumRecord er;
76     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
77     return GetIntegralTypeInfo(er.UnderlyingType, tpi);
78   }
79   default:
80     assert(false && "Type is not integral!");
81     return {0, false};
82   }
83 }
84 
85 template <typename StreamWriter>
86 static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
87                                                       StreamWriter &&writer) {
88   const ArchSpec &architecture = module->GetArchitecture();
89   ByteOrder byte_order = architecture.GetByteOrder();
90   uint32_t address_size = architecture.GetAddressByteSize();
91   uint32_t byte_size = architecture.GetDataByteSize();
92   if (byte_order == eByteOrderInvalid || address_size == 0)
93     return DWARFExpression(nullptr);
94 
95   RegisterKind register_kind = eRegisterKindDWARF;
96   StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
97 
98   if (!writer(stream, register_kind))
99     return DWARFExpression(nullptr);
100 
101   DataBufferSP buffer =
102       std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
103   DataExtractor extractor(buffer, byte_order, address_size, byte_size);
104   DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize());
105   result.SetRegisterKind(register_kind);
106 
107   return result;
108 }
109 
110 DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
111     uint16_t section, uint32_t offset, ModuleSP module) {
112   assert(section > 0);
113   assert(module);
114 
115   return MakeLocationExpressionInternal(
116       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
117         stream.PutHex8(llvm::dwarf::DW_OP_addr);
118 
119         SectionList *section_list = module->GetSectionList();
120         assert(section_list);
121 
122         // Section indices in PDB are 1-based, but in DWARF they are 0-based, so
123         // we need to subtract 1.
124         uint32_t section_idx = section - 1;
125         if (section_idx >= section_list->GetSize())
126           return false;
127 
128         auto section_ptr = section_list->GetSectionAtIndex(section_idx);
129         if (!section_ptr)
130           return false;
131 
132         stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
133                            stream.GetAddressByteSize(), stream.GetByteOrder());
134 
135         return true;
136       });
137 }
138 
139 DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
140     TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
141     ModuleSP module) {
142   const ArchSpec &architecture = module->GetArchitecture();
143   uint32_t address_size = architecture.GetAddressByteSize();
144 
145   size_t size = 0;
146   bool is_signed = false;
147   std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
148 
149   union {
150     llvm::support::little64_t I;
151     llvm::support::ulittle64_t U;
152   } Value;
153 
154   std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
155   buffer->SetByteSize(size);
156 
157   llvm::ArrayRef<uint8_t> bytes;
158   if (is_signed) {
159     Value.I = constant.getSExtValue();
160   } else {
161     Value.U = constant.getZExtValue();
162   }
163 
164   bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
165               .take_front(size);
166   buffer->CopyData(bytes.data(), size);
167   DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
168   DWARFExpression result(nullptr, extractor, nullptr, 0, size);
169   return result;
170 }
171