1//===-- PDBLocationToDWARFExpression.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 "PDBLocationToDWARFExpression.h"
10
11#include "lldb/Core/Section.h"
12#include "lldb/Core/dwarf.h"
13#include "lldb/Expression/DWARFExpression.h"
14#include "lldb/Symbol/Variable.h"
15#include "lldb/Utility/DataBufferHeap.h"
16#include "lldb/Utility/StreamBuffer.h"
17
18#include "llvm/DebugInfo/CodeView/CodeView.h"
19#include "llvm/DebugInfo/PDB/IPDBSession.h"
20#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
21
22#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
23#include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::npdb;
28using namespace lldb_private::dwarf;
29using namespace llvm::pdb;
30
31static std::unique_ptr<IPDBFrameData>
32GetCorrespondingFrameData(const IPDBSession &session,
33                          const Variable::RangeList &ranges) {
34  auto enumFrameData = session.getFrameData();
35  if (!enumFrameData)
36    return nullptr;
37
38  std::unique_ptr<IPDBFrameData> found;
39  while (auto fd = enumFrameData->getNext()) {
40    Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
41                                              fd->getLengthBlock());
42
43    for (size_t i = 0; i < ranges.GetSize(); i++) {
44      auto range = ranges.GetEntryAtIndex(i);
45      if (!range)
46        continue;
47
48      if (!range->DoesIntersect(fdRange))
49        continue;
50
51      found = std::move(fd);
52
53      break;
54    }
55  }
56
57  return found;
58}
59
60static bool EmitVFrameEvaluationDWARFExpression(
61    llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
62  // VFrame value always stored in $TO pseudo-register
63  return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
64                                              stream);
65}
66
67DWARFExpression ConvertPDBLocationToDWARFExpression(
68    ModuleSP module, const PDBSymbolData &symbol,
69    const Variable::RangeList &ranges, bool &is_constant) {
70  is_constant = true;
71
72  if (!module)
73    return DWARFExpression();
74
75  const ArchSpec &architecture = module->GetArchitecture();
76  llvm::Triple::ArchType arch_type = architecture.GetMachine();
77  ByteOrder byte_order = architecture.GetByteOrder();
78  uint32_t address_size = architecture.GetAddressByteSize();
79  uint32_t byte_size = architecture.GetDataByteSize();
80  if (byte_order == eByteOrderInvalid || address_size == 0)
81    return DWARFExpression();
82
83  RegisterKind register_kind = eRegisterKindDWARF;
84  StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
85  switch (symbol.getLocationType()) {
86  case PDB_LocType::Static:
87  case PDB_LocType::TLS: {
88    stream.PutHex8(DW_OP_addr);
89
90    SectionList *section_list = module->GetSectionList();
91    if (!section_list)
92      return DWARFExpression();
93
94    uint32_t section_id = symbol.getAddressSection();
95
96    auto section = section_list->FindSectionByID(section_id);
97    if (!section)
98      return DWARFExpression();
99
100    uint32_t offset = symbol.getAddressOffset();
101    stream.PutMaxHex64(section->GetFileAddress() + offset, address_size,
102                       byte_order);
103
104    is_constant = false;
105
106    break;
107  }
108  case PDB_LocType::RegRel: {
109    uint32_t reg_num;
110    auto reg_id = symbol.getRegisterId();
111    if (reg_id == llvm::codeview::RegisterId::VFRAME) {
112      if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
113        if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
114                                                stream)) {
115          int32_t offset = symbol.getOffset();
116          stream.PutHex8(DW_OP_consts);
117          stream.PutSLEB128(offset);
118          stream.PutHex8(DW_OP_plus);
119
120          register_kind = eRegisterKindLLDB;
121
122          is_constant = false;
123          break;
124        }
125      }
126
127      register_kind = eRegisterKindGeneric;
128      reg_num = LLDB_REGNUM_GENERIC_FP;
129    } else {
130      register_kind = eRegisterKindLLDB;
131      reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
132      if (reg_num == LLDB_INVALID_REGNUM)
133        return DWARFExpression();
134    }
135
136    if (reg_num > 31) {
137      stream.PutHex8(DW_OP_bregx);
138      stream.PutULEB128(reg_num);
139    } else
140      stream.PutHex8(DW_OP_breg0 + reg_num);
141
142    int32_t offset = symbol.getOffset();
143    stream.PutSLEB128(offset);
144
145    is_constant = false;
146
147    break;
148  }
149  case PDB_LocType::Enregistered: {
150    register_kind = eRegisterKindLLDB;
151    uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
152    if (reg_num == LLDB_INVALID_REGNUM)
153      return DWARFExpression();
154
155    if (reg_num > 31) {
156      stream.PutHex8(DW_OP_regx);
157      stream.PutULEB128(reg_num);
158    } else
159      stream.PutHex8(DW_OP_reg0 + reg_num);
160
161    is_constant = false;
162
163    break;
164  }
165  case PDB_LocType::Constant: {
166    Variant value = symbol.getValue();
167    stream.PutRawBytes(&value.Value, sizeof(value.Value),
168                       endian::InlHostByteOrder());
169    break;
170  }
171  default:
172    return DWARFExpression();
173  }
174
175  DataBufferSP buffer =
176      std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
177  DataExtractor extractor(buffer, byte_order, address_size, byte_size);
178  DWARFExpression result(extractor);
179  result.SetRegisterKind(register_kind);
180
181  return result;
182}
183