blob: 7ac89d2de2d13782faf982c27d239808df54683a [file] [log] [blame]
Andrew Geissler84ad7c52020-06-27 00:00:16 -05001From c347f9727cc86bb0174dc001446c0670e7306692 Mon Sep 17 00:00:00 2001
2From: Mahesh Bodapati <mbodapat@xilinx.com>
3Date: Mon, 23 Jan 2017 19:07:44 +0530
4Subject: [PATCH 32/43] Add initial port of linux gdbserver add
5 gdb_proc_service_h to gdbserver microblaze-linux
6
7gdbserver needs to initialise the microblaze registers
8
9other archs use this step to run a *_arch_setup() to carry out all
10architecture specific setup - may need to add in future
11
12 * add linux-ptrace.o to gdbserver configure
13 * Update breakpoint opcode
14 * fix segfault on connecting gdbserver
15 * add microblaze_linux_memory_remove_breakpoint
16 * add set_solib_svr4_fetch_link_map_offsets
17 * add set_gdbarch_fetch_tls_load_module_address
18 * Force reading of r0 as 0, prevent stores
19
20Signed-off-by: David Holsgrove <david.holsgrove@petalogix.com>
21Signed-off-by: Nathan Rossi <nathan.rossi@petalogix.com>
22---
23 gdb/configure.host | 3 +
24 gdb/gdbserver/linux-microblaze-low.c | 189 +++++++++++++++++++++++++++
25 gdb/microblaze-linux-tdep.c | 29 +++-
26 gdb/microblaze-tdep.c | 35 ++++-
27 gdb/microblaze-tdep.h | 4 +-
28 gdb/regformats/reg-microblaze.dat | 41 ++++++
29 6 files changed, 298 insertions(+), 3 deletions(-)
30 create mode 100644 gdb/gdbserver/linux-microblaze-low.c
31 create mode 100644 gdb/regformats/reg-microblaze.dat
32
33diff --git a/gdb/configure.host b/gdb/configure.host
34index c87f997abc..de8d6b00f3 100644
35--- a/gdb/configure.host
36+++ b/gdb/configure.host
37@@ -65,6 +65,7 @@ hppa*) gdb_host_cpu=pa ;;
38 i[34567]86*) gdb_host_cpu=i386 ;;
39 m68*) gdb_host_cpu=m68k ;;
40 mips*) gdb_host_cpu=mips ;;
41+microblaze*) gdb_host_cpu=microblaze ;;
42 powerpc* | rs6000) gdb_host_cpu=powerpc ;;
43 sparcv9 | sparc64) gdb_host_cpu=sparc ;;
44 s390*) gdb_host_cpu=s390 ;;
45@@ -133,6 +134,8 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu)
46 mips*-*-freebsd*) gdb_host=fbsd ;;
47 mips64*-*-openbsd*) gdb_host=obsd64 ;;
48
49+microblaze*-*linux*) gdb_host=linux ;;
50+
51 powerpc-*-aix* | rs6000-*-* | powerpc64-*-aix*)
52 gdb_host=aix ;;
53 powerpc*-*-freebsd*) gdb_host=fbsd ;;
54diff --git a/gdb/gdbserver/linux-microblaze-low.c b/gdb/gdbserver/linux-microblaze-low.c
55new file mode 100644
56index 0000000000..cba5d6fc58
57--- /dev/null
58+++ b/gdb/gdbserver/linux-microblaze-low.c
59@@ -0,0 +1,189 @@
60+/* GNU/Linux/Microblaze specific low level interface, for the remote server for
61+ GDB.
62+ Copyright (C) 1995-2013 Free Software Foundation, Inc.
63+
64+ This file is part of GDB.
65+
66+ This program is free software; you can redistribute it and/or modify
67+ it under the terms of the GNU General Public License as published by
68+ the Free Software Foundation; either version 3 of the License, or
69+ (at your option) any later version.
70+
71+ This program is distributed in the hope that it will be useful,
72+ but WITHOUT ANY WARRANTY; without even the implied warranty of
73+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74+ GNU General Public License for more details.
75+
76+ You should have received a copy of the GNU General Public License
77+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
78+
79+#include "server.h"
80+#include "linux-low.h"
81+
82+#include <asm/ptrace.h>
83+#include <sys/procfs.h>
84+#include <sys/ptrace.h>
85+
86+#include "gdb_proc_service.h"
87+
88+static int microblaze_regmap[] =
89+ {PT_GPR(0), PT_GPR(1), PT_GPR(2), PT_GPR(3),
90+ PT_GPR(4), PT_GPR(5), PT_GPR(6), PT_GPR(7),
91+ PT_GPR(8), PT_GPR(9), PT_GPR(10), PT_GPR(11),
92+ PT_GPR(12), PT_GPR(13), PT_GPR(14), PT_GPR(15),
93+ PT_GPR(16), PT_GPR(17), PT_GPR(18), PT_GPR(19),
94+ PT_GPR(20), PT_GPR(21), PT_GPR(22), PT_GPR(23),
95+ PT_GPR(24), PT_GPR(25), PT_GPR(26), PT_GPR(27),
96+ PT_GPR(28), PT_GPR(29), PT_GPR(30), PT_GPR(31),
97+ PT_PC, PT_MSR, PT_EAR, PT_ESR,
98+ PT_FSR
99+ };
100+
101+#define microblaze_num_regs (sizeof microblaze_regmap / sizeof microblaze_regmap[0])
102+
103+/* Defined in auto-generated file microblaze-linux.c. */
104+void init_registers_microblaze (void);
105+
106+static int
107+microblaze_cannot_store_register (int regno)
108+{
109+ if (microblaze_regmap[regno] == -1 || regno == 0)
110+ return 1;
111+
112+ return 0;
113+}
114+
115+static int
116+microblaze_cannot_fetch_register (int regno)
117+{
118+ return 0;
119+}
120+
121+static CORE_ADDR
122+microblaze_get_pc (struct regcache *regcache)
123+{
124+ unsigned long pc;
125+
126+ collect_register_by_name (regcache, "pc", &pc);
127+ return (CORE_ADDR) pc;
128+}
129+
130+static void
131+microblaze_set_pc (struct regcache *regcache, CORE_ADDR pc)
132+{
133+ unsigned long newpc = pc;
134+
135+ supply_register_by_name (regcache, "pc", &newpc);
136+}
137+
138+/* dbtrap insn */
139+/* brki r16, 0x18; */
140+static const unsigned long microblaze_breakpoint = 0xba0c0018;
141+#define microblaze_breakpoint_len 4
142+
143+static int
144+microblaze_breakpoint_at (CORE_ADDR where)
145+{
146+ unsigned long insn;
147+
148+ (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
149+ if (insn == microblaze_breakpoint)
150+ return 1;
151+ /* If necessary, recognize more trap instructions here. GDB only uses the
152+ one. */
153+ return 0;
154+}
155+
156+static CORE_ADDR
157+microblaze_reinsert_addr (struct regcache *regcache)
158+{
159+ unsigned long pc;
160+ collect_register_by_name (regcache, "r15", &pc);
161+ return pc;
162+}
163+
164+#ifdef HAVE_PTRACE_GETREGS
165+
166+static void
167+microblaze_collect_ptrace_register (struct regcache *regcache, int regno, char *buf)
168+{
169+ int size = register_size (regno);
170+
171+ memset (buf, 0, sizeof (long));
172+
173+ if (size < sizeof (long))
174+ collect_register (regcache, regno, buf + sizeof (long) - size);
175+ else
176+ collect_register (regcache, regno, buf);
177+}
178+
179+static void
180+microblaze_supply_ptrace_register (struct regcache *regcache,
181+ int regno, const char *buf)
182+{
183+ int size = register_size (regno);
184+
185+ if (regno == 0) {
186+ unsigned long regbuf_0 = 0;
187+ /* clobbering r0 so that it is always 0 as enforced by hardware */
188+ supply_register (regcache, regno, (const char*)&regbuf_0);
189+ } else {
190+ if (size < sizeof (long))
191+ supply_register (regcache, regno, buf + sizeof (long) - size);
192+ else
193+ supply_register (regcache, regno, buf);
194+ }
195+}
196+
197+/* Provide only a fill function for the general register set. ps_lgetregs
198+ will use this for NPTL support. */
199+
200+static void microblaze_fill_gregset (struct regcache *regcache, void *buf)
201+{
202+ int i;
203+
204+ for (i = 0; i < 32; i++)
205+ microblaze_collect_ptrace_register (regcache, i, (char *) buf + microblaze_regmap[i]);
206+}
207+
208+static void
209+microblaze_store_gregset (struct regcache *regcache, const void *buf)
210+{
211+ int i;
212+
213+ for (i = 0; i < 32; i++)
214+ supply_register (regcache, i, (char *) buf + microblaze_regmap[i]);
215+}
216+
217+#endif /* HAVE_PTRACE_GETREGS */
218+
219+struct regset_info target_regsets[] = {
220+#ifdef HAVE_PTRACE_GETREGS
221+ { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), GENERAL_REGS, microblaze_fill_gregset, microblaze_store_gregset },
222+ { 0, 0, 0, -1, -1, NULL, NULL },
223+#endif /* HAVE_PTRACE_GETREGS */
224+ { 0, 0, 0, -1, -1, NULL, NULL }
225+};
226+
227+struct linux_target_ops the_low_target = {
228+ init_registers_microblaze,
229+ microblaze_num_regs,
230+ microblaze_regmap,
231+ NULL,
232+ microblaze_cannot_fetch_register,
233+ microblaze_cannot_store_register,
234+ NULL, /* fetch_register */
235+ microblaze_get_pc,
236+ microblaze_set_pc,
237+ (const unsigned char *) &microblaze_breakpoint,
238+ microblaze_breakpoint_len,
239+ microblaze_reinsert_addr,
240+ 0,
241+ microblaze_breakpoint_at,
242+ NULL,
243+ NULL,
244+ NULL,
245+ NULL,
246+ microblaze_collect_ptrace_register,
247+ microblaze_supply_ptrace_register,
248+};
249diff --git a/gdb/microblaze-linux-tdep.c b/gdb/microblaze-linux-tdep.c
250index 4e5f60cd4e..7ab650a1cc 100644
251--- a/gdb/microblaze-linux-tdep.c
252+++ b/gdb/microblaze-linux-tdep.c
253@@ -37,6 +37,22 @@
254 #include "tramp-frame.h"
255 #include "linux-tdep.h"
256
257+static int microblaze_debug_flag = 0;
258+
259+static void
260+microblaze_debug (const char *fmt, ...)
261+{
262+ if (microblaze_debug_flag)
263+ {
264+ va_list args;
265+
266+ va_start (args, fmt);
267+ printf_unfiltered ("MICROBLAZE LINUX: ");
268+ vprintf_unfiltered (fmt, args);
269+ va_end (args);
270+ }
271+}
272+
273 static int
274 microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
275 struct bp_target_info *bp_tgt)
276@@ -46,18 +62,25 @@ microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
277 int val;
278 int bplen;
279 gdb_byte old_contents[BREAKPOINT_MAX];
280+ struct cleanup *cleanup;
281
282 /* Determine appropriate breakpoint contents and size for this address. */
283 bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
284
285+ /* Make sure we see the memory breakpoints. */
286+ cleanup = make_show_memory_breakpoints_cleanup (1);
287 val = target_read_memory (addr, old_contents, bplen);
288
289 /* If our breakpoint is no longer at the address, this means that the
290 program modified the code on us, so it is wrong to put back the
291 old value. */
292 if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
293- val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
294+ {
295+ val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
296+ microblaze_debug ("microblaze_linux_memory_remove_breakpoint writing back to memory at addr 0x%lx\n", addr);
297+ }
298
299+ do_cleanups (cleanup);
300 return val;
301 }
302
303@@ -129,6 +152,10 @@ microblaze_linux_init_abi (struct gdbarch_info info,
304 /* Trampolines. */
305 tramp_frame_prepend_unwinder (gdbarch,
306 &microblaze_linux_sighandler_tramp_frame);
307+
308+ /* Enable TLS support. */
309+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
310+ svr4_fetch_objfile_link_map);
311 }
312
313 void
314diff --git a/gdb/microblaze-tdep.c b/gdb/microblaze-tdep.c
315index 1248acbdc9..730a2b281f 100644
316--- a/gdb/microblaze-tdep.c
317+++ b/gdb/microblaze-tdep.c
318@@ -137,7 +137,38 @@ microblaze_fetch_instruction (CORE_ADDR pc)
319 constexpr gdb_byte microblaze_break_insn[] = MICROBLAZE_BREAKPOINT;
320
321 typedef BP_MANIPULATION (microblaze_break_insn) microblaze_breakpoint;
322-
323+static int
324+microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
325+ struct bp_target_info *bp_tgt)
326+{
327+ CORE_ADDR addr = bp_tgt->placed_address;
328+ const unsigned char *bp;
329+ int val;
330+ int bplen;
331+ gdb_byte old_contents[BREAKPOINT_MAX];
332+ struct cleanup *cleanup;
333+
334+ /* Determine appropriate breakpoint contents and size for this address. */
335+ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
336+ if (bp == NULL)
337+ error (_("Software breakpoints not implemented for this target."));
338+
339+ /* Make sure we see the memory breakpoints. */
340+ cleanup = make_show_memory_breakpoints_cleanup (1);
341+ val = target_read_memory (addr, old_contents, bplen);
342+
343+ /* If our breakpoint is no longer at the address, this means that the
344+ program modified the code on us, so it is wrong to put back the
345+ old value. */
346+ if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
347+ {
348+ val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
349+ microblaze_debug ("microblaze_linux_memory_remove_breakpoint writing back to memory at addr 0x%lx\n", addr);
350+ }
351+
352+ do_cleanups (cleanup);
353+ return val;
354+}
355
356 /* Allocate and initialize a frame cache. */
357
358@@ -731,6 +762,7 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
359 microblaze_breakpoint::kind_from_pc);
360 set_gdbarch_sw_breakpoint_from_kind (gdbarch,
361 microblaze_breakpoint::bp_from_kind);
362+ set_gdbarch_memory_remove_breakpoint (gdbarch, microblaze_linux_memory_remove_breakpoint);
363
364 set_gdbarch_frame_args_skip (gdbarch, 8);
365
366@@ -770,4 +802,5 @@ When non-zero, microblaze specific debugging is enabled."),
367 NULL,
368 &setdebuglist, &showdebuglist);
369
370+
371 }
372diff --git a/gdb/microblaze-tdep.h b/gdb/microblaze-tdep.h
373index a0048148e4..63aab84ef6 100644
374--- a/gdb/microblaze-tdep.h
375+++ b/gdb/microblaze-tdep.h
376@@ -117,6 +117,8 @@ struct microblaze_frame_cache
377
378 /* MICROBLAZE_BREAKPOINT defines the breakpoint that should be used.
379 Only used for native debugging. */
380-#define MICROBLAZE_BREAKPOINT {0xb9, 0xcc, 0x00, 0x60}
381+#define MICROBLAZE_BREAKPOINT {0xba, 0x0c, 0x00, 0x18}
382+#define MICROBLAZE_BREAKPOINT_LE {0x18, 0x00, 0x0c, 0xba}
383+
384
385 #endif /* microblaze-tdep.h */
386diff --git a/gdb/regformats/reg-microblaze.dat b/gdb/regformats/reg-microblaze.dat
387new file mode 100644
388index 0000000000..bd8a438442
389--- /dev/null
390+++ b/gdb/regformats/reg-microblaze.dat
391@@ -0,0 +1,41 @@
392+name:microblaze
393+expedite:r1,pc
394+32:r0
395+32:r1
396+32:r2
397+32:r3
398+32:r4
399+32:r5
400+32:r6
401+32:r7
402+32:r8
403+32:r9
404+32:r10
405+32:r11
406+32:r12
407+32:r13
408+32:r14
409+32:r15
410+32:r16
411+32:r17
412+32:r18
413+32:r19
414+32:r20
415+32:r21
416+32:r22
417+32:r23
418+32:r24
419+32:r25
420+32:r26
421+32:r27
422+32:r28
423+32:r29
424+32:r30
425+32:r31
426+32:pc
427+32:msr
428+32:ear
429+32:esr
430+32:fsr
431+32:slr
432+32:shr
433--
4342.17.1
435