1 /* Native-dependent code for GNU/Linux on LoongArch processors.
3 Copyright (C) 2022 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
6 This file is part of GDB.
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.
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.
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/>. */
22 #include "elf/common.h"
25 #include "linux-nat-trad.h"
26 #include "loongarch-tdep.h"
27 #include "nat/gdb_ptrace.h"
28 #include "target-descriptions.h"
30 #include <asm/ptrace.h>
32 /* LoongArch Linux native additions to the default Linux support. */
34 class loongarch_linux_nat_target final
: public linux_nat_trad_target
37 /* Add our register access methods. */
38 void fetch_registers (struct regcache
*, int) override
;
39 void store_registers (struct regcache
*, int) override
;
42 /* Override linux_nat_trad_target methods. */
43 CORE_ADDR
register_u_offset (struct gdbarch
*gdbarch
, int regno
,
44 int store_p
) override
;
47 /* Fill GDB's register array with the general-purpose, pc and badv
48 register values from the current thread. */
51 fetch_gregs_from_thread (struct regcache
*regcache
, int regno
, pid_t tid
)
53 loongarch_gdbarch_tdep
*tdep
54 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (regcache
->arch ());
55 auto regs
= tdep
->regs
;
58 if (regno
== -1 || (regs
.r
<= regno
&& regno
< regs
.r
+ 32)
59 || regs
.pc
== regno
|| regs
.badv
== regno
)
63 iov
.iov_base
= ®set
;
64 iov
.iov_len
= sizeof (regset
);
66 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
, (long) &iov
) < 0)
67 perror_with_name (_("Couldn't get NT_PRSTATUS registers"));
69 loongarch_gregset
.supply_regset (nullptr, regcache
, regno
,
70 ®set
, sizeof (regset
));
74 /* Store to the current thread the valid general-purpose, pc and badv
75 register values in the GDB's register array. */
78 store_gregs_to_thread (struct regcache
*regcache
, int regno
, pid_t tid
)
80 loongarch_gdbarch_tdep
*tdep
81 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (regcache
->arch ());
82 auto regs
= tdep
->regs
;
85 if (regno
== -1 || (regs
.r
<= regno
&& regno
< regs
.r
+ 32)
86 || regs
.pc
== regno
|| regs
.badv
== regno
)
90 iov
.iov_base
= ®set
;
91 iov
.iov_len
= sizeof (regset
);
93 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
, (long) &iov
) < 0)
94 perror_with_name (_("Couldn't get NT_PRSTATUS registers"));
97 loongarch_gregset
.collect_regset (nullptr, regcache
, regno
,
98 ®set
, sizeof (regset
));
99 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
, (long) &iov
) < 0)
100 perror_with_name (_("Couldn't set NT_PRSTATUS registers"));
105 /* Implement the "fetch_registers" target_ops method. */
108 loongarch_linux_nat_target::fetch_registers (struct regcache
*regcache
,
111 pid_t tid
= get_ptrace_pid (regcache
->ptid ());
113 fetch_gregs_from_thread(regcache
, regno
, tid
);
116 /* Implement the "store_registers" target_ops method. */
119 loongarch_linux_nat_target::store_registers (struct regcache
*regcache
,
122 pid_t tid
= get_ptrace_pid (regcache
->ptid ());
124 store_gregs_to_thread (regcache
, regno
, tid
);
127 /* Return the address in the core dump or inferior of register REGNO. */
130 loongarch_linux_nat_target::register_u_offset (struct gdbarch
*gdbarch
,
131 int regno
, int store_p
)
133 loongarch_gdbarch_tdep
*tdep
134 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (gdbarch
);
135 auto regs
= tdep
->regs
;
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
)
146 static loongarch_linux_nat_target the_loongarch_linux_nat_target
;
148 /* Wrapper functions. These are only used by libthread_db. */
151 supply_gregset (struct regcache
*regcache
, const gdb_gregset_t
*gregset
)
153 loongarch_gregset
.supply_regset (nullptr, regcache
, -1, gregset
,
154 sizeof (gdb_gregset_t
));
158 fill_gregset (const struct regcache
*regcache
, gdb_gregset_t
*gregset
,
161 loongarch_gregset
.collect_regset (nullptr, regcache
, regno
, gregset
,
162 sizeof (gdb_gregset_t
));
166 supply_fpregset (struct regcache
*regcache
, const gdb_fpregset_t
*fpregset
)
171 fill_fpregset (const struct regcache
*regcache
, gdb_fpregset_t
*fpregset
,
176 /* Initialize LoongArch Linux native support. */
178 void _initialize_loongarch_linux_nat ();
180 _initialize_loongarch_linux_nat ()
182 linux_target
= &the_loongarch_linux_nat_target
;
183 add_inf_child_target (&the_loongarch_linux_nat_target
);