| 1 | //===-- RegisterContextMinidumpTest.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 "Plugins/Process/Utility/RegisterContextLinux_i386.h" |
| 10 | #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" |
| 11 | #include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h" |
| 12 | #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" |
| 13 | #include "Plugins/Process/minidump/RegisterContextMinidump_ARM.h" |
| 14 | #include "lldb/Utility/DataBuffer.h" |
| 15 | #include "llvm/ADT/StringRef.h" |
| 16 | #include "gtest/gtest.h" |
| 17 | |
| 18 | using namespace lldb_private; |
| 19 | using namespace lldb_private::minidump; |
| 20 | |
| 21 | static uint32_t reg32(const DataBuffer &Buf, const RegisterInfo &Info) { |
| 22 | return *reinterpret_cast<const uint32_t *>(Buf.GetBytes() + Info.byte_offset); |
| 23 | } |
| 24 | |
| 25 | static uint64_t reg64(const DataBuffer &Buf, const RegisterInfo &Info) { |
| 26 | return *reinterpret_cast<const uint64_t *>(Buf.GetBytes() + Info.byte_offset); |
| 27 | } |
| 28 | |
| 29 | TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_32) { |
| 30 | MinidumpContext_x86_32 Context; |
| 31 | Context.context_flags = |
| 32 | static_cast<uint32_t>(MinidumpContext_x86_32_Flags::x86_32_Flag | |
| 33 | MinidumpContext_x86_32_Flags::Control | |
| 34 | MinidumpContext_x86_32_Flags::Segments | |
| 35 | MinidumpContext_x86_32_Flags::Integer); |
| 36 | Context.eax = 0x00010203; |
| 37 | Context.ebx = 0x04050607; |
| 38 | Context.ecx = 0x08090a0b; |
| 39 | Context.edx = 0x0c0d0e0f; |
| 40 | Context.edi = 0x10111213; |
| 41 | Context.esi = 0x14151617; |
| 42 | Context.ebp = 0x18191a1b; |
| 43 | Context.esp = 0x1c1d1e1f; |
| 44 | Context.eip = 0x20212223; |
| 45 | Context.eflags = 0x24252627; |
| 46 | Context.cs = 0x2829; |
| 47 | Context.fs = 0x2a2b; |
| 48 | Context.gs = 0x2c2d; |
| 49 | Context.ss = 0x2e2f; |
| 50 | Context.ds = 0x3031; |
| 51 | Context.es = 0x3233; |
| 52 | llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context), |
| 53 | sizeof(Context)); |
| 54 | |
| 55 | ArchSpec arch("i386-pc-linux" ); |
| 56 | auto RegInterface = std::make_unique<RegisterContextLinux_i386>(args&: arch); |
| 57 | lldb::DataBufferSP Buf = |
| 58 | ConvertMinidumpContext_x86_32(source_data: ContextRef, target_reg_interface: RegInterface.get()); |
| 59 | ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize()); |
| 60 | |
| 61 | const RegisterInfo *Info = RegInterface->GetRegisterInfo(); |
| 62 | ASSERT_NE(nullptr, Info); |
| 63 | |
| 64 | EXPECT_EQ(Context.eax, reg32(*Buf, Info[lldb_eax_i386])); |
| 65 | EXPECT_EQ(Context.ebx, reg32(*Buf, Info[lldb_ebx_i386])); |
| 66 | EXPECT_EQ(Context.ecx, reg32(*Buf, Info[lldb_ecx_i386])); |
| 67 | EXPECT_EQ(Context.edx, reg32(*Buf, Info[lldb_edx_i386])); |
| 68 | EXPECT_EQ(Context.edi, reg32(*Buf, Info[lldb_edi_i386])); |
| 69 | EXPECT_EQ(Context.esi, reg32(*Buf, Info[lldb_esi_i386])); |
| 70 | EXPECT_EQ(Context.ebp, reg32(*Buf, Info[lldb_ebp_i386])); |
| 71 | EXPECT_EQ(Context.esp, reg32(*Buf, Info[lldb_esp_i386])); |
| 72 | EXPECT_EQ(Context.eip, reg32(*Buf, Info[lldb_eip_i386])); |
| 73 | EXPECT_EQ(Context.eflags, reg32(*Buf, Info[lldb_eflags_i386])); |
| 74 | EXPECT_EQ(Context.cs, reg32(*Buf, Info[lldb_cs_i386])); |
| 75 | EXPECT_EQ(Context.fs, reg32(*Buf, Info[lldb_fs_i386])); |
| 76 | EXPECT_EQ(Context.gs, reg32(*Buf, Info[lldb_gs_i386])); |
| 77 | EXPECT_EQ(Context.ss, reg32(*Buf, Info[lldb_ss_i386])); |
| 78 | EXPECT_EQ(Context.ds, reg32(*Buf, Info[lldb_ds_i386])); |
| 79 | EXPECT_EQ(Context.es, reg32(*Buf, Info[lldb_es_i386])); |
| 80 | } |
| 81 | |
| 82 | TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_64) { |
| 83 | MinidumpContext_x86_64 Context; |
| 84 | Context.context_flags = |
| 85 | static_cast<uint32_t>(MinidumpContext_x86_64_Flags::x86_64_Flag | |
| 86 | MinidumpContext_x86_64_Flags::Control | |
| 87 | MinidumpContext_x86_64_Flags::Segments | |
| 88 | MinidumpContext_x86_64_Flags::Integer); |
| 89 | Context.rax = 0x0001020304050607; |
| 90 | Context.rbx = 0x08090a0b0c0d0e0f; |
| 91 | Context.rcx = 0x1011121314151617; |
| 92 | Context.rdx = 0x18191a1b1c1d1e1f; |
| 93 | Context.rdi = 0x2021222324252627; |
| 94 | Context.rsi = 0x28292a2b2c2d2e2f; |
| 95 | Context.rbp = 0x3031323334353637; |
| 96 | Context.rsp = 0x38393a3b3c3d3e3f; |
| 97 | Context.r8 = 0x4041424344454647; |
| 98 | Context.r9 = 0x48494a4b4c4d4e4f; |
| 99 | Context.r10 = 0x5051525354555657; |
| 100 | Context.r11 = 0x58595a5b5c5d5e5f; |
| 101 | Context.r12 = 0x6061626364656667; |
| 102 | Context.r13 = 0x68696a6b6c6d6e6f; |
| 103 | Context.r14 = 0x7071727374757677; |
| 104 | Context.r15 = 0x78797a7b7c7d7e7f; |
| 105 | Context.rip = 0x8081828384858687; |
| 106 | Context.eflags = 0x88898a8b; |
| 107 | Context.cs = 0x8c8d; |
| 108 | Context.fs = 0x8e8f; |
| 109 | Context.gs = 0x9091; |
| 110 | Context.ss = 0x9293; |
| 111 | Context.ds = 0x9495; |
| 112 | Context.es = 0x9697; |
| 113 | llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context), |
| 114 | sizeof(Context)); |
| 115 | |
| 116 | ArchSpec arch("x86_64-pc-linux" ); |
| 117 | auto RegInterface = std::make_unique<RegisterContextLinux_x86_64>(args&: arch); |
| 118 | lldb::DataBufferSP Buf = |
| 119 | ConvertMinidumpContext_x86_64(source_data: ContextRef, target_reg_interface: RegInterface.get()); |
| 120 | ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize()); |
| 121 | |
| 122 | const RegisterInfo *Info = RegInterface->GetRegisterInfo(); |
| 123 | EXPECT_EQ(Context.rax, reg64(*Buf, Info[lldb_rax_x86_64])); |
| 124 | EXPECT_EQ(Context.rbx, reg64(*Buf, Info[lldb_rbx_x86_64])); |
| 125 | EXPECT_EQ(Context.rcx, reg64(*Buf, Info[lldb_rcx_x86_64])); |
| 126 | EXPECT_EQ(Context.rdx, reg64(*Buf, Info[lldb_rdx_x86_64])); |
| 127 | EXPECT_EQ(Context.rdi, reg64(*Buf, Info[lldb_rdi_x86_64])); |
| 128 | EXPECT_EQ(Context.rsi, reg64(*Buf, Info[lldb_rsi_x86_64])); |
| 129 | EXPECT_EQ(Context.rbp, reg64(*Buf, Info[lldb_rbp_x86_64])); |
| 130 | EXPECT_EQ(Context.rsp, reg64(*Buf, Info[lldb_rsp_x86_64])); |
| 131 | EXPECT_EQ(Context.r8, reg64(*Buf, Info[lldb_r8_x86_64])); |
| 132 | EXPECT_EQ(Context.r9, reg64(*Buf, Info[lldb_r9_x86_64])); |
| 133 | EXPECT_EQ(Context.r10, reg64(*Buf, Info[lldb_r10_x86_64])); |
| 134 | EXPECT_EQ(Context.r11, reg64(*Buf, Info[lldb_r11_x86_64])); |
| 135 | EXPECT_EQ(Context.r12, reg64(*Buf, Info[lldb_r12_x86_64])); |
| 136 | EXPECT_EQ(Context.r13, reg64(*Buf, Info[lldb_r13_x86_64])); |
| 137 | EXPECT_EQ(Context.r14, reg64(*Buf, Info[lldb_r14_x86_64])); |
| 138 | EXPECT_EQ(Context.r15, reg64(*Buf, Info[lldb_r15_x86_64])); |
| 139 | EXPECT_EQ(Context.rip, reg64(*Buf, Info[lldb_rip_x86_64])); |
| 140 | EXPECT_EQ(Context.eflags, reg64(*Buf, Info[lldb_rflags_x86_64])); |
| 141 | EXPECT_EQ(Context.cs, reg64(*Buf, Info[lldb_cs_x86_64])); |
| 142 | EXPECT_EQ(Context.fs, reg64(*Buf, Info[lldb_fs_x86_64])); |
| 143 | EXPECT_EQ(Context.gs, reg64(*Buf, Info[lldb_gs_x86_64])); |
| 144 | EXPECT_EQ(Context.ss, reg64(*Buf, Info[lldb_ss_x86_64])); |
| 145 | EXPECT_EQ(Context.ds, reg64(*Buf, Info[lldb_ds_x86_64])); |
| 146 | EXPECT_EQ(Context.es, reg64(*Buf, Info[lldb_es_x86_64])); |
| 147 | } |
| 148 | |
| 149 | static void TestARMRegInfo(const lldb_private::RegisterInfo *info) { |
| 150 | // Make sure we have valid register numbers for eRegisterKindEHFrame and |
| 151 | // eRegisterKindDWARF for GPR registers r0-r15 so that we can unwind |
| 152 | // correctly when using this information. |
| 153 | llvm::StringRef name(info->name); |
| 154 | llvm::StringRef alt_name(info->alt_name); |
| 155 | if (name.starts_with(Prefix: "r" ) || alt_name.starts_with(Prefix: "r" )) { |
| 156 | EXPECT_NE(info->kinds[lldb::eRegisterKindEHFrame], LLDB_INVALID_REGNUM); |
| 157 | EXPECT_NE(info->kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM); |
| 158 | } |
| 159 | // Verify generic register are set correctly |
| 160 | if (name == "r0" ) { |
| 161 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 162 | (uint32_t)LLDB_REGNUM_GENERIC_ARG1); |
| 163 | } else if (name == "r1" ) { |
| 164 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 165 | (uint32_t)LLDB_REGNUM_GENERIC_ARG2); |
| 166 | } else if (name == "r2" ) { |
| 167 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 168 | (uint32_t)LLDB_REGNUM_GENERIC_ARG3); |
| 169 | } else if (name == "r3" ) { |
| 170 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 171 | (uint32_t)LLDB_REGNUM_GENERIC_ARG4); |
| 172 | } else if (name == "sp" ) { |
| 173 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 174 | (uint32_t)LLDB_REGNUM_GENERIC_SP); |
| 175 | } else if (name == "fp" ) { |
| 176 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 177 | (uint32_t)LLDB_REGNUM_GENERIC_FP); |
| 178 | } else if (name == "lr" ) { |
| 179 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 180 | (uint32_t)LLDB_REGNUM_GENERIC_RA); |
| 181 | } else if (name == "pc" ) { |
| 182 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 183 | (uint32_t)LLDB_REGNUM_GENERIC_PC); |
| 184 | } else if (name == "cpsr" ) { |
| 185 | EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric], |
| 186 | (uint32_t)LLDB_REGNUM_GENERIC_FLAGS); |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | TEST(RegisterContextMinidump, CheckRegisterContextMinidump_ARM) { |
| 191 | size_t num_regs = RegisterContextMinidump_ARM::GetRegisterCountStatic(); |
| 192 | const lldb_private::RegisterInfo *reg_info; |
| 193 | for (size_t reg=0; reg<num_regs; ++reg) { |
| 194 | reg_info = RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(reg, |
| 195 | apple: true); |
| 196 | TestARMRegInfo(info: reg_info); |
| 197 | reg_info = RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(reg, |
| 198 | apple: false); |
| 199 | TestARMRegInfo(info: reg_info); |
| 200 | } |
| 201 | } |
| 202 | |