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 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 RegisterContextOpenBSDKernel_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 
36 bool RegisterContextOpenBSDKernel_x86_64::ReadGPR() { return true; }
37 
38 bool RegisterContextOpenBSDKernel_x86_64::ReadFPR() { return true; }
39 
40 bool RegisterContextOpenBSDKernel_x86_64::WriteGPR() {
41   assert(0);
42   return false;
43 }
44 
45 bool RegisterContextOpenBSDKernel_x86_64::WriteFPR() {
46   assert(0);
47   return false;
48 }
49 
50 bool 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 
108 bool RegisterContextOpenBSDKernel_x86_64::WriteRegister(
109     const RegisterInfo *reg_info, const RegisterValue &value) {
110   return false;
111 }
112