Skip to content

Commit

Permalink
Adding a RegisterContextMinidump_x86_64 converter
Browse files Browse the repository at this point in the history
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

llvm-svn: 282529
  • Loading branch information
dvlahovski committed Sep 27, 2016
1 parent 5a751c6 commit 4c31907
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 6 deletions.
11 changes: 11 additions & 0 deletions lldb/include/lldb/lldb-private-types.h
Expand Up @@ -14,6 +14,8 @@

#include "lldb/lldb-private.h"

#include "llvm/ADT/ArrayRef.h"

namespace llvm {
namespace sys {
class DynamicLibrary;
Expand Down Expand Up @@ -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);
}
};

//----------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/Process/minidump/CMakeLists.txt
Expand Up @@ -3,4 +3,5 @@ include_directories(../Utility)
add_lldb_library(lldbPluginProcessMinidump
MinidumpTypes.cpp
MinidumpParser.cpp
RegisterContextMinidump_x86_64.cpp
)
5 changes: 3 additions & 2 deletions lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
Expand Up @@ -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>
Expand Down
6 changes: 3 additions & 3 deletions lldb/source/Plugins/Process/minidump/MinidumpParser.h
Expand Up @@ -39,7 +39,7 @@ class MinidumpParser {
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);

Expand Down Expand Up @@ -71,6 +71,6 @@ class MinidumpParser {
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map);
};

} // namespace minidump
} // namespace lldb_private
} // end namespace minidump
} // end namespace lldb_private
#endif // liblldb_MinidumpParser_h_
@@ -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;
}
119 changes: 119 additions & 0 deletions lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
@@ -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_

0 comments on commit 4c31907

Please sign in to comment.