[Lldb-commits] [lldb] r282529 - Adding a RegisterContextMinidump_x86_64 converter

Dimitar Vlahovski via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 27 12:05:55 PDT 2016


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> &reg_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 &reg) {
+  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));
+    }
+  }
+}




More information about the lldb-commits mailing list