xref: /llvm-project/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp (revision 47b76631e76810bfc6d91d534dc1b095e8058ff4)
130c2441aSAleksandr Urakov #include "PECallFrameInfo.h"
230c2441aSAleksandr Urakov 
330c2441aSAleksandr Urakov #include "ObjectFilePECOFF.h"
430c2441aSAleksandr Urakov 
530c2441aSAleksandr Urakov #include "Plugins/Process/Utility/lldb-x86-register-enums.h"
630c2441aSAleksandr Urakov #include "lldb/Symbol/UnwindPlan.h"
730c2441aSAleksandr Urakov #include "llvm/Support/Win64EH.h"
830c2441aSAleksandr Urakov 
930c2441aSAleksandr Urakov using namespace lldb;
1030c2441aSAleksandr Urakov using namespace lldb_private;
1130c2441aSAleksandr Urakov using namespace llvm::Win64EH;
1230c2441aSAleksandr Urakov 
1330c2441aSAleksandr Urakov template <typename T>
TypedRead(const DataExtractor & data_extractor,offset_t & offset,offset_t size=sizeof (T))1430c2441aSAleksandr Urakov static const T *TypedRead(const DataExtractor &data_extractor, offset_t &offset,
1530c2441aSAleksandr Urakov                           offset_t size = sizeof(T)) {
1630c2441aSAleksandr Urakov   return static_cast<const T *>(data_extractor.GetData(&offset, size));
1730c2441aSAleksandr Urakov }
1830c2441aSAleksandr Urakov 
1930c2441aSAleksandr Urakov struct EHInstruction {
2030c2441aSAleksandr Urakov   enum class Type {
2130c2441aSAleksandr Urakov     PUSH_REGISTER,
2230c2441aSAleksandr Urakov     ALLOCATE,
2330c2441aSAleksandr Urakov     SET_FRAME_POINTER_REGISTER,
2430c2441aSAleksandr Urakov     SAVE_REGISTER
2530c2441aSAleksandr Urakov   };
2630c2441aSAleksandr Urakov 
2730c2441aSAleksandr Urakov   uint8_t offset;
2830c2441aSAleksandr Urakov   Type type;
2930c2441aSAleksandr Urakov   uint32_t reg;
3030c2441aSAleksandr Urakov   uint32_t frame_offset;
3130c2441aSAleksandr Urakov };
3230c2441aSAleksandr Urakov 
3330c2441aSAleksandr Urakov using EHProgram = std::vector<EHInstruction>;
3430c2441aSAleksandr Urakov 
3530c2441aSAleksandr Urakov class UnwindCodesIterator {
3630c2441aSAleksandr Urakov public:
3730c2441aSAleksandr Urakov   UnwindCodesIterator(ObjectFilePECOFF &object_file, uint32_t unwind_info_rva);
3830c2441aSAleksandr Urakov 
3930c2441aSAleksandr Urakov   bool GetNext();
IsError() const4030c2441aSAleksandr Urakov   bool IsError() const { return m_error; }
4130c2441aSAleksandr Urakov 
GetUnwindInfo() const4230c2441aSAleksandr Urakov   const UnwindInfo *GetUnwindInfo() const { return m_unwind_info; }
GetUnwindCode() const4330c2441aSAleksandr Urakov   const UnwindCode *GetUnwindCode() const { return m_unwind_code; }
IsChained() const4430c2441aSAleksandr Urakov   bool IsChained() const { return m_chained; }
4530c2441aSAleksandr Urakov 
4630c2441aSAleksandr Urakov private:
4730c2441aSAleksandr Urakov   ObjectFilePECOFF &m_object_file;
4830c2441aSAleksandr Urakov 
4928c878aeSShafik Yaghmour   bool m_error = false;
5030c2441aSAleksandr Urakov 
5130c2441aSAleksandr Urakov   uint32_t m_unwind_info_rva;
5230c2441aSAleksandr Urakov   DataExtractor m_unwind_info_data;
5328c878aeSShafik Yaghmour   const UnwindInfo *m_unwind_info = nullptr;
5430c2441aSAleksandr Urakov 
5530c2441aSAleksandr Urakov   DataExtractor m_unwind_code_data;
5630c2441aSAleksandr Urakov   offset_t m_unwind_code_offset;
5728c878aeSShafik Yaghmour   const UnwindCode *m_unwind_code = nullptr;
5830c2441aSAleksandr Urakov 
5928c878aeSShafik Yaghmour   bool m_chained = false;
6030c2441aSAleksandr Urakov };
6130c2441aSAleksandr Urakov 
UnwindCodesIterator(ObjectFilePECOFF & object_file,uint32_t unwind_info_rva)6230c2441aSAleksandr Urakov UnwindCodesIterator::UnwindCodesIterator(ObjectFilePECOFF &object_file,
6330c2441aSAleksandr Urakov                                          uint32_t unwind_info_rva)
6428c878aeSShafik Yaghmour     : m_object_file(object_file),
6528c878aeSShafik Yaghmour       m_unwind_info_rva(unwind_info_rva), m_unwind_code_offset{} {}
6630c2441aSAleksandr Urakov 
GetNext()6730c2441aSAleksandr Urakov bool UnwindCodesIterator::GetNext() {
6830c2441aSAleksandr Urakov   static constexpr int UNWIND_INFO_SIZE = 4;
6930c2441aSAleksandr Urakov 
7030c2441aSAleksandr Urakov   m_error = false;
7130c2441aSAleksandr Urakov   m_unwind_code = nullptr;
7230c2441aSAleksandr Urakov   while (!m_unwind_code) {
7330c2441aSAleksandr Urakov     if (!m_unwind_info) {
7430c2441aSAleksandr Urakov       m_unwind_info_data =
7530c2441aSAleksandr Urakov           m_object_file.ReadImageDataByRVA(m_unwind_info_rva, UNWIND_INFO_SIZE);
7630c2441aSAleksandr Urakov 
7730c2441aSAleksandr Urakov       offset_t offset = 0;
7830c2441aSAleksandr Urakov       m_unwind_info =
7930c2441aSAleksandr Urakov           TypedRead<UnwindInfo>(m_unwind_info_data, offset, UNWIND_INFO_SIZE);
8030c2441aSAleksandr Urakov       if (!m_unwind_info) {
8130c2441aSAleksandr Urakov         m_error = true;
8230c2441aSAleksandr Urakov         break;
8330c2441aSAleksandr Urakov       }
8430c2441aSAleksandr Urakov 
8530c2441aSAleksandr Urakov       m_unwind_code_data = m_object_file.ReadImageDataByRVA(
8630c2441aSAleksandr Urakov           m_unwind_info_rva + UNWIND_INFO_SIZE,
8730c2441aSAleksandr Urakov           m_unwind_info->NumCodes * sizeof(UnwindCode));
8830c2441aSAleksandr Urakov       m_unwind_code_offset = 0;
8930c2441aSAleksandr Urakov     }
9030c2441aSAleksandr Urakov 
9130c2441aSAleksandr Urakov     if (m_unwind_code_offset < m_unwind_code_data.GetByteSize()) {
9230c2441aSAleksandr Urakov       m_unwind_code =
9330c2441aSAleksandr Urakov           TypedRead<UnwindCode>(m_unwind_code_data, m_unwind_code_offset);
9430c2441aSAleksandr Urakov       m_error = !m_unwind_code;
9530c2441aSAleksandr Urakov       break;
9630c2441aSAleksandr Urakov     }
9730c2441aSAleksandr Urakov 
9830c2441aSAleksandr Urakov     if (!(m_unwind_info->getFlags() & UNW_ChainInfo))
9930c2441aSAleksandr Urakov       break;
10030c2441aSAleksandr Urakov 
10130c2441aSAleksandr Urakov     uint32_t runtime_function_rva =
10230c2441aSAleksandr Urakov         m_unwind_info_rva + UNWIND_INFO_SIZE +
10330c2441aSAleksandr Urakov         ((m_unwind_info->NumCodes + 1) & ~1) * sizeof(UnwindCode);
10430c2441aSAleksandr Urakov     DataExtractor runtime_function_data = m_object_file.ReadImageDataByRVA(
10530c2441aSAleksandr Urakov         runtime_function_rva, sizeof(RuntimeFunction));
10630c2441aSAleksandr Urakov 
10730c2441aSAleksandr Urakov     offset_t offset = 0;
10830c2441aSAleksandr Urakov     const auto *runtime_function =
10930c2441aSAleksandr Urakov         TypedRead<RuntimeFunction>(runtime_function_data, offset);
11030c2441aSAleksandr Urakov     if (!runtime_function) {
11130c2441aSAleksandr Urakov       m_error = true;
11230c2441aSAleksandr Urakov       break;
11330c2441aSAleksandr Urakov     }
11430c2441aSAleksandr Urakov 
11530c2441aSAleksandr Urakov     m_unwind_info_rva = runtime_function->UnwindInfoOffset;
11630c2441aSAleksandr Urakov     m_unwind_info = nullptr;
11730c2441aSAleksandr Urakov     m_chained = true;
11830c2441aSAleksandr Urakov   }
11930c2441aSAleksandr Urakov 
12030c2441aSAleksandr Urakov   return !!m_unwind_code;
12130c2441aSAleksandr Urakov }
12230c2441aSAleksandr Urakov 
12330c2441aSAleksandr Urakov class EHProgramBuilder {
12430c2441aSAleksandr Urakov public:
12530c2441aSAleksandr Urakov   EHProgramBuilder(ObjectFilePECOFF &object_file, uint32_t unwind_info_rva);
12630c2441aSAleksandr Urakov 
12730c2441aSAleksandr Urakov   bool Build();
12830c2441aSAleksandr Urakov 
GetProgram() const12930c2441aSAleksandr Urakov   const EHProgram &GetProgram() const { return m_program; }
13030c2441aSAleksandr Urakov 
13130c2441aSAleksandr Urakov private:
13230c2441aSAleksandr Urakov   static uint32_t ConvertMachineToLLDBRegister(uint8_t machine_reg);
13330c2441aSAleksandr Urakov   static uint32_t ConvertXMMToLLDBRegister(uint8_t xmm_reg);
13430c2441aSAleksandr Urakov 
13530c2441aSAleksandr Urakov   bool ProcessUnwindCode(UnwindCode code);
13630c2441aSAleksandr Urakov   void Finalize();
13730c2441aSAleksandr Urakov 
13830c2441aSAleksandr Urakov   bool ParseBigOrScaledFrameOffset(uint32_t &result, bool big, uint32_t scale);
13930c2441aSAleksandr Urakov   bool ParseBigFrameOffset(uint32_t &result);
14030c2441aSAleksandr Urakov   bool ParseFrameOffset(uint32_t &result);
14130c2441aSAleksandr Urakov 
14230c2441aSAleksandr Urakov   UnwindCodesIterator m_iterator;
14330c2441aSAleksandr Urakov   EHProgram m_program;
14430c2441aSAleksandr Urakov };
14530c2441aSAleksandr Urakov 
EHProgramBuilder(ObjectFilePECOFF & object_file,uint32_t unwind_info_rva)14630c2441aSAleksandr Urakov EHProgramBuilder::EHProgramBuilder(ObjectFilePECOFF &object_file,
14730c2441aSAleksandr Urakov                                    uint32_t unwind_info_rva)
14830c2441aSAleksandr Urakov     : m_iterator(object_file, unwind_info_rva) {}
14930c2441aSAleksandr Urakov 
Build()15030c2441aSAleksandr Urakov bool EHProgramBuilder::Build() {
15130c2441aSAleksandr Urakov   while (m_iterator.GetNext())
15230c2441aSAleksandr Urakov     if (!ProcessUnwindCode(*m_iterator.GetUnwindCode()))
15330c2441aSAleksandr Urakov       return false;
15430c2441aSAleksandr Urakov 
15530c2441aSAleksandr Urakov   if (m_iterator.IsError())
15630c2441aSAleksandr Urakov     return false;
15730c2441aSAleksandr Urakov 
15830c2441aSAleksandr Urakov   Finalize();
15930c2441aSAleksandr Urakov 
16030c2441aSAleksandr Urakov   return true;
16130c2441aSAleksandr Urakov }
16230c2441aSAleksandr Urakov 
ConvertMachineToLLDBRegister(uint8_t machine_reg)16330c2441aSAleksandr Urakov uint32_t EHProgramBuilder::ConvertMachineToLLDBRegister(uint8_t machine_reg) {
16430c2441aSAleksandr Urakov   static uint32_t machine_to_lldb_register[] = {
16530c2441aSAleksandr Urakov       lldb_rax_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, lldb_rbx_x86_64,
16630c2441aSAleksandr Urakov       lldb_rsp_x86_64, lldb_rbp_x86_64, lldb_rsi_x86_64, lldb_rdi_x86_64,
16730c2441aSAleksandr Urakov       lldb_r8_x86_64,  lldb_r9_x86_64,  lldb_r10_x86_64, lldb_r11_x86_64,
16830c2441aSAleksandr Urakov       lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64};
16930c2441aSAleksandr Urakov 
170*47b76631SJoe Loser   if (machine_reg >= std::size(machine_to_lldb_register))
17130c2441aSAleksandr Urakov     return LLDB_INVALID_REGNUM;
17230c2441aSAleksandr Urakov 
17330c2441aSAleksandr Urakov   return machine_to_lldb_register[machine_reg];
17430c2441aSAleksandr Urakov }
17530c2441aSAleksandr Urakov 
ConvertXMMToLLDBRegister(uint8_t xmm_reg)17630c2441aSAleksandr Urakov uint32_t EHProgramBuilder::ConvertXMMToLLDBRegister(uint8_t xmm_reg) {
17730c2441aSAleksandr Urakov   static uint32_t xmm_to_lldb_register[] = {
17830c2441aSAleksandr Urakov       lldb_xmm0_x86_64,  lldb_xmm1_x86_64,  lldb_xmm2_x86_64,
17930c2441aSAleksandr Urakov       lldb_xmm3_x86_64,  lldb_xmm4_x86_64,  lldb_xmm5_x86_64,
18030c2441aSAleksandr Urakov       lldb_xmm6_x86_64,  lldb_xmm7_x86_64,  lldb_xmm8_x86_64,
18130c2441aSAleksandr Urakov       lldb_xmm9_x86_64,  lldb_xmm10_x86_64, lldb_xmm11_x86_64,
18230c2441aSAleksandr Urakov       lldb_xmm12_x86_64, lldb_xmm13_x86_64, lldb_xmm14_x86_64,
18330c2441aSAleksandr Urakov       lldb_xmm15_x86_64};
18430c2441aSAleksandr Urakov 
185*47b76631SJoe Loser   if (xmm_reg >= std::size(xmm_to_lldb_register))
18630c2441aSAleksandr Urakov     return LLDB_INVALID_REGNUM;
18730c2441aSAleksandr Urakov 
18830c2441aSAleksandr Urakov   return xmm_to_lldb_register[xmm_reg];
18930c2441aSAleksandr Urakov }
19030c2441aSAleksandr Urakov 
ProcessUnwindCode(UnwindCode code)19130c2441aSAleksandr Urakov bool EHProgramBuilder::ProcessUnwindCode(UnwindCode code) {
19230c2441aSAleksandr Urakov   uint8_t o = m_iterator.IsChained() ? 0 : code.u.CodeOffset;
19330c2441aSAleksandr Urakov   uint8_t unwind_operation = code.getUnwindOp();
19430c2441aSAleksandr Urakov   uint8_t operation_info = code.getOpInfo();
19530c2441aSAleksandr Urakov 
19630c2441aSAleksandr Urakov   switch (unwind_operation) {
19730c2441aSAleksandr Urakov   case UOP_PushNonVol: {
19830c2441aSAleksandr Urakov     uint32_t r = ConvertMachineToLLDBRegister(operation_info);
19930c2441aSAleksandr Urakov     if (r == LLDB_INVALID_REGNUM)
20030c2441aSAleksandr Urakov       return false;
20130c2441aSAleksandr Urakov 
20230c2441aSAleksandr Urakov     m_program.emplace_back(
20330c2441aSAleksandr Urakov         EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, r, 8});
20430c2441aSAleksandr Urakov 
20530c2441aSAleksandr Urakov     return true;
20630c2441aSAleksandr Urakov   }
20730c2441aSAleksandr Urakov   case UOP_AllocLarge: {
20830c2441aSAleksandr Urakov     uint32_t fo;
20930c2441aSAleksandr Urakov     if (!ParseBigOrScaledFrameOffset(fo, operation_info, 8))
21030c2441aSAleksandr Urakov       return false;
21130c2441aSAleksandr Urakov 
21230c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::ALLOCATE,
21330c2441aSAleksandr Urakov                                          LLDB_INVALID_REGNUM, fo});
21430c2441aSAleksandr Urakov 
21530c2441aSAleksandr Urakov     return true;
21630c2441aSAleksandr Urakov   }
21730c2441aSAleksandr Urakov   case UOP_AllocSmall: {
21830c2441aSAleksandr Urakov     m_program.emplace_back(
21930c2441aSAleksandr Urakov         EHInstruction{o, EHInstruction::Type::ALLOCATE, LLDB_INVALID_REGNUM,
22030c2441aSAleksandr Urakov                       static_cast<uint32_t>(operation_info) * 8 + 8});
22130c2441aSAleksandr Urakov     return true;
22230c2441aSAleksandr Urakov   }
22330c2441aSAleksandr Urakov   case UOP_SetFPReg: {
22430c2441aSAleksandr Urakov     uint32_t fpr = LLDB_INVALID_REGNUM;
22530c2441aSAleksandr Urakov     if (m_iterator.GetUnwindInfo()->getFrameRegister())
22630c2441aSAleksandr Urakov       fpr = ConvertMachineToLLDBRegister(
22730c2441aSAleksandr Urakov           m_iterator.GetUnwindInfo()->getFrameRegister());
22830c2441aSAleksandr Urakov     if (fpr == LLDB_INVALID_REGNUM)
22930c2441aSAleksandr Urakov       return false;
23030c2441aSAleksandr Urakov 
23130c2441aSAleksandr Urakov     uint32_t fpro =
23230c2441aSAleksandr Urakov         static_cast<uint32_t>(m_iterator.GetUnwindInfo()->getFrameOffset()) *
23330c2441aSAleksandr Urakov         16;
23430c2441aSAleksandr Urakov 
23530c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{
23630c2441aSAleksandr Urakov         o, EHInstruction::Type::SET_FRAME_POINTER_REGISTER, fpr, fpro});
23730c2441aSAleksandr Urakov 
23830c2441aSAleksandr Urakov     return true;
23930c2441aSAleksandr Urakov   }
24030c2441aSAleksandr Urakov   case UOP_SaveNonVol:
24130c2441aSAleksandr Urakov   case UOP_SaveNonVolBig: {
24230c2441aSAleksandr Urakov     uint32_t r = ConvertMachineToLLDBRegister(operation_info);
24330c2441aSAleksandr Urakov     if (r == LLDB_INVALID_REGNUM)
24430c2441aSAleksandr Urakov       return false;
24530c2441aSAleksandr Urakov 
24630c2441aSAleksandr Urakov     uint32_t fo;
24730c2441aSAleksandr Urakov     if (!ParseBigOrScaledFrameOffset(fo, unwind_operation == UOP_SaveNonVolBig,
24830c2441aSAleksandr Urakov                                      8))
24930c2441aSAleksandr Urakov       return false;
25030c2441aSAleksandr Urakov 
25130c2441aSAleksandr Urakov     m_program.emplace_back(
25230c2441aSAleksandr Urakov         EHInstruction{o, EHInstruction::Type::SAVE_REGISTER, r, fo});
25330c2441aSAleksandr Urakov 
25430c2441aSAleksandr Urakov     return true;
25530c2441aSAleksandr Urakov   }
25630c2441aSAleksandr Urakov   case UOP_Epilog: {
25730c2441aSAleksandr Urakov     return m_iterator.GetNext();
25830c2441aSAleksandr Urakov   }
25930c2441aSAleksandr Urakov   case UOP_SpareCode: {
26030c2441aSAleksandr Urakov     // ReSharper disable once CppIdenticalOperandsInBinaryExpression
26130c2441aSAleksandr Urakov     return m_iterator.GetNext() && m_iterator.GetNext();
26230c2441aSAleksandr Urakov   }
26330c2441aSAleksandr Urakov   case UOP_SaveXMM128:
26430c2441aSAleksandr Urakov   case UOP_SaveXMM128Big: {
26530c2441aSAleksandr Urakov     uint32_t r = ConvertXMMToLLDBRegister(operation_info);
26630c2441aSAleksandr Urakov     if (r == LLDB_INVALID_REGNUM)
26730c2441aSAleksandr Urakov       return false;
26830c2441aSAleksandr Urakov 
26930c2441aSAleksandr Urakov     uint32_t fo;
27030c2441aSAleksandr Urakov     if (!ParseBigOrScaledFrameOffset(fo, unwind_operation == UOP_SaveXMM128Big,
27130c2441aSAleksandr Urakov                                      16))
27230c2441aSAleksandr Urakov       return false;
27330c2441aSAleksandr Urakov 
27430c2441aSAleksandr Urakov     m_program.emplace_back(
27530c2441aSAleksandr Urakov         EHInstruction{o, EHInstruction::Type::SAVE_REGISTER, r, fo});
27630c2441aSAleksandr Urakov 
27730c2441aSAleksandr Urakov     return true;
27830c2441aSAleksandr Urakov   }
27930c2441aSAleksandr Urakov   case UOP_PushMachFrame: {
28030c2441aSAleksandr Urakov     if (operation_info)
28130c2441aSAleksandr Urakov       m_program.emplace_back(EHInstruction{o, EHInstruction::Type::ALLOCATE,
28230c2441aSAleksandr Urakov                                            LLDB_INVALID_REGNUM, 8});
28330c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
28430c2441aSAleksandr Urakov                                          lldb_rip_x86_64, 8});
28530c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
28630c2441aSAleksandr Urakov                                          lldb_cs_x86_64, 8});
28730c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
28830c2441aSAleksandr Urakov                                          lldb_rflags_x86_64, 8});
28930c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
29030c2441aSAleksandr Urakov                                          lldb_rsp_x86_64, 8});
29130c2441aSAleksandr Urakov     m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER,
29230c2441aSAleksandr Urakov                                          lldb_ss_x86_64, 8});
29330c2441aSAleksandr Urakov 
29430c2441aSAleksandr Urakov     return true;
29530c2441aSAleksandr Urakov   }
29630c2441aSAleksandr Urakov   default:
29730c2441aSAleksandr Urakov     return false;
29830c2441aSAleksandr Urakov   }
29930c2441aSAleksandr Urakov }
30030c2441aSAleksandr Urakov 
Finalize()30130c2441aSAleksandr Urakov void EHProgramBuilder::Finalize() {
30230c2441aSAleksandr Urakov   for (const EHInstruction &i : m_program)
30330c2441aSAleksandr Urakov     if (i.reg == lldb_rip_x86_64)
30430c2441aSAleksandr Urakov       return;
30530c2441aSAleksandr Urakov 
30630c2441aSAleksandr Urakov   m_program.emplace_back(
30730c2441aSAleksandr Urakov       EHInstruction{0, EHInstruction::Type::PUSH_REGISTER, lldb_rip_x86_64, 8});
30830c2441aSAleksandr Urakov }
30930c2441aSAleksandr Urakov 
ParseBigOrScaledFrameOffset(uint32_t & result,bool big,uint32_t scale)31030c2441aSAleksandr Urakov bool EHProgramBuilder::ParseBigOrScaledFrameOffset(uint32_t &result, bool big,
31130c2441aSAleksandr Urakov                                                    uint32_t scale) {
31230c2441aSAleksandr Urakov   if (big) {
31330c2441aSAleksandr Urakov     if (!ParseBigFrameOffset(result))
31430c2441aSAleksandr Urakov       return false;
31530c2441aSAleksandr Urakov   } else {
31630c2441aSAleksandr Urakov     if (!ParseFrameOffset(result))
31730c2441aSAleksandr Urakov       return false;
31830c2441aSAleksandr Urakov 
31930c2441aSAleksandr Urakov     result *= scale;
32030c2441aSAleksandr Urakov   }
32130c2441aSAleksandr Urakov 
32230c2441aSAleksandr Urakov   return true;
32330c2441aSAleksandr Urakov }
32430c2441aSAleksandr Urakov 
ParseBigFrameOffset(uint32_t & result)32530c2441aSAleksandr Urakov bool EHProgramBuilder::ParseBigFrameOffset(uint32_t &result) {
32630c2441aSAleksandr Urakov   if (!m_iterator.GetNext())
32730c2441aSAleksandr Urakov     return false;
32830c2441aSAleksandr Urakov 
32930c2441aSAleksandr Urakov   result = m_iterator.GetUnwindCode()->FrameOffset;
33030c2441aSAleksandr Urakov 
33130c2441aSAleksandr Urakov   if (!m_iterator.GetNext())
33230c2441aSAleksandr Urakov     return false;
33330c2441aSAleksandr Urakov 
33430c2441aSAleksandr Urakov   result += static_cast<uint32_t>(m_iterator.GetUnwindCode()->FrameOffset)
33530c2441aSAleksandr Urakov             << 16;
33630c2441aSAleksandr Urakov 
33730c2441aSAleksandr Urakov   return true;
33830c2441aSAleksandr Urakov }
33930c2441aSAleksandr Urakov 
ParseFrameOffset(uint32_t & result)34030c2441aSAleksandr Urakov bool EHProgramBuilder::ParseFrameOffset(uint32_t &result) {
34130c2441aSAleksandr Urakov   if (!m_iterator.GetNext())
34230c2441aSAleksandr Urakov     return false;
34330c2441aSAleksandr Urakov 
34430c2441aSAleksandr Urakov   result = m_iterator.GetUnwindCode()->FrameOffset;
34530c2441aSAleksandr Urakov 
34630c2441aSAleksandr Urakov   return true;
34730c2441aSAleksandr Urakov }
34830c2441aSAleksandr Urakov 
34930c2441aSAleksandr Urakov class EHProgramRange {
35030c2441aSAleksandr Urakov public:
35130c2441aSAleksandr Urakov   EHProgramRange(EHProgram::const_iterator begin,
35230c2441aSAleksandr Urakov                  EHProgram::const_iterator end);
35330c2441aSAleksandr Urakov 
35430c2441aSAleksandr Urakov   std::unique_ptr<UnwindPlan::Row> BuildUnwindPlanRow() const;
35530c2441aSAleksandr Urakov 
35630c2441aSAleksandr Urakov private:
35730c2441aSAleksandr Urakov   int32_t GetCFAFrameOffset() const;
35830c2441aSAleksandr Urakov 
35930c2441aSAleksandr Urakov   EHProgram::const_iterator m_begin;
36030c2441aSAleksandr Urakov   EHProgram::const_iterator m_end;
36130c2441aSAleksandr Urakov };
36230c2441aSAleksandr Urakov 
EHProgramRange(EHProgram::const_iterator begin,EHProgram::const_iterator end)36330c2441aSAleksandr Urakov EHProgramRange::EHProgramRange(EHProgram::const_iterator begin,
36430c2441aSAleksandr Urakov                                EHProgram::const_iterator end)
36530c2441aSAleksandr Urakov     : m_begin(begin), m_end(end) {}
36630c2441aSAleksandr Urakov 
BuildUnwindPlanRow() const36730c2441aSAleksandr Urakov std::unique_ptr<UnwindPlan::Row> EHProgramRange::BuildUnwindPlanRow() const {
36830c2441aSAleksandr Urakov   std::unique_ptr<UnwindPlan::Row> row = std::make_unique<UnwindPlan::Row>();
36930c2441aSAleksandr Urakov 
37030c2441aSAleksandr Urakov   if (m_begin != m_end)
37130c2441aSAleksandr Urakov     row->SetOffset(m_begin->offset);
37230c2441aSAleksandr Urakov 
37330c2441aSAleksandr Urakov   int32_t cfa_frame_offset = GetCFAFrameOffset();
37430c2441aSAleksandr Urakov 
37530c2441aSAleksandr Urakov   bool frame_pointer_found = false;
37630c2441aSAleksandr Urakov   for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) {
37730c2441aSAleksandr Urakov     switch (it->type) {
37830c2441aSAleksandr Urakov     case EHInstruction::Type::SET_FRAME_POINTER_REGISTER:
37930c2441aSAleksandr Urakov       row->GetCFAValue().SetIsRegisterPlusOffset(it->reg, cfa_frame_offset -
38030c2441aSAleksandr Urakov                                                               it->frame_offset);
38130c2441aSAleksandr Urakov       frame_pointer_found = true;
38230c2441aSAleksandr Urakov       break;
38330c2441aSAleksandr Urakov     default:
38430c2441aSAleksandr Urakov       break;
38530c2441aSAleksandr Urakov     }
38630c2441aSAleksandr Urakov     if (frame_pointer_found)
38730c2441aSAleksandr Urakov       break;
38830c2441aSAleksandr Urakov   }
38930c2441aSAleksandr Urakov   if (!frame_pointer_found)
39030c2441aSAleksandr Urakov     row->GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64,
39130c2441aSAleksandr Urakov                                                cfa_frame_offset);
39230c2441aSAleksandr Urakov 
39330c2441aSAleksandr Urakov   int32_t rsp_frame_offset = 0;
39430c2441aSAleksandr Urakov   for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) {
39530c2441aSAleksandr Urakov     switch (it->type) {
39630c2441aSAleksandr Urakov     case EHInstruction::Type::PUSH_REGISTER:
39730c2441aSAleksandr Urakov       row->SetRegisterLocationToAtCFAPlusOffset(
39830c2441aSAleksandr Urakov           it->reg, rsp_frame_offset - cfa_frame_offset, false);
39930c2441aSAleksandr Urakov       rsp_frame_offset += it->frame_offset;
40030c2441aSAleksandr Urakov       break;
40130c2441aSAleksandr Urakov     case EHInstruction::Type::ALLOCATE:
40230c2441aSAleksandr Urakov       rsp_frame_offset += it->frame_offset;
40330c2441aSAleksandr Urakov       break;
40430c2441aSAleksandr Urakov     case EHInstruction::Type::SAVE_REGISTER:
40530c2441aSAleksandr Urakov       row->SetRegisterLocationToAtCFAPlusOffset(
40630c2441aSAleksandr Urakov           it->reg, it->frame_offset - cfa_frame_offset, false);
40730c2441aSAleksandr Urakov       break;
40830c2441aSAleksandr Urakov     default:
40930c2441aSAleksandr Urakov       break;
41030c2441aSAleksandr Urakov     }
41130c2441aSAleksandr Urakov   }
41230c2441aSAleksandr Urakov 
41330c2441aSAleksandr Urakov   row->SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, false);
41430c2441aSAleksandr Urakov 
41530c2441aSAleksandr Urakov   return row;
41630c2441aSAleksandr Urakov }
41730c2441aSAleksandr Urakov 
GetCFAFrameOffset() const41830c2441aSAleksandr Urakov int32_t EHProgramRange::GetCFAFrameOffset() const {
41930c2441aSAleksandr Urakov   int32_t result = 0;
42030c2441aSAleksandr Urakov 
42130c2441aSAleksandr Urakov   for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) {
42230c2441aSAleksandr Urakov     switch (it->type) {
42330c2441aSAleksandr Urakov     case EHInstruction::Type::PUSH_REGISTER:
42430c2441aSAleksandr Urakov     case EHInstruction::Type::ALLOCATE:
42530c2441aSAleksandr Urakov       result += it->frame_offset;
426cb5324c4SKadir Cetinkaya       break;
42730c2441aSAleksandr Urakov     default:
42830c2441aSAleksandr Urakov       break;
42930c2441aSAleksandr Urakov     }
43030c2441aSAleksandr Urakov   }
43130c2441aSAleksandr Urakov 
43230c2441aSAleksandr Urakov   return result;
43330c2441aSAleksandr Urakov }
43430c2441aSAleksandr Urakov 
PECallFrameInfo(ObjectFilePECOFF & object_file,uint32_t exception_dir_rva,uint32_t exception_dir_size)43530c2441aSAleksandr Urakov PECallFrameInfo::PECallFrameInfo(ObjectFilePECOFF &object_file,
43630c2441aSAleksandr Urakov                                  uint32_t exception_dir_rva,
43730c2441aSAleksandr Urakov                                  uint32_t exception_dir_size)
43830c2441aSAleksandr Urakov     : m_object_file(object_file),
43930c2441aSAleksandr Urakov       m_exception_dir(object_file.ReadImageDataByRVA(exception_dir_rva,
44030c2441aSAleksandr Urakov                                                       exception_dir_size)) {}
44130c2441aSAleksandr Urakov 
GetAddressRange(Address addr,AddressRange & range)44230c2441aSAleksandr Urakov bool PECallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {
44330c2441aSAleksandr Urakov   range.Clear();
44430c2441aSAleksandr Urakov 
44530c2441aSAleksandr Urakov   const RuntimeFunction *runtime_function =
44630c2441aSAleksandr Urakov       FindRuntimeFunctionIntersectsWithRange(AddressRange(addr, 1));
44730c2441aSAleksandr Urakov   if (!runtime_function)
44830c2441aSAleksandr Urakov     return false;
44930c2441aSAleksandr Urakov 
45030c2441aSAleksandr Urakov   range.GetBaseAddress() =
45130c2441aSAleksandr Urakov       m_object_file.GetAddress(runtime_function->StartAddress);
45230c2441aSAleksandr Urakov   range.SetByteSize(runtime_function->EndAddress -
45330c2441aSAleksandr Urakov                     runtime_function->StartAddress);
45430c2441aSAleksandr Urakov 
45530c2441aSAleksandr Urakov   return true;
45630c2441aSAleksandr Urakov }
45730c2441aSAleksandr Urakov 
GetUnwindPlan(const Address & addr,UnwindPlan & unwind_plan)45830c2441aSAleksandr Urakov bool PECallFrameInfo::GetUnwindPlan(const Address &addr,
45930c2441aSAleksandr Urakov                                     UnwindPlan &unwind_plan) {
46030c2441aSAleksandr Urakov   return GetUnwindPlan(AddressRange(addr, 1), unwind_plan);
46130c2441aSAleksandr Urakov }
46230c2441aSAleksandr Urakov 
GetUnwindPlan(const AddressRange & range,UnwindPlan & unwind_plan)46330c2441aSAleksandr Urakov bool PECallFrameInfo::GetUnwindPlan(const AddressRange &range,
46430c2441aSAleksandr Urakov                                     UnwindPlan &unwind_plan) {
46530c2441aSAleksandr Urakov   unwind_plan.Clear();
46630c2441aSAleksandr Urakov 
46730c2441aSAleksandr Urakov   unwind_plan.SetSourceName("PE EH info");
46830c2441aSAleksandr Urakov   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
46930c2441aSAleksandr Urakov   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
47030c2441aSAleksandr Urakov 
47130c2441aSAleksandr Urakov   const RuntimeFunction *runtime_function =
47230c2441aSAleksandr Urakov       FindRuntimeFunctionIntersectsWithRange(range);
47330c2441aSAleksandr Urakov   if (!runtime_function)
47430c2441aSAleksandr Urakov     return false;
47530c2441aSAleksandr Urakov 
47630c2441aSAleksandr Urakov   EHProgramBuilder builder(m_object_file, runtime_function->UnwindInfoOffset);
47730c2441aSAleksandr Urakov   if (!builder.Build())
47830c2441aSAleksandr Urakov     return false;
47930c2441aSAleksandr Urakov 
48030c2441aSAleksandr Urakov   std::vector<UnwindPlan::RowSP> rows;
48130c2441aSAleksandr Urakov 
48230c2441aSAleksandr Urakov   uint32_t last_offset = UINT32_MAX;
48330c2441aSAleksandr Urakov   for (auto it = builder.GetProgram().begin(); it != builder.GetProgram().end();
48430c2441aSAleksandr Urakov        ++it) {
48530c2441aSAleksandr Urakov     if (it->offset == last_offset)
48630c2441aSAleksandr Urakov       continue;
48730c2441aSAleksandr Urakov 
48830c2441aSAleksandr Urakov     EHProgramRange program_range =
48930c2441aSAleksandr Urakov         EHProgramRange(it, builder.GetProgram().end());
49030c2441aSAleksandr Urakov     rows.push_back(program_range.BuildUnwindPlanRow());
49130c2441aSAleksandr Urakov 
49230c2441aSAleksandr Urakov     last_offset = it->offset;
49330c2441aSAleksandr Urakov   }
49430c2441aSAleksandr Urakov 
49530c2441aSAleksandr Urakov   for (auto it = rows.rbegin(); it != rows.rend(); ++it)
49630c2441aSAleksandr Urakov     unwind_plan.AppendRow(*it);
49730c2441aSAleksandr Urakov 
49830c2441aSAleksandr Urakov   unwind_plan.SetPlanValidAddressRange(AddressRange(
49930c2441aSAleksandr Urakov       m_object_file.GetAddress(runtime_function->StartAddress),
50030c2441aSAleksandr Urakov       runtime_function->EndAddress - runtime_function->StartAddress));
50130c2441aSAleksandr Urakov   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
50230c2441aSAleksandr Urakov 
50330c2441aSAleksandr Urakov   return true;
50430c2441aSAleksandr Urakov }
50530c2441aSAleksandr Urakov 
FindRuntimeFunctionIntersectsWithRange(const AddressRange & range) const50630c2441aSAleksandr Urakov const RuntimeFunction *PECallFrameInfo::FindRuntimeFunctionIntersectsWithRange(
50730c2441aSAleksandr Urakov     const AddressRange &range) const {
50830c2441aSAleksandr Urakov   uint32_t rva = m_object_file.GetRVA(range.GetBaseAddress());
50930c2441aSAleksandr Urakov   addr_t size = range.GetByteSize();
51030c2441aSAleksandr Urakov 
51130c2441aSAleksandr Urakov   uint32_t begin = 0;
51230c2441aSAleksandr Urakov   uint32_t end = m_exception_dir.GetByteSize() / sizeof(RuntimeFunction);
51330c2441aSAleksandr Urakov   while (begin < end) {
51430c2441aSAleksandr Urakov     uint32_t curr = (begin + end) / 2;
51530c2441aSAleksandr Urakov 
51630c2441aSAleksandr Urakov     offset_t offset = curr * sizeof(RuntimeFunction);
51730c2441aSAleksandr Urakov     const auto *runtime_function =
51830c2441aSAleksandr Urakov         TypedRead<RuntimeFunction>(m_exception_dir, offset);
51930c2441aSAleksandr Urakov     if (!runtime_function)
52030c2441aSAleksandr Urakov       break;
52130c2441aSAleksandr Urakov 
52230c2441aSAleksandr Urakov     if (runtime_function->StartAddress < rva + size &&
52330c2441aSAleksandr Urakov         runtime_function->EndAddress > rva)
52430c2441aSAleksandr Urakov       return runtime_function;
52530c2441aSAleksandr Urakov 
52630c2441aSAleksandr Urakov     if (runtime_function->StartAddress >= rva + size)
52730c2441aSAleksandr Urakov       end = curr;
52830c2441aSAleksandr Urakov 
52930c2441aSAleksandr Urakov     if (runtime_function->EndAddress <= rva)
53030c2441aSAleksandr Urakov       begin = curr + 1;
53130c2441aSAleksandr Urakov   }
53230c2441aSAleksandr Urakov 
53330c2441aSAleksandr Urakov   return nullptr;
53430c2441aSAleksandr Urakov }
535