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