Fetch the NT_ARM_TLS register set for native FreeBSD/arm processes.
[binutils-gdb.git] / gdb / loongarch-linux-nat.c
1 /* Native-dependent code for GNU/Linux on LoongArch processors.
2
3 Copyright (C) 2022 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21 #include "defs.h"
22 #include "elf/common.h"
23 #include "gregset.h"
24 #include "inferior.h"
25 #include "linux-nat-trad.h"
26 #include "loongarch-tdep.h"
27 #include "nat/gdb_ptrace.h"
28 #include "target-descriptions.h"
29
30 #include <asm/ptrace.h>
31
32 /* LoongArch Linux native additions to the default Linux support. */
33
34 class loongarch_linux_nat_target final : public linux_nat_trad_target
35 {
36 public:
37 /* Add our register access methods. */
38 void fetch_registers (struct regcache *, int) override;
39 void store_registers (struct regcache *, int) override;
40
41 protected:
42 /* Override linux_nat_trad_target methods. */
43 CORE_ADDR register_u_offset (struct gdbarch *gdbarch, int regno,
44 int store_p) override;
45 };
46
47 /* Fill GDB's register array with the general-purpose, pc and badv
48 register values from the current thread. */
49
50 static void
51 fetch_gregs_from_thread (struct regcache *regcache, int regno, pid_t tid)
52 {
53 loongarch_gdbarch_tdep *tdep
54 = (loongarch_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
55 auto regs = tdep->regs;
56 elf_gregset_t regset;
57
58 if (regno == -1 || (regs.r <= regno && regno < regs.r + 32)
59 || regs.pc == regno || regs.badv == regno)
60 {
61 struct iovec iov;
62
63 iov.iov_base = &regset;
64 iov.iov_len = sizeof (regset);
65
66 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (long) &iov) < 0)
67 perror_with_name (_("Couldn't get NT_PRSTATUS registers"));
68 else
69 loongarch_gregset.supply_regset (nullptr, regcache, regno,
70 &regset, sizeof (regset));
71 }
72 }
73
74 /* Store to the current thread the valid general-purpose, pc and badv
75 register values in the GDB's register array. */
76
77 static void
78 store_gregs_to_thread (struct regcache *regcache, int regno, pid_t tid)
79 {
80 loongarch_gdbarch_tdep *tdep
81 = (loongarch_gdbarch_tdep *) gdbarch_tdep (regcache->arch ());
82 auto regs = tdep->regs;
83 elf_gregset_t regset;
84
85 if (regno == -1 || (regs.r <= regno && regno < regs.r + 32)
86 || regs.pc == regno || regs.badv == regno)
87 {
88 struct iovec iov;
89
90 iov.iov_base = &regset;
91 iov.iov_len = sizeof (regset);
92
93 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (long) &iov) < 0)
94 perror_with_name (_("Couldn't get NT_PRSTATUS registers"));
95 else
96 {
97 loongarch_gregset.collect_regset (nullptr, regcache, regno,
98 &regset, sizeof (regset));
99 if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, (long) &iov) < 0)
100 perror_with_name (_("Couldn't set NT_PRSTATUS registers"));
101 }
102 }
103 }
104
105 /* Implement the "fetch_registers" target_ops method. */
106
107 void
108 loongarch_linux_nat_target::fetch_registers (struct regcache *regcache,
109 int regno)
110 {
111 pid_t tid = get_ptrace_pid (regcache->ptid ());
112
113 fetch_gregs_from_thread(regcache, regno, tid);
114 }
115
116 /* Implement the "store_registers" target_ops method. */
117
118 void
119 loongarch_linux_nat_target::store_registers (struct regcache *regcache,
120 int regno)
121 {
122 pid_t tid = get_ptrace_pid (regcache->ptid ());
123
124 store_gregs_to_thread (regcache, regno, tid);
125 }
126
127 /* Return the address in the core dump or inferior of register REGNO. */
128
129 CORE_ADDR
130 loongarch_linux_nat_target::register_u_offset (struct gdbarch *gdbarch,
131 int regno, int store_p)
132 {
133 loongarch_gdbarch_tdep *tdep
134 = (loongarch_gdbarch_tdep *) gdbarch_tdep (gdbarch);
135 auto regs = tdep->regs;
136
137 /* According to <asm/ptrace.h> */
138 if (0 <= regs.r && regs.r <= regno && regno < regs.r + GPR_NUM)
139 return GPR_BASE + regno - regs.r;
140 else if (regs.pc == regno)
141 return PC;
142 else
143 return -1;
144 }
145
146 static loongarch_linux_nat_target the_loongarch_linux_nat_target;
147
148 /* Wrapper functions. These are only used by libthread_db. */
149
150 void
151 supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregset)
152 {
153 loongarch_gregset.supply_regset (nullptr, regcache, -1, gregset,
154 sizeof (gdb_gregset_t));
155 }
156
157 void
158 fill_gregset (const struct regcache *regcache, gdb_gregset_t *gregset,
159 int regno)
160 {
161 loongarch_gregset.collect_regset (nullptr, regcache, regno, gregset,
162 sizeof (gdb_gregset_t));
163 }
164
165 void
166 supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregset)
167 {
168 }
169
170 void
171 fill_fpregset (const struct regcache *regcache, gdb_fpregset_t *fpregset,
172 int regno)
173 {
174 }
175
176 /* Initialize LoongArch Linux native support. */
177
178 void _initialize_loongarch_linux_nat ();
179 void
180 _initialize_loongarch_linux_nat ()
181 {
182 linux_target = &the_loongarch_linux_nat_target;
183 add_inf_child_target (&the_loongarch_linux_nat_target);
184 }