blob: 31cf0b0be2323f609325a7b72144226752dcefcf [file] [log] [blame]
Andrew Geissler09036742021-06-25 14:25:14 -05001From 32b366249fd42d74cbc4a91039431554ebadcfd0 Mon Sep 17 00:00:00 2001
2From: Anton Kolesov <anton.kolesov@synopsys.com>
3Date: Fri, 14 Feb 2014 11:56:23 +0400
4Subject: [PATCH 4/4] gdb: Add native support for ARC in GNU/Linux
5
6With this patch in place it is possible to build a GDB that
7can run on ARC (GNU/Linux) hosts for debugging ARC targets.
8
9The "arc-linux-nat.c" is a rather small one that mostly deals
10with registers and a few thread related hooks.
11
12v2 [1]:
13- Remove "void" from the input of "_initialize_arc_linux_nat ()"
14
15[1] Tom's remark after the first patch
16https://sourceware.org/pipermail/gdb-patches/2020-November/173223.html
17
18gdb/ChangeLog:
19
20 * Makefile.in (ALLDEPFILES): Add arc-linux-nat.c.
21 * configure.host (host to gdb names): Add arc*-*-linux*.
22 * configure.nat (gdb_host_cpu): Add arc.
23 * arc-linux-nat.c: New.
24
25Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=04c9f85efcd8df5fc482ce97c0104cc7dd5d19e6]
26
27Signed-off-by: Anton Kolesov <Anton.Kolesov@synopsys.com>
28Signed-off-by: Shahab Vahedi <shahab@synopsys.com>
29Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
30---
31 gdb/Makefile.in | 1 +
32 gdb/arc-linux-nat.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++
33 gdb/configure.host | 3 +
34 gdb/configure.nat | 4 +
35 4 files changed, 328 insertions(+)
36 create mode 100644 gdb/arc-linux-nat.c
37
38diff --git a/gdb/Makefile.in b/gdb/Makefile.in
39index ec371fc7e52..c76136907ae 100644
40--- a/gdb/Makefile.in
41+++ b/gdb/Makefile.in
42@@ -2136,6 +2136,7 @@ ALLDEPFILES = \
43 amd64-obsd-tdep.c \
44 amd64-sol2-tdep.c \
45 amd64-tdep.c \
46+ arc-linux-nat.c \
47 arc-tdep.c \
48 arm.c \
49 arm-bsd-tdep.c \
50diff --git a/gdb/arc-linux-nat.c b/gdb/arc-linux-nat.c
51new file mode 100644
52index 00000000000..41301fd4fed
53--- /dev/null
54+++ b/gdb/arc-linux-nat.c
55@@ -0,0 +1,320 @@
56+/* Native-dependent code for GNU/Linux ARC.
57+
58+ Copyright 2020 Free Software Foundation, Inc.
59+
60+ This file is part of GDB.
61+
62+ This program is free software; you can redistribute it and/or modify
63+ it under the terms of the GNU General Public License as published by
64+ the Free Software Foundation; either version 3 of the License, or
65+ (at your option) any later version.
66+
67+ This program is distributed in the hope that it will be useful,
68+ but WITHOUT ANY WARRANTY; without even the implied warranty of
69+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
70+ GNU General Public License for more details.
71+
72+ You should have received a copy of the GNU General Public License
73+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
74+
75+#include "defs.h"
76+#include "frame.h"
77+#include "inferior.h"
78+#include "gdbcore.h"
79+#include "regcache.h"
80+#include "gdbsupport/gdb_assert.h"
81+#include "target.h"
82+#include "linux-nat.h"
83+#include "nat/gdb_ptrace.h"
84+
85+#include <stdint.h>
86+#include <sys/types.h>
87+#include <sys/param.h>
88+#include <signal.h>
89+#include <sys/user.h>
90+#include <sys/ioctl.h>
91+#include "gdbsupport/gdb_wait.h"
92+#include <fcntl.h>
93+#include <sys/procfs.h>
94+#include <linux/elf.h>
95+
96+#include "gregset.h"
97+#include "arc-tdep.h"
98+#include "arc-linux-tdep.h"
99+#include "arch/arc.h"
100+
101+/* Defines ps_err_e, struct ps_prochandle. */
102+#include "gdb_proc_service.h"
103+
104+/* Linux starting with 4.12 supports NT_ARC_V2 note type, which adds R30,
105+ R58 and R59 registers, which are specific to ARC HS and aren't
106+ available in ARC 700. */
107+#if defined (NT_ARC_V2) && defined (__ARCHS__)
108+#define ARC_HAS_V2_REGSET
109+#endif
110+
111+class arc_linux_nat_target final : public linux_nat_target
112+{
113+public:
114+ /* Add ARC register access methods. */
115+ void fetch_registers (struct regcache *, int) override;
116+ void store_registers (struct regcache *, int) override;
117+
118+ const struct target_desc *read_description () override;
119+
120+ /* Handle threads */
121+ void low_prepare_to_resume (struct lwp_info *lp) override;
122+};
123+
124+static arc_linux_nat_target the_arc_linux_nat_target;
125+
126+/* Read general registers from target process/thread (via ptrace)
127+ into REGCACHE. */
128+
129+static void
130+fetch_gregs (struct regcache *regcache, int regnum)
131+{
132+ const int tid = get_ptrace_pid (regcache->ptid ());
133+ struct iovec iov;
134+ gdb_gregset_t regs;
135+
136+ iov.iov_base = &regs;
137+ iov.iov_len = sizeof (gdb_gregset_t);
138+
139+ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (void *) &iov) < 0)
140+ perror_with_name (_("Couldn't get general registers"));
141+ else
142+ arc_linux_supply_gregset (NULL, regcache, regnum, &regs, 0);
143+}
144+
145+#ifdef ARC_HAS_V2_REGSET
146+/* Read ARC v2 registers from target process/thread (via ptrace)
147+ into REGCACHE. */
148+
149+static void
150+fetch_v2_regs (struct regcache *regcache, int regnum)
151+{
152+ const int tid = get_ptrace_pid (regcache->ptid ());
153+ struct iovec iov;
154+ bfd_byte v2_buffer[ARC_LINUX_SIZEOF_V2_REGSET];
155+
156+ iov.iov_base = &v2_buffer;
157+ iov.iov_len = ARC_LINUX_SIZEOF_V2_REGSET;
158+
159+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARC_V2, (void *) &iov) < 0)
160+ perror_with_name (_("Couldn't get ARC HS registers"));
161+ else
162+ arc_linux_supply_v2_regset (NULL, regcache, regnum, v2_buffer, 0);
163+}
164+#endif
165+
166+/* Store general registers from REGCACHE into the target process/thread. */
167+
168+static void
169+store_gregs (const struct regcache *regcache, int regnum)
170+{
171+ const int tid = get_ptrace_pid (regcache->ptid ());
172+ struct iovec iov;
173+ gdb_gregset_t regs;
174+
175+ iov.iov_base = &regs;
176+ iov.iov_len = sizeof (gdb_gregset_t);
177+
178+ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (void *) &iov) < 0)
179+ perror_with_name (_("Couldn't get general registers"));
180+ else
181+ {
182+ arc_linux_collect_gregset (NULL, regcache, regnum, regs, 0);
183+
184+ if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, (void *) &iov) < 0)
185+ perror_with_name (_("Couldn't write general registers"));
186+ }
187+}
188+
189+#ifdef ARC_HAS_V2_REGSET
190+/* Store ARC v2 registers from REGCACHE into the target process/thread. */
191+
192+static void
193+store_v2_regs (const struct regcache *regcache, int regnum)
194+{
195+ const int tid = get_ptrace_pid (regcache->ptid ());
196+ struct iovec iov;
197+ bfd_byte v2_buffer[ARC_LINUX_SIZEOF_V2_REGSET];
198+
199+ iov.iov_base = &v2_buffer;
200+ iov.iov_len = ARC_LINUX_SIZEOF_V2_REGSET;
201+
202+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARC_V2, (void *) &iov) < 0)
203+ perror_with_name (_("Couldn't get ARC HS registers"));
204+ else
205+ {
206+ arc_linux_collect_v2_regset (NULL, regcache, regnum, v2_buffer, 0);
207+
208+ if (ptrace (PTRACE_SETREGSET, tid, NT_ARC_V2, (void *) &iov) < 0)
209+ perror_with_name (_("Couldn't write ARC HS registers"));
210+ }
211+}
212+#endif
213+
214+/* Target operation: Read REGNUM register (all registers if REGNUM == -1)
215+ from target process into REGCACHE. */
216+
217+void
218+arc_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
219+{
220+
221+ if (regnum == -1 || regnum <= ARC_LAST_REGNUM)
222+ fetch_gregs (regcache, regnum);
223+
224+#ifdef ARC_HAS_V2_REGSET
225+ if (regnum == -1
226+ || regnum == ARC_R30_REGNUM
227+ || regnum == ARC_R58_REGNUM
228+ || regnum == ARC_R59_REGNUM)
229+ fetch_v2_regs (regcache, regnum);
230+#endif
231+}
232+
233+/* Target operation: Store REGNUM register (all registers if REGNUM == -1)
234+ to the target process from REGCACHE. */
235+
236+void
237+arc_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
238+{
239+ if (regnum == -1 || regnum <= ARC_LAST_REGNUM)
240+ store_gregs (regcache, regnum);
241+
242+#ifdef ARC_HAS_V2_REGSET
243+ if (regnum == -1
244+ || regnum == ARC_R30_REGNUM
245+ || regnum == ARC_R58_REGNUM
246+ || regnum == ARC_R59_REGNUM)
247+ store_v2_regs (regcache, regnum);
248+#endif
249+}
250+
251+/* Copy general purpose register(s) from REGCACHE into regset GREGS.
252+ This function is exported to proc-service.c */
253+
254+void
255+fill_gregset (const struct regcache *regcache,
256+ gdb_gregset_t *gregs, int regnum)
257+{
258+ arc_linux_collect_gregset (NULL, regcache, regnum, gregs, 0);
259+}
260+
261+/* Copy all the general purpose registers from regset GREGS into REGCACHE.
262+ This function is exported to proc-service.c. */
263+
264+void
265+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs)
266+{
267+ arc_linux_supply_gregset (NULL, regcache, -1, gregs, 0);
268+}
269+
270+/* ARC doesn't have separate FP registers. This function is exported
271+ to proc-service.c. */
272+
273+void
274+fill_fpregset (const struct regcache *regcache,
275+ gdb_fpregset_t *fpregsetp, int regnum)
276+{
277+ if (arc_debug)
278+ debug_printf ("arc-linux-nat: fill_fpregset called.");
279+ return;
280+}
281+
282+/* ARC doesn't have separate FP registers. This function is exported
283+ to proc-service.c. */
284+
285+void
286+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
287+{
288+ if (arc_debug)
289+ debug_printf ("arc-linux-nat: supply_fpregset called.");
290+ return;
291+}
292+
293+/* Implement the "read_description" method of linux_nat_target. */
294+
295+const struct target_desc *
296+arc_linux_nat_target::read_description ()
297+{
298+ /* This is a native target, hence description is hardcoded. */
299+#ifdef __ARCHS__
300+ arc_arch_features features (4, ARC_ISA_ARCV2);
301+#else
302+ arc_arch_features features (4, ARC_ISA_ARCV1);
303+#endif
304+ return arc_lookup_target_description (features);
305+}
306+
307+/* As described in arc_linux_collect_gregset(), we need to write resume-PC
308+ to ERET. However by default GDB for native targets doesn't write
309+ registers if they haven't been changed. This is a callback called by
310+ generic GDB, and in this callback we have to rewrite PC value so it
311+ would force rewrite of register on target. It seems that the only
312+ other arch that utilizes this hook is x86/x86-64 for HW breakpoint
313+ support. But then, AFAIK no other arch has this stop_pc/eret
314+ complexity.
315+
316+ No better way was found, other than this fake write of register value,
317+ to force GDB into writing register to target. Is there any? */
318+
319+void
320+arc_linux_nat_target::low_prepare_to_resume (struct lwp_info *lwp)
321+{
322+ /* When new processes and threads are created we do not have the address
323+ space for them and calling get_thread_regcache will cause an internal
324+ error in GDB. It looks like that checking for last_resume_kind is the
325+ sensible way to determine processes for which we cannot get regcache.
326+ Ultimately, a better way would be removing the need for
327+ low_prepare_to_resume in the first place. */
328+ if (lwp->last_resume_kind == resume_stop)
329+ return;
330+
331+ struct regcache *regcache = get_thread_regcache (this, lwp->ptid);
332+ struct gdbarch *gdbarch = regcache->arch ();
333+
334+ /* Read current PC value, then write it back. It is required to call
335+ invalidate(), otherwise GDB will note that new value is equal to old
336+ value and will skip write. */
337+ ULONGEST new_pc;
338+ regcache_cooked_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
339+ &new_pc);
340+ regcache->invalidate (gdbarch_pc_regnum (gdbarch));
341+ regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
342+ new_pc);
343+}
344+
345+/* Fetch the thread-local storage pointer for libthread_db. Note that
346+ this function is not called from GDB, but is called from libthread_db.
347+ This is required to debug multithreaded applications with NPTL. */
348+
349+ps_err_e
350+ps_get_thread_area (struct ps_prochandle *ph, lwpid_t lwpid, int idx,
351+ void **base)
352+{
353+ if (arc_debug >= 2)
354+ debug_printf ("arc-linux-nat: ps_get_thread_area called");
355+
356+ if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
357+ return PS_ERR;
358+
359+ /* IDX is the bias from the thread pointer to the beginning of the
360+ thread descriptor. It has to be subtracted due to implementation
361+ quirks in libthread_db. */
362+ *base = (void *) ((char *) *base - idx);
363+
364+ return PS_OK;
365+}
366+
367+/* Suppress warning from -Wmissing-prototypes. */
368+void _initialize_arc_linux_nat ();
369+void
370+_initialize_arc_linux_nat ()
371+{
372+ /* Register the target. */
373+ linux_target = &the_arc_linux_nat_target;
374+ add_inf_child_target (&the_arc_linux_nat_target);
375+}
376diff --git a/gdb/configure.host b/gdb/configure.host
377index ce528237291..e94a19b0332 100644
378--- a/gdb/configure.host
379+++ b/gdb/configure.host
380@@ -60,6 +60,7 @@ case "${host_cpu}" in
381
382 aarch64*) gdb_host_cpu=aarch64 ;;
383 alpha*) gdb_host_cpu=alpha ;;
384+arc*) gdb_host_cpu=arc ;;
385 arm*) gdb_host_cpu=arm ;;
386 hppa*) gdb_host_cpu=pa ;;
387 i[34567]86*) gdb_host_cpu=i386 ;;
388@@ -91,6 +92,8 @@ alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu)
389 gdb_host=nbsd ;;
390 alpha*-*-openbsd*) gdb_host=nbsd ;;
391
392+arc*-*-linux*) gdb_host=linux ;;
393+
394 arm*-*-freebsd*) gdb_host=fbsd ;;
395 arm*-*-linux*) gdb_host=linux ;;
396 arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu)
397diff --git a/gdb/configure.nat b/gdb/configure.nat
398index bb70e303384..cd11bc86dca 100644
399--- a/gdb/configure.nat
400+++ b/gdb/configure.nat
401@@ -238,6 +238,10 @@ case ${gdb_host} in
402 nat/aarch64-linux.o \
403 nat/aarch64-sve-linux-ptrace.o"
404 ;;
405+ arc)
406+ # Host: ARC based machine running GNU/Linux
407+ NATDEPFILES="${NATDEPFILES} arc-linux-nat.o"
408+ ;;
409 arm)
410 # Host: ARM based machine running GNU/Linux
411 NATDEPFILES="${NATDEPFILES} arm-linux-nat.o \
412--
4132.16.2
414