1 //===-- NativeRegisterContextLinux_mips64.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(__mips__)
10 
11 #include "NativeRegisterContextLinux_mips64.h"
12 
13 
14 #include "Plugins/Process/Linux/NativeProcessLinux.h"
15 #include "Plugins/Process/Linux/Procfs.h"
16 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
17 #include "Plugins/Process/Utility/RegisterContextLinux_mips.h"
18 #include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
19 #include "lldb/Core/EmulateInstruction.h"
20 #include "lldb/Host/Host.h"
21 #include "lldb/Host/HostInfo.h"
22 #include "lldb/Utility/DataBufferHeap.h"
23 #include "lldb/Utility/LLDBAssert.h"
24 #include "lldb/Utility/Log.h"
25 #include "lldb/Utility/RegisterValue.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/lldb-enumerations.h"
28 #include "lldb/lldb-private-enumerations.h"
29 #define NT_MIPS_MSA 0x600
30 #define CONFIG5_FRE (1 << 8)
31 #define SR_FR (1 << 26)
32 #define NUM_REGISTERS 32
33 
34 #include <asm/ptrace.h>
35 #include <sys/ptrace.h>
36 
37 #ifndef PTRACE_GET_WATCH_REGS
38 enum pt_watch_style { pt_watch_style_mips32, pt_watch_style_mips64 };
39 struct mips32_watch_regs {
40   uint32_t watchlo[8];
41   uint16_t watchhi[8];
42   uint16_t watch_masks[8];
43   uint32_t num_valid;
44 } __attribute__((aligned(8)));
45 
46 struct mips64_watch_regs {
47   uint64_t watchlo[8];
48   uint16_t watchhi[8];
49   uint16_t watch_masks[8];
50   uint32_t num_valid;
51 } __attribute__((aligned(8)));
52 
53 struct pt_watch_regs {
54   enum pt_watch_style style;
55   union {
56     struct mips32_watch_regs mips32;
57     struct mips64_watch_regs mips64;
58   };
59 };
60 
61 #define PTRACE_GET_WATCH_REGS 0xd0
62 #define PTRACE_SET_WATCH_REGS 0xd1
63 #endif
64 
65 #define W (1 << 0)
66 #define R (1 << 1)
67 #define I (1 << 2)
68 
69 #define IRW (I | R | W)
70 
71 #ifndef PTRACE_GETREGSET
72 #define PTRACE_GETREGSET 0x4204
73 #endif
74 struct pt_watch_regs default_watch_regs;
75 
76 using namespace lldb_private;
77 using namespace lldb_private::process_linux;
78 
79 std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)80 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
81     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
82   return std::make_unique<NativeRegisterContextLinux_mips64>(target_arch,
83                                                               native_thread);
84 }
85 
86 #define REG_CONTEXT_SIZE                                                       \
87   (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR_linux_mips) +          \
88    sizeof(MSA_linux_mips))
89 
90 // NativeRegisterContextLinux_mips64 members.
91 
92 static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)93 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
94   if ((target_arch.GetMachine() == llvm::Triple::mips) ||
95        (target_arch.GetMachine() == llvm::Triple::mipsel)) {
96     // 32-bit hosts run with a RegisterContextLinux_mips context.
97     return new RegisterContextLinux_mips(
98         target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable());
99   } else {
100     return new RegisterContextLinux_mips64(
101         target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable());
102   }
103 }
104 
NativeRegisterContextLinux_mips64(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)105 NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64(
106     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
107     : NativeRegisterContextRegisterInfo(
108           native_thread, CreateRegisterInfoInterface(target_arch)) {
109   switch (target_arch.GetMachine()) {
110   case llvm::Triple::mips:
111   case llvm::Triple::mipsel:
112     m_reg_info.num_registers = k_num_registers_mips;
113     m_reg_info.num_gpr_registers = k_num_gpr_registers_mips;
114     m_reg_info.num_fpr_registers = k_num_fpr_registers_mips;
115     m_reg_info.last_gpr = k_last_gpr_mips;
116     m_reg_info.first_fpr = k_first_fpr_mips;
117     m_reg_info.last_fpr = k_last_fpr_mips;
118     m_reg_info.first_msa = k_first_msa_mips;
119     m_reg_info.last_msa = k_last_msa_mips;
120     break;
121   case llvm::Triple::mips64:
122   case llvm::Triple::mips64el:
123     m_reg_info.num_registers = k_num_registers_mips64;
124     m_reg_info.num_gpr_registers = k_num_gpr_registers_mips64;
125     m_reg_info.num_fpr_registers = k_num_fpr_registers_mips64;
126     m_reg_info.last_gpr = k_last_gpr_mips64;
127     m_reg_info.first_fpr = k_first_fpr_mips64;
128     m_reg_info.last_fpr = k_last_fpr_mips64;
129     m_reg_info.first_msa = k_first_msa_mips64;
130     m_reg_info.last_msa = k_last_msa_mips64;
131     break;
132   default:
133     assert(false && "Unhandled target architecture.");
134     break;
135   }
136 
137   // Initialize m_iovec to point to the buffer and buffer size using the
138   // conventions of Berkeley style UIO structures, as required by PTRACE
139   // extensions.
140   m_iovec.iov_base = &m_msa;
141   m_iovec.iov_len = sizeof(MSA_linux_mips);
142 
143   // init h/w watchpoint addr map
144   for (int index = 0; index <= MAX_NUM_WP; index++)
145     hw_addr_map[index] = LLDB_INVALID_ADDRESS;
146 
147   ::memset(&m_gpr, 0, sizeof(GPR_linux_mips));
148   ::memset(&m_fpr, 0, sizeof(FPR_linux_mips));
149   ::memset(&m_msa, 0, sizeof(MSA_linux_mips));
150 }
151 
GetRegisterSetCount() const152 uint32_t NativeRegisterContextLinux_mips64::GetRegisterSetCount() const {
153   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
154   case llvm::Triple::mips64:
155   case llvm::Triple::mips64el: {
156     const auto context = static_cast<const RegisterContextLinux_mips64 &>
157                          (GetRegisterInfoInterface());
158     return context.GetRegisterSetCount();
159   }
160   case llvm::Triple::mips:
161   case llvm::Triple::mipsel: {
162     const auto context = static_cast<const RegisterContextLinux_mips &>
163                          (GetRegisterInfoInterface());
164     return context.GetRegisterSetCount();
165   }
166   default:
167     llvm_unreachable("Unhandled target architecture.");
168   }
169 }
170 
GetPCfromBreakpointLocation(lldb::addr_t fail_value)171 lldb::addr_t NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation(
172     lldb::addr_t fail_value) {
173   Status error;
174   RegisterValue pc_value;
175   lldb::addr_t pc = fail_value;
176   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
177   LLDB_LOG(log, "Reading PC from breakpoint location");
178 
179   // PC register is at index 34 of the register array
180   const RegisterInfo *const pc_info_p = GetRegisterInfoAtIndex(gpr_pc_mips64);
181 
182   error = ReadRegister(pc_info_p, pc_value);
183   if (error.Success()) {
184     pc = pc_value.GetAsUInt64();
185 
186     // CAUSE register is at index 37 of the register array
187     const RegisterInfo *const cause_info_p =
188         GetRegisterInfoAtIndex(gpr_cause_mips64);
189     RegisterValue cause_value;
190 
191     ReadRegister(cause_info_p, cause_value);
192 
193     uint64_t cause = cause_value.GetAsUInt64();
194     LLDB_LOG(log, "PC {0:x} cause {1:x}", pc, cause);
195 
196     /*
197      * The breakpoint might be in a delay slot. In this case PC points
198      * to the delayed branch instruction rather then the instruction
199      * in the delay slot. If the CAUSE.BD flag is set then adjust the
200      * PC based on the size of the branch instruction.
201     */
202     if ((cause & (1 << 31)) != 0) {
203       lldb::addr_t branch_delay = 0;
204       branch_delay =
205           4; // FIXME - Adjust according to size of branch instruction at PC
206       pc = pc + branch_delay;
207       pc_value.SetUInt64(pc);
208       WriteRegister(pc_info_p, pc_value);
209       LLDB_LOG(log, "New PC {0:x}", pc);
210     }
211   }
212 
213   return pc;
214 }
215 
216 const RegisterSet *
GetRegisterSet(uint32_t set_index) const217 NativeRegisterContextLinux_mips64::GetRegisterSet(uint32_t set_index) const {
218   if (set_index >= GetRegisterSetCount())
219     return nullptr;
220 
221   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
222   case llvm::Triple::mips64:
223   case llvm::Triple::mips64el: {
224     const auto context = static_cast<const RegisterContextLinux_mips64 &>
225                           (GetRegisterInfoInterface());
226     return context.GetRegisterSet(set_index);
227   }
228   case llvm::Triple::mips:
229   case llvm::Triple::mipsel: {
230     const auto context = static_cast<const RegisterContextLinux_mips &>
231                          (GetRegisterInfoInterface());
232     return context.GetRegisterSet(set_index);
233   }
234   default:
235     llvm_unreachable("Unhandled target architecture.");
236   }
237 }
238 
239 lldb_private::Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)240 NativeRegisterContextLinux_mips64::ReadRegister(const RegisterInfo *reg_info,
241                                                 RegisterValue &reg_value) {
242   Status error;
243 
244   if (!reg_info) {
245     error.SetErrorString("reg_info NULL");
246     return error;
247   }
248 
249   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
250   uint8_t byte_size = reg_info->byte_size;
251   if (reg == LLDB_INVALID_REGNUM) {
252     // This is likely an internal register for lldb use only and should not be
253     // directly queried.
254     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
255                                    "register, cannot read directly",
256                                    reg_info->name);
257     return error;
258   }
259 
260   if (IsMSA(reg) && !IsMSAAvailable()) {
261     error.SetErrorString("MSA not available on this processor");
262     return error;
263   }
264 
265   if (IsMSA(reg) || IsFPR(reg)) {
266     uint8_t *src = nullptr;
267     lldbassert(reg_info->byte_offset < sizeof(UserArea));
268 
269     error = ReadCP1();
270 
271     if (!error.Success()) {
272       error.SetErrorString("failed to read co-processor 1 register");
273       return error;
274     }
275 
276     if (IsFPR(reg)) {
277       if (IsFR0() && (byte_size != 4)) {
278         byte_size = 4;
279         uint8_t ptrace_index;
280         ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin];
281         src = ReturnFPOffset(ptrace_index, reg_info->byte_offset);
282       } else
283         src = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr);
284     } else
285       src = (uint8_t *)&m_msa + reg_info->byte_offset -
286             (sizeof(m_gpr) + sizeof(m_fpr));
287     switch (byte_size) {
288     case 4:
289       reg_value.SetUInt32(*(uint32_t *)src);
290       break;
291     case 8:
292       reg_value.SetUInt64(*(uint64_t *)src);
293       break;
294     case 16:
295       reg_value.SetBytes((const void *)src, 16, GetByteOrder());
296       break;
297     default:
298       assert(false && "Unhandled data size.");
299       error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
300                                      reg_info->byte_size);
301       break;
302     }
303   } else {
304     error = ReadRegisterRaw(reg, reg_value);
305   }
306 
307   return error;
308 }
309 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)310 lldb_private::Status NativeRegisterContextLinux_mips64::WriteRegister(
311     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
312   Status error;
313 
314   assert(reg_info && "reg_info is null");
315 
316   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
317 
318   if (reg_index == LLDB_INVALID_REGNUM)
319     return Status("no lldb regnum for %s", reg_info && reg_info->name
320                                                ? reg_info->name
321                                                : "<unknown register>");
322 
323   if (IsMSA(reg_index) && !IsMSAAvailable()) {
324     error.SetErrorString("MSA not available on this processor");
325     return error;
326   }
327 
328   if (IsFPR(reg_index) || IsMSA(reg_index)) {
329     uint8_t *dst = nullptr;
330     uint64_t *src = nullptr;
331     uint8_t byte_size = reg_info->byte_size;
332     lldbassert(reg_info->byte_offset < sizeof(UserArea));
333 
334     // Initialise the FP and MSA buffers by reading all co-processor 1
335     // registers
336     ReadCP1();
337 
338     if (IsFPR(reg_index)) {
339       if (IsFR0() && (byte_size != 4)) {
340         byte_size = 4;
341         uint8_t ptrace_index;
342         ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin];
343         dst = ReturnFPOffset(ptrace_index, reg_info->byte_offset);
344       } else
345         dst = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr);
346     } else
347       dst = (uint8_t *)&m_msa + reg_info->byte_offset -
348             (sizeof(m_gpr) + sizeof(m_fpr));
349     switch (byte_size) {
350     case 4:
351       *(uint32_t *)dst = reg_value.GetAsUInt32();
352       break;
353     case 8:
354       *(uint64_t *)dst = reg_value.GetAsUInt64();
355       break;
356     case 16:
357       src = (uint64_t *)reg_value.GetBytes();
358       *(uint64_t *)dst = *src;
359       *(uint64_t *)(dst + 8) = *(src + 1);
360       break;
361     default:
362       assert(false && "Unhandled data size.");
363       error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
364                                      reg_info->byte_size);
365       break;
366     }
367     error = WriteCP1();
368     if (!error.Success()) {
369       error.SetErrorString("failed to write co-processor 1 register");
370       return error;
371     }
372   } else {
373     error = WriteRegisterRaw(reg_index, reg_value);
374   }
375 
376   return error;
377 }
378 
ReadAllRegisterValues(lldb::DataBufferSP & data_sp)379 Status NativeRegisterContextLinux_mips64::ReadAllRegisterValues(
380     lldb::DataBufferSP &data_sp) {
381   Status error;
382 
383   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
384   error = ReadGPR();
385   if (!error.Success()) {
386     error.SetErrorString("ReadGPR() failed");
387     return error;
388   }
389 
390   error = ReadCP1();
391   if (!error.Success()) {
392     error.SetErrorString("ReadCP1() failed");
393     return error;
394   }
395 
396   uint8_t *dst = data_sp->GetBytes();
397   ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize());
398   dst += GetRegisterInfoInterface().GetGPRSize();
399 
400   ::memcpy(dst, &m_fpr, GetFPRSize());
401   dst += GetFPRSize();
402 
403   ::memcpy(dst, &m_msa, sizeof(MSA_linux_mips));
404 
405   return error;
406 }
407 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)408 Status NativeRegisterContextLinux_mips64::WriteAllRegisterValues(
409     const lldb::DataBufferSP &data_sp) {
410   Status error;
411 
412   if (!data_sp) {
413     error.SetErrorStringWithFormat(
414         "NativeRegisterContextLinux_mips64::%s invalid data_sp provided",
415         __FUNCTION__);
416     return error;
417   }
418 
419   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
420     error.SetErrorStringWithFormat(
421         "NativeRegisterContextLinux_mips64::%s data_sp contained mismatched "
422         "data size, expected %" PRIu64 ", actual %" PRIu64,
423         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
424     return error;
425   }
426 
427   uint8_t *src = data_sp->GetBytes();
428   if (src == nullptr) {
429     error.SetErrorStringWithFormat("NativeRegisterContextLinux_mips64::%s "
430                                    "DataBuffer::GetBytes() returned a null "
431                                    "pointer",
432                                    __FUNCTION__);
433     return error;
434   }
435 
436   ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize());
437   src += GetRegisterInfoInterface().GetGPRSize();
438 
439   ::memcpy(&m_fpr, src, GetFPRSize());
440   src += GetFPRSize();
441 
442   ::memcpy(&m_msa, src, sizeof(MSA_linux_mips));
443 
444   error = WriteGPR();
445   if (!error.Success()) {
446     error.SetErrorStringWithFormat(
447         "NativeRegisterContextLinux_mips64::%s WriteGPR() failed",
448         __FUNCTION__);
449     return error;
450   }
451 
452   error = WriteCP1();
453   if (!error.Success()) {
454     error.SetErrorStringWithFormat(
455         "NativeRegisterContextLinux_mips64::%s WriteCP1() failed",
456         __FUNCTION__);
457     return error;
458   }
459 
460   return error;
461 }
462 
ReadCP1()463 Status NativeRegisterContextLinux_mips64::ReadCP1() {
464   Status error;
465 
466   uint8_t *src = nullptr;
467   uint8_t *dst = nullptr;
468 
469   lldb::ByteOrder byte_order = GetByteOrder();
470 
471   bool IsBigEndian = (byte_order == lldb::eByteOrderBig);
472 
473   if (IsMSAAvailable()) {
474     error = NativeRegisterContextLinux::ReadRegisterSet(
475         &m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA);
476     src = (uint8_t *)&m_msa + (IsBigEndian * 8);
477     dst = (uint8_t *)&m_fpr;
478     for (int i = 0; i < NUM_REGISTERS; i++) {
479       // Copy fp values from msa buffer fetched via ptrace
480       *(uint64_t *)dst = *(uint64_t *)src;
481       src = src + 16;
482       dst = dst + 8;
483     }
484     m_fpr.fir = m_msa.fir;
485     m_fpr.fcsr = m_msa.fcsr;
486     m_fpr.config5 = m_msa.config5;
487   } else {
488     error = NativeRegisterContextLinux::ReadFPR();
489   }
490   return error;
491 }
492 
493 uint8_t *
ReturnFPOffset(uint8_t reg_index,uint32_t byte_offset)494 NativeRegisterContextLinux_mips64::ReturnFPOffset(uint8_t reg_index,
495                                                   uint32_t byte_offset) {
496 
497   uint8_t *fp_buffer_ptr = nullptr;
498   lldb::ByteOrder byte_order = GetByteOrder();
499   bool IsBigEndian = (byte_order == lldb::eByteOrderBig);
500   if (reg_index % 2) {
501     uint8_t offset_diff = (IsBigEndian) ? 8 : 4;
502     fp_buffer_ptr =
503         (uint8_t *)&m_fpr + byte_offset - offset_diff - sizeof(m_gpr);
504   } else {
505     fp_buffer_ptr =
506         (uint8_t *)&m_fpr + byte_offset + 4 * (IsBigEndian) - sizeof(m_gpr);
507   }
508   return fp_buffer_ptr;
509 }
510 
WriteCP1()511 Status NativeRegisterContextLinux_mips64::WriteCP1() {
512   Status error;
513 
514   uint8_t *src = nullptr;
515   uint8_t *dst = nullptr;
516 
517   lldb::ByteOrder byte_order = GetByteOrder();
518 
519   bool IsBigEndian = (byte_order == lldb::eByteOrderBig);
520 
521   if (IsMSAAvailable()) {
522     dst = (uint8_t *)&m_msa + (IsBigEndian * 8);
523     src = (uint8_t *)&m_fpr;
524     for (int i = 0; i < NUM_REGISTERS; i++) {
525       // Copy fp values to msa buffer for ptrace
526       *(uint64_t *)dst = *(uint64_t *)src;
527       dst = dst + 16;
528       src = src + 8;
529     }
530     m_msa.fir = m_fpr.fir;
531     m_msa.fcsr = m_fpr.fcsr;
532     m_msa.config5 = m_fpr.config5;
533     error = NativeRegisterContextLinux::WriteRegisterSet(
534         &m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA);
535   } else {
536     error = NativeRegisterContextLinux::WriteFPR();
537   }
538 
539   return error;
540 }
541 
IsFR0()542 bool NativeRegisterContextLinux_mips64::IsFR0() {
543   const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex(gpr_sr_mips64);
544 
545   RegisterValue reg_value;
546   ReadRegister(reg_info_p, reg_value);
547 
548   uint64_t value = reg_value.GetAsUInt64();
549 
550   return (!(value & SR_FR));
551 }
552 
IsFRE()553 bool NativeRegisterContextLinux_mips64::IsFRE() {
554   const RegisterInfo *const reg_info_p =
555       GetRegisterInfoAtIndex(gpr_config5_mips64);
556 
557   RegisterValue reg_value;
558   ReadRegister(reg_info_p, reg_value);
559 
560   uint64_t config5 = reg_value.GetAsUInt64();
561 
562   return (config5 & CONFIG5_FRE);
563 }
564 
IsFPR(uint32_t reg_index) const565 bool NativeRegisterContextLinux_mips64::IsFPR(uint32_t reg_index) const {
566   return (m_reg_info.first_fpr <= reg_index &&
567           reg_index <= m_reg_info.last_fpr);
568 }
569 
GetWatchHi(struct pt_watch_regs * regs,uint32_t index)570 static uint32_t GetWatchHi(struct pt_watch_regs *regs, uint32_t index) {
571   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
572   if (regs->style == pt_watch_style_mips32)
573     return regs->mips32.watchhi[index];
574   else if (regs->style == pt_watch_style_mips64)
575     return regs->mips64.watchhi[index];
576   LLDB_LOG(log, "Invalid watch register style");
577   return 0;
578 }
579 
SetWatchHi(struct pt_watch_regs * regs,uint32_t index,uint16_t value)580 static void SetWatchHi(struct pt_watch_regs *regs, uint32_t index,
581                        uint16_t value) {
582   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
583   if (regs->style == pt_watch_style_mips32)
584     regs->mips32.watchhi[index] = value;
585   else if (regs->style == pt_watch_style_mips64)
586     regs->mips64.watchhi[index] = value;
587   LLDB_LOG(log, "Invalid watch register style");
588   return;
589 }
590 
GetWatchLo(struct pt_watch_regs * regs,uint32_t index)591 static lldb::addr_t GetWatchLo(struct pt_watch_regs *regs, uint32_t index) {
592   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
593   if (regs->style == pt_watch_style_mips32)
594     return regs->mips32.watchlo[index];
595   else if (regs->style == pt_watch_style_mips64)
596     return regs->mips64.watchlo[index];
597   LLDB_LOG(log, "Invalid watch register style");
598   return LLDB_INVALID_ADDRESS;
599 }
600 
SetWatchLo(struct pt_watch_regs * regs,uint32_t index,uint64_t value)601 static void SetWatchLo(struct pt_watch_regs *regs, uint32_t index,
602                        uint64_t value) {
603   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
604   if (regs->style == pt_watch_style_mips32)
605     regs->mips32.watchlo[index] = (uint32_t)value;
606   else if (regs->style == pt_watch_style_mips64)
607     regs->mips64.watchlo[index] = value;
608   else
609     LLDB_LOG(log, "Invalid watch register style");
610 }
611 
GetIRWMask(struct pt_watch_regs * regs,uint32_t index)612 static uint32_t GetIRWMask(struct pt_watch_regs *regs, uint32_t index) {
613   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
614   if (regs->style == pt_watch_style_mips32)
615     return regs->mips32.watch_masks[index] & IRW;
616   else if (regs->style == pt_watch_style_mips64)
617     return regs->mips64.watch_masks[index] & IRW;
618   LLDB_LOG(log, "Invalid watch register style");
619   return 0;
620 }
621 
GetRegMask(struct pt_watch_regs * regs,uint32_t index)622 static uint32_t GetRegMask(struct pt_watch_regs *regs, uint32_t index) {
623   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
624   if (regs->style == pt_watch_style_mips32)
625     return regs->mips32.watch_masks[index] & ~IRW;
626   else if (regs->style == pt_watch_style_mips64)
627     return regs->mips64.watch_masks[index] & ~IRW;
628   LLDB_LOG(log, "Invalid watch register style");
629   return 0;
630 }
631 
GetRangeMask(lldb::addr_t mask)632 static lldb::addr_t GetRangeMask(lldb::addr_t mask) {
633   lldb::addr_t mask_bit = 1;
634   while (mask_bit < mask) {
635     mask = mask | mask_bit;
636     mask_bit <<= 1;
637   }
638   return mask;
639 }
640 
GetVacantWatchIndex(struct pt_watch_regs * regs,lldb::addr_t addr,uint32_t size,uint32_t irw,uint32_t num_valid)641 static int GetVacantWatchIndex(struct pt_watch_regs *regs, lldb::addr_t addr,
642                                uint32_t size, uint32_t irw,
643                                uint32_t num_valid) {
644   lldb::addr_t last_byte = addr + size - 1;
645   lldb::addr_t mask = GetRangeMask(addr ^ last_byte) | IRW;
646   lldb::addr_t base_addr = addr & ~mask;
647 
648   // Check if this address is already watched by previous watch points.
649   lldb::addr_t lo;
650   uint16_t hi;
651   uint32_t vacant_watches = 0;
652   for (uint32_t index = 0; index < num_valid; index++) {
653     lo = GetWatchLo(regs, index);
654     if (lo != 0 && irw == ((uint32_t)lo & irw)) {
655       hi = GetWatchHi(regs, index) | IRW;
656       lo &= ~(lldb::addr_t)hi;
657       if (addr >= lo && last_byte <= (lo + hi))
658         return index;
659     } else
660       vacant_watches++;
661   }
662 
663   // Now try to find a vacant index
664   if (vacant_watches > 0) {
665     vacant_watches = 0;
666     for (uint32_t index = 0; index < num_valid; index++) {
667       lo = GetWatchLo(regs, index);
668       if (lo == 0 && irw == (GetIRWMask(regs, index) & irw)) {
669         if (mask <= (GetRegMask(regs, index) | IRW)) {
670           // It fits, we can use it.
671           SetWatchLo(regs, index, base_addr | irw);
672           SetWatchHi(regs, index, mask & ~IRW);
673           return index;
674         } else {
675           // It doesn't fit, but has the proper IRW capabilities
676           vacant_watches++;
677         }
678       }
679     }
680 
681     if (vacant_watches > 1) {
682       // Split this watchpoint across several registers
683       struct pt_watch_regs regs_copy;
684       regs_copy = *regs;
685       lldb::addr_t break_addr;
686       uint32_t segment_size;
687       for (uint32_t index = 0; index < num_valid; index++) {
688         lo = GetWatchLo(&regs_copy, index);
689         hi = GetRegMask(&regs_copy, index) | IRW;
690         if (lo == 0 && irw == (hi & irw)) {
691           lo = addr & ~(lldb::addr_t)hi;
692           break_addr = lo + hi + 1;
693           if (break_addr >= addr + size)
694             segment_size = size;
695           else
696             segment_size = break_addr - addr;
697           mask = GetRangeMask(addr ^ (addr + segment_size - 1));
698           SetWatchLo(&regs_copy, index, (addr & ~mask) | irw);
699           SetWatchHi(&regs_copy, index, mask & ~IRW);
700           if (break_addr >= addr + size) {
701             *regs = regs_copy;
702             return index;
703           }
704           size = addr + size - break_addr;
705           addr = break_addr;
706         }
707       }
708     }
709   }
710   return LLDB_INVALID_INDEX32;
711 }
712 
IsMSA(uint32_t reg_index) const713 bool NativeRegisterContextLinux_mips64::IsMSA(uint32_t reg_index) const {
714   return (m_reg_info.first_msa <= reg_index &&
715           reg_index <= m_reg_info.last_msa);
716 }
717 
IsMSAAvailable()718 bool NativeRegisterContextLinux_mips64::IsMSAAvailable() {
719   MSA_linux_mips msa_buf;
720   unsigned int regset = NT_MIPS_MSA;
721 
722   Status error = NativeProcessLinux::PtraceWrapper(
723       PTRACE_GETREGSET, Host::GetCurrentProcessID(),
724       static_cast<void *>(&regset), &msa_buf, sizeof(MSA_linux_mips));
725 
726   if (error.Success() && msa_buf.mir) {
727     return true;
728   }
729 
730   return false;
731 }
732 
IsWatchpointHit(uint32_t wp_index,bool & is_hit)733 Status NativeRegisterContextLinux_mips64::IsWatchpointHit(uint32_t wp_index,
734                                                           bool &is_hit) {
735   if (wp_index >= NumSupportedHardwareWatchpoints())
736     return Status("Watchpoint index out of range");
737 
738   // reading the current state of watch regs
739   struct pt_watch_regs watch_readback;
740   Status error = DoReadWatchPointRegisterValue(
741       m_thread.GetID(), static_cast<void *>(&watch_readback));
742 
743   if (GetWatchHi(&watch_readback, wp_index) & (IRW)) {
744     // clear hit flag in watchhi
745     SetWatchHi(&watch_readback, wp_index,
746                (GetWatchHi(&watch_readback, wp_index) & ~(IRW)));
747     DoWriteWatchPointRegisterValue(m_thread.GetID(),
748                                    static_cast<void *>(&watch_readback));
749 
750     is_hit = true;
751     return error;
752   }
753   is_hit = false;
754   return error;
755 }
756 
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)757 Status NativeRegisterContextLinux_mips64::GetWatchpointHitIndex(
758     uint32_t &wp_index, lldb::addr_t trap_addr) {
759   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
760   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
761     bool is_hit;
762     Status error = IsWatchpointHit(wp_index, is_hit);
763     if (error.Fail()) {
764       wp_index = LLDB_INVALID_INDEX32;
765     } else if (is_hit) {
766       return error;
767     }
768   }
769   wp_index = LLDB_INVALID_INDEX32;
770   return Status();
771 }
772 
IsWatchpointVacant(uint32_t wp_index,bool & is_vacant)773 Status NativeRegisterContextLinux_mips64::IsWatchpointVacant(uint32_t wp_index,
774                                                              bool &is_vacant) {
775   is_vacant = false;
776   return Status("MIPS TODO: "
777                 "NativeRegisterContextLinux_mips64::IsWatchpointVacant not "
778                 "implemented");
779 }
780 
ClearHardwareWatchpoint(uint32_t wp_index)781 bool NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(
782     uint32_t wp_index) {
783   if (wp_index >= NumSupportedHardwareWatchpoints())
784     return false;
785 
786   struct pt_watch_regs regs;
787   // First reading the current state of watch regs
788   DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
789 
790   if (regs.style == pt_watch_style_mips32) {
791     regs.mips32.watchlo[wp_index] = default_watch_regs.mips32.watchlo[wp_index];
792     regs.mips32.watchhi[wp_index] = default_watch_regs.mips32.watchhi[wp_index];
793     regs.mips32.watch_masks[wp_index] =
794         default_watch_regs.mips32.watch_masks[wp_index];
795   } else // pt_watch_style_mips64
796   {
797     regs.mips64.watchlo[wp_index] = default_watch_regs.mips64.watchlo[wp_index];
798     regs.mips64.watchhi[wp_index] = default_watch_regs.mips64.watchhi[wp_index];
799     regs.mips64.watch_masks[wp_index] =
800         default_watch_regs.mips64.watch_masks[wp_index];
801   }
802 
803   Status error = DoWriteWatchPointRegisterValue(m_thread.GetID(),
804                                                 static_cast<void *>(&regs));
805   if (!error.Fail()) {
806     hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS;
807     return true;
808   }
809   return false;
810 }
811 
ClearAllHardwareWatchpoints()812 Status NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints() {
813   return DoWriteWatchPointRegisterValue(
814       m_thread.GetID(), static_cast<void *>(&default_watch_regs));
815 }
816 
SetHardwareWatchpointWithIndex(lldb::addr_t addr,size_t size,uint32_t watch_flags,uint32_t wp_index)817 Status NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex(
818     lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
819   Status error;
820   error.SetErrorString("MIPS TODO: "
821                        "NativeRegisterContextLinux_mips64::"
822                        "SetHardwareWatchpointWithIndex not implemented");
823   return error;
824 }
825 
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)826 uint32_t NativeRegisterContextLinux_mips64::SetHardwareWatchpoint(
827     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
828   struct pt_watch_regs regs;
829 
830   // First reading the current state of watch regs
831   DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
832 
833   // Try if a new watch point fits in this state
834   int index = GetVacantWatchIndex(&regs, addr, size, watch_flags,
835                                   NumSupportedHardwareWatchpoints());
836 
837   // New watchpoint doesn't fit
838   if (index == LLDB_INVALID_INDEX32)
839     return LLDB_INVALID_INDEX32;
840 
841   // It fits, so we go ahead with updating the state of watch regs
842   DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
843 
844   // Storing exact address
845   hw_addr_map[index] = addr;
846   return index;
847 }
848 
849 lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)850 NativeRegisterContextLinux_mips64::GetWatchpointAddress(uint32_t wp_index) {
851   if (wp_index >= NumSupportedHardwareWatchpoints())
852     return LLDB_INVALID_ADDRESS;
853 
854   return hw_addr_map[wp_index];
855 }
856 
857 struct EmulatorBaton {
858   lldb::addr_t m_watch_hit_addr;
859   NativeProcessLinux *m_process;
860   NativeRegisterContext *m_reg_context;
861 
EmulatorBatonEmulatorBaton862   EmulatorBaton(NativeProcessLinux *process, NativeRegisterContext *reg_context)
863       : m_watch_hit_addr(LLDB_INVALID_ADDRESS), m_process(process),
864         m_reg_context(reg_context) {}
865 };
866 
ReadMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,void * dst,size_t length)867 static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
868                                  const EmulateInstruction::Context &context,
869                                  lldb::addr_t addr, void *dst, size_t length) {
870   size_t bytes_read;
871   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
872   emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
873   return bytes_read;
874 }
875 
WriteMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t length)876 static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
877                                   const EmulateInstruction::Context &context,
878                                   lldb::addr_t addr, const void *dst,
879                                   size_t length) {
880   return length;
881 }
882 
ReadRegisterCallback(EmulateInstruction * instruction,void * baton,const RegisterInfo * reg_info,RegisterValue & reg_value)883 static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
884                                  const RegisterInfo *reg_info,
885                                  RegisterValue &reg_value) {
886   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
887 
888   const RegisterInfo *full_reg_info =
889       emulator_baton->m_reg_context->GetRegisterInfo(
890           lldb::eRegisterKindDWARF, reg_info->kinds[lldb::eRegisterKindDWARF]);
891 
892   Status error =
893       emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
894   if (error.Success())
895     return true;
896 
897   return false;
898 }
899 
WriteRegisterCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,const RegisterInfo * reg_info,const RegisterValue & reg_value)900 static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
901                                   const EmulateInstruction::Context &context,
902                                   const RegisterInfo *reg_info,
903                                   const RegisterValue &reg_value) {
904   if (reg_info->kinds[lldb::eRegisterKindDWARF] == dwarf_bad_mips64) {
905     EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
906     emulator_baton->m_watch_hit_addr = reg_value.GetAsUInt64();
907   }
908 
909   return true;
910 }
911 
912 /*
913  * MIPS Linux kernel returns a masked address (last 3bits are masked)
914  * when a HW watchpoint is hit. However user may not have set a watchpoint
915  * on this address. Emulate instruction at PC and find the base address of
916  * the load/store instruction. This will give the exact address used to
917  * read/write the variable. Send this exact address to client so that
918  * it can decide to stop or continue the thread.
919 */
920 lldb::addr_t
GetWatchpointHitAddress(uint32_t wp_index)921 NativeRegisterContextLinux_mips64::GetWatchpointHitAddress(uint32_t wp_index) {
922   if (wp_index >= NumSupportedHardwareWatchpoints())
923     return LLDB_INVALID_ADDRESS;
924 
925   lldb_private::ArchSpec arch;
926   arch = GetRegisterInfoInterface().GetTargetArchitecture();
927   std::unique_ptr<EmulateInstruction> emulator_up(
928       EmulateInstruction::FindPlugin(arch, lldb_private::eInstructionTypeAny,
929                                      nullptr));
930 
931   if (emulator_up == nullptr)
932     return LLDB_INVALID_ADDRESS;
933 
934   EmulatorBaton baton(
935       static_cast<NativeProcessLinux *>(&m_thread.GetProcess()), this);
936   emulator_up->SetBaton(&baton);
937   emulator_up->SetReadMemCallback(&ReadMemoryCallback);
938   emulator_up->SetReadRegCallback(&ReadRegisterCallback);
939   emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
940   emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
941 
942   if (!emulator_up->ReadInstruction())
943     return LLDB_INVALID_ADDRESS;
944 
945   if (emulator_up->EvaluateInstruction(lldb::eEmulateInstructionOptionNone))
946     return baton.m_watch_hit_addr;
947 
948   return LLDB_INVALID_ADDRESS;
949 }
950 
NumSupportedHardwareWatchpoints()951 uint32_t NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints() {
952   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
953   struct pt_watch_regs regs;
954   static int num_valid = 0;
955   if (!num_valid) {
956     DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&regs));
957     default_watch_regs =
958         regs; // Keeping default watch regs values for future use
959     switch (regs.style) {
960     case pt_watch_style_mips32:
961       num_valid = regs.mips32.num_valid; // Using num_valid as cache
962       return num_valid;
963     case pt_watch_style_mips64:
964       num_valid = regs.mips64.num_valid;
965       return num_valid;
966     }
967     LLDB_LOG(log, "Invalid watch register style");
968     return 0;
969   }
970   return num_valid;
971 }
972 
973 Status
ReadRegisterRaw(uint32_t reg_index,RegisterValue & value)974 NativeRegisterContextLinux_mips64::ReadRegisterRaw(uint32_t reg_index,
975                                                    RegisterValue &value) {
976   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
977 
978   if (!reg_info)
979     return Status("register %" PRIu32 " not found", reg_index);
980 
981   uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin];
982 
983   if ((offset == ptrace_sr_mips) || (offset == ptrace_config5_mips))
984     return Read_SR_Config(reg_info->byte_offset, reg_info->name,
985                           reg_info->byte_size, value);
986 
987   return DoReadRegisterValue(offset, reg_info->name, reg_info->byte_size,
988                              value);
989 }
990 
WriteRegisterRaw(uint32_t reg_index,const RegisterValue & value)991 Status NativeRegisterContextLinux_mips64::WriteRegisterRaw(
992     uint32_t reg_index, const RegisterValue &value) {
993   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
994 
995   if (!reg_info)
996     return Status("register %" PRIu32 " not found", reg_index);
997 
998   if (reg_info->invalidate_regs)
999     lldbassert(false && "reg_info->invalidate_regs is unhandled");
1000 
1001   uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin];
1002   return DoWriteRegisterValue(offset, reg_info->name, value);
1003 }
1004 
Read_SR_Config(uint32_t offset,const char * reg_name,uint32_t size,RegisterValue & value)1005 Status NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset,
1006                                                          const char *reg_name,
1007                                                          uint32_t size,
1008                                                          RegisterValue &value) {
1009   GPR_linux_mips regs;
1010   ::memset(&regs, 0, sizeof(GPR_linux_mips));
1011 
1012   Status error = NativeProcessLinux::PtraceWrapper(
1013       PTRACE_GETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
1014   if (error.Success()) {
1015     const lldb_private::ArchSpec &arch =
1016         m_thread.GetProcess().GetArchitecture();
1017     void *target_address = ((uint8_t *)&regs) + offset +
1018                            4 * (arch.GetMachine() == llvm::Triple::mips);
1019     value.SetUInt(*(uint32_t *)target_address, size);
1020   }
1021   return error;
1022 }
1023 
DoReadWatchPointRegisterValue(lldb::tid_t tid,void * watch_readback)1024 Status NativeRegisterContextLinux_mips64::DoReadWatchPointRegisterValue(
1025     lldb::tid_t tid, void *watch_readback) {
1026   return NativeProcessLinux::PtraceWrapper(PTRACE_GET_WATCH_REGS,
1027                                            m_thread.GetID(), watch_readback);
1028 }
1029 
DoWriteWatchPointRegisterValue(lldb::tid_t tid,void * watch_reg_value)1030 Status NativeRegisterContextLinux_mips64::DoWriteWatchPointRegisterValue(
1031     lldb::tid_t tid, void *watch_reg_value) {
1032   return NativeProcessLinux::PtraceWrapper(PTRACE_SET_WATCH_REGS,
1033                                            m_thread.GetID(), watch_reg_value);
1034 }
1035 
1036 #endif // defined (__mips__)
1037