dvlahovski created this revision. dvlahovski added reviewers: labath, zturner. dvlahovski added subscribers: amccarth, lldb-commits. Herald added subscribers: mgorny, beanz.
This is a register context converter from Minidump to Linux reg context. This knows the layout of the register context in the Minidump file (which is the same as in Windows FYI) and as a result emits a binary data buffer that matches the Linux register context binary layout. This way we can reuse the existing RegisterContextLinux_x86_64 and RegisterContextCorePOSIX_x86_64 classes. https://reviews.llvm.org/D24919 Files: source/Plugins/Process/minidump/CMakeLists.txt source/Plugins/Process/minidump/MinidumpParser.cpp source/Plugins/Process/minidump/MinidumpParser.h source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h unittests/Process/minidump/MinidumpParserTest.cpp
Index: unittests/Process/minidump/MinidumpParserTest.cpp =================================================================== --- unittests/Process/minidump/MinidumpParserTest.cpp +++ unittests/Process/minidump/MinidumpParserTest.cpp @@ -8,16 +8,19 @@ //===----------------------------------------------------------------------===// // Project includes +#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/minidump/MinidumpParser.h" #include "Plugins/Process/minidump/MinidumpTypes.h" +#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" // Other libraries and framework includes #include "gtest/gtest.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Host/FileSpec.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -167,3 +170,63 @@ ASSERT_TRUE(pid.hasValue()); ASSERT_EQ(4440UL, pid.getValue()); } + +// Register stuff +// TODO probably split register stuff tests into different file? +void registerEqualToVal(const uint64_t val, uint8_t *reg_val) { + ASSERT_EQ(val, *(reinterpret_cast<uint64_t *>(reg_val))); +} + +TEST_F(MinidumpParserTest, ConvertRegisterContext) { + SetUpData("linux-x86_64.dmp"); + llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads(); + const MinidumpThread thread = thread_list[0]; + llvm::ArrayRef<uint8_t> registers(parser->GetBaseAddr() + + thread.thread_context.rva, + thread.thread_context.data_size); + + ArchSpec arch = parser->GetArchitecture(); + RegisterInfoInterface *reg_interface = new RegisterContextLinux_x86_64(arch); + lldb::DataBufferSP buf = + MinidumpContext_x86_64::Convert(registers, reg_interface); + ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize()); + + const RegisterInfo *reg_info = reg_interface->GetRegisterInfo(); + + std::map<uint64_t, uint64_t> reg_values; + + // clang-format off + reg_values[lldb_rax_x86_64] = 0x0000000000000000; + reg_values[lldb_rbx_x86_64] = 0x0000000000000000; + reg_values[lldb_rcx_x86_64] = 0x0000000000000010; + reg_values[lldb_rdx_x86_64] = 0x0000000000000000; + reg_values[lldb_rdi_x86_64] = 0x00007ffceb349cf0; + reg_values[lldb_rsi_x86_64] = 0x0000000000000000; + reg_values[lldb_rbp_x86_64] = 0x00007ffceb34a210; + reg_values[lldb_rsp_x86_64] = 0x00007ffceb34a210; + reg_values[lldb_r8_x86_64] = 0x00007fe9bc1aa9c0; + reg_values[lldb_r9_x86_64] = 0x0000000000000000; + reg_values[lldb_r10_x86_64] = 0x00007fe9bc3f16a0; + reg_values[lldb_r11_x86_64] = 0x0000000000000246; + reg_values[lldb_r12_x86_64] = 0x0000000000401c92; + reg_values[lldb_r13_x86_64] = 0x00007ffceb34a430; + reg_values[lldb_r14_x86_64] = 0x0000000000000000; + reg_values[lldb_r15_x86_64] = 0x0000000000000000; + reg_values[lldb_rip_x86_64] = 0x0000000000401dc6; + reg_values[lldb_rflags_x86_64] = 0x0000000000010206; + reg_values[lldb_cs_x86_64] = 0x0000000000000033; + reg_values[lldb_fs_x86_64] = 0x0000000000000000; + reg_values[lldb_gs_x86_64] = 0x0000000000000000; + reg_values[lldb_ss_x86_64] = 0x0000000000000000; + reg_values[lldb_ds_x86_64] = 0x0000000000000000; + reg_values[lldb_es_x86_64] = 0x0000000000000000; + // clang-format on + + for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount(); + ++reg_index) { + if (reg_values.find(reg_index) != reg_values.end()) { + registerEqualToVal(reg_values[reg_index], + buf->GetBytes() + reg_info[reg_index].byte_offset); + } + } +} Index: source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h =================================================================== --- /dev/null +++ source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h @@ -0,0 +1,189 @@ +//===-- Registers_x86_64.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_MinidumpRegisterContext_h_ +#define liblldb_MinidumpRegisterContext_h_ + +// Project includes +#include "MinidumpTypes.h" + +// Other libraries and framework includes +#include "Plugins/Process/Utility/RegisterInfoInterface.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +#include "lldb/Target/RegisterContext.h" + +#include "llvm/ADT/BitmaskEnum.h" + +// C includes +// C++ includes + +namespace lldb_private { + +namespace minidump { + +struct uint128_struct { + uint64_t high; + uint64_t low; +}; + +struct MinidumpXmmSaveArea32AMD64 { + uint16_t control_word; + uint16_t status_word; + uint8_t tag_word; + uint8_t reserved1; + uint16_t error_opcode; + uint32_t error_offset; + uint16_t error_selector; + uint16_t reserved2; + uint32_t data_offset; + uint16_t data_selector; + uint16_t reserved3; + uint32_t mx_csr; + uint32_t mx_csr_mask; + uint128_struct float_registers[8]; + uint128_struct xmm_registers[16]; + uint8_t reserved4[96]; +}; + +struct MinidumpContext_x86_64 { + // Register parameter home addresses. + uint64_t p1_home; + uint64_t p2_home; + uint64_t p3_home; + uint64_t p4_home; + uint64_t p5_home; + uint64_t p6_home; + + // The next field determines the layout of the structure, and which parts of + // it are populated + uint32_t context_flags; + uint32_t mx_csr; + + // The next register is included with MinidumpContext_x86_64_Flags::Control + uint16_t cs; + + // The next 4 registers are included with + // MinidumpContext_x86_64_Flags::Segments + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + + // The next 2 registers are included with + // MinidumpContext_x86_64_Flags::Control + uint16_t ss; + uint32_t rflags; + + // The next 6 registers are included with + // MinidumpContext_x86_64_Flags::DebugRegisters + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr6; + uint64_t dr7; + + // The next 4 registers are included with + // MinidumpContext_x86_64_Flags::Integer + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + + // The next register is included with MinidumpContext_x86_64_Flags::Control + uint64_t rsp; + + // The next 11 registers are included with + // MinidumpContext_x86_64_Flags::Integer + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + // The next register is included with MinidumpContext_x86_64_Flags::Control + uint64_t rip; + + // The next set of registers are included with + // MinidumpContext_x86_64_Flags::FloatingPoint + union { + MinidumpXmmSaveArea32AMD64 flt_save; + struct { + uint128_struct header[2]; + uint128_struct legacy[8]; + uint128_struct xmm0; + uint128_struct xmm1; + uint128_struct xmm2; + uint128_struct xmm3; + uint128_struct xmm4; + uint128_struct xmm5; + uint128_struct xmm6; + uint128_struct xmm7; + uint128_struct xmm8; + uint128_struct xmm9; + uint128_struct xmm10; + uint128_struct xmm11; + uint128_struct xmm12; + uint128_struct xmm13; + uint128_struct xmm14; + uint128_struct xmm15; + } sse_registers; + }; + + enum { + VRCount = 26, + }; + + uint128_struct vector_register[VRCount]; + uint64_t vector_control; + + // The next 5 registers are included with + // MinidumpContext_x86_64_Flags::DebugRegisters + uint64_t debug_control; + uint64_t last_branch_to_rip; + uint64_t last_branch_from_rip; + uint64_t last_exception_to_rip; + uint64_t last_exception_from_rip; + + static void writeRegister(llvm::ArrayRef<uint8_t> &data, uint8_t *base, + const RegisterInfo *reg_info, size_t size); + static lldb::DataBufferSP Convert(llvm::ArrayRef<uint8_t> data, + RegisterInfoInterface *reg_interface); +}; + +// For MinidumpContext_x86_64.context_flags. These values indicate the type of +// context stored in the structure. The high 24 bits identify the CPU, the +// low 8 bits identify the type of context saved. +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +enum class MinidumpContext_x86_64_Flags : uint32_t { + x86_64_Flag = 0x00100000, + Control = x86_64_Flag | 0x00000001, + Integer = x86_64_Flag | 0x00000002, + Segments = x86_64_Flag | 0x00000004, + FloatingPoint = x86_64_Flag | 0x00000008, + DebugRegisters = x86_64_Flag | 0x00000010, + XState = x86_64_Flag | 0x00000040, + + Full = Control | Integer | FloatingPoint, + All = Full | Segments | DebugRegisters, + + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All) +}; +} +} + +#endif // liblldb_RegisterContextMinidump_h_ Index: source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp @@ -0,0 +1,127 @@ +//===-- Registers_x86_64.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Project includes +#include "RegisterContextMinidump_x86_64.h" + +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" + +// C includes +// C++ includes + +using namespace lldb_private; +using namespace minidump; + +void MinidumpContext_x86_64::writeRegister(llvm::ArrayRef<uint8_t> &source_data, + uint8_t *base, + const RegisterInfo *reg_info, + size_t size) { + memcpy(base + reg_info->byte_offset, source_data.data(), size); + source_data = source_data.drop_front(size); +} + +// This function receives an ArrayRef pointing to the bytes of the Minidump +// register context and returns a DataBuffer that's ordered by the offsets +// specified in the RegisterInfoInterface argument +// This way we can reuse the already existing register contexts +lldb::DataBufferSP +MinidumpContext_x86_64::Convert(llvm::ArrayRef<uint8_t> source_data, + RegisterInfoInterface *target_reg_interface) { + MinidumpContext_x86_64 context; + + const RegisterInfo *reg_info = target_reg_interface->GetRegisterInfo(); + + lldb::DataBufferSP result_context_buf( + new DataBufferHeap(target_reg_interface->GetGPRSize(), 0)); + uint8_t *result_base = result_context_buf->GetBytes(); + + source_data = source_data.drop_front(6 * 8); // p[1-6] home registers + const uint32_t *context_flags; + consumeObject(source_data, context_flags); + source_data = source_data.drop_front(4); // mx_csr + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Control)) { + writeRegister(source_data, result_base, ®_info[lldb_cs_x86_64], + sizeof(context.cs)); + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Segments)) { + writeRegister(source_data, result_base, ®_info[lldb_ds_x86_64], + sizeof(context.ds)); + writeRegister(source_data, result_base, ®_info[lldb_es_x86_64], + sizeof(context.es)); + writeRegister(source_data, result_base, ®_info[lldb_fs_x86_64], + sizeof(context.fs)); + writeRegister(source_data, result_base, ®_info[lldb_gs_x86_64], + sizeof(context.gs)); + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Control)) { + writeRegister(source_data, result_base, ®_info[lldb_ss_x86_64], + sizeof(context.ss)); + writeRegister(source_data, result_base, ®_info[lldb_rflags_x86_64], + sizeof(context.rflags)); + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::DebugRegisters)) { + source_data = + source_data.drop_front(6 * 8); // 6 debug registers 64 bit each + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Integer)) { + writeRegister(source_data, result_base, ®_info[lldb_rax_x86_64], + sizeof(context.rax)); + writeRegister(source_data, result_base, ®_info[lldb_rcx_x86_64], + sizeof(context.rcx)); + writeRegister(source_data, result_base, ®_info[lldb_rdx_x86_64], + sizeof(context.rdx)); + writeRegister(source_data, result_base, ®_info[lldb_rbx_x86_64], + sizeof(context.rbx)); + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Control)) { + writeRegister(source_data, result_base, ®_info[lldb_rsp_x86_64], + sizeof(context.rsp)); + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Integer)) { + writeRegister(source_data, result_base, ®_info[lldb_rbp_x86_64], + sizeof(context.rbp)); + writeRegister(source_data, result_base, ®_info[lldb_rsi_x86_64], + sizeof(context.rsi)); + writeRegister(source_data, result_base, ®_info[lldb_rdi_x86_64], + sizeof(context.rdi)); + writeRegister(source_data, result_base, ®_info[lldb_r8_x86_64], + sizeof(context.r8)); + writeRegister(source_data, result_base, ®_info[lldb_r9_x86_64], + sizeof(context.r9)); + writeRegister(source_data, result_base, ®_info[lldb_r10_x86_64], + sizeof(context.r10)); + writeRegister(source_data, result_base, ®_info[lldb_r11_x86_64], + sizeof(context.r11)); + writeRegister(source_data, result_base, ®_info[lldb_r12_x86_64], + sizeof(context.r12)); + writeRegister(source_data, result_base, ®_info[lldb_r13_x86_64], + sizeof(context.r13)); + writeRegister(source_data, result_base, ®_info[lldb_r14_x86_64], + sizeof(context.r14)); + writeRegister(source_data, result_base, ®_info[lldb_r15_x86_64], + sizeof(context.r15)); + } + + if (*context_flags & uint32_t(MinidumpContext_x86_64_Flags::Control)) { + writeRegister(source_data, result_base, ®_info[lldb_rip_x86_64], + sizeof(context.rip)); + } + + // TODO parse the floating point registers + + return result_context_buf; +} Index: source/Plugins/Process/minidump/MinidumpParser.h =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.h +++ source/Plugins/Process/minidump/MinidumpParser.h @@ -39,6 +39,8 @@ static llvm::Optional<MinidumpParser> Create(const lldb::DataBufferSP &data_buf_sp); + const uint8_t *GetBaseAddr(); + lldb::offset_t GetByteSize(); llvm::ArrayRef<uint8_t> GetStream(MinidumpStreamType stream_type); Index: source/Plugins/Process/minidump/MinidumpParser.cpp =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.cpp +++ source/Plugins/Process/minidump/MinidumpParser.cpp @@ -64,6 +64,8 @@ : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { } +const uint8_t *MinidumpParser::GetBaseAddr() { return m_data_sp->GetBytes(); } + lldb::offset_t MinidumpParser::GetByteSize() { return m_data_sp->GetByteSize(); } Index: source/Plugins/Process/minidump/CMakeLists.txt =================================================================== --- source/Plugins/Process/minidump/CMakeLists.txt +++ source/Plugins/Process/minidump/CMakeLists.txt @@ -3,4 +3,5 @@ add_lldb_library(lldbPluginProcessMinidump MinidumpTypes.cpp MinidumpParser.cpp + RegisterContextMinidump_x86_64.cpp )
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits