diff options
author | Franck Jullien <franck.jullien@gmail.com> | 2017-12-09 05:57:25 +0900 |
---|---|---|
committer | Stafford Horne <shorne@gmail.com> | 2017-12-12 23:36:00 +0900 |
commit | a994fec4f8f7a886be61cfb3023c354cd2483b9d (patch) | |
tree | a95c3f3bdea6b9a51ddffd2c74d7a7286cf41e25 /gdb | |
parent | db9077b7275e86637218a7a7d165cb85a4de116f (diff) | |
download | gdb-a994fec4f8f7a886be61cfb3023c354cd2483b9d.zip gdb-a994fec4f8f7a886be61cfb3023c354cd2483b9d.tar.gz gdb-a994fec4f8f7a886be61cfb3023c354cd2483b9d.tar.bz2 |
gdb: Add OpenRISC or1k and or1knd target support
This patch prepares the current GDB port of the OpenRISC processor from
https://github.com/openrisc/binutils-gdb for upstream merging.
Testing has been done with a cgen sim provided in a separate patch. This
has been tested with 2 toolchains. GCC [1] 5.4.0 from the OpenRISC
project with Newlib [2] and GCC 5.4.0 with Musl [3] 1.1.4.
It supports or1knd (no delay slot target).
The default target is or1k (with delay slot).
You can change the target arch with:
(gdb) set architecture or1knd
The target architecture is assumed to be or1knd
[1] https://github.com/openrisc/or1k-gcc
[2] https://github.com/openrisc/newlib
[3] https://github.com/openrisc/musl-cross
gdb/doc/ChangeLog:
2017-12-12 Stafford Horne <shorne@gmail.com>
Stefan Wallentowitz <stefan@wallentowitz.de>
Franck Jullien <franck.jullien@gmail.com>
Jeremy Bennett <jeremy.bennett@embecosm.com>
* gdb.texinfo: Add OpenRISC documentation.
gdb/ChangeLog:
2017-12-12 Stafford Horne <shorne@gmail.com>
Stefan Wallentowitz <stefan@wallentowitz.de>
Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Franck Jullien <franck.jullien@gmail.com>
Jeremy Bennett <jeremy.bennett@embecosm.com>
* configure.tgt: Add targets for or1k and or1knd.
* or1k-tdep.c: New file.
* or1k-tdep.h: New file.
* features/Makefile: Add or1k.xml to build.
* features/or1k.xml: New file.
* features/or1k-core.xml: New file.
* features/or1k.c: Generated.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 14 | ||||
-rw-r--r-- | gdb/configure.tgt | 6 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 47 | ||||
-rw-r--r-- | gdb/features/Makefile | 2 | ||||
-rw-r--r-- | gdb/features/or1k-core.xml | 65 | ||||
-rw-r--r-- | gdb/features/or1k.c | 77 | ||||
-rw-r--r-- | gdb/features/or1k.xml | 12 | ||||
-rw-r--r-- | gdb/or1k-tdep.c | 1294 | ||||
-rw-r--r-- | gdb/or1k-tdep.h | 56 |
10 files changed, 1580 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 52ccbf5..201a9f3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2017-12-12 Stafford Horne <shorne@gmail.com> + Stefan Wallentowitz <stefan@wallentowitz.de> + Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> + Franck Jullien <franck.jullien@gmail.com> + Jeremy Bennett <jeremy.bennett@embecosm.com> + + * configure.tgt: Add targets for or1k and or1knd. + * or1k-tdep.c: New file. + * or1k-tdep.h: New file. + * features/Makefile: Add or1k.xml to build. + * features/or1k.xml: New file. + * features/or1k-core.xml: New file. + * features/or1k.c: Generated. + 2017-12-12 Alan Modra <amodra@gmail.com> PR tdep/22576 diff --git a/gdb/configure.tgt b/gdb/configure.tgt index f720154..fb8014a 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -463,6 +463,12 @@ nios2*-*-*) gdb_target_obs="nios2-tdep.o" ;; +or1k-*-* | or1knd-*-*) + # Target: OpenCores OpenRISC 1000 32-bit implementation bare metal + gdb_target_obs="or1k-tdep.o" + gdb_sim=../sim/or1k/libsim.a + ;; + powerpc*-*-freebsd*) # Target: FreeBSD/powerpc gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 7710640..4e032ec 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2017-12-12 Stafford Horne <shorne@gmail.com> + Stefan Wallentowitz <stefan@wallentowitz.de> + Franck Jullien <franck.jullien@gmail.com> + Jeremy Bennett <jeremy.bennett@embecosm.com> + + * gdb.texinfo: Add OpenRISC documentation. + 2017-12-08 Jan Kratochvil <jan.kratochvil@redhat.com> * gdb.texinfo (Index Files): Document .debug_names and -dwarf-5. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 062f01d..da3ed28 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -546,6 +546,11 @@ was developed by SRI International and the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. +The original port to the OpenRISC 1000 is believed to be due to +Alessandro Forin and Per Bothner. More recent ports have been the work +of Jeremy Bennett, Franck Jullien, Stefan Wallentowitz and +Stafford Horne. + @node Sample Session @chapter A Sample @value{GDBN} Session @@ -22442,6 +22447,7 @@ acceptable commands. * M68K:: Motorola M68K * MicroBlaze:: Xilinx MicroBlaze * MIPS Embedded:: MIPS Embedded +* OpenRISC 1000:: OpenRISC 1000 (or1k) * PowerPC Embedded:: PowerPC Embedded * AVR:: Atmel AVR * CRIS:: CRIS @@ -22651,6 +22657,38 @@ As usual, you can inquire about the @code{mipsfpu} variable with @samp{show mipsfpu}. @end table +@node OpenRISC 1000 +@subsection OpenRISC 1000 +@cindex OpenRISC 1000 + +@noindent +The OpenRISC 1000 provides a free RISC instruction set architecture. It is +mainly provided as a soft-core which can run on Xilinx, Altera and other +FPGA's. + +@value{GDBN} for OpenRISC supports the below commands when connecting to +a target: + +@table @code + +@kindex target sim +@item target sim + +Runs the builtin CPU simulator which can run very basic +programs but does not support most hardware functions like MMU. +For more complex use cases the user is advised to run an external +target, and connect using @samp{target remote}. + +Example: @code{target sim} + +@item set debug or1k +Toggle whether to display OpenRISC-specific debugging messages from the +OpenRISC target support subsystem. + +@item show debug or1k +Show whether OpenRISC-specific debugging messages are enabled. +@end table + @node PowerPC Embedded @subsection PowerPC Embedded @@ -41739,6 +41777,7 @@ registers using the capitalization used in the description. * M68K Features:: * NDS32 Features:: * Nios II Features:: +* OpenRISC 1000 Features:: * PowerPC Features:: * S/390 and System z Features:: * Sparc Features:: @@ -42025,6 +42064,14 @@ targets. It should contain the 32 core registers (@samp{zero}, @samp{pc}, and the 16 control registers (@samp{status} through @samp{mpuacc}). +@node OpenRISC 1000 Features +@subsection Openrisc 1000 Features +@cindex target descriptions, OpenRISC 1000 features + +The @samp{org.gnu.gdb.or1k.group0} feature is required for OpenRISC 1000 +targets. It should contain the 32 general purpose registers (@samp{r0} +through @samp{r31}), @samp{ppc}, @samp{npc} and @samp{sr}. + @node PowerPC Features @subsection PowerPC Features @cindex target descriptions, PowerPC features diff --git a/gdb/features/Makefile b/gdb/features/Makefile index 73be34c..c78349e 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -93,6 +93,7 @@ mips64-expedite = r29,pc mips64-dsp-expedite = r29,pc microblaze-expedite = r1,rpc nios2-linux-expedite = sp,pc +or1k-expedite = r1,npc powerpc-expedite = r1,pc rs6000/powerpc-cell32l-expedite = r1,pc,r0,orig_r3,r4 rs6000/powerpc-cell64l-expedite = r1,pc,r0,orig_r3,r4 @@ -136,6 +137,7 @@ XMLTOC = \ mips64-linux.xml \ nds32.xml \ nios2.xml \ + or1k.xml \ rs6000/powerpc-32.xml \ rs6000/powerpc-32l.xml \ rs6000/powerpc-403.xml \ diff --git a/gdb/features/or1k-core.xml b/gdb/features/or1k-core.xml new file mode 100644 index 0000000..1a9673d --- /dev/null +++ b/gdb/features/or1k-core.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2017 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.or1k.group0"> + <reg name="r0" bitsize="32" type="int"/> + <reg name="r1" bitsize="32" type="data_ptr"/> + <reg name="r2" bitsize="32" type="data_ptr"/> + <reg name="r3" bitsize="32" type="int"/> + <reg name="r4" bitsize="32" type="int"/> + <reg name="r5" bitsize="32" type="int"/> + <reg name="r6" bitsize="32" type="int"/> + <reg name="r7" bitsize="32" type="int"/> + <reg name="r8" bitsize="32" type="int"/> + <reg name="r9" bitsize="32" type="code_ptr"/> + <reg name="r10" bitsize="32" type="int"/> + <reg name="r11" bitsize="32" type="int"/> + <reg name="r12" bitsize="32" type="int"/> + <reg name="r13" bitsize="32" type="int"/> + <reg name="r14" bitsize="32" type="int"/> + <reg name="r15" bitsize="32" type="int"/> + <reg name="r16" bitsize="32" type="int"/> + <reg name="r17" bitsize="32" type="int"/> + <reg name="r18" bitsize="32" type="int"/> + <reg name="r19" bitsize="32" type="int"/> + <reg name="r20" bitsize="32" type="int"/> + <reg name="r21" bitsize="32" type="int"/> + <reg name="r22" bitsize="32" type="int"/> + <reg name="r23" bitsize="32" type="int"/> + <reg name="r24" bitsize="32" type="int"/> + <reg name="r25" bitsize="32" type="int"/> + <reg name="r26" bitsize="32" type="int"/> + <reg name="r27" bitsize="32" type="int"/> + <reg name="r28" bitsize="32" type="int"/> + <reg name="r29" bitsize="32" type="int"/> + <reg name="r30" bitsize="32" type="int"/> + <reg name="r31" bitsize="32" type="int"/> + <reg name="ppc" bitsize="32" type="code_ptr"/> + <reg name="npc" bitsize="32" type="code_ptr"/> + <flags id="sr_flags" size="4"> + <field name="SM" start="0" end="0"/> + <field name="TEE" start="1" end="1"/> + <field name="IEE" start="2" end="2"/> + <field name="DCE" start="3" end="3"/> + <field name="ICE" start="4" end="4"/> + <field name="DME" start="5" end="5"/> + <field name="IME" start="6" end="6"/> + <field name="LEE" start="7" end="7"/> + <field name="CE" start="8" end="8"/> + <field name="F" start="9" end="9"/> + <field name="CY" start="10" end="10"/> + <field name="OV" start="11" end="11"/> + <field name="OVE" start="12" end="12"/> + <field name="DSX" start="13" end="13"/> + <field name="EPH" start="14" end="14"/> + <field name="FO" start="15" end="15"/> + <field name="SUMRA" start="16" end="16"/> + <field name="CID" start="28" end="31"/> + </flags> + <reg name="sr" bitsize="32" type="sr_flags"/> +</feature> diff --git a/gdb/features/or1k.c b/gdb/features/or1k.c new file mode 100644 index 0000000..929a5f9 --- /dev/null +++ b/gdb/features/or1k.c @@ -0,0 +1,77 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: or1k.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_or1k; +static void +initialize_tdesc_or1k (void) +{ + struct target_desc *result = allocate_target_description (); + set_tdesc_architecture (result, bfd_scan_arch ("or1k")); + + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.or1k.group0"); + tdesc_type_with_fields *type_with_fields; + tdesc_type *field_type; + type_with_fields = tdesc_create_flags (feature, "sr_flags", 4); + tdesc_add_flag (type_with_fields, 0, "SM"); + tdesc_add_flag (type_with_fields, 1, "TEE"); + tdesc_add_flag (type_with_fields, 2, "IEE"); + tdesc_add_flag (type_with_fields, 3, "DCE"); + tdesc_add_flag (type_with_fields, 4, "ICE"); + tdesc_add_flag (type_with_fields, 5, "DME"); + tdesc_add_flag (type_with_fields, 6, "IME"); + tdesc_add_flag (type_with_fields, 7, "LEE"); + tdesc_add_flag (type_with_fields, 8, "CE"); + tdesc_add_flag (type_with_fields, 9, "F"); + tdesc_add_flag (type_with_fields, 10, "CY"); + tdesc_add_flag (type_with_fields, 11, "OV"); + tdesc_add_flag (type_with_fields, 12, "OVE"); + tdesc_add_flag (type_with_fields, 13, "DSX"); + tdesc_add_flag (type_with_fields, 14, "EPH"); + tdesc_add_flag (type_with_fields, 15, "FO"); + tdesc_add_flag (type_with_fields, 16, "SUMRA"); + tdesc_add_bitfield (type_with_fields, "CID", 28, 31); + + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r26", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r27", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r28", 28, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r29", 29, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r30", 30, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r31", 31, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "ppc", 32, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "npc", 33, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "sr", 34, 1, NULL, 32, "sr_flags"); + + tdesc_or1k = result; +} diff --git a/gdb/features/or1k.xml b/gdb/features/or1k.xml new file mode 100644 index 0000000..c138a02 --- /dev/null +++ b/gdb/features/or1k.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2016 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE target SYSTEM "gdb-target.dtd"> +<target> + <architecture>or1k</architecture> + <xi:include href="or1k-core.xml"/> +</target> diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c new file mode 100644 index 0000000..54b365e --- /dev/null +++ b/gdb/or1k-tdep.c @@ -0,0 +1,1294 @@ +/* Target-dependent code for the 32-bit OpenRISC 1000, for the GDB. + Copyright (C) 2008-2017 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" +#include "language.h" +#include "gdbcore.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbtypes.h" +#include "target.h" +#include "regcache.h" +#include "safe-ctype.h" +#include "block.h" +#include "reggroups.h" +#include "arch-utils.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "dwarf2-frame.h" +#include "trad-frame.h" +#include "regset.h" +#include "remote.h" +#include "target-descriptions.h" +#include <inttypes.h> +#include "dis-asm.h" + +/* OpenRISC specific includes. */ +#include "or1k-tdep.h" +#include "features/or1k.c" + + +/* Global debug flag. */ + +static int or1k_debug = 0; + +static void +show_or1k_debug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("OpenRISC debugging is %s.\n"), value); +} + + +/* The target-dependent structure for gdbarch. */ + +struct gdbarch_tdep +{ + int bytes_per_word; + int bytes_per_address; + CGEN_CPU_DESC gdb_cgen_cpu_desc; +}; + +/* Support functions for the architecture definition. */ + +/* Get an instruction from memory. */ + +static ULONGEST +or1k_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[OR1K_INSTLEN]; + + if (target_read_code (addr, buf, OR1K_INSTLEN)) { + memory_error (TARGET_XFER_E_IO, addr); + } + + return extract_unsigned_integer (buf, OR1K_INSTLEN, byte_order); +} + +/* Generic function to read bits from an instruction. */ + +static bool +or1k_analyse_inst (uint32_t inst, const char *format, ...) +{ + /* Break out each field in turn, validating as we go. */ + va_list ap; + int i; + int iptr = 0; /* Instruction pointer */ + + va_start (ap, format); + + for (i = 0; 0 != format[i];) + { + const char *start_ptr; + char *end_ptr; + + uint32_t bits; /* Bit substring of interest */ + uint32_t width; /* Substring width */ + uint32_t *arg_ptr; + + switch (format[i]) + { + case ' ': + i++; + break; /* Formatting: ignored */ + + case '0': + case '1': /* Constant bit field */ + bits = (inst >> (OR1K_INSTBITLEN - iptr - 1)) & 0x1; + + if ((format[i] - '0') != bits) + return false; + + iptr++; + i++; + break; + + case '%': /* Bit field */ + i++; + start_ptr = &(format[i]); + width = strtoul (start_ptr, &end_ptr, 10); + + /* Check we got something, and if so skip on. */ + if (start_ptr == end_ptr) + error ("bitstring \"%s\" at offset %d has no length field.\n", + format, i); + + i += end_ptr - start_ptr; + + /* Look for and skip the terminating 'b'. If it's not there, we + still give a fatal error, because these are fixed strings that + just should not be wrong. */ + if ('b' != format[i++]) + error ("bitstring \"%s\" at offset %d has no terminating 'b'.\n", + format, i); + + /* Break out the field. There is a special case with a bit width + of 32. */ + if (32 == width) + bits = inst; + else + bits = + (inst >> (OR1K_INSTBITLEN - iptr - width)) & ((1 << width) - 1); + + arg_ptr = va_arg (ap, uint32_t *); + *arg_ptr = bits; + iptr += width; + break; + + default: + error ("invalid character in bitstring \"%s\" at offset %d.\n", + format, i); + break; + } + } + + /* Is the length OK? */ + gdb_assert (OR1K_INSTBITLEN == iptr); + + return true; /* Success */ +} + +/* This is used to parse l.addi instructions during various prologue + analysis routines. The l.addi instruction has semantics: + + assembly: l.addi rD,rA,I + implementation: rD = rA + sign_extend(Immediate) + + The rd_ptr, ra_ptr and simm_ptr must be non NULL pointers and are used + to store the parse results. Upon successful parsing true is returned, + false on failure. */ + +static bool +or1k_analyse_l_addi (uint32_t inst, unsigned int *rd_ptr, + unsigned int *ra_ptr, int *simm_ptr) +{ + /* Instruction fields */ + uint32_t rd, ra, i; + + if (or1k_analyse_inst (inst, "10 0111 %5b %5b %16b", &rd, &ra, &i)) + { + /* Found it. Construct the result fields. */ + *rd_ptr = (unsigned int) rd; + *ra_ptr = (unsigned int) ra; + *simm_ptr = (int) (((i & 0x8000) == 0x8000) ? 0xffff0000 | i : i); + + return true; /* Success */ + } + else + return false; /* Failure */ +} + +/* This is used to to parse store instructions during various prologue + analysis routines. The l.sw instruction has semantics: + + assembly: l.sw I(rA),rB + implementation: store rB contents to memory at effective address of + rA + sign_extend(Immediate) + + The simm_ptr, ra_ptr and rb_ptr must be non NULL pointers and are used + to store the parse results. Upon successful parsing true is returned, + false on failure. */ + +static bool +or1k_analyse_l_sw (uint32_t inst, int *simm_ptr, unsigned int *ra_ptr, + unsigned int *rb_ptr) +{ + /* Instruction fields */ + uint32_t ihi, ilo, ra, rb; + + if (or1k_analyse_inst (inst, "11 0101 %5b %5b %5b %11b", &ihi, &ra, &rb, + &ilo)) + + { + /* Found it. Construct the result fields. */ + *simm_ptr = (int) ((ihi << 11) | ilo); + *simm_ptr |= ((ihi & 0x10) == 0x10) ? 0xffff0000 : 0; + + *ra_ptr = (unsigned int) ra; + *rb_ptr = (unsigned int) rb; + + return true; /* Success */ + } + else + return false; /* Failure */ +} + + +/* Functions defining the architecture. */ + +/* Implement the return_value gdbarch method. */ + +static enum return_value_convention +or1k_return_value (struct gdbarch *gdbarch, struct value *functype, + struct type *valtype, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + enum type_code rv_type = TYPE_CODE (valtype); + unsigned int rv_size = TYPE_LENGTH (valtype); + int bpw = (gdbarch_tdep (gdbarch))->bytes_per_word; + + /* Deal with struct/union as addresses. If an array won't fit in a + single register it is returned as address. Anything larger than 2 + registers needs to also be passed as address (matches gcc + default_return_in_memory). */ + if ((TYPE_CODE_STRUCT == rv_type) || (TYPE_CODE_UNION == rv_type) + || ((TYPE_CODE_ARRAY == rv_type) && (rv_size > bpw)) + || (rv_size > 2 * bpw)) + { + if (readbuf != NULL) + { + ULONGEST tmp; + + regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, &tmp); + read_memory (tmp, readbuf, rv_size); + } + if (writebuf != NULL) + { + ULONGEST tmp; + + regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, &tmp); + write_memory (tmp, writebuf, rv_size); + } + + return RETURN_VALUE_ABI_RETURNS_ADDRESS; + } + + if (rv_size <= bpw) + { + /* Up to one word scalars are returned in R11. */ + if (readbuf != NULL) + { + ULONGEST tmp; + + regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, &tmp); + store_unsigned_integer (readbuf, rv_size, byte_order, tmp); + + } + if (writebuf != NULL) + { + gdb_byte *buf = XCNEWVEC(gdb_byte, bpw); + + if (BFD_ENDIAN_BIG == byte_order) + memcpy (buf + (sizeof (gdb_byte) * bpw) - rv_size, writebuf, + rv_size); + else + memcpy (buf, writebuf, rv_size); + + regcache_cooked_write (regcache, OR1K_RV_REGNUM, buf); + + free (buf); + } + } + else + { + /* 2 word scalars are returned in r11/r12 (with the MS word in r11). */ + if (readbuf != NULL) + { + ULONGEST tmp_lo; + ULONGEST tmp_hi; + ULONGEST tmp; + + regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, + &tmp_hi); + regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM + 1, + &tmp_lo); + tmp = (tmp_hi << (bpw * 8)) | tmp_lo; + + store_unsigned_integer (readbuf, rv_size, byte_order, tmp); + } + if (writebuf != NULL) + { + gdb_byte *buf_lo = XCNEWVEC(gdb_byte, bpw); + gdb_byte *buf_hi = XCNEWVEC(gdb_byte, bpw); + + /* This is cheating. We assume that we fit in 2 words exactly, + which wouldn't work if we had (say) a 6-byte scalar type on a + big endian architecture (with the OpenRISC 1000 usually is). */ + memcpy (buf_hi, writebuf, rv_size - bpw); + memcpy (buf_lo, writebuf + bpw, bpw); + + regcache_cooked_write (regcache, OR1K_RV_REGNUM, buf_hi); + regcache_cooked_write (regcache, OR1K_RV_REGNUM + 1, buf_lo); + + free (buf_lo); + free (buf_hi); + } + } + + return RETURN_VALUE_REGISTER_CONVENTION; +} + +/* OR1K always uses a l.trap instruction for breakpoints. */ + +constexpr gdb_byte or1k_break_insn[] = {0x21, 0x00, 0x00, 0x01}; + +typedef BP_MANIPULATION (or1k_break_insn) or1k_breakpoint; + +/* Implement the single_step_through_delay gdbarch method. */ + +static int +or1k_single_step_through_delay (struct gdbarch *gdbarch, + struct frame_info *this_frame) +{ + ULONGEST val; + CORE_ADDR ppc; + CORE_ADDR npc; + CGEN_FIELDS tmp_fields; + const CGEN_INSN *insn; + struct regcache *regcache = get_current_regcache (); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* Get the previous and current instruction addresses. If they are not + adjacent, we cannot be in a delay slot. */ + regcache_cooked_read_unsigned (regcache, OR1K_PPC_REGNUM, &val); + ppc = (CORE_ADDR) val; + regcache_cooked_read_unsigned (regcache, OR1K_NPC_REGNUM, &val); + npc = (CORE_ADDR) val; + + if (0x4 != (npc - ppc)) + return 0; + + insn = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc, + NULL, + or1k_fetch_instruction (gdbarch, ppc), + NULL, 32, &tmp_fields, 0); + + /* NULL here would mean the last instruction was not understood by cgen. + This should not usually happen, but if does its not a delay slot. */ + if (insn == NULL) + return 0; + + /* TODO: we should add a delay slot flag to the CGEN_INSN and remove + this hard coded test. */ + return ((CGEN_INSN_NUM (insn) == OR1K_INSN_L_J) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JAL) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JR) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_JALR) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BNF) + || (CGEN_INSN_NUM (insn) == OR1K_INSN_L_BF)); +} + +/* Name for or1k general registers. */ + +static const char *const or1k_reg_names[OR1K_NUM_REGS] = { + /* general purpose registers */ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + + /* previous program counter, next program counter and status register */ + "ppc", "npc", "sr" +}; + +static int +or1k_is_arg_reg (unsigned int regnum) +{ + return (OR1K_FIRST_ARG_REGNUM <= regnum) + && (regnum <= OR1K_LAST_ARG_REGNUM); +} + +static int +or1k_is_callee_saved_reg (unsigned int regnum) +{ + return (OR1K_FIRST_SAVED_REGNUM <= regnum) && (0 == regnum % 2); +} + +/* Implement the skip_prologue gdbarch method. */ + +static CORE_ADDR +or1k_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR start_pc; + CORE_ADDR addr; + uint32_t inst; + + unsigned int ra, rb, rd; /* for instruction analysis */ + int simm; + + int frame_size = 0; + + /* Try using SAL first if we have symbolic information available. This + only works for DWARF 2, not STABS. */ + + if (find_pc_partial_function (pc, NULL, &start_pc, NULL)) + { + CORE_ADDR prologue_end = skip_prologue_using_sal (gdbarch, pc); + + if (0 != prologue_end) + { + struct symtab_and_line prologue_sal = find_pc_line (start_pc, 0); + struct compunit_symtab *compunit + = SYMTAB_COMPUNIT (prologue_sal.symtab); + const char *debug_format = COMPUNIT_DEBUGFORMAT (compunit); + + if ((NULL != debug_format) + && (strlen ("dwarf") <= strlen (debug_format)) + && (0 == strncasecmp ("dwarf", debug_format, strlen ("dwarf")))) + return (prologue_end > pc) ? prologue_end : pc; + } + } + + /* Look to see if we can find any of the standard prologue sequence. All + quite difficult, since any or all of it may be missing. So this is + just a best guess! */ + + addr = pc; /* Where we have got to */ + inst = or1k_fetch_instruction (gdbarch, addr); + + /* Look for the new stack pointer being set up. */ + if (or1k_analyse_l_addi (inst, &rd, &ra, &simm) + && (OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) + && (simm < 0) && (0 == (simm % 4))) + { + frame_size = -simm; + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + } + + /* Look for the frame pointer being manipulated. */ + if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) + && (OR1K_SP_REGNUM == ra) && (OR1K_FP_REGNUM == rb) + && (simm >= 0) && (0 == (simm % 4))) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + + gdb_assert (or1k_analyse_l_addi (inst, &rd, &ra, &simm) + && (OR1K_FP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) + && (simm == frame_size)); + + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + } + + /* Look for the link register being saved. */ + if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) + && (OR1K_SP_REGNUM == ra) && (OR1K_LR_REGNUM == rb) + && (simm >= 0) && (0 == (simm % 4))) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + } + + /* Look for arguments or callee-saved register being saved. The register + must be one of the arguments (r3-r8) or the 10 callee saved registers + (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base + register must be the FP (for the args) or the SP (for the callee_saved + registers). */ + while (1) + { + if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) + && (((OR1K_FP_REGNUM == ra) && or1k_is_arg_reg (rb)) + || ((OR1K_SP_REGNUM == ra) && or1k_is_callee_saved_reg (rb))) + && (0 == (simm % 4))) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + } + else + { + /* Nothing else to look for. We have found the end of the + prologue. */ + break; + } + } + return addr; +} + +/* Implement the frame_align gdbarch method. */ + +static CORE_ADDR +or1k_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) +{ + return align_down (sp, OR1K_STACK_ALIGN); +} + +/* Implement the unwind_pc gdbarch method. */ + +static CORE_ADDR +or1k_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + CORE_ADDR pc; + + if (or1k_debug) + fprintf_unfiltered (gdb_stdlog, "or1k_unwind_pc, next_frame=%d\n", + frame_relative_level (next_frame)); + + pc = frame_unwind_register_unsigned (next_frame, OR1K_NPC_REGNUM); + + if (or1k_debug) + fprintf_unfiltered (gdb_stdlog, "or1k_unwind_pc, pc=0x%p\n", + (void *) pc); + + return pc; +} + +/* Implement the unwind_sp gdbarch method. */ + +static CORE_ADDR +or1k_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + CORE_ADDR sp; + + if (or1k_debug) + fprintf_unfiltered (gdb_stdlog, "or1k_unwind_sp, next_frame=%d\n", + frame_relative_level (next_frame)); + + sp = frame_unwind_register_unsigned (next_frame, OR1K_SP_REGNUM); + + if (or1k_debug) + fprintf_unfiltered (gdb_stdlog, "or1k_unwind_sp, sp=0x%p\n", + (void *) sp); + + return sp; +} + +/* Implement the push_dummy_code gdbarch method. */ + +static CORE_ADDR +or1k_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, + CORE_ADDR function, struct value **args, int nargs, + struct type *value_type, CORE_ADDR * real_pc, + CORE_ADDR * bp_addr, struct regcache *regcache) +{ + CORE_ADDR bp_slot; + + /* Reserve enough room on the stack for our breakpoint instruction. */ + bp_slot = sp - 4; + /* Store the address of that breakpoint. */ + *bp_addr = bp_slot; + /* keeping the stack aligned. */ + sp = or1k_frame_align (gdbarch, bp_slot); + /* The call starts at the callee's entry point. */ + *real_pc = function; + + return sp; +} + +/* Implement the push_dummy_call gdbarch method. */ + +static CORE_ADDR +or1k_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + + int argreg; + int argnum; + int first_stack_arg; + int stack_offset = 0; + int heap_offset = 0; + CORE_ADDR heap_sp = sp - 128; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int bpa = (gdbarch_tdep (gdbarch))->bytes_per_address; + int bpw = (gdbarch_tdep (gdbarch))->bytes_per_word; + struct type *func_type = value_type (function); + + /* Return address */ + regcache_cooked_write_unsigned (regcache, OR1K_LR_REGNUM, bp_addr); + + /* Register for the next argument. */ + argreg = OR1K_FIRST_ARG_REGNUM; + + /* Location for a returned structure. This is passed as a silent first + argument. */ + if (struct_return) + { + regcache_cooked_write_unsigned (regcache, OR1K_FIRST_ARG_REGNUM, + struct_addr); + argreg++; + } + + /* Put as many args as possible in registers. */ + for (argnum = 0; argnum < nargs; argnum++) + { + const gdb_byte *val; + gdb_byte valbuf[sizeof (ULONGEST)]; + + struct value *arg = args[argnum]; + struct type *arg_type = check_typedef (value_type (arg)); + int len = TYPE_LENGTH (arg_type); + enum type_code typecode = TYPE_CODE (arg_type); + + if (TYPE_VARARGS (func_type) && argnum >= TYPE_NFIELDS (func_type)) + break; /* end or regular args, varargs go to stack. */ + + /* Extract the value, either a reference or the data. */ + if ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode) + || (len > bpw * 2)) + { + CORE_ADDR valaddr = value_address (arg); + + /* If the arg is fabricated (i.e. 3*i, instead of i) valaddr is + undefined. */ + if (valaddr == 0) + { + /* The argument needs to be copied into the target space. + Since the bottom of the stack is reserved for function + arguments we store this at the these at the top growing + down. */ + heap_offset += align_up (len, bpw); + valaddr = heap_sp + heap_offset; + + write_memory (valaddr, value_contents (arg), len); + } + + /* The ABI passes all structures by reference, so get its + address. */ + store_unsigned_integer (valbuf, bpa, byte_order, valaddr); + len = bpa; + val = valbuf; + } + else + { + /* Everything else, we just get the value. */ + val = value_contents (arg); + } + + /* Stick the value in a register. */ + if (len > bpw) + { + /* Big scalars use two registers, but need NOT be pair aligned. */ + + if (argreg <= (OR1K_LAST_ARG_REGNUM - 1)) + { + ULONGEST regval = extract_unsigned_integer (val, len, + byte_order); + + unsigned int bits_per_word = bpw * 8; + ULONGEST mask = (((ULONGEST) 1) << bits_per_word) - 1; + ULONGEST lo = regval & mask; + ULONGEST hi = regval >> bits_per_word; + + regcache_cooked_write_unsigned (regcache, argreg, hi); + regcache_cooked_write_unsigned (regcache, argreg + 1, lo); + argreg += 2; + } + else + { + /* Run out of regs */ + break; + } + } + else if (argreg <= OR1K_LAST_ARG_REGNUM) + { + /* Smaller scalars fit in a single register. */ + regcache_cooked_write_unsigned + (regcache, argreg, extract_unsigned_integer (val, len, + byte_order)); + argreg++; + } + else + { + /* Ran out of regs. */ + break; + } + } + + first_stack_arg = argnum; + + /* If we get here with argnum < nargs, then arguments remain to be + placed on the stack. This is tricky, since they must be pushed in + reverse order and the stack in the end must be aligned. The only + solution is to do it in two stages, the first to compute the stack + size, the second to save the args. */ + + for (argnum = first_stack_arg; argnum < nargs; argnum++) + { + struct value *arg = args[argnum]; + struct type *arg_type = check_typedef (value_type (arg)); + int len = TYPE_LENGTH (arg_type); + enum type_code typecode = TYPE_CODE (arg_type); + + if ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode) + || (len > bpw * 2)) + { + /* Structures are passed as addresses. */ + sp -= bpa; + } + else + { + /* Big scalars use more than one word. Code here allows for + future quad-word entities (e.g. long double.) */ + sp -= align_up (len, bpw); + } + + /* Ensure our dummy heap doesn't touch the stack, this could only + happen if we have many arguments including fabricated arguments. */ + gdb_assert (heap_offset == 0 || ((heap_sp + heap_offset) < sp)); + } + + sp = gdbarch_frame_align (gdbarch, sp); + stack_offset = 0; + + /* Push the remaining args on the stack. */ + for (argnum = first_stack_arg; argnum < nargs; argnum++) + { + const gdb_byte *val; + gdb_byte valbuf[sizeof (ULONGEST)]; + + struct value *arg = args[argnum]; + struct type *arg_type = check_typedef (value_type (arg)); + int len = TYPE_LENGTH (arg_type); + enum type_code typecode = TYPE_CODE (arg_type); + /* The EABI passes structures that do not fit in a register by + reference. In all other cases, pass the structure by value. */ + if ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode) + || (len > bpw * 2)) + { + store_unsigned_integer (valbuf, bpa, byte_order, + value_address (arg)); + len = bpa; + val = valbuf; + } + else + val = value_contents (arg); + + while (len > 0) + { + int partial_len = (len < bpw ? len : bpw); + + write_memory (sp + stack_offset, val, partial_len); + stack_offset += align_up (partial_len, bpw); + len -= partial_len; + val += partial_len; + } + } + + /* Save the updated stack pointer. */ + regcache_cooked_write_unsigned (regcache, OR1K_SP_REGNUM, sp); + + if (heap_offset > 0) + sp = heap_sp; + + return sp; +} + +/* Implement the dummy_id gdbarch method. */ + +static struct frame_id +or1k_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + return frame_id_build (get_frame_sp (this_frame), + get_frame_pc (this_frame)); +} + + +/* Support functions for frame handling. */ + +/* Initialize a prologue cache + + We build a cache, saying where registers of the prev frame can be found + from the data so far set up in this this. + + We also compute a unique ID for this frame, based on the function start + address and the stack pointer (as it will be, even if it has yet to be + computed. + + STACK FORMAT + ============ + + The OR1K has a falling stack frame and a simple prolog. The Stack + pointer is R1 and the frame pointer R2. The frame base is therefore the + address held in R2 and the stack pointer (R1) is the frame base of the + next frame. + + l.addi r1,r1,-frame_size # SP now points to end of new stack frame + + The stack pointer may not be set up in a frameless function (e.g. a + simple leaf function). + + l.sw fp_loc(r1),r2 # old FP saved in new stack frame + l.addi r2,r1,frame_size # FP now points to base of new stack frame + + The frame pointer is not necessarily saved right at the end of the stack + frame - OR1K saves enough space for any args to called functions right + at the end (this is a difference from the Architecture Manual). + + l.sw lr_loc(r1),r9 # Link (return) address + + The link register is usally saved at fp_loc - 4. It may not be saved at + all in a leaf function. + + l.sw reg_loc(r1),ry # Save any callee saved regs + + The offsets x for the callee saved registers generally (always?) rise in + increments of 4, starting at fp_loc + 4. If the frame pointer is + omitted (an option to GCC), then it may not be saved at all. There may + be no callee saved registers. + + So in summary none of this may be present. However what is present + seems always to follow this fixed order, and occur before any + substantive code (it is possible for GCC to have more flexible + scheduling of the prologue, but this does not seem to occur for OR1K). + + ANALYSIS + ======== + + This prolog is used, even for -O3 with GCC. + + All this analysis must allow for the possibility that the PC is in the + middle of the prologue. Data in the cache should only be set up insofar + as it has been computed. + + HOWEVER. The frame_id must be created with the SP *as it will be* at + the end of the Prologue. Otherwise a recursive call, checking the frame + with the PC at the start address will end up with the same frame_id as + the caller. + + A suite of "helper" routines are used, allowing reuse for + or1k_skip_prologue(). + + Reportedly, this is only valid for frames less than 0x7fff in size. */ + +static struct trad_frame_cache * +or1k_frame_cache (struct frame_info *this_frame, void **prologue_cache) +{ + struct gdbarch *gdbarch; + struct trad_frame_cache *info; + + CORE_ADDR this_pc; + CORE_ADDR this_sp; + CORE_ADDR this_sp_for_id; + int frame_size = 0; + + CORE_ADDR start_addr; + CORE_ADDR end_addr; + + if (or1k_debug) + fprintf_unfiltered (gdb_stdlog, + "or1k_frame_cache, prologue_cache = 0x%p\n", + *prologue_cache); + + /* Nothing to do if we already have this info. */ + if (NULL != *prologue_cache) + return (struct trad_frame_cache *) *prologue_cache; + + /* Get a new prologue cache and populate it with default values. */ + info = trad_frame_cache_zalloc (this_frame); + *prologue_cache = info; + + /* Find the start address of this function (which is a normal frame, even + if the next frame is the sentinel frame) and the end of its prologue. */ + this_pc = get_frame_pc (this_frame); + find_pc_partial_function (this_pc, NULL, &start_addr, NULL); + + /* Get the stack pointer if we have one (if there's no process executing + yet we won't have a frame. */ + this_sp = (NULL == this_frame) ? 0 : + get_frame_register_unsigned (this_frame, OR1K_SP_REGNUM); + + /* Return early if GDB couldn't find the function. */ + if (start_addr == 0) + { + if (or1k_debug) + fprintf_unfiltered (gdb_stdlog, " couldn't find function\n"); + + /* JPB: 28-Apr-11. This is a temporary patch, to get round GDB + crashing right at the beginning. Build the frame ID as best we + can. */ + trad_frame_set_id (info, frame_id_build (this_sp, this_pc)); + + return info; + } + + /* The default frame base of this frame (for ID purposes only - frame + base is an overloaded term) is its stack pointer. For now we use the + value of the SP register in this frame. However if the PC is in the + prologue of this frame, before the SP has been set up, then the value + will actually be that of the prev frame, and we'll need to adjust it + later. */ + trad_frame_set_this_base (info, this_sp); + this_sp_for_id = this_sp; + + /* The default is to find the PC of the previous frame in the link + register of this frame. This may be changed if we find the link + register was saved on the stack. */ + trad_frame_set_reg_realreg (info, OR1K_NPC_REGNUM, OR1K_LR_REGNUM); + + /* We should only examine code that is in the prologue. This is all code + up to (but not including) end_addr. We should only populate the cache + while the address is up to (but not including) the PC or end_addr, + whichever is first. */ + gdbarch = get_frame_arch (this_frame); + end_addr = or1k_skip_prologue (gdbarch, start_addr); + + /* All the following analysis only occurs if we are in the prologue and + have executed the code. Check we have a sane prologue size, and if + zero we are frameless and can give up here. */ + if (end_addr < start_addr) + error ("end addr 0x%08x is less than start addr 0x%08x\n", + (unsigned int) end_addr, (unsigned int) start_addr); + + if (end_addr == start_addr) + frame_size = 0; + else + { + /* We have a frame. Look for the various components. */ + CORE_ADDR addr = start_addr; /* Where we have got to */ + uint32_t inst = or1k_fetch_instruction (gdbarch, addr); + + unsigned int ra, rb, rd; /* for instruction analysis */ + int simm; + + /* Look for the new stack pointer being set up. */ + if (or1k_analyse_l_addi (inst, &rd, &ra, &simm) + && (OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) + && (simm < 0) && (0 == (simm % 4))) + { + frame_size = -simm; + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + + /* If the PC has not actually got to this point, then the frame + base will be wrong, and we adjust it. + + If we are past this point, then we need to populate the stack + accordingly. */ + if (this_pc <= addr) + { + /* Only do if executing. */ + if (0 != this_sp) + { + this_sp_for_id = this_sp + frame_size; + trad_frame_set_this_base (info, this_sp_for_id); + } + } + else + { + /* We are past this point, so the stack pointer of the prev + frame is frame_size greater than the stack pointer of this + frame. */ + trad_frame_set_reg_value (info, OR1K_SP_REGNUM, + this_sp + frame_size); + } + } + + /* From now on we are only populating the cache, so we stop once we + get to either the end OR the current PC. */ + end_addr = (this_pc < end_addr) ? this_pc : end_addr; + + /* Look for the frame pointer being manipulated. */ + if ((addr < end_addr) + && or1k_analyse_l_sw (inst, &simm, &ra, &rb) + && (OR1K_SP_REGNUM == ra) && (OR1K_FP_REGNUM == rb) + && (simm >= 0) && (0 == (simm % 4))) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + + /* At this stage, we can find the frame pointer of the previous + frame on the stack of the current frame. */ + trad_frame_set_reg_addr (info, OR1K_FP_REGNUM, this_sp + simm); + + /* Look for the new frame pointer being set up. */ + if ((addr < end_addr) + && or1k_analyse_l_addi (inst, &rd, &ra, &simm) + && (OR1K_FP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) + && (simm == frame_size)) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + + /* If we have got this far, the stack pointer of the previous + frame is the frame pointer of this frame. */ + trad_frame_set_reg_realreg (info, OR1K_SP_REGNUM, + OR1K_FP_REGNUM); + } + } + + /* Look for the link register being saved. */ + if ((addr < end_addr) + && or1k_analyse_l_sw (inst, &simm, &ra, &rb) + && (OR1K_SP_REGNUM == ra) && (OR1K_LR_REGNUM == rb) + && (simm >= 0) && (0 == (simm % 4))) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + + /* If the link register is saved in the this frame, it holds the + value of the PC in the previous frame. This overwrites the + previous information about finding the PC in the link + register. */ + trad_frame_set_reg_addr (info, OR1K_NPC_REGNUM, this_sp + simm); + } + + /* Look for arguments or callee-saved register being saved. The + register must be one of the arguments (r3-r8) or the 10 callee + saved registers (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, + r30). The base register must be the FP (for the args) or the SP + (for the callee_saved registers). */ + while (addr < end_addr) + { + if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) + && (((OR1K_FP_REGNUM == ra) && or1k_is_arg_reg (rb)) + || ((OR1K_SP_REGNUM == ra) + && or1k_is_callee_saved_reg (rb))) + && (0 == (simm % 4))) + { + addr += OR1K_INSTLEN; + inst = or1k_fetch_instruction (gdbarch, addr); + + /* The register in the previous frame can be found at this + location in this frame. */ + trad_frame_set_reg_addr (info, rb, this_sp + simm); + } + else + break; /* Not a register save instruction. */ + } + } + + /* Build the frame ID */ + trad_frame_set_id (info, frame_id_build (this_sp_for_id, start_addr)); + + if (or1k_debug) + { + fprintf_unfiltered (gdb_stdlog, " this_sp_for_id = 0x%p\n", + (void *) this_sp_for_id); + fprintf_unfiltered (gdb_stdlog, " start_addr = 0x%p\n", + (void *) start_addr); + } + + return info; +} + +/* Implement the this_id function for the stub unwinder. */ + +static void +or1k_frame_this_id (struct frame_info *this_frame, + void **prologue_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *info = or1k_frame_cache (this_frame, + prologue_cache); + + trad_frame_get_id (info, this_id); +} + +/* Implement the prev_register function for the stub unwinder. */ + +static struct value * +or1k_frame_prev_register (struct frame_info *this_frame, + void **prologue_cache, int regnum) +{ + struct trad_frame_cache *info = or1k_frame_cache (this_frame, + prologue_cache); + + return trad_frame_get_register (info, this_frame, regnum); +} + +/* Data structures for the normal prologue-analysis-based unwinder. */ + +static const struct frame_unwind or1k_frame_unwind = { + NORMAL_FRAME, + default_frame_unwind_stop_reason, + or1k_frame_this_id, + or1k_frame_prev_register, + NULL, + default_frame_sniffer, + NULL, +}; + +/* Architecture initialization for OpenRISC 1000. */ + +static struct gdbarch * +or1k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + const struct bfd_arch_info *binfo; + struct tdesc_arch_data *tdesc_data = NULL; + const struct target_desc *tdesc = info.target_desc; + + /* Find a candidate among the list of pre-declared architectures. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (NULL != arches) + return arches->gdbarch; + + /* None found, create a new architecture from the information + provided. Can't initialize all the target dependencies until we + actually know which target we are talking to, but put in some defaults + for now. */ + binfo = info.bfd_arch_info; + tdep = XCNEW (struct gdbarch_tdep); + tdep->bytes_per_word = binfo->bits_per_word / binfo->bits_per_byte; + tdep->bytes_per_address = binfo->bits_per_address / binfo->bits_per_byte; + gdbarch = gdbarch_alloc (&info, tdep); + + /* Target data types */ + set_gdbarch_short_bit (gdbarch, 16); + set_gdbarch_int_bit (gdbarch, 32); + set_gdbarch_long_bit (gdbarch, 32); + set_gdbarch_long_long_bit (gdbarch, 64); + set_gdbarch_float_bit (gdbarch, 32); + set_gdbarch_float_format (gdbarch, floatformats_ieee_single); + set_gdbarch_double_bit (gdbarch, 64); + set_gdbarch_double_format (gdbarch, floatformats_ieee_double); + set_gdbarch_long_double_bit (gdbarch, 64); + set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double); + set_gdbarch_ptr_bit (gdbarch, binfo->bits_per_address); + set_gdbarch_addr_bit (gdbarch, binfo->bits_per_address); + set_gdbarch_char_signed (gdbarch, 1); + + /* Information about the target architecture */ + set_gdbarch_return_value (gdbarch, or1k_return_value); + set_gdbarch_breakpoint_kind_from_pc (gdbarch, + or1k_breakpoint::kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, + or1k_breakpoint::bp_from_kind); + set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); + + /* Register architecture */ + set_gdbarch_num_regs (gdbarch, OR1K_NUM_REGS); + set_gdbarch_num_pseudo_regs (gdbarch, OR1K_NUM_PSEUDO_REGS); + set_gdbarch_sp_regnum (gdbarch, OR1K_SP_REGNUM); + set_gdbarch_pc_regnum (gdbarch, OR1K_NPC_REGNUM); + set_gdbarch_ps_regnum (gdbarch, OR1K_SR_REGNUM); + set_gdbarch_deprecated_fp_regnum (gdbarch, OR1K_FP_REGNUM); + + /* Functions to analyse frames */ + set_gdbarch_skip_prologue (gdbarch, or1k_skip_prologue); + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_frame_align (gdbarch, or1k_frame_align); + set_gdbarch_frame_red_zone_size (gdbarch, OR1K_FRAME_RED_ZONE_SIZE); + + /* Functions to access frame data */ + set_gdbarch_unwind_pc (gdbarch, or1k_unwind_pc); + set_gdbarch_unwind_sp (gdbarch, or1k_unwind_sp); + + /* Functions handling dummy frames */ + set_gdbarch_call_dummy_location (gdbarch, ON_STACK); + set_gdbarch_push_dummy_code (gdbarch, or1k_push_dummy_code); + set_gdbarch_push_dummy_call (gdbarch, or1k_push_dummy_call); + set_gdbarch_dummy_id (gdbarch, or1k_dummy_id); + + /* Frame unwinders. Use DWARF debug info if available, otherwise use our + own unwinder. */ + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &or1k_frame_unwind); + + /* Get a CGEN CPU descriptor for this architecture. */ + { + + const char *mach_name = binfo->printable_name; + enum cgen_endian endian = (info.byte_order == BFD_ENDIAN_BIG + ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); + + tdep->gdb_cgen_cpu_desc = + or1k_cgen_cpu_open (CGEN_CPU_OPEN_BFDMACH, mach_name, + CGEN_CPU_OPEN_ENDIAN, endian, CGEN_CPU_OPEN_END); + + or1k_cgen_init_asm (tdep->gdb_cgen_cpu_desc); + } + + /* If this mach has a delay slot. */ + if (binfo->mach == bfd_mach_or1k) + set_gdbarch_single_step_through_delay (gdbarch, + or1k_single_step_through_delay); + + if (!tdesc_has_registers (info.target_desc)) + /* Pick a default target description. */ + tdesc = tdesc_or1k; + + /* Check any target description for validity. */ + if (tdesc_has_registers (tdesc)) + { + const struct tdesc_feature *feature; + int valid_p; + int i; + + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.or1k.group0"); + if (feature == NULL) + return NULL; + + tdesc_data = tdesc_data_alloc (); + + valid_p = 1; + + for (i = 0; i < OR1K_NUM_REGS; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + or1k_reg_names[i]); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + } + + if (tdesc_data != NULL) + { + /* If we are using tdesc, register our own reggroups, otherwise we + will used the defaults. */ + reggroup_add (gdbarch, general_reggroup); + reggroup_add (gdbarch, system_reggroup); + reggroup_add (gdbarch, float_reggroup); + reggroup_add (gdbarch, vector_reggroup); + reggroup_add (gdbarch, all_reggroup); + reggroup_add (gdbarch, save_reggroup); + reggroup_add (gdbarch, restore_reggroup); + + tdesc_use_registers (gdbarch, tdesc, tdesc_data); + } + + return gdbarch; +} + +/* Dump the target specific data for this architecture. */ + +static void +or1k_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (NULL == tdep) + return; /* Nothing to report */ + + fprintf_unfiltered (file, "or1k_dump_tdep: %d bytes per word\n", + tdep->bytes_per_word); + fprintf_unfiltered (file, "or1k_dump_tdep: %d bytes per address\n", + tdep->bytes_per_address); +} + + +void +_initialize_or1k_tdep (void) +{ + /* Register this architecture. */ + gdbarch_register (bfd_arch_or1k, or1k_gdbarch_init, or1k_dump_tdep); + + initialize_tdesc_or1k (); + + /* Debugging flag. */ + add_setshow_boolean_cmd ("or1k", class_maintenance, &or1k_debug, + _("Set OpenRISC debugging."), + _("Show OpenRISC debugging."), + _("When on, OpenRISC specific debugging is enabled."), + NULL, + show_or1k_debug, + &setdebuglist, &showdebuglist); +} diff --git a/gdb/or1k-tdep.h b/gdb/or1k-tdep.h new file mode 100644 index 0000000..edcad88 --- /dev/null +++ b/gdb/or1k-tdep.h @@ -0,0 +1,56 @@ +/* Definitions to target GDB to OpenRISC 1000 32-bit targets. + Copyright (C) 2008-2017 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + With this program. If not, see <http://www.gnu.org/licenses/>. */ + + +#ifndef OR1K_TDEP__H +#define OR1K_TDEP__H + +#ifndef TARGET_OR1K +#define TARGET_OR1K +#endif + +#include "opcodes/or1k-desc.h" +#include "opcodes/or1k-opc.h" + +/* General Purpose Registers */ +#define OR1K_ZERO_REGNUM 0 +#define OR1K_SP_REGNUM 1 +#define OR1K_FP_REGNUM 2 +#define OR1K_FIRST_ARG_REGNUM 3 +#define OR1K_LAST_ARG_REGNUM 8 +#define OR1K_LR_REGNUM 9 +#define OR1K_FIRST_SAVED_REGNUM 10 +#define OR1K_RV_REGNUM 11 +#define OR1K_PPC_REGNUM (OR1K_MAX_GPR_REGS + 0) +#define OR1K_NPC_REGNUM (OR1K_MAX_GPR_REGS + 1) +#define OR1K_SR_REGNUM (OR1K_MAX_GPR_REGS + 2) + +/* Properties of the architecture. GDB mapping of registers is all the GPRs + and SPRs followed by the PPC, NPC and SR at the end. Red zone is the area + past the end of the stack reserved for exception handlers etc. */ + +#define OR1K_MAX_GPR_REGS 32 +#define OR1K_NUM_PSEUDO_REGS 0 +#define OR1K_NUM_REGS (OR1K_MAX_GPR_REGS + 3) +#define OR1K_STACK_ALIGN 4 +#define OR1K_INSTLEN 4 +#define OR1K_INSTBITLEN (OR1K_INSTLEN * 8) +#define OR1K_NUM_TAP_RECORDS 8 +#define OR1K_FRAME_RED_ZONE_SIZE 2536 + +#endif /* OR1K_TDEP__H */ |