xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick #include "PECallFrameInfo.h"
2061da546Spatrick 
3061da546Spatrick #include "ObjectFilePECOFF.h"
4061da546Spatrick 
5061da546Spatrick #include "Plugins/Process/Utility/lldb-x86-register-enums.h"
6061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
7061da546Spatrick #include "llvm/Support/Win64EH.h"
8061da546Spatrick 
9061da546Spatrick using namespace lldb;
10061da546Spatrick using namespace lldb_private;
11061da546Spatrick using namespace llvm::Win64EH;
12061da546Spatrick 
13061da546Spatrick template <typename T>
TypedRead(const DataExtractor & data_extractor,offset_t & offset,offset_t size=sizeof (T))14061da546Spatrick static const T *TypedRead(const DataExtractor &data_extractor, offset_t &offset,
15061da546Spatrick                           offset_t size = sizeof(T)) {
16061da546Spatrick   return static_cast<const T *>(data_extractor.GetData(&offset, size));
17061da546Spatrick }
18061da546Spatrick 
19061da546Spatrick struct EHInstruction {
20061da546Spatrick   enum class Type {
21061da546Spatrick     PUSH_REGISTER,
22061da546Spatrick     ALLOCATE,
23061da546Spatrick     SET_FRAME_POINTER_REGISTER,
24061da546Spatrick     SAVE_REGISTER
25061da546Spatrick   };
26061da546Spatrick 
27061da546Spatrick   uint8_t offset;
28061da546Spatrick   Type type;
29061da546Spatrick   uint32_t reg;
30061da546Spatrick   uint32_t frame_offset;
31061da546Spatrick };
32061da546Spatrick 
33061da546Spatrick using EHProgram = std::vector<EHInstruction>;
34061da546Spatrick 
35061da546Spatrick class UnwindCodesIterator {
36061da546Spatrick public:
37061da546Spatrick   UnwindCodesIterator(ObjectFilePECOFF &object_file, uint32_t unwind_info_rva);
38061da546Spatrick 
39061da546Spatrick   bool GetNext();
IsError() const40061da546Spatrick   bool IsError() const { return m_error; }
41061da546Spatrick 
GetUnwindInfo() const42061da546Spatrick   const UnwindInfo *GetUnwindInfo() const { return m_unwind_info; }
GetUnwindCode() const43061da546Spatrick   const UnwindCode *GetUnwindCode() const { return m_unwind_code; }
IsChained() const44061da546Spatrick   bool IsChained() const { return m_chained; }
45061da546Spatrick 
46061da546Spatrick private:
47061da546Spatrick   ObjectFilePECOFF &m_object_file;
48061da546Spatrick 
49*f6aab3d8Srobert   bool m_error = false;
50061da546Spatrick 
51061da546Spatrick   uint32_t m_unwind_info_rva;
52061da546Spatrick   DataExtractor m_unwind_info_data;
53*f6aab3d8Srobert   const UnwindInfo *m_unwind_info = nullptr;
54061da546Spatrick 
55061da546Spatrick   DataExtractor m_unwind_code_data;
56061da546Spatrick   offset_t m_unwind_code_offset;
57*f6aab3d8Srobert   const UnwindCode *m_unwind_code = nullptr;
58061da546Spatrick 
59*f6aab3d8Srobert   bool m_chained = false;
60061da546Spatrick };
61061da546Spatrick 
UnwindCodesIterator(ObjectFilePECOFF & object_file,uint32_t unwind_info_rva)62061da546Spatrick UnwindCodesIterator::UnwindCodesIterator(ObjectFilePECOFF &object_file,
63061da546Spatrick                                          uint32_t unwind_info_rva)
64*f6aab3d8Srobert     : m_object_file(object_file),
65*f6aab3d8Srobert       m_unwind_info_rva(unwind_info_rva), m_unwind_code_offset{} {}
66061da546Spatrick 
GetNext()67061da546Spatrick bool UnwindCodesIterator::GetNext() {
68061da546Spatrick   static constexpr int UNWIND_INFO_SIZE = 4;
69061da546Spatrick 
70061da546Spatrick   m_error = false;
71061da546Spatrick   m_unwind_code = nullptr;
72061da546Spatrick   while (!m_unwind_code) {
73061da546Spatrick     if (!m_unwind_info) {
74061da546Spatrick       m_unwind_info_data =
75061da546Spatrick           m_object_file.ReadImageDataByRVA(m_unwind_info_rva, UNWIND_INFO_SIZE);
76061da546Spatrick 
77061da546Spatrick       offset_t offset = 0;
78061da546Spatrick       m_unwind_info =
79061da546Spatrick           TypedRead<UnwindInfo>(m_unwind_info_data, offset, UNWIND_INFO_SIZE);
80061da546Spatrick       if (!m_unwind_info) {
81061da546Spatrick         m_error = true;
82061da546Spatrick         break;
83061da546Spatrick       }
84061da546Spatrick 
85061da546Spatrick       m_unwind_code_data = m_object_file.ReadImageDataByRVA(
86061da546Spatrick           m_unwind_info_rva + UNWIND_INFO_SIZE,
87061da546Spatrick           m_unwind_info->NumCodes * sizeof(UnwindCode));
88061da546Spatrick       m_unwind_code_offset = 0;
89061da546Spatrick     }
90061da546Spatrick 
91061da546Spatrick     if (m_unwind_code_offset < m_unwind_code_data.GetByteSize()) {
92061da546Spatrick       m_unwind_code =
93061da546Spatrick           TypedRead<UnwindCode>(m_unwind_code_data, m_unwind_code_offset);
94061da546Spatrick       m_error = !m_unwind_code;
95061da546Spatrick       break;
96061da546Spatrick     }
97061da546Spatrick 
98061da546Spatrick     if (!(m_unwind_info->getFlags() & UNW_ChainInfo))
99061da546Spatrick       break;
100061da546Spatrick 
101061da546Spatrick     uint32_t runtime_function_rva =
102061da546Spatrick         m_unwind_info_rva + UNWIND_INFO_SIZE +
103061da546Spatrick         ((m_unwind_info->NumCodes + 1) & ~1) * sizeof(UnwindCode);
104061da546Spatrick     DataExtractor runtime_function_data = m_object_file.ReadImageDataByRVA(
105061da546Spatrick         runtime_function_rva, sizeof(RuntimeFunction));
106061da546Spatrick 
107061da546Spatrick     offset_t offset = 0;
108061da546Spatrick     const auto *runtime_function =
109061da546Spatrick         TypedRead<RuntimeFunction>(runtime_function_data, offset);
110061da546Spatrick     if (!runtime_function) {
111061da546Spatrick       m_error = true;
112061da546Spatrick       break;
113061da546Spatrick     }
114061da546Spatrick 
115061da546Spatrick     m_unwind_info_rva = runtime_function->UnwindInfoOffset;
116061da546Spatrick     m_unwind_info = nullptr;
117061da546Spatrick     m_chained = true;
118061da546Spatrick   }
119061da546Spatrick 
120061da546Spatrick   return !!m_unwind_code;
121061da546Spatrick }
122061da546Spatrick 
123061da546Spatrick class EHProgramBuilder {
124061da546Spatrick public:
125061da546Spatrick   EHProgramBuilder(ObjectFilePECOFF &object_file, uint32_t unwind_info_rva);
126061da546Spatrick 
127061da546Spatrick   bool Build();
128061da546Spatrick 
GetProgram() const129061da546Spatrick   const EHProgram &GetProgram() const { return m_program; }
130061da546Spatrick 
131061da546Spatrick private:
132061da546Spatrick   static uint32_t ConvertMachineToLLDBRegister(uint8_t machine_reg);
133061da546Spatrick   static uint32_t ConvertXMMToLLDBRegister(uint8_t xmm_reg);
134061da546Spatrick 
135061da546Spatrick   bool ProcessUnwindCode(UnwindCode code);
136061da546Spatrick   void Finalize();
137061da546Spatrick 
138061da546Spatrick   bool ParseBigOrScaledFrameOffset(uint32_t &result, bool big, uint32_t scale);
139061da546Spatrick   bool ParseBigFrameOffset(uint32_t &result);
140061da546Spatrick   bool ParseFrameOffset(uint32_t &result);
141061da546Spatrick 
142061da546Spatrick   UnwindCodesIterator m_iterator;
143061da546Spatrick   EHProgram m_program;
144061da546Spatrick };
145061da546Spatrick 
EHProgramBuilder(ObjectFilePECOFF & object_file,uint32_t unwind_info_rva)146061da546Spatrick EHProgramBuilder::EHProgramBuilder(ObjectFilePECOFF &object_file,
147061da546Spatrick                                    uint32_t unwind_info_rva)
148061da546Spatrick     : m_iterator(object_file, unwind_info_rva) {}
149061da546Spatrick 
Build()150061da546Spatrick bool EHProgramBuilder::Build() {
151061da546Spatrick   while (m_iterator.GetNext())
152061da546Spatrick     if (!ProcessUnwindCode(*m_iterator.GetUnwindCode()))
153061da546Spatrick       return false;
154061da546Spatrick 
155061da546Spatrick   if (m_iterator.IsError())
156061da546Spatrick     return false;
157061da546Spatrick 
158061da546Spatrick   Finalize();
159061da546Spatrick 
160061da546Spatrick   return true;
161061da546Spatrick }
162061da546Spatrick 
ConvertMachineToLLDBRegister(uint8_t machine_reg)163061da546Spatrick uint32_t EHProgramBuilder::ConvertMachineToLLDBRegister(uint8_t machine_reg) {
164061da546Spatrick   static uint32_t machine_to_lldb_register[] = {
165061da546Spatrick       lldb_rax_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, lldb_rbx_x86_64,
166061da546Spatrick       lldb_rsp_x86_64, lldb_rbp_x86_64, lldb_rsi_x86_64, lldb_rdi_x86_64,
167061da546Spatrick       lldb_r8_x86_64,  lldb_r9_x86_64,  lldb_r10_x86_64, lldb_r11_x86_64,
168061da546Spatrick       lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64};
169061da546Spatrick 
170*f6aab3d8Srobert   if (machine_reg >= std::size(machine_to_lldb_register))
171061da546Spatrick     return LLDB_INVALID_REGNUM;
172061da546Spatrick 
173061da546Spatrick   return machine_to_lldb_register[machine_reg];
174061da546Spatrick }
175061da546Spatrick 
ConvertXMMToLLDBRegister(uint8_t xmm_reg)176061da546Spatrick uint32_t EHProgramBuilder::ConvertXMMToLLDBRegister(uint8_t xmm_reg) {
177061da546Spatrick   static uint32_t xmm_to_lldb_register[] = {
178061da546Spatrick       lldb_xmm0_x86_64,  lldb_xmm1_x86_64,  lldb_xmm2_x86_64,
179061da546Spatrick       lldb_xmm3_x86_64,  lldb_xmm4_x86_64,  lldb_xmm5_x86_64,
180061da546Spatrick       lldb_xmm6_x86_64,  lldb_xmm7_x86_64,  lldb_xmm8_x86_64,
181061da546Spatrick       lldb_xmm9_x86_64,  lldb_xmm10_x86_64, lldb_xmm11_x86_64,
182061da546Spatrick       lldb_xmm12_x86_64, lldb_xmm13_x86_64, lldb_xmm14_x86_64,
183061da546Spatrick       lldb_xmm15_x86_64};
184061da546Spatrick 
185*f6aab3d8Srobert   if (xmm_reg >= std::size(xmm_to_lldb_register))
186061da546Spatrick     return LLDB_INVALID_REGNUM;
187061da546Spatrick 
188061da546Spatrick   return xmm_to_lldb_register[xmm_reg];
189061da546Spatrick }
190061da546Spatrick 
ProcessUnwindCode(UnwindCode code)191061da546Spatrick bool EHProgramBuilder::ProcessUnwindCode(UnwindCode code) {
192061da546Spatrick   uint8_t o = m_iterator.IsChained() ? 0 : code.u.CodeOffset;
193061da546Spatrick   uint8_t unwind_operation = code.getUnwindOp();
194061da546Spatrick   uint8_t operation_info = code.getOpInfo();
195061da546Spatrick 
196061da546Spatrick   switch (unwind_operation) {
197061da546Spatrick   case UOP_PushNonVol: {
198061da546Spatrick     uint32_t r = ConvertMachineToLLDBRegister(operation_info);
199061da546Spatrick     if (r == LLDB_INVALID_REGNUM)
200061da546Spatrick       return false;
201061da546Spatrick 
202061da546Spatrick     m_program.emplace_back(
203061da546Spatrick         EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, r, 8});
204061da546Spatrick 
205061da546Spatrick     return true;
206061da546Spatrick   }
207061da546Spatrick   case UOP_AllocLarge: {
208061da546Spatrick     uint32_t fo;
209061da546Spatrick     if (!ParseBigOrScaledFrameOffset(fo, operation_info, 8))
210061da546Spatrick       return false;
211061da546Spatrick 
212061da546Spatrick     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::ALLOCATE,
213061da546Spatrick                                          LLDB_INVALID_REGNUM, fo});
214061da546Spatrick 
215061da546Spatrick     return true;
216061da546Spatrick   }
217061da546Spatrick   case UOP_AllocSmall: {
218061da546Spatrick     m_program.emplace_back(
219061da546Spatrick         EHInstruction{o, EHInstruction::Type::ALLOCATE, LLDB_INVALID_REGNUM,
220061da546Spatrick                       static_cast<uint32_t>(operation_info) * 8 + 8});
221061da546Spatrick     return true;
222061da546Spatrick   }
223061da546Spatrick   case UOP_SetFPReg: {
224061da546Spatrick     uint32_t fpr = LLDB_INVALID_REGNUM;
225061da546Spatrick     if (m_iterator.GetUnwindInfo()->getFrameRegister())
226061da546Spatrick       fpr = ConvertMachineToLLDBRegister(
227061da546Spatrick           m_iterator.GetUnwindInfo()->getFrameRegister());
228061da546Spatrick     if (fpr == LLDB_INVALID_REGNUM)
229061da546Spatrick       return false;
230061da546Spatrick 
231061da546Spatrick     uint32_t fpro =
232061da546Spatrick         static_cast<uint32_t>(m_iterator.GetUnwindInfo()->getFrameOffset()) *
233061da546Spatrick         16;
234061da546Spatrick 
235061da546Spatrick     m_program.emplace_back(EHInstruction{
236061da546Spatrick         o, EHInstruction::Type::SET_FRAME_POINTER_REGISTER, fpr, fpro});
237061da546Spatrick 
238061da546Spatrick     return true;
239061da546Spatrick   }
240061da546Spatrick   case UOP_SaveNonVol:
241061da546Spatrick   case UOP_SaveNonVolBig: {
242061da546Spatrick     uint32_t r = ConvertMachineToLLDBRegister(operation_info);
243061da546Spatrick     if (r == LLDB_INVALID_REGNUM)
244061da546Spatrick       return false;
245061da546Spatrick 
246061da546Spatrick     uint32_t fo;
247061da546Spatrick     if (!ParseBigOrScaledFrameOffset(fo, unwind_operation == UOP_SaveNonVolBig,
248061da546Spatrick                                      8))
249061da546Spatrick       return false;
250061da546Spatrick 
251061da546Spatrick     m_program.emplace_back(
252061da546Spatrick         EHInstruction{o, EHInstruction::Type::SAVE_REGISTER, r, fo});
253061da546Spatrick 
254061da546Spatrick     return true;
255061da546Spatrick   }
256061da546Spatrick   case UOP_Epilog: {
257061da546Spatrick     return m_iterator.GetNext();
258061da546Spatrick   }
259061da546Spatrick   case UOP_SpareCode: {
260061da546Spatrick     // ReSharper disable once CppIdenticalOperandsInBinaryExpression
261061da546Spatrick     return m_iterator.GetNext() && m_iterator.GetNext();
262061da546Spatrick   }
263061da546Spatrick   case UOP_SaveXMM128:
264061da546Spatrick   case UOP_SaveXMM128Big: {
265061da546Spatrick     uint32_t r = ConvertXMMToLLDBRegister(operation_info);
266061da546Spatrick     if (r == LLDB_INVALID_REGNUM)
267061da546Spatrick       return false;
268061da546Spatrick 
269061da546Spatrick     uint32_t fo;
270061da546Spatrick     if (!ParseBigOrScaledFrameOffset(fo, unwind_operation == UOP_SaveXMM128Big,
271061da546Spatrick                                      16))
272061da546Spatrick       return false;
273061da546Spatrick 
274061da546Spatrick     m_program.emplace_back(
275061da546Spatrick         EHInstruction{o, EHInstruction::Type::SAVE_REGISTER, r, fo});
276061da546Spatrick 
277061da546Spatrick     return true;
278061da546Spatrick   }
279061da546Spatrick   case UOP_PushMachFrame: {
280061da546Spatrick     if (operation_info)
281061da546Spatrick       m_program.emplace_back(EHInstruction{o, EHInstruction::Type::ALLOCATE,
282061da546Spatrick                                            LLDB_INVALID_REGNUM, 8});
283061da546Spatrick     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
284061da546Spatrick                                          lldb_rip_x86_64, 8});
285061da546Spatrick     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
286061da546Spatrick                                          lldb_cs_x86_64, 8});
287061da546Spatrick     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
288061da546Spatrick                                          lldb_rflags_x86_64, 8});
289061da546Spatrick     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
290061da546Spatrick                                          lldb_rsp_x86_64, 8});
291061da546Spatrick     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
292061da546Spatrick                                          lldb_ss_x86_64, 8});
293061da546Spatrick 
294061da546Spatrick     return true;
295061da546Spatrick   }
296061da546Spatrick   default:
297061da546Spatrick     return false;
298061da546Spatrick   }
299061da546Spatrick }
300061da546Spatrick 
Finalize()301061da546Spatrick void EHProgramBuilder::Finalize() {
302061da546Spatrick   for (const EHInstruction &i : m_program)
303061da546Spatrick     if (i.reg == lldb_rip_x86_64)
304061da546Spatrick       return;
305061da546Spatrick 
306061da546Spatrick   m_program.emplace_back(
307061da546Spatrick       EHInstruction{0, EHInstruction::Type::PUSH_REGISTER, lldb_rip_x86_64, 8});
308061da546Spatrick }
309061da546Spatrick 
ParseBigOrScaledFrameOffset(uint32_t & result,bool big,uint32_t scale)310061da546Spatrick bool EHProgramBuilder::ParseBigOrScaledFrameOffset(uint32_t &result, bool big,
311061da546Spatrick                                                    uint32_t scale) {
312061da546Spatrick   if (big) {
313061da546Spatrick     if (!ParseBigFrameOffset(result))
314061da546Spatrick       return false;
315061da546Spatrick   } else {
316061da546Spatrick     if (!ParseFrameOffset(result))
317061da546Spatrick       return false;
318061da546Spatrick 
319061da546Spatrick     result *= scale;
320061da546Spatrick   }
321061da546Spatrick 
322061da546Spatrick   return true;
323061da546Spatrick }
324061da546Spatrick 
ParseBigFrameOffset(uint32_t & result)325061da546Spatrick bool EHProgramBuilder::ParseBigFrameOffset(uint32_t &result) {
326061da546Spatrick   if (!m_iterator.GetNext())
327061da546Spatrick     return false;
328061da546Spatrick 
329061da546Spatrick   result = m_iterator.GetUnwindCode()->FrameOffset;
330061da546Spatrick 
331061da546Spatrick   if (!m_iterator.GetNext())
332061da546Spatrick     return false;
333061da546Spatrick 
334061da546Spatrick   result += static_cast<uint32_t>(m_iterator.GetUnwindCode()->FrameOffset)
335061da546Spatrick             << 16;
336061da546Spatrick 
337061da546Spatrick   return true;
338061da546Spatrick }
339061da546Spatrick 
ParseFrameOffset(uint32_t & result)340061da546Spatrick bool EHProgramBuilder::ParseFrameOffset(uint32_t &result) {
341061da546Spatrick   if (!m_iterator.GetNext())
342061da546Spatrick     return false;
343061da546Spatrick 
344061da546Spatrick   result = m_iterator.GetUnwindCode()->FrameOffset;
345061da546Spatrick 
346061da546Spatrick   return true;
347061da546Spatrick }
348061da546Spatrick 
349061da546Spatrick class EHProgramRange {
350061da546Spatrick public:
351061da546Spatrick   EHProgramRange(EHProgram::const_iterator begin,
352061da546Spatrick                  EHProgram::const_iterator end);
353061da546Spatrick 
354061da546Spatrick   std::unique_ptr<UnwindPlan::Row> BuildUnwindPlanRow() const;
355061da546Spatrick 
356061da546Spatrick private:
357061da546Spatrick   int32_t GetCFAFrameOffset() const;
358061da546Spatrick 
359061da546Spatrick   EHProgram::const_iterator m_begin;
360061da546Spatrick   EHProgram::const_iterator m_end;
361061da546Spatrick };
362061da546Spatrick 
EHProgramRange(EHProgram::const_iterator begin,EHProgram::const_iterator end)363061da546Spatrick EHProgramRange::EHProgramRange(EHProgram::const_iterator begin,
364061da546Spatrick                                EHProgram::const_iterator end)
365061da546Spatrick     : m_begin(begin), m_end(end) {}
366061da546Spatrick 
BuildUnwindPlanRow() const367061da546Spatrick std::unique_ptr<UnwindPlan::Row> EHProgramRange::BuildUnwindPlanRow() const {
368061da546Spatrick   std::unique_ptr<UnwindPlan::Row> row = std::make_unique<UnwindPlan::Row>();
369061da546Spatrick 
370061da546Spatrick   if (m_begin != m_end)
371061da546Spatrick     row->SetOffset(m_begin->offset);
372061da546Spatrick 
373061da546Spatrick   int32_t cfa_frame_offset = GetCFAFrameOffset();
374061da546Spatrick 
375061da546Spatrick   bool frame_pointer_found = false;
376061da546Spatrick   for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) {
377061da546Spatrick     switch (it->type) {
378061da546Spatrick     case EHInstruction::Type::SET_FRAME_POINTER_REGISTER:
379061da546Spatrick       row->GetCFAValue().SetIsRegisterPlusOffset(it->reg, cfa_frame_offset -
380061da546Spatrick                                                               it->frame_offset);
381061da546Spatrick       frame_pointer_found = true;
382061da546Spatrick       break;
383061da546Spatrick     default:
384061da546Spatrick       break;
385061da546Spatrick     }
386061da546Spatrick     if (frame_pointer_found)
387061da546Spatrick       break;
388061da546Spatrick   }
389061da546Spatrick   if (!frame_pointer_found)
390061da546Spatrick     row->GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64,
391061da546Spatrick                                                cfa_frame_offset);
392061da546Spatrick 
393061da546Spatrick   int32_t rsp_frame_offset = 0;
394061da546Spatrick   for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) {
395061da546Spatrick     switch (it->type) {
396061da546Spatrick     case EHInstruction::Type::PUSH_REGISTER:
397061da546Spatrick       row->SetRegisterLocationToAtCFAPlusOffset(
398061da546Spatrick           it->reg, rsp_frame_offset - cfa_frame_offset, false);
399061da546Spatrick       rsp_frame_offset += it->frame_offset;
400061da546Spatrick       break;
401061da546Spatrick     case EHInstruction::Type::ALLOCATE:
402061da546Spatrick       rsp_frame_offset += it->frame_offset;
403061da546Spatrick       break;
404061da546Spatrick     case EHInstruction::Type::SAVE_REGISTER:
405061da546Spatrick       row->SetRegisterLocationToAtCFAPlusOffset(
406061da546Spatrick           it->reg, it->frame_offset - cfa_frame_offset, false);
407061da546Spatrick       break;
408061da546Spatrick     default:
409061da546Spatrick       break;
410061da546Spatrick     }
411061da546Spatrick   }
412061da546Spatrick 
413061da546Spatrick   row->SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, false);
414061da546Spatrick 
415061da546Spatrick   return row;
416061da546Spatrick }
417061da546Spatrick 
GetCFAFrameOffset() const418061da546Spatrick int32_t EHProgramRange::GetCFAFrameOffset() const {
419061da546Spatrick   int32_t result = 0;
420061da546Spatrick 
421061da546Spatrick   for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) {
422061da546Spatrick     switch (it->type) {
423061da546Spatrick     case EHInstruction::Type::PUSH_REGISTER:
424061da546Spatrick     case EHInstruction::Type::ALLOCATE:
425061da546Spatrick       result += it->frame_offset;
426061da546Spatrick       break;
427061da546Spatrick     default:
428061da546Spatrick       break;
429061da546Spatrick     }
430061da546Spatrick   }
431061da546Spatrick 
432061da546Spatrick   return result;
433061da546Spatrick }
434061da546Spatrick 
PECallFrameInfo(ObjectFilePECOFF & object_file,uint32_t exception_dir_rva,uint32_t exception_dir_size)435061da546Spatrick PECallFrameInfo::PECallFrameInfo(ObjectFilePECOFF &object_file,
436061da546Spatrick                                  uint32_t exception_dir_rva,
437061da546Spatrick                                  uint32_t exception_dir_size)
438061da546Spatrick     : m_object_file(object_file),
439061da546Spatrick       m_exception_dir(object_file.ReadImageDataByRVA(exception_dir_rva,
440061da546Spatrick                                                       exception_dir_size)) {}
441061da546Spatrick 
GetAddressRange(Address addr,AddressRange & range)442061da546Spatrick bool PECallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {
443061da546Spatrick   range.Clear();
444061da546Spatrick 
445061da546Spatrick   const RuntimeFunction *runtime_function =
446061da546Spatrick       FindRuntimeFunctionIntersectsWithRange(AddressRange(addr, 1));
447061da546Spatrick   if (!runtime_function)
448061da546Spatrick     return false;
449061da546Spatrick 
450061da546Spatrick   range.GetBaseAddress() =
451061da546Spatrick       m_object_file.GetAddress(runtime_function->StartAddress);
452061da546Spatrick   range.SetByteSize(runtime_function->EndAddress -
453061da546Spatrick                     runtime_function->StartAddress);
454061da546Spatrick 
455061da546Spatrick   return true;
456061da546Spatrick }
457061da546Spatrick 
GetUnwindPlan(const Address & addr,UnwindPlan & unwind_plan)458061da546Spatrick bool PECallFrameInfo::GetUnwindPlan(const Address &addr,
459061da546Spatrick                                     UnwindPlan &unwind_plan) {
460061da546Spatrick   return GetUnwindPlan(AddressRange(addr, 1), unwind_plan);
461061da546Spatrick }
462061da546Spatrick 
GetUnwindPlan(const AddressRange & range,UnwindPlan & unwind_plan)463061da546Spatrick bool PECallFrameInfo::GetUnwindPlan(const AddressRange &range,
464061da546Spatrick                                     UnwindPlan &unwind_plan) {
465061da546Spatrick   unwind_plan.Clear();
466061da546Spatrick 
467061da546Spatrick   unwind_plan.SetSourceName("PE EH info");
468061da546Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
469061da546Spatrick   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
470061da546Spatrick 
471061da546Spatrick   const RuntimeFunction *runtime_function =
472061da546Spatrick       FindRuntimeFunctionIntersectsWithRange(range);
473061da546Spatrick   if (!runtime_function)
474061da546Spatrick     return false;
475061da546Spatrick 
476061da546Spatrick   EHProgramBuilder builder(m_object_file, runtime_function->UnwindInfoOffset);
477061da546Spatrick   if (!builder.Build())
478061da546Spatrick     return false;
479061da546Spatrick 
480061da546Spatrick   std::vector<UnwindPlan::RowSP> rows;
481061da546Spatrick 
482061da546Spatrick   uint32_t last_offset = UINT32_MAX;
483061da546Spatrick   for (auto it = builder.GetProgram().begin(); it != builder.GetProgram().end();
484061da546Spatrick        ++it) {
485061da546Spatrick     if (it->offset == last_offset)
486061da546Spatrick       continue;
487061da546Spatrick 
488061da546Spatrick     EHProgramRange program_range =
489061da546Spatrick         EHProgramRange(it, builder.GetProgram().end());
490061da546Spatrick     rows.push_back(program_range.BuildUnwindPlanRow());
491061da546Spatrick 
492061da546Spatrick     last_offset = it->offset;
493061da546Spatrick   }
494061da546Spatrick 
495061da546Spatrick   for (auto it = rows.rbegin(); it != rows.rend(); ++it)
496061da546Spatrick     unwind_plan.AppendRow(*it);
497061da546Spatrick 
498061da546Spatrick   unwind_plan.SetPlanValidAddressRange(AddressRange(
499061da546Spatrick       m_object_file.GetAddress(runtime_function->StartAddress),
500061da546Spatrick       runtime_function->EndAddress - runtime_function->StartAddress));
501061da546Spatrick   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
502061da546Spatrick 
503061da546Spatrick   return true;
504061da546Spatrick }
505061da546Spatrick 
FindRuntimeFunctionIntersectsWithRange(const AddressRange & range) const506061da546Spatrick const RuntimeFunction *PECallFrameInfo::FindRuntimeFunctionIntersectsWithRange(
507061da546Spatrick     const AddressRange &range) const {
508061da546Spatrick   uint32_t rva = m_object_file.GetRVA(range.GetBaseAddress());
509061da546Spatrick   addr_t size = range.GetByteSize();
510061da546Spatrick 
511061da546Spatrick   uint32_t begin = 0;
512061da546Spatrick   uint32_t end = m_exception_dir.GetByteSize() / sizeof(RuntimeFunction);
513061da546Spatrick   while (begin < end) {
514061da546Spatrick     uint32_t curr = (begin + end) / 2;
515061da546Spatrick 
516061da546Spatrick     offset_t offset = curr * sizeof(RuntimeFunction);
517061da546Spatrick     const auto *runtime_function =
518061da546Spatrick         TypedRead<RuntimeFunction>(m_exception_dir, offset);
519061da546Spatrick     if (!runtime_function)
520061da546Spatrick       break;
521061da546Spatrick 
522061da546Spatrick     if (runtime_function->StartAddress < rva + size &&
523061da546Spatrick         runtime_function->EndAddress > rva)
524061da546Spatrick       return runtime_function;
525061da546Spatrick 
526061da546Spatrick     if (runtime_function->StartAddress >= rva + size)
527061da546Spatrick       end = curr;
528061da546Spatrick 
529061da546Spatrick     if (runtime_function->EndAddress <= rva)
530061da546Spatrick       begin = curr + 1;
531061da546Spatrick   }
532061da546Spatrick 
533061da546Spatrick   return nullptr;
534061da546Spatrick }
535