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