Author: dvlahovski Date: Tue Sep 27 14:05:55 2016 New Revision: 282529 URL: http://llvm.org/viewvc/llvm-project?rev=282529&view=rev Log: Adding a RegisterContextMinidump_x86_64 converter
Summary: 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. Reviewers: labath, zturner Subscribers: beanz, mgorny, lldb-commits, amccarth Differential Revision: https://reviews.llvm.org/D24919 Added: lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h Modified: lldb/trunk/include/lldb/lldb-private-types.h lldb/trunk/source/Plugins/Process/minidump/CMakeLists.txt lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp Modified: lldb/trunk/include/lldb/lldb-private-types.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-types.h?rev=282529&r1=282528&r2=282529&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-private-types.h (original) +++ lldb/trunk/include/lldb/lldb-private-types.h Tue Sep 27 14:05:55 2016 @@ -14,6 +14,8 @@ #include "lldb/lldb-private.h" +#include "llvm/ADT/ArrayRef.h" + namespace llvm { namespace sys { class DynamicLibrary; @@ -61,6 +63,15 @@ struct RegisterInfo { // the byte size of this register. size_t dynamic_size_dwarf_len; // The length of the DWARF expression in bytes // in the dynamic_size_dwarf_expr_bytes member. + + llvm::ArrayRef<uint8_t> data(const uint8_t *context_base) const { + return llvm::ArrayRef<uint8_t>(context_base + byte_offset, byte_size); + } + + llvm::MutableArrayRef<uint8_t> mutable_data(uint8_t *context_base) const { + return llvm::MutableArrayRef<uint8_t>(context_base + byte_offset, + byte_size); + } }; //---------------------------------------------------------------------- Modified: lldb/trunk/source/Plugins/Process/minidump/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/CMakeLists.txt?rev=282529&r1=282528&r2=282529&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/minidump/CMakeLists.txt (original) +++ lldb/trunk/source/Plugins/Process/minidump/CMakeLists.txt Tue Sep 27 14:05:55 2016 @@ -3,4 +3,5 @@ include_directories(../Utility) add_lldb_library(lldbPluginProcessMinidump MinidumpTypes.cpp MinidumpParser.cpp + RegisterContextMinidump_x86_64.cpp ) Modified: lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp?rev=282529&r1=282528&r2=282529&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp (original) +++ lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp Tue Sep 27 14:05:55 2016 @@ -64,8 +64,9 @@ MinidumpParser::MinidumpParser( : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { } -lldb::offset_t MinidumpParser::GetByteSize() { - return m_data_sp->GetByteSize(); +llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { + return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), + m_data_sp->GetByteSize()); } llvm::ArrayRef<uint8_t> Modified: lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h?rev=282529&r1=282528&r2=282529&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h (original) +++ lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h Tue Sep 27 14:05:55 2016 @@ -39,7 +39,7 @@ public: static llvm::Optional<MinidumpParser> Create(const lldb::DataBufferSP &data_buf_sp); - lldb::offset_t GetByteSize(); + llvm::ArrayRef<uint8_t> GetData(); llvm::ArrayRef<uint8_t> GetStream(MinidumpStreamType stream_type); @@ -71,6 +71,6 @@ private: llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map); }; -} // namespace minidump -} // namespace lldb_private +} // end namespace minidump +} // end namespace lldb_private #endif // liblldb_MinidumpParser_h_ Added: lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp?rev=282529&view=auto ============================================================================== --- lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp (added) +++ lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp Tue Sep 27 14:05:55 2016 @@ -0,0 +1,158 @@ +//===-- RegisterContextMinidump_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 writeRegister(llvm::ArrayRef<uint8_t> ®_src, + llvm::MutableArrayRef<uint8_t> reg_dest) { + memcpy(reg_dest.data(), reg_src.data(), reg_dest.size()); + reg_src = reg_src.drop_front(reg_dest.size()); +} + +llvm::MutableArrayRef<uint8_t> getDestRegister(uint8_t *context, + uint32_t lldb_reg_num, + const RegisterInfo ®) { + auto bytes = reg.mutable_data(context); + + switch (lldb_reg_num) { + case lldb_cs_x86_64: + case lldb_ds_x86_64: + case lldb_es_x86_64: + case lldb_fs_x86_64: + case lldb_gs_x86_64: + case lldb_ss_x86_64: + return bytes.take_front(2); + break; + case lldb_rflags_x86_64: + return bytes.take_front(4); + break; + default: + return bytes.take_front(8); + break; + } +} + +lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContextToRegIface( + llvm::ArrayRef<uint8_t> source_data, + RegisterInfoInterface *target_reg_interface) { + + 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); + const uint32_t x86_64_Flag = + static_cast<uint32_t>(MinidumpContext_x86_64_Flags::x86_64_Flag); + const uint32_t ControlFlag = + static_cast<uint32_t>(MinidumpContext_x86_64_Flags::Control); + const uint32_t IntegerFlag = + static_cast<uint32_t>(MinidumpContext_x86_64_Flags::Integer); + const uint32_t SegmentsFlag = + static_cast<uint32_t>(MinidumpContext_x86_64_Flags::Segments); + const uint32_t DebugRegistersFlag = + static_cast<uint32_t>(MinidumpContext_x86_64_Flags::DebugRegisters); + + if (!(*context_flags & x86_64_Flag)) { + return result_context_buf; // error + } + + source_data = source_data.drop_front(4); // mx_csr + + if (*context_flags & ControlFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_cs_x86_64, + reg_info[lldb_cs_x86_64])); + } + + if (*context_flags & SegmentsFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_ds_x86_64, + reg_info[lldb_ds_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_es_x86_64, + reg_info[lldb_es_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_fs_x86_64, + reg_info[lldb_fs_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_gs_x86_64, + reg_info[lldb_gs_x86_64])); + } + + if (*context_flags & ControlFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_ss_x86_64, + reg_info[lldb_ss_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_rflags_x86_64, + reg_info[lldb_rflags_x86_64])); + } + + if (*context_flags & DebugRegistersFlag) { + source_data = + source_data.drop_front(6 * 8); // 6 debug registers 64 bit each + } + + if (*context_flags & IntegerFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_rax_x86_64, + reg_info[lldb_rax_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_rcx_x86_64, + reg_info[lldb_rcx_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_rdx_x86_64, + reg_info[lldb_rdx_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_rbx_x86_64, + reg_info[lldb_rbx_x86_64])); + } + + if (*context_flags & ControlFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_rsp_x86_64, + reg_info[lldb_rsp_x86_64])); + } + + if (*context_flags & IntegerFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_rbp_x86_64, + reg_info[lldb_rbp_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_rsi_x86_64, + reg_info[lldb_rsi_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_rdi_x86_64, + reg_info[lldb_rdi_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r8_x86_64, + reg_info[lldb_r8_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r9_x86_64, + reg_info[lldb_r9_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r10_x86_64, + reg_info[lldb_r10_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r11_x86_64, + reg_info[lldb_r11_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r12_x86_64, + reg_info[lldb_r12_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r13_x86_64, + reg_info[lldb_r13_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r14_x86_64, + reg_info[lldb_r14_x86_64])); + writeRegister(source_data, getDestRegister(result_base, lldb_r15_x86_64, + reg_info[lldb_r15_x86_64])); + } + + if (*context_flags & ControlFlag) { + writeRegister(source_data, getDestRegister(result_base, lldb_rip_x86_64, + reg_info[lldb_rip_x86_64])); + } + + // TODO parse the floating point registers + + return result_context_buf; +} Added: lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h?rev=282529&view=auto ============================================================================== --- lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h (added) +++ lldb/trunk/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h Tue Sep 27 14:05:55 2016 @@ -0,0 +1,119 @@ +//===-- RegisterContextMinidump_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_RegisterContextMinidump_h_ +#define liblldb_RegisterContextMinidump_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/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" + +// C includes +// C++ includes + +namespace lldb_private { + +namespace minidump { + +// The content of the Minidump register context is as follows: +// (for reference see breakpad's source or WinNT.h) +// Register parameter home addresses: (p1_home .. p6_home) +// - uint64_t p1_home +// - uint64_t p2_home +// - uint64_t p3_home +// - uint64_t p4_home +// - uint64_t p5_home +// - uint64_t p6_home +// +// - uint32_t context_flags - field that determines the layout of the structure +// and which parts of it are populated +// - uint32_t mx_csr +// +// - uint16_t cs - included if MinidumpContext_x86_64_Flags::Control +// +// - uint16_t ds - included if MinidumpContext_x86_64_Flags::Segments +// - uint16_t es - included if MinidumpContext_x86_64_Flags::Segments +// - uint16_t fs - included if MinidumpContext_x86_64_Flags::Segments +// - uint16_t gs - included if MinidumpContext_x86_64_Flags::Segments +// +// - uint16_t ss - included if MinidumpContext_x86_64_Flags::Control +// - uint32_t rflags - included if MinidumpContext_x86_64_Flags::Control +// +// Debug registers: (included if 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 if MinidumpContext_x86_64_Flags::Integer +// - uint64_t rax +// - uint64_t rcx +// - uint64_t rdx +// - uint64_t rbx +// +// - uint64_t rsp - included if MinidumpContext_x86_64_Flags::Control +// +// The next 11 registers are included if 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 +// +// - uint64_t rip - included if MinidumpContext_x86_64_Flags::Control +// +// TODO: add floating point registers here + +// 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 +ConvertMinidumpContextToRegIface(llvm::ArrayRef<uint8_t> source_data, + RegisterInfoInterface *target_reg_interface); + +// For 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) +}; + +} // end namespace minidump +} // end namespace lldb_private +#endif // liblldb_RegisterContextMinidump_h_ Modified: lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp?rev=282529&r1=282528&r2=282529&view=diff ============================================================================== --- lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp (original) +++ lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp Tue Sep 27 14:05:55 2016 @@ -8,8 +8,10 @@ //===----------------------------------------------------------------------===// // 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" @@ -18,6 +20,7 @@ #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" @@ -50,7 +53,7 @@ public: MinidumpParser::Create(data_sp); ASSERT_TRUE(optional_parser.hasValue()); parser.reset(new MinidumpParser(optional_parser.getValue())); - ASSERT_GT(parser->GetByteSize(), 0UL); + ASSERT_GT(parser->GetData().size(), 0UL); } llvm::SmallString<128> inputs_folder; @@ -167,3 +170,61 @@ TEST_F(MinidumpParserTest, GetPidWindows ASSERT_TRUE(pid.hasValue()); ASSERT_EQ(4440UL, pid.getValue()); } + +// Register stuff +// TODO probably split register stuff tests into different file? +#define REG_VAL(x) *(reinterpret_cast<uint64_t *>(x)) + +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->GetData().data() + + thread.thread_context.rva, + thread.thread_context.data_size); + + ArchSpec arch = parser->GetArchitecture(); + RegisterInfoInterface *reg_interface = new RegisterContextLinux_x86_64(arch); + lldb::DataBufferSP buf = + ConvertMinidumpContextToRegIface(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()) { + EXPECT_EQ(reg_values[reg_index], + REG_VAL(buf->GetBytes() + reg_info[reg_index].byte_offset)); + } + } +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits