blob: ca37355ce616dcc0f78a177d136bb450ec98f1a4 [file] [log] [blame]
Andrew Geissler84ad7c52020-06-27 00:00:16 -05001From fef2dfc9c55d19be25262175a4fa4921167a30b7 Mon Sep 17 00:00:00 2001
Brad Bishop286d45c2018-10-02 15:21:57 -04002From: David Holsgrove <david.holsgrove@petalogix.com>
3Date: Fri, 20 Jul 2012 15:18:35 +1000
Andrew Geissler84ad7c52020-06-27 00:00:16 -05004Subject: [PATCH 38/43] Initial support for native gdb
Brad Bishop286d45c2018-10-02 15:21:57 -04005
6microblaze: Follow PPC method of getting setting registers
7using PTRACE PEEK/POKE
8
9Signed-off-by: David Holsgrove <david.holsgrove@petalogix.com>
Andrew Geissler84ad7c52020-06-27 00:00:16 -050010
11Conflicts:
12 gdb/Makefile.in
Brad Bishop286d45c2018-10-02 15:21:57 -040013---
14 gdb/Makefile.in | 4 +-
Andrew Geissler84ad7c52020-06-27 00:00:16 -050015 gdb/config/microblaze/linux.mh | 9 +
16 gdb/microblaze-linux-nat.c | 431 +++++++++++++++++++++++++++++++++
17 3 files changed, 443 insertions(+), 1 deletion(-)
Brad Bishop286d45c2018-10-02 15:21:57 -040018 create mode 100644 gdb/config/microblaze/linux.mh
19 create mode 100644 gdb/microblaze-linux-nat.c
20
21diff --git a/gdb/Makefile.in b/gdb/Makefile.in
Andrew Geissler84ad7c52020-06-27 00:00:16 -050022index 5614cc3386..d620580498 100644
Brad Bishop286d45c2018-10-02 15:21:57 -040023--- a/gdb/Makefile.in
24+++ b/gdb/Makefile.in
Andrew Geissler84ad7c52020-06-27 00:00:16 -050025@@ -1316,6 +1316,7 @@ HFILES_NO_SRCDIR = \
26 memory-map.h \
27 memrange.h \
28 microblaze-tdep.h \
29+ microblaze-linux-tdep.h \
30 mips-linux-tdep.h \
31 mips-nbsd-tdep.h \
32 mips-tdep.h \
33@@ -1349,6 +1350,7 @@ HFILES_NO_SRCDIR = \
34 prologue-value.h \
35 psympriv.h \
36 psymtab.h \
37+ ia64-hpux-tdep.h \
38 ravenscar-thread.h \
39 record.h \
40 record-full.h \
41@@ -2263,6 +2265,7 @@ ALLDEPFILES = \
42 m68k-tdep.c \
43 microblaze-linux-tdep.c \
44 microblaze-tdep.c \
45+ microblaze-linux-nat.c \
Brad Bishop286d45c2018-10-02 15:21:57 -040046 mingw-hdep.c \
Andrew Geissler84ad7c52020-06-27 00:00:16 -050047 mips-fbsd-nat.c \
48 mips-fbsd-tdep.c \
49@@ -2365,7 +2368,6 @@ ALLDEPFILES = \
50 xtensa-linux-tdep.c \
51 xtensa-tdep.c \
52 xtensa-xtregs.c \
53- common/mingw-strerror.c \
54 common/posix-strerror.c
55
56 # Some files need explicit build rules (due to -Werror problems) or due
Brad Bishop286d45c2018-10-02 15:21:57 -040057diff --git a/gdb/config/microblaze/linux.mh b/gdb/config/microblaze/linux.mh
58new file mode 100644
Andrew Geissler84ad7c52020-06-27 00:00:16 -050059index 0000000000..a4eaf540e1
Brad Bishop286d45c2018-10-02 15:21:57 -040060--- /dev/null
61+++ b/gdb/config/microblaze/linux.mh
Andrew Geissler84ad7c52020-06-27 00:00:16 -050062@@ -0,0 +1,9 @@
Brad Bishop286d45c2018-10-02 15:21:57 -040063+# Host: Microblaze, running Linux
64+
65+NAT_FILE= config/nm-linux.h
66+NATDEPFILES= inf-ptrace.o fork-child.o \
67+ microblaze-linux-nat.o proc-service.o linux-thread-db.o \
Andrew Geissler84ad7c52020-06-27 00:00:16 -050068+ linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o
Brad Bishop286d45c2018-10-02 15:21:57 -040069+NAT_CDEPS = $(srcdir)/proc-service.list
70+
71+LOADLIBES = -ldl $(RDYNAMIC)
72diff --git a/gdb/microblaze-linux-nat.c b/gdb/microblaze-linux-nat.c
73new file mode 100644
Andrew Geissler84ad7c52020-06-27 00:00:16 -050074index 0000000000..e9b8c9c522
Brad Bishop286d45c2018-10-02 15:21:57 -040075--- /dev/null
76+++ b/gdb/microblaze-linux-nat.c
77@@ -0,0 +1,431 @@
78+/* Microblaze GNU/Linux native support.
79+
80+ Copyright (C) 1988-1989, 1991-1992, 1994, 1996, 2000-2012 Free
81+ Software Foundation, Inc.
82+
83+ This file is part of GDB.
84+
85+ This program is free software; you can redistribute it and/or modify
86+ it under the terms of the GNU General Public License as published by
87+ the Free Software Foundation; either version 3 of the License, or
88+ (at your option) any later version.
89+
90+ This program is distributed in the hope that it will be useful,
91+ but WITHOUT ANY WARRANTY; without even the implied warranty of
92+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93+ GNU General Public License for more details.
94+
95+ You should have received a copy of the GNU General Public License
96+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
97+
98+#include "defs.h"
99+#include "arch-utils.h"
100+#include "dis-asm.h"
101+#include "frame.h"
102+#include "trad-frame.h"
103+#include "symtab.h"
104+#include "value.h"
105+#include "gdbcmd.h"
106+#include "breakpoint.h"
107+#include "inferior.h"
108+#include "regcache.h"
109+#include "target.h"
110+#include "frame.h"
111+#include "frame-base.h"
112+#include "frame-unwind.h"
113+#include "dwarf2-frame.h"
114+#include "osabi.h"
115+
116+#include "gdb_assert.h"
Andrew Geissler84ad7c52020-06-27 00:00:16 -0500117+#include "gdb_string.h"
Brad Bishop286d45c2018-10-02 15:21:57 -0400118+#include "target-descriptions.h"
119+#include "opcodes/microblaze-opcm.h"
120+#include "opcodes/microblaze-dis.h"
121+
122+#include "linux-nat.h"
123+#include "target-descriptions.h"
124+
125+#include <sys/user.h>
126+#include <sys/utsname.h>
127+#include <sys/procfs.h>
128+#include <sys/ptrace.h>
129+
130+/* Prototypes for supply_gregset etc. */
131+#include "gregset.h"
132+
133+#include "microblaze-tdep.h"
134+
135+#include <elf/common.h>
136+#include "auxv.h"
137+
138+/* Defines ps_err_e, struct ps_prochandle. */
139+#include "gdb_proc_service.h"
140+
141+/* On GNU/Linux, threads are implemented as pseudo-processes, in which
142+ case we may be tracing more than one process at a time. In that
143+ case, inferior_ptid will contain the main process ID and the
144+ individual thread (process) ID. get_thread_id () is used to get
145+ the thread id if it's available, and the process id otherwise. */
146+
147+int
148+get_thread_id (ptid_t ptid)
149+{
Andrew Geissler84ad7c52020-06-27 00:00:16 -0500150+ int tid = TIDGET (ptid);
Brad Bishop286d45c2018-10-02 15:21:57 -0400151+ if (0 == tid)
Andrew Geissler84ad7c52020-06-27 00:00:16 -0500152+ tid = PIDGET (ptid);
Brad Bishop286d45c2018-10-02 15:21:57 -0400153+ return tid;
154+}
155+
156+#define GET_THREAD_ID(PTID) get_thread_id (PTID)
157+
158+/* Non-zero if our kernel may support the PTRACE_GETREGS and
159+ PTRACE_SETREGS requests, for reading and writing the
160+ general-purpose registers. Zero if we've tried one of
161+ them and gotten an error. */
162+int have_ptrace_getsetregs = 1;
163+
164+static int
165+microblaze_register_u_addr (struct gdbarch *gdbarch, int regno)
166+{
167+ int u_addr = -1;
168+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
169+ /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
170+ interface, and not the wordsize of the program's ABI. */
171+ int wordsize = sizeof (long);
172+
173+ /* General purpose registers occupy 1 slot each in the buffer. */
174+ if (regno >= MICROBLAZE_R0_REGNUM
175+ && regno <= MICROBLAZE_FSR_REGNUM)
176+ u_addr = (regno * wordsize);
177+
178+ return u_addr;
179+}
180+
181+
182+static void
183+fetch_register (struct regcache *regcache, int tid, int regno)
184+{
185+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
186+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
187+ /* This isn't really an address. But ptrace thinks of it as one. */
188+ CORE_ADDR regaddr = microblaze_register_u_addr (gdbarch, regno);
189+ int bytes_transferred;
190+ unsigned int offset; /* Offset of registers within the u area. */
191+ char buf[MAX_REGISTER_SIZE];
192+
193+ if (regaddr == -1)
194+ {
195+ memset (buf, '\0', register_size (gdbarch, regno)); /* Supply zeroes */
196+ regcache_raw_supply (regcache, regno, buf);
197+ return;
198+ }
199+
200+ /* Read the raw register using sizeof(long) sized chunks. On a
201+ 32-bit platform, 64-bit floating-point registers will require two
202+ transfers. */
203+ for (bytes_transferred = 0;
204+ bytes_transferred < register_size (gdbarch, regno);
205+ bytes_transferred += sizeof (long))
206+ {
207+ long l;
208+
209+ errno = 0;
210+ l = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
211+ regaddr += sizeof (long);
212+ if (errno != 0)
213+ {
214+ char message[128];
215+ sprintf (message, "reading register %s (#%d)",
216+ gdbarch_register_name (gdbarch, regno), regno);
217+ perror_with_name (message);
218+ }
219+ memcpy (&buf[bytes_transferred], &l, sizeof (l));
220+ }
221+
222+ /* Now supply the register. Keep in mind that the regcache's idea
223+ of the register's size may not be a multiple of sizeof
224+ (long). */
225+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
226+ {
227+ /* Little-endian values are always found at the left end of the
228+ bytes transferred. */
229+ regcache_raw_supply (regcache, regno, buf);
230+ }
231+ else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
232+ {
233+ /* Big-endian values are found at the right end of the bytes
234+ transferred. */
235+ size_t padding = (bytes_transferred - register_size (gdbarch, regno));
236+ regcache_raw_supply (regcache, regno, buf + padding);
237+ }
238+ else
239+ internal_error (__FILE__, __LINE__,
240+ _("fetch_register: unexpected byte order: %d"),
241+ gdbarch_byte_order (gdbarch));
242+}
243+
244+/* This function actually issues the request to ptrace, telling
245+ it to get all general-purpose registers and put them into the
246+ specified regset.
247+
248+ If the ptrace request does not exist, this function returns 0
249+ and properly sets the have_ptrace_* flag. If the request fails,
250+ this function calls perror_with_name. Otherwise, if the request
251+ succeeds, then the regcache gets filled and 1 is returned. */
252+static int
253+fetch_all_gp_regs (struct regcache *regcache, int tid)
254+{
255+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
256+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
257+ gdb_gregset_t gregset;
258+
259+ if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
260+ {
261+ if (errno == EIO)
262+ {
263+ have_ptrace_getsetregs = 0;
264+ return 0;
265+ }
266+ perror_with_name (_("Couldn't get general-purpose registers."));
267+ }
268+
269+ supply_gregset (regcache, (const gdb_gregset_t *) &gregset);
270+
271+ return 1;
272+}
273+
274+
275+/* This is a wrapper for the fetch_all_gp_regs function. It is
276+ responsible for verifying if this target has the ptrace request
277+ that can be used to fetch all general-purpose registers at one
278+ shot. If it doesn't, then we should fetch them using the
279+ old-fashioned way, which is to iterate over the registers and
280+ request them one by one. */
281+static void
282+fetch_gp_regs (struct regcache *regcache, int tid)
283+{
284+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
285+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
286+ int i;
287+
288+ if (have_ptrace_getsetregs)
289+ if (fetch_all_gp_regs (regcache, tid))
290+ return;
291+
292+ /* If we've hit this point, it doesn't really matter which
293+ architecture we are using. We just need to read the
294+ registers in the "old-fashioned way". */
295+ for (i = MICROBLAZE_R0_REGNUM; i <= MICROBLAZE_FSR_REGNUM; i++)
296+ fetch_register (regcache, tid, i);
297+}
298+
299+
300+static void
301+store_register (const struct regcache *regcache, int tid, int regno)
302+{
303+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
304+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
305+ /* This isn't really an address. But ptrace thinks of it as one. */
306+ CORE_ADDR regaddr = microblaze_register_u_addr (gdbarch, regno);
307+ int i;
308+ size_t bytes_to_transfer;
309+ char buf[MAX_REGISTER_SIZE];
310+
311+ if (regaddr == -1)
312+ return;
313+
314+ /* First collect the register. Keep in mind that the regcache's
315+ idea of the register's size may not be a multiple of sizeof
316+ (long). */
317+ memset (buf, 0, sizeof buf);
318+ bytes_to_transfer = align_up (register_size (gdbarch, regno), sizeof (long));
319+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
320+ {
321+ /* Little-endian values always sit at the left end of the buffer. */
322+ regcache_raw_collect (regcache, regno, buf);
323+ }
324+ else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
325+ {
326+ /* Big-endian values sit at the right end of the buffer. */
327+ size_t padding = (bytes_to_transfer - register_size (gdbarch, regno));
328+ regcache_raw_collect (regcache, regno, buf + padding);
329+ }
330+
331+ for (i = 0; i < bytes_to_transfer; i += sizeof (long))
332+ {
333+ long l;
334+
335+ memcpy (&l, &buf[i], sizeof (l));
336+ errno = 0;
337+ ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr, l);
338+ regaddr += sizeof (long);
339+
340+ if (errno != 0)
341+ {
342+ char message[128];
343+ sprintf (message, "writing register %s (#%d)",
344+ gdbarch_register_name (gdbarch, regno), regno);
345+ perror_with_name (message);
346+ }
347+ }
348+}
349+
350+/* This function actually issues the request to ptrace, telling
351+ it to store all general-purpose registers present in the specified
352+ regset.
353+
354+ If the ptrace request does not exist, this function returns 0
355+ and properly sets the have_ptrace_* flag. If the request fails,
356+ this function calls perror_with_name. Otherwise, if the request
357+ succeeds, then the regcache is stored and 1 is returned. */
358+static int
359+store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
360+{
361+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
362+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
363+ gdb_gregset_t gregset;
364+
365+ if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
366+ {
367+ if (errno == EIO)
368+ {
369+ have_ptrace_getsetregs = 0;
370+ return 0;
371+ }
372+ perror_with_name (_("Couldn't get general-purpose registers."));
373+ }
374+
375+ fill_gregset (regcache, &gregset, regno);
376+
377+ if (ptrace (PTRACE_SETREGS, tid, 0, (void *) &gregset) < 0)
378+ {
379+ if (errno == EIO)
380+ {
381+ have_ptrace_getsetregs = 0;
382+ return 0;
383+ }
384+ perror_with_name (_("Couldn't set general-purpose registers."));
385+ }
386+
387+ return 1;
388+}
389+
390+/* This is a wrapper for the store_all_gp_regs function. It is
391+ responsible for verifying if this target has the ptrace request
392+ that can be used to store all general-purpose registers at one
393+ shot. If it doesn't, then we should store them using the
394+ old-fashioned way, which is to iterate over the registers and
395+ store them one by one. */
396+static void
397+store_gp_regs (const struct regcache *regcache, int tid, int regno)
398+{
399+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
400+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
401+ int i;
402+
403+ if (have_ptrace_getsetregs)
404+ if (store_all_gp_regs (regcache, tid, regno))
405+ return;
406+
407+ /* If we hit this point, it doesn't really matter which
408+ architecture we are using. We just need to store the
409+ registers in the "old-fashioned way". */
410+ for (i = MICROBLAZE_R0_REGNUM; i <= MICROBLAZE_FSR_REGNUM; i++)
411+ store_register (regcache, tid, i);
412+}
413+
414+
415+/* Fetch registers from the child process. Fetch all registers if
416+ regno == -1, otherwise fetch all general registers or all floating
417+ point registers depending upon the value of regno. */
418+
419+static void
420+microblaze_linux_fetch_inferior_registers (struct target_ops *ops,
421+ struct regcache *regcache, int regno)
422+{
423+ /* Get the thread id for the ptrace call. */
424+ int tid = GET_THREAD_ID (inferior_ptid);
425+
426+ if (regno == -1)
427+ fetch_gp_regs (regcache, tid);
428+ else
429+ fetch_register (regcache, tid, regno);
430+}
431+
432+/* Store registers back into the inferior. Store all registers if
433+ regno == -1, otherwise store all general registers or all floating
434+ point registers depending upon the value of regno. */
435+
436+static void
437+microblaze_linux_store_inferior_registers (struct target_ops *ops,
438+ struct regcache *regcache, int regno)
439+{
440+ /* Get the thread id for the ptrace call. */
441+ int tid = GET_THREAD_ID (inferior_ptid);
442+
443+ if (regno >= 0)
444+ store_register (regcache, tid, regno);
445+ else
446+ store_gp_regs (regcache, tid, -1);
447+}
448+
449+/* Wrapper functions for the standard regset handling, used by
450+ thread debugging. */
451+
452+void
453+fill_gregset (const struct regcache *regcache,
454+ gdb_gregset_t *gregsetp, int regno)
455+{
456+ microblaze_collect_gregset (NULL, regcache, regno, gregsetp);
457+}
458+
459+void
460+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
461+{
462+ microblaze_supply_gregset (NULL, regcache, -1, gregsetp);
463+}
464+
465+void
466+fill_fpregset (const struct regcache *regcache,
467+ gdb_fpregset_t *fpregsetp, int regno)
468+{
469+ /* FIXME. */
470+}
471+
472+void
473+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
474+{
475+ /* FIXME. */
476+}
477+
478+static const struct target_desc *
479+microblaze_linux_read_description (struct target_ops *ops)
480+{
481+ CORE_ADDR microblaze_hwcap = 0;
482+
483+ if (target_auxv_search (ops, AT_HWCAP, &microblaze_hwcap) != 1)
484+ return NULL;
485+
486+ return NULL;
487+}
488+
489+
490+void _initialize_microblaze_linux_nat (void);
491+
492+void
493+_initialize_microblaze_linux_nat (void)
494+{
495+ struct target_ops *t;
496+
497+ /* Fill in the generic GNU/Linux methods. */
498+ t = linux_target ();
499+
500+ /* Add our register access methods. */
501+ t->to_fetch_registers = microblaze_linux_fetch_inferior_registers;
502+ t->to_store_registers = microblaze_linux_store_inferior_registers;
503+
504+ t->to_read_description = microblaze_linux_read_description;
505+
506+ /* Register the target. */
507+ linux_nat_add_target (t);
508+}
509--
Andrew Geissler84ad7c52020-06-27 00:00:16 -05005102.17.1
511