DWARFLocationExpression.cpp revision 360660
1//===-- DWARFLocationExpression.cpp -----------------------------*- C++ -*-===//
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/Core/StreamBuffer.h"
14#include "lldb/Expression/DWARFExpression.h"
15#include "lldb/Utility/ArchSpec.h"
16#include "lldb/Utility/DataBufferHeap.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
28using namespace lldb;
29using namespace lldb_private;
30using namespace lldb_private::npdb;
31using namespace llvm::codeview;
32using namespace llvm::pdb;
33
34uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
35  if (register_id == llvm::codeview::RegisterId::VFRAME)
36    return LLDB_REGNUM_GENERIC_FP;
37
38  return LLDB_INVALID_REGNUM;
39}
40
41static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
42                                  llvm::codeview::RegisterId register_id,
43                                  RegisterKind &register_kind) {
44  register_kind = eRegisterKindLLDB;
45  uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
46  if (reg_num != LLDB_INVALID_REGNUM)
47    return reg_num;
48
49  register_kind = eRegisterKindGeneric;
50  return GetGenericRegisterNumber(register_id);
51}
52
53static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
54  switch (kind) {
55  case SimpleTypeKind::Int128:
56  case SimpleTypeKind::Int64:
57  case SimpleTypeKind::Int64Quad:
58  case SimpleTypeKind::Int32:
59  case SimpleTypeKind::Int32Long:
60  case SimpleTypeKind::Int16:
61  case SimpleTypeKind::Int16Short:
62  case SimpleTypeKind::Float128:
63  case SimpleTypeKind::Float80:
64  case SimpleTypeKind::Float64:
65  case SimpleTypeKind::Float32:
66  case SimpleTypeKind::Float16:
67  case SimpleTypeKind::NarrowCharacter:
68  case SimpleTypeKind::SignedCharacter:
69  case SimpleTypeKind::SByte:
70    return true;
71  default:
72    return false;
73  }
74}
75
76static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
77                                                   TpiStream &tpi) {
78  if (ti.isSimple()) {
79    SimpleTypeKind stk = ti.getSimpleKind();
80    return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
81  }
82
83  CVType cvt = tpi.getType(ti);
84  switch (cvt.kind()) {
85  case LF_MODIFIER: {
86    ModifierRecord mfr;
87    llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
88    return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
89  }
90  case LF_POINTER: {
91    PointerRecord pr;
92    llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
93    return GetIntegralTypeInfo(pr.ReferentType, tpi);
94  }
95  case LF_ENUM: {
96    EnumRecord er;
97    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
98    return GetIntegralTypeInfo(er.UnderlyingType, tpi);
99  }
100  default:
101    assert(false && "Type is not integral!");
102    return {0, false};
103  }
104}
105
106template <typename StreamWriter>
107static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
108                                                      StreamWriter &&writer) {
109  const ArchSpec &architecture = module->GetArchitecture();
110  ByteOrder byte_order = architecture.GetByteOrder();
111  uint32_t address_size = architecture.GetAddressByteSize();
112  uint32_t byte_size = architecture.GetDataByteSize();
113  if (byte_order == eByteOrderInvalid || address_size == 0)
114    return DWARFExpression();
115
116  RegisterKind register_kind = eRegisterKindDWARF;
117  StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
118
119  if (!writer(stream, register_kind))
120    return DWARFExpression();
121
122  DataBufferSP buffer =
123      std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
124  DataExtractor extractor(buffer, byte_order, address_size, byte_size);
125  DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize());
126  result.SetRegisterKind(register_kind);
127
128  return result;
129}
130
131static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
132    llvm::codeview::RegisterId reg, llvm::Optional<int32_t> relative_offset,
133    lldb::ModuleSP module) {
134  return MakeLocationExpressionInternal(
135      module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
136        uint32_t reg_num = GetRegisterNumber(
137            module->GetArchitecture().GetMachine(), reg, register_kind);
138        if (reg_num == LLDB_INVALID_REGNUM)
139          return false;
140
141        if (reg_num > 31) {
142          llvm::dwarf::LocationAtom base = relative_offset
143                                               ? llvm::dwarf::DW_OP_bregx
144                                               : llvm::dwarf::DW_OP_regx;
145          stream.PutHex8(base);
146          stream.PutULEB128(reg_num);
147        } else {
148          llvm::dwarf::LocationAtom base = relative_offset
149                                               ? llvm::dwarf::DW_OP_breg0
150                                               : llvm::dwarf::DW_OP_reg0;
151          stream.PutHex8(base + reg_num);
152        }
153
154        if (relative_offset)
155          stream.PutSLEB128(*relative_offset);
156
157        return true;
158      });
159}
160
161DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
162    llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
163  return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module);
164}
165
166DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
167    llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
168  return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
169}
170
171static bool EmitVFrameEvaluationDWARFExpression(
172    llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
173  // VFrame value always stored in $TO pseudo-register
174  return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
175                                              stream);
176}
177
178DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
179    llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
180  return MakeLocationExpressionInternal(
181      module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
182        const ArchSpec &architecture = module->GetArchitecture();
183
184        if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
185                                                 stream))
186          return false;
187
188        stream.PutHex8(llvm::dwarf::DW_OP_consts);
189        stream.PutSLEB128(offset);
190        stream.PutHex8(llvm::dwarf::DW_OP_plus);
191
192        register_kind = eRegisterKindLLDB;
193
194        return true;
195      });
196}
197
198DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
199    uint16_t section, uint32_t offset, ModuleSP module) {
200  assert(section > 0);
201  assert(module);
202
203  return MakeLocationExpressionInternal(
204      module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
205        stream.PutHex8(llvm::dwarf::DW_OP_addr);
206
207        SectionList *section_list = module->GetSectionList();
208        assert(section_list);
209
210        auto section_ptr = section_list->FindSectionByID(section);
211        if (!section_ptr)
212          return false;
213
214        stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
215                           stream.GetAddressByteSize(), stream.GetByteOrder());
216
217        return true;
218      });
219}
220
221DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
222    TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
223    ModuleSP module) {
224  const ArchSpec &architecture = module->GetArchitecture();
225  uint32_t address_size = architecture.GetAddressByteSize();
226
227  size_t size = 0;
228  bool is_signed = false;
229  std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
230
231  union {
232    llvm::support::little64_t I;
233    llvm::support::ulittle64_t U;
234  } Value;
235
236  std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
237  buffer->SetByteSize(size);
238
239  llvm::ArrayRef<uint8_t> bytes;
240  if (is_signed) {
241    Value.I = constant.getSExtValue();
242  } else {
243    Value.U = constant.getZExtValue();
244  }
245
246  bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
247              .take_front(size);
248  buffer->CopyData(bytes.data(), size);
249  DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
250  DWARFExpression result(nullptr, extractor, nullptr, 0, size);
251  return result;
252}
253