1//===-- RegisterContextOpenBSDKernel_x86_64.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#if defined(__OpenBSD__)
10#include <sys/types.h>
11#include <sys/time.h>
12#define _KERNEL
13#include <machine/cpu.h>
14#undef _KERNEL
15#include <machine/pcb.h>
16#include <frame.h>
17#endif
18
19#include "RegisterContextOpenBSDKernel_x86_64.h"
20
21#include "lldb/Target/Process.h"
22#include "lldb/Target/Thread.h"
23#include "lldb/Utility/RegisterValue.h"
24#include "llvm/Support/Endian.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29RegisterContextOpenBSDKernel_x86_64::RegisterContextOpenBSDKernel_x86_64(
30    Thread &thread, RegisterInfoInterface *register_info,
31    lldb::addr_t pcb)
32  : RegisterContextPOSIX_x86(thread, 0, register_info),
33    m_pcb_addr(pcb) {
34}
35
36bool RegisterContextOpenBSDKernel_x86_64::ReadGPR() { return true; }
37
38bool RegisterContextOpenBSDKernel_x86_64::ReadFPR() { return true; }
39
40bool RegisterContextOpenBSDKernel_x86_64::WriteGPR() {
41  assert(0);
42  return false;
43}
44
45bool RegisterContextOpenBSDKernel_x86_64::WriteFPR() {
46  assert(0);
47  return false;
48}
49
50bool RegisterContextOpenBSDKernel_x86_64::ReadRegister(
51    const RegisterInfo *reg_info, RegisterValue &value) {
52  Status error;
53
54  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
55    return false;
56
57#ifdef __amd64__
58  struct pcb pcb;
59  size_t rd = m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb),
60						error);
61  if (rd != sizeof(pcb))
62    return false;
63
64  /*
65    Usually pcb is written in `cpu_switchto` function. This function writes
66    registers as same as the structure of  `swichframe`  in the stack.
67    We read the frame if it is.
68   */
69  struct switchframe sf;
70  rd = m_thread.GetProcess()->ReadMemory(pcb.pcb_rsp, &sf, sizeof(sf), error);
71  if (rd != sizeof(sf))
72    return false;
73
74  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
75  if (pcb.pcb_rbp == (u_int64_t)sf.sf_rbp) {
76#define SFREG(x)				\
77    case lldb_##x##_x86_64:			\
78      value = (u_int64_t)sf.sf_##x;		\
79      return true;
80#define PCBREG(x)				\
81    case lldb_##x##_x86_64:			\
82      value = pcb.pcb_##x;			\
83      return true;
84    switch (reg) {
85      SFREG(r15);
86      SFREG(r14);
87      SFREG(r13);
88      SFREG(r12);
89      SFREG(rbp);
90      SFREG(rbx);
91      SFREG(rip);
92      PCBREG(rsp);
93    }
94  } else {
95    switch (reg) {
96      PCBREG(rbp);
97      PCBREG(rsp);
98    case lldb_rip_x86_64:
99      value = m_thread.GetProcess()->ReadPointerFromMemory(pcb.pcb_rbp + 8,
100							   error);
101      return true;
102    }
103  }
104#endif
105  return false;
106}
107
108bool RegisterContextOpenBSDKernel_x86_64::WriteRegister(
109    const RegisterInfo *reg_info, const RegisterValue &value) {
110  return false;
111}
112